How do I make one package reference another package, but make it look like the referenced package belongs to the initial package?
package_1
|
|____ __init__.py
package_2
|
|____ __init__.py
|____ module_1.py
Inside package_1.__init__.py is
# __init__.py
import package_2
Now the following calls works fine:
>>> import package_1
>>> print package_1
<module <module 'package_1' from '...\package_1\__init__.pyc'>
>>> from package_1 import package_2
>>> print package_2
<module 'package_2' from '...\package_2\__init__.pyc'>
>>> print package_2.module_1
<module 'package_2.module_1' from '...\package_2\module_1.pyc'>
>>> from package_2 import module_1
>>> print module_1
<module 'package_2.module_1' from '...\package_2\module_1.pyc'>
But I want to be able to do this:
>>> from package_1.package_2 import module_1
But I get:
Traceback (most recent call last):
File "testfile.py", line 15, in <module>
from package_1.package_2 import module_1
ImportError: No module named package_2
The reason I want to do this is because package_2 used to be a subpackage of package_1. Now that package_2 is it's own package, I want to be able to reference it from package_1 to keep the behaviour as it was before.
You can add a package_2.py
module under package_1
that simply contains:
from package_2 import *
If you are using python2 you should add:
from __future__ import absolute_import
At the top of the file in order to have python3's behaviour.
In this way package_1.package_2
will be different from package_2
, i.e.:
import package_1.package_2
import package_2
print(package_2 is package_1.package2) #False
However all the objects inside package_1.package_2
are the same of the external module.
This has the limitations that if you want to import a submodule, and not just something defined in package_2/__init__.py
's, you get an ImportError
. If you want to avoid this you can:
Use specific import
s to import all the stuff you need:
from package_2 import *
from package_2 import submodule1, submodule2, subpackage3
Add an _all.py
module under package_2
that imports all the stuff you want exposed and import from that
Surely *
-imports are often avoided, but in this case, it seems like the only solution to your problem that doesn't required hacking the importing mechanism.
If you really hate this the other way I can think of is to write a custom importer using importing hooks, but this would require quite a bit of work to get it right.
Also, since package_2
is now its own package you should probably consider deprecating the old way of importing in order to be able to remove this "hack" in some future release. Probably it's not worth it to spend too much time writing an import hook if you are going to get rid of it in the future anyway.
Note that the from
import:
from package_1.package_2 import module1
Requires you to actually provide a package_1.package_2
module or subpackage.
The import
s of the form:
from X.Y.Z import something
First import X
, then the importer will search for a file called Y.py
under the X
directory. Then it will search a Z.py
file under X/Y
or the directory X/Y/Z
finally, if something
is found in the imported Z
module it is simply placed in the scope, otherwise something
is a module that is imported.
However this last step, checking whether something
already exists in Z
, is only performed when all of X
, Y
and Z
were completely imported. In your use case:
from package_1.package_2 import module1
You simply cannot have package_2
simply defined inside package_1
.