enthought / enthought/traits

"dictionary changed size during iteration" error from AdaptationManager operations

Open
#1,616 0 comments 0 reactions 0 assignees View on GitHub
type: bug
Dominant language
Python
Stars
462
Forks
90
PR merge metrics
No merged PRs in 30d

Description

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`:
```python
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`:
```python
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:
```python
(traits) mdickinson@mirzakhani Desktop % python file1.py
Traceback (most recent call last):
File "/Users/mdickinson/Desktop/file1.py", line 11, in
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.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.