Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resolve this import error in Python 3.6? [duplicate]

I have a very simple namespace package (contents included below, as well as the directory layout). If I try to import namespace_repro.module, I got the following error: AttributeError: module 'namespace_repro' has no attribute 'module'. As far as I understand my package has a valid layout and the import should work. Interestingly, the error is present only in Python 3.6.8 and the import succeeds in Python 3.7.

How to reproduce the problem?

I have a directory named import-error-repro with in it a setup.py (see below), then a nested directory path src/namespace_repro/module, containing three files, __init__.py, x.py and y.py. Their contents:

setup.py

from setuptools import find_namespace_packages, setup

setup(
    name='namespace-repro',
    version='0.1.0',
    python_requires='>=3.6',
    packages=find_namespace_packages('src'),
    package_dir={'': 'src'},
    zip_safe=False,
)

src/namespace_repro/module/__init__.py:

from namespace_repro.module.x import x

src/namespace_repro/module/x.py:

import namespace_repro.module.y as y

x = y.y

and finally src/namespace_repro/module/y.py:

y = True

I created a brand new Python 3.6 conda environment by conda create -n namespace6 python=3.6 ipython, then I activated it and installed the package as pip install -e ./import-error-repro (note that -e doesn't matter, the problem is reproducible without it). After that, I tried import namespace_repro.module in ipython (though the same happens in the official python interpreter). The result is

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-1-bcae5a697dad> in <module>
----> 1 import namespace_repro.module

~/namespace-repro/src/namespace_repro/module/__init__.py in <module>
----> 1 from namespace_repro.module.x import x

~/namespace-repro/src/namespace_repro/module/x.py in <module>
----> 1 import namespace_repro.module.y as y
      2 
      3 x = y.y

AttributeError: module 'namespace_repro' has no attribute 'module'
---------------------------------------------------------------------------

The strange thing is that the import system finds namespace_repro.module twice but fails at the third time!

Some other interesting behaviour:

In [1]: import namespace_repro.module.y as y  # This doesn't work.
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-4-4035347ea59b> in <module>
----> 1 import namespace_repro.module.y as y

AttributeError: module 'namespace_repro' has no attribute 'module'

In [2]: import namespace_repro.module.y  # But this one does! Why?

In [3]: dir(namespace_repro.module.y) # The error returns when we actually want to use the module.
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-3-d89bcfd9e509> in <module>
----> 1 dir(namespace_repro.module.y)

AttributeError: module 'namespace_repro' has no attribute 'module'

In [4]: from namespace_repro.module.y import y  # This works fine!

In [5]: y
Out[5]: True

Directory layout

. import-error-repro
+-- setup.py
+-- src
|   +-- namespace_repro
|   |   +-- module
|   |   |   +-- __init__.py
|   |   |   +-- x.py
|   |   |   +-- y.py
like image 434
korommatyi Avatar asked May 31 '19 11:05

korommatyi


People also ask

How do you fix an import error in Python?

If the error occurs due to a circular dependency, it can be resolved by moving the imported classes to a third file and importing them from this file. If the error occurs due to a misspelled name, the name of the class in the Python file should be verified and corrected.

Why do I need __ init __ py?

The __init__.py files are required to make Python treat directories containing the file as packages. This prevents directories with a common name, such as string , unintentionally hiding valid modules that occur later on the module search path.

How are Python imports resolved?

When resolving a relative module, Python first looks for a folder with that name and its __init__.py . If that exists, it will extract the variable from the __init__.py as in import x . If it does not exist, it will look for world.py at the same level as the import. If that is not found, an Exception will be raised.


1 Answers

This is CPython bug 30024, which unsurprisingly was fixed in 3.7. Note that the more idiomatic form with relative (circular) imports has worked since 3.5.

like image 116
Davis Herring Avatar answered Nov 10 '22 09:11

Davis Herring