I do a lot of work on different projects (I'm a scientist) in a fairly standardised directory structure. e.g.:
project
/analyses/
/lib
/doc
/results
/bin
I put all my various utility scripts in /bin/ because cleanliness is next to godliness. However, I have to hard code paths (e.g. ../../x/y/z) and then I have to run things within ./bin/ or they break.
I've used Django and that has /manage.py which runs various django-things and automatically handles the path. I've also used fabric to run various user defined functions.
Question: How do I do something similar? and what's the best way? I can easily write something in /manage.py to inject the root dir into sys.path etc, but then I'd like to be able to do "./manage.py foo" which would run /bin/foo.py. Or is it possible to get fabric to call executables from a certain directory?
Basically - I want something easy and low maintenance. I want to be able to drop an executable script/file/whatever into ./bin/ and not have to deal with path issues or import issues.
What is the best way to do this?
To use it, you just pass a path or filename into a new Path() object using forward slashes and it handles the rest: Notice two things here: You should use forward slashes with pathlib functions. The Path() object will convert forward slashes into the correct kind of slash for the current operating system.
Python looks for modules in “sys. It looks for a file called a_module.py in the directories listed in the variable sys. path .
In general, try to keep your runtime at top-level. This will straighten out your imports tremendously.
If you have to do a lot of import addressing with relative imports, there's probably a better way.
Other poster's have mentioned the PYTHONPATH
. That's a great way to do it permanently in your shell.
If you don't want to/aren't able to manipulate the PYTHONPATH
project path directly you can use sys.path
to get yourself out of relative import hell.
sys.path.append
sys.path
is just a list internally. You can append to it to add stuff to into your path.
Say I'm in /bin
and there's a library markdown
in lib/
. You can append a relative paths with sys.path
to import what you want.
import sys
sys.path.append('../lib')
import markdown
print markdown.markdown("""
Hello world!
------------
""")
Word to the wise: Don't get too crazy with your sys.path additions. Keep your schema simple to avoid yourself a lot confusion.
Overly eager imports can sometimes lead to cases where a python module needs to import itself, at which point execution will halt!
__init__.py
Another great trick is creating python packages by adding __init__.py
files. __init__.py
gets loaded before any other modules in the directory, so it's a great way to add imports across the entire directory. This makes it an ideal spot to add sys.path
hackery.
You don't even need to necessarily add anything to the file. It's sufficient to just do touch __init__.py
at the console to make a directory a package.
See this SO post for a more concrete example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With