diff --git a/benedict/dicts/base/base_dict.py b/benedict/dicts/base/base_dict.py index 7dec51f..a8ad765 100644 --- a/benedict/dicts/base/base_dict.py +++ b/benedict/dicts/base/base_dict.py @@ -22,32 +22,15 @@ class BaseDict(dict[_K, _V]): _dict: dict[_K, _V] | None _frozen: bool - # ids of mappings being unwrapped anywhere on the call stack, to detect - # self-referential structures instead of recursing forever - _unwrapping_ids: set[int] = set() - @classmethod def _get_dict_or_value(cls, value: Any) -> Any: value = value.dict() if isinstance(value, cls) else value if isinstance(value, MutableMapping): - value_id = id(value) - if value_id in cls._unwrapping_ids: - # it contains itself; unwind here before reaching code with no cycle - # protection of its own - raise ValueError( - "Cannot assign a dict that contains itself " - "(directly or indirectly): self-referential " - "(cyclic) structures are not supported." - ) - cls._unwrapping_ids.add(value_id) - try: - for key in value.keys(): - key_val = value[key] - if isinstance(key_val, cls): - key_val = cls._get_dict_or_value(value[key]) - value[key] = key_val - finally: - cls._unwrapping_ids.discard(value_id) + for key in value.keys(): + key_val = value[key] + if isinstance(key_val, cls): + key_val = cls._get_dict_or_value(value[key]) + value[key] = key_val return value def __new__(cls, *args: Any, **kwargs: Any) -> Self: diff --git a/tests/github/test_issue_0592.py b/tests/github/test_issue_0592.py deleted file mode 100644 index 525949d..0000000 --- a/tests/github/test_issue_0592.py +++ /dev/null @@ -1,44 +0,0 @@ -import unittest - -from benedict import benedict - - -class github_issue_0592_test_case(unittest.TestCase): - """ - This class describes a github issue 0592 test case. - https://github.com/fabiocaccamo/python-benedict/issues/592 - - To run this specific test: - - Run python -m unittest tests.github.test_issue_0592 - """ - - def test_assigning_dict_to_its_own_nested_descendant_does_not_raise(self) -> None: - # not self-referential yet at assignment time, so it must keep working - d = benedict(keyattr_enabled=True, keyattr_dynamic=True) - d.a.b.c = d - self.assertIs(dict.__getitem__(d, "a")["b"]["c"], d) - - def test_assigning_dict_to_its_own_nested_descendant_twice_does_not_recurse( - self, - ) -> None: - # once `d` contains itself, unwrapping it again must not raise - # RecursionError (it used to crash the process) - d = benedict(keyattr_enabled=True, keyattr_dynamic=True) - d.a.b.c = d - with self.assertRaises(ValueError): - d.a.b.d.e = d - - def test_self_assignment_at_new_key_still_works(self) -> None: - # assigning a dict to itself under a new key is unaffected by the fix - d = benedict({"a": {"b": 1}}) - d["self"] = d - self.assertIsInstance(d["self"], benedict) - self.assertEqual(d["self"]["a"], {"b": 1}) - - def test_normal_nested_dict_assignment_is_unaffected(self) -> None: - # non self-referential values must still be unwrapped as before - inner = benedict({"x": 1}) - outer = benedict() - outer["inner"] = inner - self.assertEqual(outer, {"inner": {"x": 1}}) - self.assertIsNot(outer["inner"], inner)