Importing from above path on python for windows
Solution 1:
The proper way to handle this would be putting everything that needs to know about each other under a shared package, then the individual sub-packages and sub-modules can be accessed through that package. But this will also require moving the application's entrypoint to either the package, or a module that's a sibling of the package in the directory and can import it. If moving the entrypoint is an issue, or something quick and dirty is required for prototyping, Python also implements a couple other methods for affecting where imports search for modules which can be found near the end of the answer.
For the package approach, let's say you have this structure and want to import something between the two modules:
.
├── bar_dir
│ └── bar.py
└── foo_dir
└── foo.py
Currently, the two packages do not know about each other because Python only adds the entrypoint file's parent (either bar_dir
or foo_dir
depending on which file you run) to the import search path, so we have to tell them about each other in some way, this is done through the top level package they'll both share.
.
└── top_level
├── __init__.py
├── bar_dir
│ ├── __init__.py
│ └── bar.py
└── foo_dir
├── __init__.py
└── foo.py
This is the package layout we need, but to be able to use the package in imports, it has to be initialized, which means we either need to import the top_level
package (e.g. from a main.py
entrypoint), or define it as a runnable module by implementing a __main__.py
file inside of it, next to __init__.py
, which is ran when doing python -m top_level
.
This entrypoint module would then run the module which you were running beforehand.
The __init__.py
files are used to mark the directories as proper packages and are ran when the package is imported to initialize its namespace.
With this done the packages now can see each other and can be accessed through either absolute or relative imports, an absolute import would being with the top_level
package and use the whole dotted path to the module/package we need to import, e.g. from top_level.bar_dir import bar
can be used to import bar
.
Packages also allow relative imports which are a special form of a from-style import that begins with one or more dots, where each dot means the import goes up one package - from the foo
module from . import module
would attempt to import module
from the foo_dir
package, from .. import module
would search for it in the top_level
package etc.
One thing to note is that importing a package doesn't initialize the modules under it unless it's an explicit import of that module, for example only importing top_level
won't make foo_dir
and bar_dir
available in its namespace unless they're imported directly through import top_level.foo_dir
/top_level.bar_dir
or the package's __init__.py
added them to the package's namespace through its own import.
If this doesn't work in your structure, an another way is to let Python know where to search for your modules by adding to its module search path, this can be done either at runtime by inserting path strings into the sys.path
list, or through the PYTHONPATH environment variable.
Continuing with the above example with a scenario and importing bar
from foo
, an entry for the bar_dir
directory (or the directory above it) can be added to the sys.path
list or the aforementioned environment variable. After that import bar
(or from bar_dir import bar
if the parent was added) can be used to import the module, just as if they were next to each other. The inserted path can also be relative, but that is prone to breakage with a changing cwd.