Reputation: 1965
I have a directory full of scripts (let's say project/bin
). I also have a library located in project/lib
and want the scripts to automatically load it. This is what I normally use at the top of each script:
#!/usr/bin/python
from os.path import dirname, realpath, sep, pardir
import sys
sys.path.append(dirname(realpath(__file__)) + sep + pardir + sep + "lib")
# ... now the real code
import mylib
This is kind of cumbersome, ugly, and has to be pasted at the beginning of every file. Is there a better way to do this?
Really what I'm hoping for is something as smooth as this:
#!/usr/bin/python
import sys.path
from os.path import pardir, sep
sys.path.append_relative(pardir + sep + "lib")
import mylib
Or even better, something that wouldn't break when my editor (or someone else who has commit access) decides to reorder the imports as part of its clean-up process:
#!/usr/bin/python --relpath_append ../lib
import mylib
That wouldn't port directly to non-posix platforms, but it would keep things clean.
Upvotes: 161
Views: 354041
Reputation: 1
Add these two lines before your module:
import sys,os
sys.path.append(os.pardir)
My file structure as below:
.
├── common
│ ├── __init__.py
│ └── module.py
├── main.py
└── tool
├── __init__.py
└── test.py
and my test code:
import sys,os
sys.path.append(os.pardir)
from common import module
def foo(a,b):
return module.sum(a,b)
if __name__ == '__main__':
print(foo(1,2))
So that I can run my code in tool module elegantly in terminal, I use:
(base) robben@Ro tool % python test.py
3
Upvotes: 0
Reputation: 26812
Using python 3.4+
import sys
from pathlib import Path
# As PosixPath
sys.path.append(Path(__file__).parent / "lib")
# Or as str as explained in https://stackoverflow.com/a/32701221/11043825
sys.path.append(str(Path(__file__).parent / "lib"))
Upvotes: 22
Reputation: 3943
This is how I do it many times:
import os
import sys
current_path = os.path.dirname(os.path.abspath(__file__))
sys.path.append(os.path.join(current_path, "lib"))
Upvotes: 8
Reputation: 3102
There is a problem with every answer provided that can be summarized as "just add this magical incantation to the beginning of your script. See what you can do with just a line or two of code." They will not work in every possible situation!
For example, one such magical incantation uses __file__
. Unfortunately, if you package your script using cx_Freeze or you are using IDLE, this will result in an exception.
Another such magical incantation uses os.getcwd(). This will only work if you are running your script from the command prompt and the directory containing your script is the current working directory (that is you used the cd command to change into the directory prior to running the script). Eh gods! I hope I do not have to explain why this will not work if your Python script is in the PATH somewhere and you ran it by simply typing the name of your script file.
Fortunately, there is a magical incantation that will work in all the cases I have tested. Unfortunately, the magical incantation is more than just a line or two of code.
import inspect
import os
import sys
# Add script directory to sys.path.
# This is complicated due to the fact that __file__ is not always defined.
def GetScriptDirectory():
if hasattr(GetScriptDirectory, "dir"):
return GetScriptDirectory.dir
module_path = ""
try:
# The easy way. Just use __file__.
# Unfortunately, __file__ is not available when cx_Freeze is used or in IDLE.
module_path = __file__
except NameError:
if len(sys.argv) > 0 and len(sys.argv[0]) > 0 and os.path.isabs(sys.argv[0]):
module_path = sys.argv[0]
else:
module_path = os.path.abspath(inspect.getfile(GetScriptDirectory))
if not os.path.exists(module_path):
# If cx_Freeze is used the value of the module_path variable at this point is in the following format.
# {PathToExeFile}\{NameOfPythonSourceFile}. This makes it necessary to strip off the file name to get the correct
# path.
module_path = os.path.dirname(module_path)
GetScriptDirectory.dir = os.path.dirname(module_path)
return GetScriptDirectory.dir
sys.path.append(os.path.join(GetScriptDirectory(), "lib"))
print(GetScriptDirectory())
print(sys.path)
As you can see, this is no easy task!
Upvotes: 5
Reputation: 47
I use:
from site import addsitedir
Then, can use any relative directory !
addsitedir('..\lib')
; the two dots implies move (up) one directory first.
Remember that it all depends on what your current working directory your starting from. If C:\Joe\Jen\Becky, then addsitedir('..\lib') imports to your path C:\Joe\Jen\lib
C:\
|__Joe
|_ Jen
| |_ Becky
|_ lib
Upvotes: 2
Reputation: 459
When we try to run python file with path from terminal.
import sys
#For file name
file_name=sys.argv[0]
#For first argument
dir= sys.argv[1]
print("File Name: {}, argument dir: {}".format(file_name, dir)
Save the file (test.py).
Runing system.
Open terminal and go the that dir where is save file. then write
python test.py "/home/saiful/Desktop/bird.jpg"
Hit enter
Output:
File Name: test, Argument dir: /home/saiful/Desktop/bird.jpg
Upvotes: 0
Reputation: 1833
I see a shebang in your example. If you're running your bin scripts as ./bin/foo.py
, rather than python ./bin/foo.py
, there's an option of using the shebang to change $PYTHONPATH
variable.
You can't change environment variables directly in shebangs though, so you'll need a small helper script. Put this python.sh
into your bin
folder:
#!/usr/bin/env bash
export PYTHONPATH=$PWD/lib
exec "/usr/bin/python" "$@"
And then change the shebang of your ./bin/foo.py
to be #!bin/python.sh
Upvotes: 2
Reputation: 18474
You can run the script with python -m
from the relevant root dir. And pass the "modules path" as argument.
Example: $ python -m module.sub_module.main # Notice there is no '.py' at the end.
Another example:
$ tree # Given this file structure
.
├── bar
│ ├── __init__.py
│ └── mod.py
└── foo
├── __init__.py
└── main.py
$ cat foo/main.py
from bar.mod import print1
print1()
$ cat bar/mod.py
def print1():
print('In bar/mod.py')
$ python foo/main.py # This gives an error
Traceback (most recent call last):
File "foo/main.py", line 1, in <module>
from bar.mod import print1
ImportError: No module named bar.mod
$ python -m foo.main # But this succeeds
In bar/mod.py
Upvotes: 20
Reputation: 1116
If you don't want to change the script content in any ways, prepend the current working directory .
to $PYTHONPATH (see example below)
PYTHONPATH=.:$PYTHONPATH alembic revision --autogenerate -m "First revision"
And call it a day!
Upvotes: 17
Reputation: 88845
If you don't want to edit each file
PYTHONPATH
to your lib
or if you are willing to add a single line to each file, add a import statement at top e.g.
import import_my_lib
keep import_my_lib.py
in bin and import_my_lib
can correctly set the python path to whatever lib
you want
Upvotes: 38
Reputation: 120798
Create a wrapper module project/bin/lib
, which contains this:
import sys, os
sys.path.insert(0, os.path.join(
os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib'))
import mylib
del sys.path[0], sys, os
Then you can replace all the cruft at the top of your scripts with:
#!/usr/bin/python
from lib import mylib
Upvotes: 22
Reputation: 67163
This is what I use:
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__), "lib"))
Upvotes: 168