Primos
Primos

Reputation: 1

Running Python script from a package... or not

So I have this little script that I want to run:

do_something.py

from do_something import do_it

do_it()

Now this 'do_something' package has three files in it:

do_something/__init__.py

from .things_to_do import do_it

do_something/things_to_do.py

from .the_thing import the_thing

def do_it():
    print(f"Do it with {the_thing}")

do_something/the_thing.py

the_thing = "The thing"

I can run my script with python do_something.py and I get the correct output.

Do it with The thing

Now what I need is being able to run the thing without the script, using python do_something (without the '.py' extension) as well as from the original .py script (for historical reasons).

So I created:

do_something/__main__.py

from .things_to_do import do_it

do_it()

Unfortunately, this breaks in __main__.py, line 1:

    from .things_to_do import do_it
ImportError: attempted relative import with no known parent package

If I remove the '.' in the import directive, the error now appears in line 1 of things_to_do.py...

    from .the_thing import the_thing
ImportError: attempted relative import with no known parent package

How would you fix that code so that python do_something or python do_something.py are equivalent?

Thanks a lot!

Note: I also tried to mess with sys.path with very little success...

Upvotes: 0

Views: 80

Answers (1)

Ahmed AEK
Ahmed AEK

Reputation: 17526

the correct solution is to use do_something.py and run python -m do_something, and have do_something.py directory on your PYTHONPATH or current directory.

the bad solution is to create a file do_something that has no extension next to your do_something.py and have the code inside do_something run your do_something.py.

import runpy
import os
current_folder = os.path.dirname(os.path.abspath(__file__))
runpy.run_path(os.path.join(current_folder,"do_something.py"),run_name=__name__)

now this is a very bad design, and the proper way is to use python's -m arguments as in the first line of this answer, but this will just isolate the "corruption" to one file that has no logic.

Upvotes: 1

Related Questions