Some questions about __init__.py - python

enviroment: python3.8
directory:
test\
module1\
__init__.py
mod1.py
module2\
mod2.py
main.py
1. I can import a directory without __init__.py , why?
I want to check how exactly init.py work, so I import the module1 and module2 in main.py
# test\main.py
from module1 import mod1
from module2 import mod2
In my expectation, line2 should occur error, because I didn't create __init__.py in module2
But both of them can be imported.
Now, I'm confused about how exactly __init__.py work
2. I can't import those package which is imported in __init__.py
I try to import mod1.py in main.py in this way:
# test\main.py
import module1
module.mod1.mod1_print() # mod1_print() is a function which is defined in mod1.py
So I import mod1.py in test\module1\__init__.py :
# test\module1\__init__.py
import mod1
But when I execute main.py I got this error:
D:\>"C:/Program Files/Python38/python.exe" d:/test/main.py
Traceback (most recent call last):
File "d:/test/main.py", line 2, in <module>
import module1
File "d:\test\module1\__init__.py", line 1, in <module>
import mod1
ModuleNotFoundError: No module named 'mod1'
My question is:
If I want to import mod_print() in this form: module.mod1.mod1_print() , what should I do?

Python 3.3+ has Implicit Namespace Packages that allow it to create packages without an __init__.py file.
Allowing implicit namespace packages means that the requirement to provide an init.py file can be dropped completely, and affected portions can be installed into a common directory or split across multiple directories as distributions see fit.

see https://stackoverflow.com/a/37140173/9822 - python >= 3.3 dropped the requirement for __init__.py.
You could try something like this in module1/__init__.py:
import module1.mod1

Related

Cannot import Python module in same package

I have a Python 3.9.2 project with the following directory structure:
lib/
├─ mod1.py
├─ mod2.py
├─ __init__.py
main.py
In /main.py, I have from lib import mod1. In /lib/mod1.py, I have import mod2. When I run /main.py, I receive the following error:
Traceback (most recent call last):
File "/main.py", line 1, in <module>
from lib import mod1
File "/lib/init.py", line 1, in <module>
import mod2
ModuleNotFoundError: No module named 'mod2'
Why is this happening? When I change the code in /lib/mod1.py to say from lib import mod2, the code works fine, but I don't understand why that fixes it. Shouldn't I be able to import /lib/mod2.py the way I originally tried, since both mod1.py and mod2.py are in the same directory?
In /lib/mod1.py, you probably want to do:
# relative import - entire module
from . import mod2
# relative import - specific piece
from .mod2 import foo
or
# absolute import - entire module
from lib import mod2
# absolute import - specific piece
from lib.mod2 import foo
The correct way to import things is really tricky in Python because it depends on where you run the script from.
If you run the code from the root directory, import mod2 causes problems, but
If you were to run /lib/mod1.py (say it were run-able) from inside lib, then import mod2 would be correct and the alternatives above would cause errors.

Why do I have to use a relative import in a package's __init__.py?

Setup
test/
main.py
pkg/
a.py
__init__.py
main.py contains:
import pkg
pkg.a
__init__.py contains:
from . import a
main.py can be run without errors.
Question
Changing the content of __init__.py to
import a
gives the following error when running main.py:
Traceback (most recent call last):
File "C:/Users/me/PycharmProjects/test/main.py", line 1, in <module>
import pkg
File "C:\Users\me\PycharmProjects\test\pkg\__init__.py", line 1, in <module>
import a
ModuleNotFoundError: No module named 'a'
Interestingly, __init__.py can be executed directly with python __init__.py without errors.
What's going on?
When you run a python script, it's parent folder is added to sys.path
run main.py: sys.path[0] = '../test'
run init.py: sys.path[0] = '../test/pkg'
Your case: You try to "absolute-like" import a in __init__.py but the parent folder of a.py - which is '../test/pkg' - is not in the sys.path when you run main.py. This is why you get an error. However, your absolute import is incomplete as it should always start at the top level folder, e.g.
from test.pkg import a
Final answer to your question: You don't have to use relative imports!
See: PEP-8: Absolute imports are recommended, as they are usually more readable and tend to be better behaved (or at least give better error messages) if the import system is incorrectly configured (such as when a directory inside a package ends up on sys.path).
And keep in mind that relative imports don't work in a top-level-script when __name__ = "__main__", but from imported modules only.
You can learn more about absolute and relative imports here:
Absolute vs. explicit relative import of Python module
https://realpython.com/absolute-vs-relative-python-imports/
I suppose you are using Pycharm? Then that's one of the confusion cause.
For example, let's say your directory looks like this
project1
p1.py
test/
__init__.py
main.py
pkg/
a.py
__init__.py
If you run (F10) the main.py your default working directory will be project1/test, which does not contain the a.py so import a will not find anything.
But if you run (F10) the pkg/__init__.py your working directory will be project1/test/pkg which has the a.py, and it works like what you tested.
So in these situation, if you use from . import a it will look for the directory that file is, project1/test/pkg in this case, which will always work regardless your working directory.

Using absolute import while in developing Python modules?

I know relative imports are not suggested, such as quoted from PEP8:
Relative imports for intra-package imports are highly discouraged.
Always use the absolute package path for all imports. Even now that
PEP 328 is fully implemented in Python 2.5, its style of explicit
relative imports is actively discouraged; absolute imports are more
portable and usually more readable.
What if I am developing a package (with several modules)? While in development, absolute import won't work w/o installing/deploying the package. Does that mean I have to periodically install/deploy the current WIP modules just for testing?
Here is an example provided by Cld. Given a Python project/package:
myproject/
package1/
__init__.py
somemodule.py
package2/
__init__.py
somemodule.py
somescript.py
main.py
In main.py, absolute-import works quite well:
import package1
import package2.somescript
import package2.somemodule
However, for modules, like somescript.py in package2, the following absolute-imports:
import package2.somemodule
import package1
It would raise ImportError:
Traceback (most recent call last):
File "package2/somescript.py", line 1, in <module>
import package2.somemodule
ImportError: No module named package2.somemodule
Depand where you 'main' file is.
if you have:
myproject/
package1/
__init__.py
somemodule.py
package2/
__init__.py
somemodule.py
somescript.py
main.py
somescript.py:
import package2.somemodule
import package1
main.py
import package1
import package2.somescript
import package2.somemodule
If you execute: python package2/somescript.py you get an error
Traceback (most recent call last):
File "package2/somescript.py", line 1, in <module>
import package2.somemodule
ImportError: No module named package2.somemodule
But if you execute python main.py, you get no problem.
One common practice is pip install -e /path_to_your_pkg/, which will create a symbolic link of your package in the Python site-packages directory (not copying it as in standard install), doing so will enable:
import your_pkg anywhere
you can keep developing/updating your package and the installed version is always the latest
One known issue is if you are following PEP 517 and replace setup.py with setup.cfg and pyproject.toml, the pip install -e does not work. You need a dump setup.py as follows to fix this compatibility issue (still an issue in Jan 2021):
import setuptools
setuptools.setup()

python subfolder import chaos

suppose I have a folder structure that looks like this:
.
├── A
│   ├── a.py
│   └── b.py
└── main.py
The files have the following content:
b.py:
class BClass:
pass
a.py:
from b import BClass
main.py:
from A import a
If I run python3.3 A/a.py or python3.3 B/b.by, there are no errors. However, if I run python3.3 main.py, the following error occurs:
Traceback (most recent call last):
File "main.py", line 1, in <module>
from A import a
File "/tmp/python_imports/A/a.py", line 1, in <module>
from b import BClass
ImportError: No module named 'b'
Changing the import-line in a.py to import A.b works, but obviously python3.3 A/a.py will fail then. I am not actually interested in running python3.3 A/a.py but I want the module to be importable from multiple locations. Therefore a.py should import b.py regardless of where a.py is imported.
How can this issue be resolved?
Besides the __init__.py I mentioned in my comment which is mandatory for packages, you need to import the sibling module relatively:
from .b import BClass
Then it also works in Python 3.
Alternatively you can of course import the full name:
from A.b import BClass
But then your module isn't relocatable as easily within your package tree.
In neither way, though, you are able to use a.py as a standalone. To achieve this you would need to surround the import statement with try/except and try a different version in case the first one fails:
try:
from .b import BClass
except ValueError:
from b import BClass
But that is understandable. In a larger system, modules might depend on other modules somewhere in the package, otherwise they maybe should not be part of a package but standalone. And if there are such dependencies, using a module as if it was a standalone will of course be a problem.
You need an __init__.py file (empty will be just fine) in the A directory. Otherwise, python won't recognize it as a package.
Now you're A is a package, you should use either absolute imports or explicit relative imports. In this case, in A/a.py either use from A.b import BClass or from .b import BClass.

How to import package modules from in-package "main" module

My package structure is:
main.py
mapp/
__init__.py
core/
__init__.py
tobeimported.py
test/
__init__.py
(test modules)
utils/
__init__.py
blasttofasta.py
The file blasttofasta.py is executed as script.
blasttofasta.py looks like:
import mapp.core.tobeimported
def somefunc():
pass
if __name__ == '__main__':
pass
But Exception occurs:
Traceback (most recent call last):
File "utils/blasttofasta.py", line 5, in <module>
import mapp.core.tobeimported
ImportError: No module named mapp.core.analyzers
How to import tobeimported module? I run the blasttofasta.py from top directory (where main.py is)
EDIT: Maybe better question is: How to get mapp package to the sys.path? Because script file only see its own directory but not the package directory.
Thank you
If I want to including blasttofasta.py or run it as script simultaneously mos important is to have directory containing mapp package in sys.path.
This worked for me:
Before importing mapp (or other module from this package) I wrote into blasttofasta.py:
import os
os.sys.path.append(os.path.dirname(os.path.realpath(__file__))+ '/../../')
This append mapp package path and I can run it as script. On the other side is no problem with is included in another package.
Follow the absolute structure to import.
To import blasttofasta.py in tobeimport.py
ToBeimport contents
from myapp.utils import blasttofasta
Your structure is good.
Two things need to happen:
Your map directory needs a __init__.py file.
You can simply do this (naively):
$ touch /path/to/map/__init__.py
/path/to/map needs to be in sys.path
Please read: http://docs.python.org/2/tutorial/modules.html for more details.

Categories

Resources