python subfolder import chaos - python

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.

Related

Nested package import works when called from within package directory, but not from elsewhere

Questions about this issue have been asked many times but I'm afraid I still cannot fathom why a module which imports from a subdirectory, works when I call the module from its own directory, but when I import it from another directory I get ModuleNotFoundError: No module named _nested_package. Here is the exact situation:
tbrowne#nd2110:~/scratch$ tree
.
└── topmodule
├── __init__.py
├── main.py
├── nest
│   ├── __init__.py
│   └── nestmodule.py
└── topmodule.py
now here is main.py:
from topmodule import test_add_two
if __name__ == "__main__":
print(test_add_two(11, 12))
here is topmodule.py:
from nest.nestmodule import add_two
def test_add_two(x, y):
return add_two(x, y)
if __name__ == "__main__":
print(test_add_two(1, 2))
And here is nestmodule.py:
def add_two(x, y):
return x + y
Now if I run main.py, from its own directory, no problem:
tbrowne#nd2110:~/scratch/topmodule$ python3 main.py
23
however if I move to the directory above, say scratch, and create nesttest.py:
tbrowne#nd2110:~/scratch$ cat nesttest.py
from topmodule.topmodule import test_add_two
if __name__ == "__main__":
print(test_add_two(3, 4))
Then I run it:
tbrowne#nd2110:~/scratch$ python3 nesttest.py
Traceback (most recent call last):
File "/home/tbrowne/scratch/nesttest.py", line 1, in <module>
from topmodule.topmodule import test_add_two
File "/home/tbrowne/scratch/topmodule/topmodule.py", line 1, in <module>
from nest.nestmodule import add_two
ModuleNotFoundError: No module named 'nest'
Issue is, I'm going to want to package this with Poetry or some other package creator, and I want topmodule from wherever it is imported, even if it is packaged up, to be able to import the nest.nestmodule's functions.
I'm hoping that by being very explicit on the exact situation, someone can help me on how to do this. The wider context in the real project I'm working on (not this toy analogous example) is that I am using git submodules inside other git repos, and these will have to be packaged up along with the main repo.
You have three separate but intersecting issues here:
Python 3 does not allow implicit relative imports, so from nest.nestmodule import add_two is automatically wrong since nest is not a top-level package.
Once you fix that, it becomes wrong to run main.py as a file, since doing so puts its directory in sys.path, which does make nest a top-level package that doesn’t work with from .nest…. Putting it in a package implies that it is a module, so it must be run with -m. (There are still pitfalls here: everything about __main__ is broken to some degree.)
You’re using submodules (presumably for nest), which are (opinion!) a bad idea in general and (fact) incompatible with any code, in nest or otherwise, which believes it to be a top-level package (see #1). “Fixing” this for code that you can’t edit will involve installing it as a dependency, not a subpackage, which is what you should be doing anyway.
use this and print import paths
import sys
print(sys.path)
you will see that only your current directory level is added to the path.
to solve your issue, you can do one of these:
add your sub directories to this import path list
use current folder's name as main module name like this:
from topmodule.nest.nestmodule import add_two
use nesting/submodule level with .:
from .nest.nestmodule import add_two

Some questions about __init__.py

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

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.

Python Module System - Import Sibling Subpackage

In Python, I want a file in a subpackage to import a sibling subpackage. Like so:
/proj
__init__.py
runner_main.py
/subpackageA
__init__.py
helper.py
/subpackageB
__init__.py
runnerB.py
In runner_main.py, I can call import subpackageA just fine.
However, calling from . import subpackageA fails with error
ImportError: cannot import name 'preprocessing' from '__main__'
This isn't a problem, except I want to import helper.py from runnerB. Calling from .. import subpackageA fails with a similar error.
I don't want to put /proj on my system or Python path; I want it to work as a standalone package. How can I make this simple case work?
Try
from subpackageA import classA, functionB, constantC
It depends on where you run your code. You can import helper.py from runnerB. But If you run runnerB directly, it will gives you same error as you described. However If you run from any py file placed in the parent directory that import runnder module, it will work.

What is __init__.py for?

What is __init__.py for in a Python source directory?
It used to be a required part of a package (old, pre-3.3 "regular package", not newer 3.3+ "namespace package").
Here's the documentation.
Python defines two types of packages, regular packages and namespace packages. Regular packages are traditional packages as they existed in Python 3.2 and earlier. A regular package is typically implemented as a directory containing an __init__.py file. When a regular package is imported, this __init__.py file is implicitly executed, and the objects it defines are bound to names in the package’s namespace. The __init__.py file can contain the same Python code that any other module can contain, and Python will add some additional attributes to the module when it is imported.
But just click the link, it contains an example, more information, and an explanation of namespace packages, the kind of packages without __init__.py.
Files named __init__.py are used to mark directories on disk as Python package directories.
If you have the files
mydir/spam/__init__.py
mydir/spam/module.py
and mydir is on your path, you can import the code in module.py as
import spam.module
or
from spam import module
If you remove the __init__.py file, Python will no longer look for submodules inside that directory, so attempts to import the module will fail.
The __init__.py file is usually empty, but can be used to export selected portions of the package under more convenient name, hold convenience functions, etc.
Given the example above, the contents of the init module can be accessed as
import spam
based on this
In addition to labeling a directory as a Python package and defining __all__, __init__.py allows you to define any variable at the package level. Doing so is often convenient if a package defines something that will be imported frequently, in an API-like fashion. This pattern promotes adherence to the Pythonic "flat is better than nested" philosophy.
An example
Here is an example from one of my projects, in which I frequently import a sessionmaker called Session to interact with my database. I wrote a "database" package with a few modules:
database/
__init__.py
schema.py
insertions.py
queries.py
My __init__.py contains the following code:
import os
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine(os.environ['DATABASE_URL'])
Session = sessionmaker(bind=engine)
Since I define Session here, I can start a new session using the syntax below. This code would be the same executed from inside or outside of the "database" package directory.
from database import Session
session = Session()
Of course, this is a small convenience -- the alternative would be to define Session in a new file like "create_session.py" in my database package, and start new sessions using:
from database.create_session import Session
session = Session()
Further reading
There is a pretty interesting reddit thread covering appropriate uses of __init__.py here:
http://www.reddit.com/r/Python/comments/1bbbwk/whats_your_opinion_on_what_to_include_in_init_py/
The majority opinion seems to be that __init__.py files should be very thin to avoid violating the "explicit is better than implicit" philosophy.
There are 2 main reasons for __init__.py
For convenience: the other users will not need to know your functions' exact location in your package hierarchy (documentation).
your_package/
__init__.py
file1.py
file2.py
...
fileN.py
# in __init__.py
from .file1 import *
from .file2 import *
...
from .fileN import *
# in file1.py
def add():
pass
then others can call add() by
from your_package import add
without knowing file1's inside functions, like
from your_package.file1 import add
If you want something to be initialized; for example, logging (which should be put in the top level):
import logging.config
logging.config.dictConfig(Your_logging_config)
The __init__.py file makes Python treat directories containing it as modules.
Furthermore, this is the first file to be loaded in a module, so you can use it to execute code that you want to run each time a module is loaded, or specify the submodules to be exported.
Since Python 3.3, __init__.py is no longer required to define directories as importable Python packages.
Check PEP 420: Implicit Namespace Packages:
Native support for package directories that don’t require __init__.py marker files and can automatically span multiple path segments (inspired by various third party approaches to namespace packages, as described in PEP 420)
Here's the test:
$ mkdir -p /tmp/test_init
$ touch /tmp/test_init/module.py /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
├── module.py
└── __init__.py
$ python3
>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module
$ rm -f /tmp/test_init/__init__.py
$ tree -at /tmp/test_init
/tmp/test_init
└── module.py
$ python3
>>> import sys
>>> sys.path.insert(0, '/tmp')
>>> from test_init import module
>>> import test_init.module
references:
https://docs.python.org/3/whatsnew/3.3.html#pep-420-implicit-namespace-packages
https://www.python.org/dev/peps/pep-0420/
Is __init__.py not required for packages in Python 3?
Although Python works without an __init__.py file you should still include one.
It specifies that the directory should be treated as a package, so therefore include it (even if it is empty).
There is also a case where you may actually use an __init__.py file:
Imagine you had the following file structure:
main_methods
|- methods.py
And methods.py contained this:
def foo():
return 'foo'
To use foo() you would need one of the following:
from main_methods.methods import foo # Call with foo()
from main_methods import methods # Call with methods.foo()
import main_methods.methods # Call with main_methods.methods.foo()
Maybe there you need (or want) to keep methods.py inside main_methods (runtimes/dependencies for example) but you only want to import main_methods.
If you changed the name of methods.py to __init__.py then you could use foo() by just importing main_methods:
import main_methods
print(main_methods.foo()) # Prints 'foo'
This works because __init__.py is treated as part of the package.
Some Python packages actually do this. An example is with JSON, where running import json is actually importing __init__.py from the json package (see the package file structure here):
Source code: Lib/json/__init__.py
In Python the definition of package is very simple. Like Java the hierarchical structure and the directory structure are the same. But you have to have __init__.py in a package. I will explain the __init__.py file with the example below:
package_x/
|-- __init__.py
|-- subPackage_a/
|------ __init__.py
|------ module_m1.py
|-- subPackage_b/
|------ __init__.py
|------ module_n1.py
|------ module_n2.py
|------ module_n3.py
__init__.py can be empty, as long as it exists. It indicates that the directory should be regarded as a package. Of course, __init__.py can also set the appropriate content.
If we add a function in module_n1:
def function_X():
print "function_X in module_n1"
return
After running:
>>>from package_x.subPackage_b.module_n1 import function_X
>>>function_X()
function_X in module_n1
Then we followed the hierarchy package and called module_n1 the function. We can use __init__.py in subPackage_b like this:
__all__ = ['module_n2', 'module_n3']
After running:
>>>from package_x.subPackage_b import *
>>>module_n1.function_X()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named module_n1
Hence using * importing, module package is subject to __init__.py content.
__init__.py will treat the directory it is in as a loadable module.
For people who prefer reading code, I put Two-Bit Alchemist's comment here.
$ find /tmp/mydir/
/tmp/mydir/
/tmp/mydir//spam
/tmp/mydir//spam/__init__.py
/tmp/mydir//spam/module.py
$ cd ~
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
>>> module.myfun(3)
9
>>> exit()
$
$ rm /tmp/mydir/spam/__init__.py*
$
$ python
>>> import sys
>>> sys.path.insert(0, '/tmp/mydir')
>>> from spam import module
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named spam
>>>
It facilitates importing other python files. When you placed this file in a directory (say stuff)containing other py files, then you can do something like import stuff.other.
root\
stuff\
other.py
morestuff\
another.py
Without this __init__.py inside the directory stuff, you couldn't import other.py, because Python doesn't know where the source code for stuff is and unable to recognize it as a package.
An __init__.py file makes imports easy. When an __init__.py is present within a package, function a() can be imported from file b.py like so:
from b import a
Without it, however, you can't import directly. You have to amend the system path:
import sys
sys.path.insert(0, 'path/to/b.py')
from b import a
One thing __init__.py allows is converting a module to a package without breaking the API or creating extraneous nested namespaces or private modules*. This helps when I want to extend a namespace.
If I have a file util.py containing
def foo():
...
then users will access foo with
from util import foo
If I then want to add utility functions for database interaction, and I want them to have their own namespace under util, I'll need a new directory**, and to keep API compatibility (so that from util import foo still works), I'll call it util/. I could move util.py into util/ like so,
util/
__init__.py
util.py
db.py
and in util/__init__.py do
from util import *
but this is redundant. Instead of having a util/util.py file, we can just put the util.py contents in __init__.py and the user can now
from util import foo
from util.db import check_schema
I think this nicely highlights how a util package's __init__.py acts in a similar way to a util module
* this is hinted at in the other answers, but I want to highlight it here
** short of employing import gymnastics. Note it won't work to create a new package with the same name as the file, see this
If you're using Python 2 and want to load siblings of your file you can simply add the parent folder of your file to your system paths of the session. It will behave about the same as if your current file was an init file.
import os
import sys
dir_path = os.path.dirname(__file__)
sys.path.insert(0, dir_path)
After that regular imports relative to the file's directory will work just fine. E.g.
import cheese
from vehicle_parts import *
# etc.
Generally you want to use a proper init.py file instead though, but when dealing with legacy code you might be stuck with f.ex. a library hard-coded to load a particular file and nothing but. For those cases this is an alternative.
__init__.py : It is a Python file found in a package directory, it is invoked when the package or a module in the package is imported. You can use this to execute package initialization code, i.e. whenever the package is imported the python statements are executed first before the other modules in this folder gets executed. It is similar to main function of c or Java program, but this exists in the Python package module (folder) rather than in the core Python file.
also it has access to global variables defined in this __init__.py file as when the module is imported into Python file.
for eg.
I have a __init__.py file in a folder called pymodlib, this file contains the following statements:
print(f'Invoking __init__.py for {__name__}')
pystructures = ['for_loop', 'while__loop', 'ifCondition']
When I import this package pymodlib in my solution module or notebook or python console:
These two statements get executed while importing.
So in the log or console you would see the following output:
>>> import pymodlib
Invoking __init__.py for pymodlib
in the next statement of python console: I can access the global variable:
>> pymodlib.pystructures
it gives the following output:
['for_loop', 'while__loop', 'ifCondition']
Now, from Python 3.3 onwards the use of this file has been optional to make folder a Python module. So you can skip from including it in the python module folder.

Categories

Resources