When iterating through existing adaptation offers for the first time, Traits resolves string-based protocols by performing the appropriate import. That import can execute arbitrary Python code, including code that itself registers adaptation offers. If that occurs, we get a "dictionary changed size during iteration" RuntimeError.
To reproduce, create files file1.py and file2.py in the current directory, with the following contents. For file1.py:
from traits.api import adapt, Adapter, Interface, provides, register_factory
class ISomeInterface(Interface):
pass
@provides(ISomeInterface)
class MyAdapter(Adapter):
pass
register_factory(MyAdapter, "file2.SomeFactory", ISomeInterface)
adapt(range(10), ISomeInterface)
For file2.py:
from traits.api import Adapter, Interface, provides, register_factory
class ISomeOtherInterface(Interface):
pass
@provides(ISomeOtherInterface)
class SliceAdapter(Adapter):
pass
register_factory(SliceAdapter, slice, ISomeOtherInterface)
class SomeFactory():
pass
Now executing file1.py gives the following traceback:
(traits) mdickinson@mirzakhani Desktop % python file1.py
Traceback (most recent call last):
File "/Users/mdickinson/Desktop/file1.py", line 11, in <module>
adapt(range(10), ISomeInterface)
File "/Users/mdickinson/Enthought/ETS/traits/traits/adaptation/adaptation_manager.py", line 413, in adapt
return manager.adapt(adaptee, to_protocol, default)
File "/Users/mdickinson/Enthought/ETS/traits/traits/adaptation/adaptation_manager.py", line 133, in adapt
result = self._adapt(adaptee, to_protocol)
File "/Users/mdickinson/Enthought/ETS/traits/traits/adaptation/adaptation_manager.py", line 260, in _adapt
edges = self._get_applicable_offers(current_protocol, path)
File "/Users/mdickinson/Enthought/ETS/traits/traits/adaptation/adaptation_manager.py", line 321, in _get_applicable_offers
for from_protocol_name, offers in self._adaptation_offers.items():
RuntimeError: dictionary changed size during iteration
We should fix the code to be more robust against this kind of change.
When iterating through existing adaptation offers for the first time, Traits resolves string-based protocols by performing the appropriate import. That import can execute arbitrary Python code, including code that itself registers adaptation offers. If that occurs, we get a "dictionary changed size during iteration" RuntimeError.
To reproduce, create files
file1.py
andfile2.py
in the current directory, with the following contents. Forfile1.py
:For
file2.py
:Now executing
file1.py
gives the following traceback:We should fix the code to be more robust against this kind of change.