Python import rule

Hi,

For example, the code struture likes case 1.
I could import xxx.py module in sss.py like:
import package1.subpackage1.xxx as xxx

however, for some reason, I would like to add 1 layer directory on the top of top1 directory, like “modified case 1”.
For “modified case 1” the statement:import package1.subpackage1.xxx as xxx is wrong. so I need to modify the code.

however, I would not like to modify code. I would like to import xxx.py in sss.py like this:
from …package1.subpackage1.xxx as xxx

as you konw, the statement from …package1.subpackage1.xxx as xxx in sss.py for case 1 is wrong because top1 directory should be treated as package.
is there any better solution for my case?

case 1:

top1
------->package1
--------------->__init__.py	
--------------->subpackage1
----------------------->__init__.py
----------------------->xxx.py
----------------------->yyy.py
--------------->subpackage2
----------------------->aaa.py
----------------------->bbb.py
------->package2
--------------->__init__.py
--------------->sp21
----------------------->__init__.py
----------------------->sss.py
----------------------->ttt.py
--------------->sp22
----------------------->__init__.py
main1.py



modified case 1:
top2
-------->top1
---------------->package1
------------------------>__init__.py	
------------------------>subpackage1
-------------------------------->__init__.py
-------------------------------->xxx.py
-------------------------------->yyy.py
------------------------>subpackage2
-------------------------------->aaa.py
-------------------------------->bbb.py
---------------->package2
------------------------>__init__.py
------------------------>sp21
-------------------------------->__init__.py
-------------------------------->sss.py
-------------------------------->ttt.py
------------------------>sp22
-------------------------------->__init__.py
main2.py

Packages and modules are not something that is from the file system. It is a way to create pieces of relocatable code, that you can reuse. Relocatable is emphasized, it means that a package or module can be put in a different place and still work.

To get at the code, it has to be loaded first. The import system uses a loader for that. The default loader will scan the locations on PYTHONPATH for a file <module_name>.py or a directory <package_name>. Now if you would use your import and put your package2 in a different location, it would stop working. The relationship between the packages would break. However, if you specified it as from package1.subpackage1.xxx as xxx it would work. Now you can put package2 anywhere in a directory on the PYTHONPATH, including the current directory, which is on the path as a service to developers.

So I created:
.
├── package1
│ ├── init.py
│ ├── pycache
│ │ ├── init.cpython-36.pyc
│ │ └── xxx.cpython-36.pyc
│ └── xxx.py
└── package2
├── init.py
├── pycache
│ ├── init.cpython-36.pyc
│ └── sss.cpython-36.pyc
└── sss.py

4 directories, 8 files

xxx.py contains:

print("Package1, module xxx")

sss.py contains:

import package1.xxx as xxx
print("Package2, module sss")

Now when I import the sss module, I get

>>> import package2.sss as sss
Package1, module xxx
Package2, module sss

Just what we expected.

Hi Menno,

Thank you for your reply!

I would like re-explain my questions.

In the following “case 1”, in sss.py file, I wrote:
import package1.subpackage1.xxx as xxx .
It works.

now, I add one directory on the top of top1, it becomes “modified case 1”.
in “modified case 1”, the statement in sss.py file doesn’t work any longer.

So my question is:
to make the code relocatable, I have to use statement like:
from …package1.subpackage1.xxx as xxx
however, the upper statement is wrong as the code from …package1 is invalid in python.
is there any better solution for my case?

Case 1:

top1
------->package1
--------------->__init__.py	
--------------->subpackage1
----------------------->__init__.py
----------------------->xxx.py
----------------------->yyy.py
------->package2
--------------->__init__.py
--------------->sp21
----------------------->__init__.py
----------------------->sss.py
----------------------->ttt.py
main1.py

modified case 1:

top2
-------->top1
---------------->package1
------------------------>__init__.py	
------------------------>subpackage1
-------------------------------->__init__.py
-------------------------------->xxx.py
-------------------------------->yyy.py
---------------->package2
------------------------>__init__.py
------------------------>sp21
-------------------------------->__init__.py
-------------------------------->sss.py
-------------------------------->ttt.py
main2.py

I thought that connecting the dots after my explanation was easy, but apparently I was wrong - sorry about that.

In your “modified case 1” top2 will be on the PYTHONPATH, not top1 - so package1 nor package2 will be recognised as “loadable” packages. The loader will ignore these - the packages are not on its search path. Also, any file in top1 will not be loadable as a module.

I should have added to the example some text why I included it, although that it works is clearly what you already know.

The line import package1.xxx as xxx is not dependent on package1 being a file located in package2, but in package1 being available as a package. Again, location in the file system is immaterial. Moving the package1 directory into site-packages (where installed packages and modules reside) would change nothing in the working of the code, thus the statement “It is a way to create pieces of relocatable code, that you can reuse”.

From top2 the loader can traverse the directories to package1 or package2:

>>> import top1.package1.xxx
Package1, module xxx

But as they are not loaded as packages, you cannot come from one to the other:

>>> import top1.package2.sss`
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/mennoh/python/test1/top2/top1/package2/sss.py", line 1, in <module>
    import package1.xxx as xxx
ModuleNotFoundError: No module named 'package1'

And there is no way around that without breaking up the “packageness” of package1 or package2.

Does that clear up things?