I have a module in my PYTHONPATH that looks like this:
module.py
from __future__ import absolute_import
import foo
foo.do_something()
print("I am a module!")
I later call this script using python -m module. The script works most of the time but I found that I'm cd'ed into a directory which has a folder with foo/__init__.py inside of it, Python prefers that folder over the other foo module in my PYTHONPATH. I assume it's because Python is treating the foo folder as an implicit, relative import (I'm using Python 2.7).
How do I get Python to not treat the folder in the $PWD as an implicit relative import?
from __future__ import absolute_import does not work
module.py and every other module I use has from __future__ import absolute_import included. So existing questions such as Python: Disabling relative import do not solve this issue.
You can remove the current directory from sys.path, or put the directory of the foo module at the top of sys.path
# at the very beginning of module.py
import sys
sys.path = sys.path[1:]
# or
sys.path.insert(0, <directory of foo module>)
# your code ...
from __future__ import absolute_import
import foo
foo.do_something()
print("I am a module!")
Related
Original project foo:
/foo
/module_a
/module_aa
/module_b
...
Where in the original project, module_b contains imports such as import module_a
In the new project, bar I'd like to have:
/bar
app.py
/foo
/module_a
/module_aa
/module_b
...
However, this breaks the imports in the foo subdirectory:
File "/bar/foo/module_b"
import module_a
ModuleNotFoundError: No module named 'module_a'
What should I do here, to avoid having to update/modify all of the import statements in the foo directory?
This is what relative imports are for. Change
import module_a
to
import .module_a
so that module_b will look in its own package for module_a, rather than in a directory on the Python search path that no longer contains module_a.
This is the cleanest I was able to get it working without modifying any of the original codebase:
/foo/__init__.py
import sys
sys.path.append("../foo")
from module_a import some_function_a
from module_b import some_other_function_b
sys.path.remove("../foo")
app.py
import foo
foo.somefunction_a()
foo.some_other_function_b()
I have already read Python: importing a sub‑package or sub‑module but this:
file content
============================================================================
main.py from mymodule.a import A; A()
mymodule/submodule/__init__.py (empty)
mymodule/submodule/b.py class B: pass
mymodule/__init__.py (empty)
mymodule/a.py (see below)
mymodule/a.py:
import submodule
class A:
def __init__(self):
self.b = submodule.B()
fails with:
File "a.py", line 1, in
import submodule
ModuleNotFoundError: No module named 'submodule'
when lauching the script main.py.
Question: how should I import submodule in mymodule/a.py?
TLDR:
mymodule/a.py:
from . import submodule
# or
import mymodule.submodule as submodule
Once you run your main.py, python adds to your sys.path the path to main.py folder. Python can now search subfolders to find modules trying to be imported. Once you import a.py, python DOES NOT add anything else to sys.path, therefore, to be able import subfolders, you need to do either relative importing (from . import submodule), which you can do because you aren't running a.py as your main file, OR do a full import, doing import mymodule.submodule, since python can search starting on main.py folder.
I have two file
foo.py
main.py
while executing python main.py, I want main.py to import foo.py.
I tried
from . import foo
But python complains
Attempted relative import beyond top-level package
I also tried
from foo import func_name
It works, but that means I can only directly import what get exposed. I want to use it like foo.func_name
Is it possible to import the whole module in a relative way (regardless what the current working directory is)?
The script directory is already a part of the import path. Simply use
import foo
Let's assume I have the following structure.
main.py
/mod1
__init__.py
mod1.py
/mod2
__init__.py
mod2.py
And I have the following line in main.py.
import mod1.mod2
In this case does mod1 also get imported?
Yes; mod1 is imported as well, and you can access mod1 solely as mod1 within your code if you do not write an alias like this import mod1.mod2 as mod2.
Python needs to import the modules consecutively so that it is able to import last module. You can test this by putting print statements in your __init__.py files
Yes. Try this in the interpreter:
import os.path
dir
os
As this shows, os is present in the main namespace.
My app structure is the following:
./mod1/__init__.py
./mod1/utils.py
./mod2/__init__.py
./mod2/test.py
Now in ./mod2/test.py I do:
from mod1 import utils
But I get an ImportError that no module is named utils. What's wrong?!
In order for this to work, the parent directory of mod1 and mod2 must be in sys.path, which probably means that it needs to be in the environment variable PYTHONPATH. Please see the module search path documentation.
One solution that does not require modification of PYTHONPATH is to place your executable script in the parent directory of mod1 and mod2.
Add a top-level folder in the sys.path:
import sys
sys.path.append('path_to_app_folder')
You should write this line before from mod1 import utils. Also add __init__.py:
./mod1/__init__.py
./mod1/utils.py
./mod2/__init__.py
./mod2/test.py
__init__.py
You can dynamically get the path to the app folder from ./mod2/test.py, using os.path.abspath. So, you code for ./mod2/test.py will look like this:
import os
import sys
top_level_folder = os.path.abspath('../')
sys.path.append(top_level_folder)
from mod1 import utils