2

Consider the following case in Python 3.6:

basepackage
    |---__init__.py
    |---package
            |---__init__.py
            |---subpackage
                    |---__init__.py
                    |---module.py

Important detail: inside basepackage.package.__init__.py there's:

from basepackage.package.subpackage.module import AClass as AliasedClass

Now, let's say inside basepackage.package.subpackage.module.py we want to use:

import basepackage.package.subpackage.module as aliased_module [1]

The result is:

AttributeError: module 'basepackage' has no attribute 'package'

with a stack trace listing following culprit statements (in the below order):

from basepackage.package.subpackage.module import AClass as AliasedClass
import basepackage.package.subpackage.module as aliased_module

But if instead of [1] one'd like to use:

from basepackage.package.subpackage import module as aliased_module [2]

then everything works.

How is [1] so much different than [2] that the former results in an error and the latter not?

z33k
  • 3,280
  • 6
  • 24
  • 38

1 Answers1

3

For the first option (import basepackage.package.subpackage.module as aliased_module) to work, these conditions have to be met:

  • basepackage/__init__.py has to contain a line similar to from . import package (the name package has to be defined inside this basepackage/__init__.py file)
  • basepackage/package/__init__.py has to contain a line similar to from . import subpackage
  • basepackage/package/subpackage/__init__.py has to contain a line similar to from . import module

Note: the import statements inside the __init__.py files can also be absolute instead of relative paths.


For the second option (from basepackage.package.subpackage import module as aliased_module), it is enough if there are empty __init__.py files at each level, as long as these __init__.py files exist.

Ralf
  • 16,086
  • 4
  • 44
  • 68
  • Thx. Do you by any chance know some other (bit more comprehensible) resource than [this section in the official docs](https://docs.python.org/3/reference/import.html) to read up on this behavior? – z33k Sep 03 '19 at 13:49
  • @z33k Maybe this can help https://realpython.com/python-modules-packages/ – Ralf Sep 03 '19 at 13:53
  • Is it somehow different with the standard library? Because I use `import xml.etree.ElementTree as ET` without problems (mind that `ElementTree` is a module) and I checked the source and `etree` package has an empty `__init__.py` and in `xml`'s one there are no imports and only `__all__` is defined. – z33k Sep 03 '19 at 14:14
  • @z33k Hm... maybe I was wrong? I don't know, I'm confused, I'm not sure about this case. In [this part of the already linked tutorial](https://docs.python.org/3/tutorial/modules.html#packages) it seems to give an example contrary to my explanation in the answer. – Ralf Sep 03 '19 at 14:53