Repository navigation
3.8.0: dictionary changed size during iteration iterating on importlib_metadata.distributions() #293
Copy link
Copy link
Closed
Description
3.8 is breaking my CI Link.
For now I will pin to 3.7.3, but you might want to investigate it.
Exception:
nox > [2021-03-27 02:20:07,146] Command pytest --nbval examples/jupyter_notebooks/compose_configs_in_notebook.ipynb failed with exit code 1:
Traceback (most recent call last):
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/bin/pytest", line 8, in <module>
sys.exit(console_main())
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/_pytest/config/__init__.py", line 185, in console_main
code = main()
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/_pytest/config/__init__.py", line 143, in main
config = _prepareconfig(args, plugins)
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/_pytest/config/__init__.py", line 319, in _prepareconfig
pluginmanager=pluginmanager, args=args
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/pluggy/hooks.py", line 286, in __call__
return self._hookexec(self, self.get_hookimpls(), kwargs)
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/pluggy/manager.py", line 93, in _hookexec
return self._inner_hookexec(hook, methods, kwargs)
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/pluggy/manager.py", line 87, in <lambda>
firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/pluggy/callers.py", line 203, in _multicall
gen.send(outcome)
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/_pytest/helpconfig.py", line 100, in pytest_cmdline_parse
config: Config = outcome.get_result()
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/pluggy/callers.py", line 80, in get_result
raise ex[1].with_traceback(ex[2])
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/pluggy/callers.py", line 187, in _multicall
res = hook_impl.function(*args)
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/_pytest/config/__init__.py", line 1003, in pytest_cmdline_parse
self.parse(args)
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/_pytest/config/__init__.py", line 1283, in parse
self._preparse(args, addopts=addopts)
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/_pytest/config/__init__.py", line 1172, in _preparse
self.pluginmanager.load_setuptools_entrypoints("pytest11")
File "/home/circleci/project/.nox/test_jupyter_notebooks-3-6/lib/python3.6/site-packages/pluggy/manager.py", line 289, in load_setuptools_entrypoints
for dist in importlib_metadata.distributions():
RuntimeError: dictionary changed size during iteration
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
m-melis commentedon Mar 27, 2021
Confirmed. All our CI pipeline unittests fail due to the new version: https://gitlab.com/secml/secml/-/pipelines/277431124
This is independent of the Python version.
jaraco commentedon Mar 27, 2021
Thanks for the report. I can't tell from the traceback what's happening, and the issue isn't happening in my CI environments that also rely on importlib_metadata 3.8 and pluggy. Moreover, when looking at #290, I don't see anything in particular where a dictionary size might be altered. There is this line, but the
infosandeggsare mutated in the__init__so shouldn't be iterated over before they're fully constructed.Can someone help distill the issue into a reproducer I can use to troubleshoot?
jaraco commentedon Mar 27, 2021
I'm able to reproduce the issue by checking out secml and running tox -e py36.
jaraco commentedon Mar 27, 2021
If I disable the
lru_cachearoundFastPath.lookup, the problem goes away:jaraco commentedon Mar 27, 2021
If I switch to a different method of memoization of that method, the problem remains:
That indicates that it's the memoization of the lookup object that's implicated in the failure.
omry commentedon Mar 27, 2021
The only change between 3.7.3 and 3.8.0 is the caching (v3.7.3...v3.8.0).
Can the content of the cached object somehow change after it's created?
jaraco commentedon Mar 27, 2021
I've figured out the issue. It's in how Lookup.search uses lazy evaluation of self.info and how
collections.defaultdictwill add keys to the dict when none exist. So here's what happens:jsonschema, which invokesimportlib_metadata.version('jsonschema'), which invokes Lookup.search('jsonschema').jsonschema, by dint of collections.defaultdict, creates a new entry inLookup.infos, which is still being iterated over by Pluggy in 1.Eagerly consume infos and eggs. Workaround for #293. Still needs a test.
omry commentedon Mar 27, 2021
Gotcha.
A solution can be to give a copy of the dict for users to iterate on.
There is a tiny perf cost but it will should work around the problem.
jaraco commentedon Mar 27, 2021
I've got a workaround going out in 3.8.1. I still want to produce a test that captures the failure, but I wanted to get the fix out asap.
omry commentedon Mar 27, 2021
I just tested your fix and it solves my problem.
jaraco commentedon Mar 27, 2021
Sorry for the inconvenience.
Add test capturing failure. Ref #293.
omry commentedon Mar 27, 2021
No worries, thanks for fixing it so quickly.
Test looks good to me, I hope that's the last of this problem :).