RecursionError when calling `pytest --help`
When calling pytest --help I get the following backtrace:
noes-MBP:... noe$ pytest --help
Traceback (most recent call last):
File "/Users/noe/.pyenv/versions/.../bin/pytest", line 10, in <module>
sys.exit(main())
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/_pytest/config/__init__.py", line 59, in main
config = _prepareconfig(args, plugins)
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/_pytest/config/__init__.py", line 209, in _prepareconfig
pluginmanager=pluginmanager, args=args
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/pluggy/hooks.py", line 286, in __call__
return self._hookexec(self, self.get_hookimpls(), kwargs)
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/pluggy/manager.py", line 92, in _hookexec
return self._inner_hookexec(hook, methods, kwargs)
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/pluggy/manager.py", line 86, in <lambda>
firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/pluggy/callers.py", line 203, in _multicall
gen.send(outcome)
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/_pytest/helpconfig.py", line 89, in pytest_cmdline_parse
config = outcome.get_result()
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/pluggy/callers.py", line 80, in get_result
raise ex[1].with_traceback(ex[2])
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/pluggy/callers.py", line 187, in _multicall
res = hook_impl.function(*args)
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/_pytest/config/__init__.py", line 720, in pytest_cmdline_parse
self.parse(args)
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/_pytest/config/__init__.py", line 928, in parse
self._preparse(args, addopts=addopts)
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/_pytest/config/__init__.py", line 874, in _preparse
self.pluginmanager.load_setuptools_entrypoints("pytest11")
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/pluggy/manager.py", line 297, in load_setuptools_entrypoints
plugin = ep.load()
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/importlib_metadata/__init__.py", line 94, in load
module = import_module(match.group('module'))
File "/Users/noe/.pyenv/versions/3.7.3/lib/python3.7/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "/Users/noe/.pyenv/versions/3.7.3/envs/.../lib/python3.7/site-packages/_pytest/assertion/rewrite.py", line 140, in exec_module
exec(co, module.__dict__)
File "/Users/noe/.pyenv/versions/.../lib/python3.7/site-packages/pytest_bdd/plugin.py", line 21, in <module>
@then('trace')
File "/Users/noe/.pyenv/versions/.../lib/python3.7/site-packages/pytest_bdd/steps.py", line 186, in decorator
setattr(get_caller_module(), get_step_fixture_name(parsed_step_name, step_type), lazy_step_func)
File "/Users/noe/.pyenv/versions/.../lib/python3.7/site-packages/pytest_bdd/steps.py", line 197, in get_caller_module
return get_caller_module(depth=depth)
File "/Users/noe/.pyenv/versions/.../lib/python3.7/site-packages/pytest_bdd/steps.py", line 197, in get_caller_module
return get_caller_module(depth=depth)
File "/Users/noe/.pyenv/versions/.../lib/python3.7/site-packages/pytest_bdd/steps.py", line 197, in get_caller_module
return get_caller_module(depth=depth)
[Previous line repeated 968 more times]
File "/Users/noe/.pyenv/versions/.../lib/python3.7/site-packages/pytest_bdd/steps.py", line 195, in get_caller_module
module = inspect.getmodule(frame)
File "/Users/noe/.pyenv/versions/3.7.3/lib/python3.7/inspect.py", line 725, in getmodule
file = getabsfile(object, _filename)
File "/Users/noe/.pyenv/versions/3.7.3/lib/python3.7/inspect.py", line 708, in getabsfile
_filename = getsourcefile(object) or getfile(object)
File "/Users/noe/.pyenv/versions/3.7.3/lib/python3.7/inspect.py", line 684, in getsourcefile
filename = getfile(object)
File "/Users/noe/.pyenv/versions/3.7.3/lib/python3.7/inspect.py", line 644, in getfile
if ismodule(object):
File "/Users/noe/.pyenv/versions/3.7.3/lib/python3.7/inspect.py", line 70, in ismodule
return isinstance(object, types.ModuleType)
RecursionError: maximum recursion depth exceeded while calling a Python object
Workarounds
-
python -m pytest --helpworks -
pip uninstall pytest_bdd && pip install pytest_bddfixed the problem on my machine
How to reproduce
Sorry, I do not have a proper reproduction scenario.
Here is the output of pip freeze | grep pytest:
pytest==5.1.2
pytest-bdd==3.2.1
pytest-cov==2.7.1
pytest-dotenv==0.4.0
pytest-forked==1.1.3
pytest-xdist==1.29.0
Investigation
The function get_caller_module does look fishy to me:
def get_caller_module(depth=2):
"""Return the module of the caller."""
frame = sys._getframe(depth)
module = inspect.getmodule(frame)
if module is None:
return get_caller_module(depth=depth)
return module
To me it looks like it's trying to loop towards the outermost stackframe, but forgets to change depth and therefore loops recursively towards the innermost stackframe, until triggering a recursion error.
Hi @Phlogistique, I'm not sure how to help you here, since there are no steps to reproduce the issue.
While I'm not able to reproduce this, I agree get_caller_module looks weird. If module was None, why would calling the function again with the exact same arguments change anything?
A colleague has experienced the same problem on his machine. Like for me, the problem disappeared when re-installing pytest_bdd.
Would you accept a patch to get_caller_module that tries to fix this?
@Phlogistique yes