Move python modules to subdirectory without breaking imports - python

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()

Related

Import a submodule in a Python module

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.

Prevent Python relative import from current directory

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!")

Python __init__.py so that package can be imported without 'from' keyword

Lets say my package looks like this:
mydir/a/__init__.py
mydir/a/b.py
mydir/a/c.py
I have a package which has a few .py files in the same directory as __init__.py. Everything involving __init__.py I have tried so far results in imports needing to look like:
from a import b
from a import c
or
import a.b
import a.c
or by using the __all__ variable in __init__.py:
from a import *
how can I setup the __init__.py so that I can import all packages within 'a' using:
import a

Relative import in Python 3.6

I want to use relative import in Python 3.
My project:
main_folder
- __init__.py
- run.py
- tools.py
I want to have in run.py (MyClass declared in __init__.py):
from . import MyClass
And in run.py:
from .tools import my_func
An ImportError is raise.
Alternatively, with absolute import, debugging in PyCharm does not work and the library takes from installed packages, not my directory.
I know one way, but it is terrible:
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
How to use this import in my project?
When you use PyCharm, it automatically makes the current module main, so relative statements like from . import <module> will not work. read more here.
to fix your problem, put the __init__.py and tools.py files in a sub-directory
main_directory/
run.py
sub_directory/
__init__.py
tools.py
in your run.py file, write the following as your import statements
from sub_directory import tools
from sub_directory.__init__ import MyClass
Edit: as #9000 mentioned, you can write from sub_directory import MyClass and achieve the same thing.

python modules hierarchy naming convention

I'd like to have modules/packages structure like following:
/__init__.py
/mymodule.py
/mymodule/
/mymodule/__init__.py
/mymodule/submodule.py
And then use modules like:
import mymodule
import mymodule.submodule
But it seems like file "mymodule.py" conflicts with "mymodule" directory.
What's the correct naming convention here?
If you want to make a package, you have to understand how Python translates filenames to module names.
The file mymodule.py will be available as the mymodule, assuming the interpreter finds it in a directory in the Python search path. If you're on a case-insensitive filesystem, it might also be importable with different capitalization (but you should avoid using such system-dependent behavior).
A package is a directory with an __init__.py file in it. There's been some movement recently to allow packages without those files, but I'm going to ignore that less-common case for this answer. A package becomes a module inside Python, with its code coming from the __init__.py file. So the file mypackage/__init__.py can be imported as mypackage.
There's no meaning to an __init__.py file directly in the Python search path (well, I suppose you could import it an an __init__ module, but this is probably a bad idea).
So, for your situation, here's the appropriate filesystem layout:
toplevel/
mymodule/
__init__.py # put code here for mymodule
submodule.py # put code here for mymodule.submodule
Only the toplevel folder should be in the Python search path.
You are dealing with a package. The package structure you should have is:
/some-parent-directory # This needs to be on sys.path
/mymodule # This is not really a module - it's a package
__init__.py # import mymodule
# init is loaded when you `import mymodule` or anything below it
some.py # import mymodule.some
implementation.py # import mymodule.implementation
files.py # import mymodule.files
/submodule
__init__.py # import mymodule.submodule
# init is loaded when you `import mymodule.submodule` or anything below it
submodule_impl.py # import mymodule.submodule.submodule_impl
goes.py # import mymodule.submodule.goes
here.py # import mymodule.submodule.here
As long as the parent directory is on sys.path you will be able to call import mymodule or from mymodule.submodule import something without issue.
If you want something to be available from the root level of a package (i. e. from mymodule import SomeItem or from a sub-package from mymodule.submodule import AnotherItem) then you can import it into the appropriate __init__.py file.
So, for example, let's say you wanted the class CustomClass defined in the submodule_impl.py module to be importable directly from submodule. Your submodule/__init__.py would have to contain the following:
from .submodule_impl import CustomClass
Then you would be able to import CustomClass directly from submodule (i. e. from mymodule.submodule import CustomClass)

Categories