Python packages and imports - python

I wanted to know if you can use the import statement in python from a directory that is not your local directory if that directory is not a package? Also, do all the directories on your system path have to be packages? If you add a relative path to your system path, what is it relative to?

you can alter sys.path in order to achieve all the results you are asking for.
Yes you can. To add a directory that is not your local directory:
import sys
sys.path += '/your_path/your_subpath/' # absolute paths
import your_package
If you need to load the module from an arbitrary path in the filesystem without adding it to sys.path you can use also imp.load_module
do all the directories on your system path have to be packages? No, they do not
If you add a relative path to your system path, what is it relative to?
to the directory containing the script that was used to invoke the Python interpreter.
I suggest, however, to set it in this way:
import sys,os
sys.path.append(os.path.realpath('..'))
or from the path of the script:
import sys,os
sys.path.append(os.path.realpath(os.path.join(os.path.dirname(sys.argv[0]), '..')))
both the examples work also from interactive shells. Both examples ensure the relative path is what you meant, regardless of the OS
see also this post for more details on relative paths in python

That's really 3 different questions:
I wanted to know if you can use the import statement in python from a directory that is not your local directory if that directory is not a package
Yes, you can.
Also, do all the directories on your system path have to be packages?
No, they don't.
If you add a relative path to your system path, what is it relative to?
Relative to the current working directory.

Related

Set working directory in Python / Spyder so that it's reproducible

Coming from R, using setwd to change the directory is a big no-no against reproducibility because others do not have the same directory structure as mine. Hence, it's recommended to use relative path from the location of the script.
IDEs slightly complicate this because they set their own working directory. In Rstudio, I can easily get around this problem with Rstudio's projects, setting the project's directory to be my script folder.
With Python and Spyder, there doesn't seem to be any solution. Spyder does not have a feature like Rstudio's project. Setting the directory to the script's location does not work while doing interactive analysis (since __file__ is not available).
What to do so that the working directory in Python / Spyder is reproducible?
To do this automatically, put this at the beginning of your script:
from os import chdir, getcwd
wd=getcwd()
chdir(wd)
In the interim, you can use os.chdir
import os
os.chdir('C:\Users\me\Documents')
It appears they did consider this as a feature in Spyder based on this GitHub ticket, but it is still waiting implementation as of mid-May:
We could add an option to the Run dialog to automatically set the
working directory to the one your script is being ran.
However, someone else will have to implement it. We're pretty busy
with other things at the moment, sorry.
https://github.com/spyder-ide/spyder/issues/3154
#ccordoba12 ccordoba12 added this to the wishlist milestone on May 14
as I wrote here, Mark8888 pointed out to run the whole script (run file (F5)) instead of just pieces of the script
this way multiple approaches should work to get the script file location and change the current working directory
import os
# directory of script file
print(os.path.abspath(os.path.dirname(__file__)))
# change current working directory
os.chdir(os.path.abspath(os.path.dirname(__file__)))
# current working directory
print(os.getcwd())
also
import os
import sys
# directory of script file
print(os.path.abspath(os.path.dirname(sys.argv[0])))
# change current working directory
os.chdir(os.path.abspath(os.path.dirname(sys.argv[0])))
# current working directory
print(os.getcwd())
Well, there are a lot of things that you can try!
1. Change the directory to the current directory in the toolbar.
2. Change the Global directory to the current directory in Preferences>Global Working Directory. Click 'the current file directory' radio button.
Hope it helps!
I tried this and it works.
import os
abspath = os.path.abspath('') ## String which contains absolute path to the script file
os.chdir(abspath) ## Setting up working directory

How to import a python module from a relative path?

I've got the following file structure:
I'm trying to initialize some objects in main.py that belong to modules in the Listener, Parser and Configurations folders.
I understand I can't just write import listener since it's not in the same path.
What simple ways are there for the imports to work without adding the paths to the PYTHONPATH env variable?
Is there a way to make it work on any machine "out of the box" without the need to add the paths to PYTHONPATH or any solution like that? Preferably something with a relative path like in C++?
Possible duplicate: Importing from a relative path in Python
In short, you need to programmatically define PYTHONPATH in main.py, something like:
import sys, os
sys.path.append(os.path.dirname(__file__))
This implicitly adds current directory to PYTHONPATH. Rest of the part is straightforward
Create __init__.py file in each of the directories. After that, each of the modules can be imported as from Listener import ... or from Misc import ... etc.
The approach works 'out of box' without redefining any environmental variable.

Using .pth files

I am trying to make a module discoverable on a system where I don't have write access to the global site-packages directory, and without changing the environment (PYTHONPATH). I have tried to place a .pth file in the same directory as a script I'm executing, but it seems to be ignored. E.g., I created a file extras.pth with the following content:
N:\PythonExtras\lib\site-packages
But the following script, placed and run in the same directory, prints False.
import sys
print r"N:\PythonExtras\lib\site-packages" in sys.paths
The only directory in sys.path to which I have write access is the directory containing the script. Is there another (currently non-existent) directory where I could place extras.pth and have it be seen? Is there a better way to go about this?
I'm using python 2.7 on Windows. All .pth questions I could find here use the system module directories.
Edit: I've tracked down the Windows per-user installation directory, at %APPDATA%\Python\Python27\site-packages. I can place a module there and it will be imported, but if I put a .pth file there, it has no effect. Is this really not supposed to work, or am I doing something wrong?
As described in the documentation, PTH files are only processed if they are in the site-packages directory. (More precisely, they are processed if they are in a "site directory", but "site directory" itself is a setting global to the Python installation and does not depend on the current directory or the directory where the script resides.)
If the directory containing your script is on sys.path, you could create a sitecustomize.py in that directory. This will be loaded when Python starts up. Inside sitecustomize.py, you can do:
import site
site.addsitedir('/some/dir/you/want/on/the/path')
This will not only add that directory, but will add it as a "site directory", causing PTH files there to be processed. This is handy if you want to create your own personal site-packages-like-directory.
If you only need to add one or two directories to the path, you could do so more simply. Just create a tiny Python library that manipulates sys.path, and then import that library from your script. Something like:
# makepath.py
import sys
sys.path.append('/whatever/dir/you/want')
# script.py
import makepath
Edit: Again, according to the documentation, there is the possibility of a site-specific directory in %APPDATA%\Python\PythonXY\site-packages (on Windows). You could try that, if in fact you have write access to that (and not just to your script directory).
You can make a .pth (path) file in a directory already in sys.path so it can be included/

How does python find a module file if the import statement only contains the filename?

Everywhere I see Python code importing modules using import sys or import mymodule
How does the interpreter find the correct file if no directory or path is provided?
http://docs.python.org/3/tutorial/modules.html#the-module-search-path
6.1.2. The Module Search Path
When a module named spam is imported, the interpreter first searches for a built-in module with that name. If not found, it then searches for a file named spam.py in a list of directories given by the variable sys.path. sys.path is initialized from these locations:
The directory containing the input script (or the current directory when no file is specified).
PYTHONPATH (a list of directory names, with the same syntax as the shell variable PATH).
The installation-dependent default.
Note: On file systems which support symlinks, the directory containing the input script is calculated after the symlink is followed. In other words the directory containing the symlink is not added to the module search path.
After initialization, Python programs can modify sys.path. The directory containing the script being run is placed at the beginning of the search path, ahead of the standard library path. This means that scripts in that directory will be loaded instead of modules of the same name in the library directory. This is an error unless the replacement is intended. See section Standard Modules for more information.
For information on the "installation-specific default", see documentation on the site module.
Also, you can see what the current path is by using the sys module
import sys
print(sys.path)
It uses the PYTHONPATH, set as an environment variable, to find packages (folders containing __init__.py files) and modules (or, if already loaded once, retrieves the module object from sys.modules).
Python has a path variable just like the one you have inside your terminal. Python looks for modules in folders inside that path, or in the folder where your program is located.

Importing in Python

In Python 2.5, I import modules by changing environment variables. It works, but using site-packages does not. Is there another way to import modules in directories other than C:\Python25 ?
On way is with PYTHONPATH environment variable. Other one is to add path to sys.path either directly by sys.path.append(path) or by defining .pth files and add them to with site.addsitedir(dirWithPths). Path files (.pth) are simple text files with a path in each line. Every .pth file in dirWithPths will be read.
Append the location to the module to sys.path.
Edit: (to counter the post below ;-) )
os.path does something completely different. You need to use sys.path.
sys.path.append("/home/me/local/modules")
Directories added to the PYTHONPATH environment variable are searched after site-packages, so if you have a module in site-packages with the same name as the module you want from your PYTHONPATH, the site-packages version will win. Also, you may need to restart your interpreter and the shell that launched it for the change to the environment variable to take effect.
If you want to add a directory to the search path at run time, without restarting your program, add the directory to sys.path. For example:
import sys
sys.path.append(newpath)
If you want your new directory to be searched before site-packages, put the directory at the front of the list, like this:
import sys
sys.path.insert(0, newpath)
sys.path is a list to which you can append custom paths to search like this:
sys.path.append("/home/foo")

Categories