So I have this python thing that needs to process a file.
First it was:
my_project/
├── script.py
And I would simply run it with python script.py file.csv
.
Then it grew and became:
my_project/
├── script.py
├── util/
│ └── string_util.py
├── services/
│ └── my_service.py
(There is an empty __init__.py
in every directory)
But now my_service.py
would like to use string_util.py
and it's so damn not straightforward how to do this nicely.
I would like to do from ..util import string_util
in my_service.py
(which is imported into script.py
with from services import my_service
), but that does not work with python script.py
since my_service
's __name__
is then only services.my_service
(and I get the Attempted relative import beyond toplevel package
)
I can do
cd ..
andpython -m my_project.script
, but that seems so unnatural and would be really bad to put it in the README for the instructions how to run this.Right now I'm solving it with the ugly
sys.path.append()
hack.
What other options do I have?
This is bordering on opinion, but I'll share my take on this.
You should look at your project a different way. Choose one execution point, and reference your imports from there, to avoid all of the odd relative imports you are trying to work around. So, looking at your project structure:
As you are currently doing, execute your code from within
my_project
. That way all your imports should be with respect to that point. Therefore, your imports actually look like this:Another way to think about this, is that if you are moving your project around, or have a CI, you need to make sure you specify what is the project root you want to execute from. Keeping these things in mind, and specifying the single execution point of where your project should be executed, will make your life much easier when it comes to dealing with structuring your packages and modules and referencing them appropriately, allowing other systems to properly use your project without having to deal with odd relative imports.
Hope this helps.