Discussion:
[Tutor] relative imports within a package?
James Hartley
2015-11-07 22:09:19 UTC
Permalink
The Python 3 tutorial discusses relative imports at:

https://docs.python.org/3/tutorial/modules.html#intra-package-references

I have the following directory structure for a package in development:

+ outer_package/
+ __init__.py
+ inner_package
| + __init__.py
| + myclass.py
+ collateral_directory
+ arbitrary_tool.py

arbitrary_tool.py needs to instantiate the class MyClass found in
myclass.py. I have made MyClass accessible by adding the following to
inner_package/__init__.py:

from myclass import MyClass

Within arbitrary_tool.py, I have attempted the following:

from ..inner_package import MyClass

...but executing with Python 3.4 yields the following stack trace:

Traceback (most recent call last):
File "./arbitrary_tool.py", line 5, in <module>
from ..inner_package import MyClass
SystemError: Parent module '' not loaded, cannot perform relative import

Suggestions on how to solve this would be most certainly welcomed!
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Steven D'Aprano
2015-11-08 01:17:12 UTC
Permalink
Post by James Hartley
https://docs.python.org/3/tutorial/modules.html#intra-package-references
+ outer_package/
+ __init__.py
+ inner_package
| + __init__.py
| + myclass.py
+ collateral_directory
+ arbitrary_tool.py
As shown above, "collateral_directory" is not part of the package. It is
just a directory with stuff in it. The fact that the "stuff" happens to
include a Python script is irrelevant.

If "arbitrary_tool.py" is actually independent of outer_package, you
should have this layout:


+ arbitrary_tool.py
+ outer_package/
+ __init__.py
+ inner_package
| + __init__.py
| + myclass.py


where the enclosing directory is part of your PYTHONPATH. Then, in
arbitrary_tool, you say:

from outer_package import MyClass
# assuming outer_package has already made this available

or

from outer_package.inner_packages import MyClass
# assuming inner_package has made this available
# which you have done

or

from outer_package.inner_package.myclass import MyClass

whichever you prefer.

If arbitrary_tool is not independent of outer_package, then you should
convert it to a package with this layout:


+ outer_package/
+ __init__.py
+ inner_package
| + __init__.py
| + myclass.py
+ collateral_directory
+ __init__.py
+ arbitrary_tool.py


__init__.py may be an empty file, it just has to exist. Now
collateral_directory is a sub-package, and you can do things like this:


# from outer_package.__init__
import collateral_directory.arbitrary_tool

# from inner_package.myclass (but watch out for circular imports)
from ..collateral_directory.arbitrary_tool import Spam


But if arbitrary_tool is part of the package, and it is the only file in
collateral_directory, why mess about with a subpackage? Lay your package
out like this:

+ outer_package/
+ __init__.py
+ arbitrary_tool.py
+ inner_package
| + __init__.py
| + myclass.py

and inside arbitrary_tool say:

from inner_package.myclass import MyClass


(P.S. this is Python, not Java. There is no requirement to put every
class in its own file, in fact doing so is mildly discouraged. Does
MyClass truly deserve its own file? If not, you may be able to simplify
your package structure even more.)
--
Steve
_______________________________________________
Tutor maillist - ***@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor
Continue reading on narkive:
Loading...