Search code examples
pytestpython-importpython-packagingrelative-import

Why does the same code in one file import a function, and in a different file the module of the same name?


The same import statement from mypackage._aux import is_error has two different meanings in similar files:

The first is the expected behavior, because _aux/__init__.py contains from .is_error._is_error import is_error. (format from .folder.file import function)

When I run pytest, the two tests in _abbrev_testing_test.py fail, because is_error is not the expected function. (TypeError: 'module' object is not callable)

It works when I use the line that I would like to abbreviate with the new function: enter image description here This includes the test in _foobar_test.py - so in _foobar.py the function was imported.

But in _abbrev_testing.py the module was imported: enter image description here

Does someone understand the difference between the two files? Should I have done this in a different way?

I would love to know if there is some logical rule that would have avoided this. (To me this just looks absurd and erratic.)

Edit: In both files it works, when I use a long import statement not relying on _aux/__init__.py:

  • short: from mypackage._aux import is_error (format from _aux import function)

  • long: from mypackage._aux.is_error._is_error import is_error
    (format from _aux.folder.file import function)

This question can be summarized as:
What in _abbrev_testing.py is sabotaging the __init__.py?

Edit 2: Steps to reproduce:

me@ubuntu:~$ git clone https://github.com/watchduck/module_object_is_not_callable.git
me@ubuntu:~$ cd module_object_is_not_callable/
me@ubuntu:~/module_object_is_not_callable$ virtualenv -p python3 env

Open project with IDE.

(env) me@ubuntu:~/module_object_is_not_callable$ pip install pytest
(env) me@ubuntu:~/module_object_is_not_callable$ pytest

Solution

  • What in _abbrev_testing.py is sabotaging the init.py?

    Gotcha - if you change:

    from .is_error._is_error import is_error
    from .abbrev_testing._abbrev_testing import abbrev_testing
    from .foobar._foobar import foobar
    

    in your init problem goes away. You were:

    from .abbrev_testing._abbrev_testing import abbrev_testing
    from .is_error._is_error import is_error
    

    setting the is_error to the function "is_error" only after you imported .abbrev_testing._abbrev_testing - where the is_error is (correctly) already been imported as a module.

    Should I have done this in a different way?

    Certainly. Do not name functions the same name as modules/packages. They are different things, so should have different names. Also - avoid similar repetitive names, and leading underscores. Makes code very difficult to read (so I opened many times the _abbrev_testing_errors.py cause it looked very similar to _abbrev_testing.py or _abbrev_testing_test.py) - reserve "test" for tests. I say this in all seriousness - python's import system is complex but the complexity is due, cause it's a complex problem. Correct naming makes this complexity manageable.