Q: pytest error when importing my function decorator I'm creating a pytest unit test for a function in my software.
Before even starting to test, pyunit seems to be unable to import my "cache_offline" decorator which is indirectly imported when I import the function I'm testing in my test.
I'm using Anaconda embedding Python 3.7 and pytest 5.2.2
I tried to comment out the code where the decorator is applied to my functions, when I do so the pytest error disappear and the tests execute properly.
My test is in ./tests/scripts/test_scripts_helper.py and I run pytest at the project root .
Pytest finds properly my test (see the error message), so this is not the problem at hand here.
My test imports and wants to test the function read_tiff_tag from a package vorace.scripts_helper, which imports a function safe_mkdir from package vorace.core.misc, which imports the package vorace.core.vorace, in which 3 functions are decorated with the decorator cache_offline from package vorace.core.misc
I tried both running the tests using either py.test or python -m pytest at the root of my project.
My project have the following structure (simplified).
The code root is ./vorace
The tests root is ./tests
.
├── conftest.py
├── tests
│   ├── __init__.py
│   ├── scripts
│   │   ├── __init__.py
│   │   └── test_scripts_helper.py
│   └── tests_data
│       └── test_ROI.tif
└── vorace
    ├── __init__.py
    ├── core
    │   ├── __init__.py
    │   ├── misc.py
    │   └── vorace.py
    └── scripts
        ├── __init__.py
        ├── batch_analyzis.py
        └── scripts_helper.py

I tried :


*

*with and without empty __init__.py in each subfolder of the tests folder. -> no change

*with and without an empty conftest.py at the root of the project. -> no change

*executing a test which doesn't need any import in my test_scripts_helper.py file (with my test causing the problem being commented out) -> the test executes properly


I suspect kind of a circular import problem but I've always been told that it can't happen in python. Maybe the decorators are an exception to this rule ?
My vorace.core.misc code, with the decorator
from vorace.core import vorace
[...]
def cache_offline(cache_path=os.getcwd()):
    [...]
    def decorator(func):
        [...]
        def wrapper(*args, **kwargs):
            [...]
            return result
        return wrapper
    return decorator

def safe_mkdir(path):
    [...]

One of the decorated functions in vorace.core.vorace
from vorace.core.misc import *
[...]
@cache_offline(cache_path=".cache")
def classify_clusters_by_connectivity(xyz_data):
   [...]
[...]

The output from executing py.test in the project root
==================== test session starts ====================
platform linux -- Python 3.7.3, pytest-5.2.2, py-1.8.0, pluggy-0.12.0
rootdir: /home/flo/PycharmProjects/VorAce
plugins: arraydiff-0.3, openfiles-0.3.2, doctestplus-0.3.0, remotedata-0.3.1
collected 0 items / 1 errors                                                                                  

==================== ERRORS ====================
_________ ERROR collecting tests/scripts/test_scripts_helper.py _________
tests/scripts/test_scripts_helper.py:1: in <module>
    import vorace.scripts.scripts_helper as sh
vorace/scripts/scripts_helper.py:6: in <module>
    from vorace.core.misc import safe_mkdir
vorace/core/misc.py:8: in <module>
    from vorace.core import vorace
vorace/core/vorace.py:91: in <module>
    @cache_offline(cache_path=".cache")
E   NameError: name 'cache_offline' is not defined



If I execute a simple 0 == 0 test in my tests/scripts/test_scripts_helper.py file without importing from my project, the test runs with success.

A: When you run ./tests/scripts/test_scripts_helper.py python automatically sets ./tests/scripts/ into PYTHONPATH but not sets any other directories, so all your imports from other custom files should fail.
Set all your working directories into PYTHONPATH environment variable.
Something like that on Linux shell.
PYTHONPATH="${PYTHONPATH}:$dir


A: EDIT: I finally got the confirmation of a circular import.
At the opposite of what I thought, importing particular names from a module
like in  from x import y can be sensitive to circular imports, where import x can't.
To solve it, I just imported the module and use the syntax using the module prefixing the function call.
More information here : https://www.reddit.com/r/Python/comments/51hdup/from_import_vs_import_on_circular_import/
The problem what finally not related specifically to the decorator or pytest.

I worked around this issue by putting my cache_offline decorator in a separated package vorace.core.caching.py. Now I import this package only from vorace.core.vorace  where the function needing to be decorated resides.
This way my decorator is artificially excluded from the code imported by my unit test, but still available to the rest of my code for a normal application execution.
However pytest still have an issue here, it should not fail to import. I'm still taking any answer that can explain why pytest fails to import my decorator, and I keep the resolve for an answer of this kind.
