What is a very *simple* way to structure a python project?
Asked Answered
R

1

7

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__.pyin 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 .. and python -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?

Rebutter answered 8/3, 2016 at 23:9 Comment(1)
I can share my take on this, but it will be posted as an answer. Le me know what you think.Satisfaction
S
2

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:

my_project/
├── script.py
├── util/
│   └── string_util.py
├── services/
│   └── my_service.py

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:

# my_service.py

from util.string_util import foo

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.

Satisfaction answered 9/3, 2016 at 0:11 Comment(1)
Wow, this actually did not occur to me at all. And it's so simple. So I can just remove the .. from the from ..util import string_util and everything's cool. (if I'm cool with absolute imports here, which I am.) It sure does help. Thanks!Rebutter

© 2022 - 2024 — McMap. All rights reserved.