I have a package for python 3.5 and 3.6 that has optional dependencies for which I want tests (pytest) that run on either version.
I made a reduced example below consisting of two files, a simple __init__.py
where the optional package "requests" (just an example) is imported and a flag is set to indicate the availability of requests.
mypackage/
├── mypackage
│ └── __init__.py
└── test_init.py
The __init__.py
file content:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
requests_available = True
try:
import requests
except ImportError:
requests_available = False
The test_init.py
file content:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pytest, sys
def test_requests_missing(monkeypatch):
import mypackage
import copy
fakesysmodules = copy.copy(sys.modules)
fakesysmodules["requests"] = None
monkeypatch.delitem(sys.modules,"requests")
monkeypatch.setattr("sys.modules", fakesysmodules)
from importlib import reload
reload(mypackage)
assert mypackage.requests_available == False
if __name__ == '__main__':
pytest.main([__file__, "-vv", "-s"])
The test_requests_missing
test works on Python 3.6.5:
runfile('/home/bjorn/python_packages/mypackage/test_init.py', wdir='/home/bjorn/python_packages/mypackage')
============================= test session starts ==============================
platform linux -- Python 3.6.5, pytest-3.6.1, py-1.5.2, pluggy-0.6.0 -- /home/bjorn/anaconda3/envs/bjorn36/bin/python
cachedir: .pytest_cache
rootdir: /home/bjorn/python_packages/mypackage, inifile:
plugins: requests-mock-1.5.0, mock-1.10.0, cov-2.5.1, nbval-0.9.0, hypothesis-3.38.5
collecting ... collected 1 item
test_init.py::test_requests_missing PASSED
=========================== 1 passed in 0.02 seconds ===========================
But not on Python 3.5.4:
runfile('/home/bjorn/python_packages/mypackage/test_init.py', wdir='/home/bjorn/python_packages/mypackage')
========================================================= test session starts ==========================================================
platform linux -- Python 3.5.4, pytest-3.6.1, py-1.5.2, pluggy-0.6.0 -- /home/bjorn/anaconda3/envs/bjorn35/bin/python
cachedir: .pytest_cache
rootdir: /home/bjorn/python_packages/mypackage, inifile:
plugins: requests-mock-1.5.0, mock-1.10.0, cov-2.5.1, nbval-0.9.1, hypothesis-3.38.5
collecting ... collected 1 item
test_init.py::test_requests_missing FAILED
=============================================================== FAILURES ===============================================================
________________________________________________________ test_requests_missing _________________________________________________________
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f9a2953acc0>
def test_requests_missing(monkeypatch):
import mypackage
import copy
fakesysmodules = copy.copy(sys.modules)
fakesysmodules["requests"] = None
monkeypatch.delitem(sys.modules,"requests")
monkeypatch.setattr("sys.modules", fakesysmodules)
from importlib import reload
> reload(mypackage)
test_init.py:13:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../anaconda3/envs/bjorn35/lib/python3.5/importlib/__init__.py:166: in reload
_bootstrap._exec(spec, module)
<frozen importlib._bootstrap>:626: in _exec
???
<frozen importlib._bootstrap_external>:697: in exec_module
???
<frozen importlib._bootstrap>:222: in _call_with_frames_removed
???
mypackage/__init__.py:8: in <module>
import requests
../../anaconda3/envs/bjorn35/lib/python3.5/site-packages/requests/__init__.py:97: in <module>
from . import utils
.... VERY LONG OUTPUT ....
from . import utils
../../anaconda3/envs/bjorn35/lib/python3.5/site-packages/requests/__init__.py:97: in <module>
from . import utils
<frozen importlib._bootstrap>:968: in _find_and_load
???
<frozen importlib._bootstrap>:953: in _find_and_load_unlocked
???
<frozen importlib._bootstrap>:896: in _find_spec
???
<frozen importlib._bootstrap_external>:1171: in find_spec
???
<frozen importlib._bootstrap_external>:1145: in _get_spec
???
<frozen importlib._bootstrap_external>:1273: in find_spec
???
<frozen importlib._bootstrap_external>:1245: in _get_spec
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
name = 'requests', location = '/home/bjorn/anaconda3/envs/bjorn35/lib/python3.5/site-packages/requests/__init__.py'
> ???
E RecursionError: maximum recursion depth exceeded
<frozen importlib._bootstrap_external>:575: RecursionError
======================================================= 1 failed in 2.01 seconds =======================================================
I have two questions:
Why do I see this difference? Relevant packages seem to be of the same version on both 3.5 and 3.6.
Is there a better way to do what I want? The code I have now is stitched together from examples found online. I have tried to patch the import mechanism in an attempt to avoid "reload", but I have not managed.