Upstream fabiocaccamo/python-benedict state of the touched files before 8e13b67bfe
This commit is contained in:
1 parent
f8fdadb938
commit
6701da5cf1
2 files changed
+5
-66
No files matched your search
@@ -22,32 +22,15 @@ class BaseDict(dict[_K, _V]):
|
|||||||
_dict: dict[_K, _V] | None
|
_dict: dict[_K, _V] | None
|
||||||
_frozen: bool
|
_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
|
@classmethod
|
||||||
def _get_dict_or_value(cls, value: Any) -> Any:
|
def _get_dict_or_value(cls, value: Any) -> Any:
|
||||||
value = value.dict() if isinstance(value, cls) else value
|
value = value.dict() if isinstance(value, cls) else value
|
||||||
if isinstance(value, MutableMapping):
|
if isinstance(value, MutableMapping):
|
||||||
value_id = id(value)
|
for key in value.keys():
|
||||||
if value_id in cls._unwrapping_ids:
|
key_val = value[key]
|
||||||
# it contains itself; unwind here before reaching code with no cycle
|
if isinstance(key_val, cls):
|
||||||
# protection of its own
|
key_val = cls._get_dict_or_value(value[key])
|
||||||
raise ValueError(
|
value[key] = key_val
|
||||||
"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)
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def __new__(cls, *args: Any, **kwargs: Any) -> Self:
|
def __new__(cls, *args: Any, **kwargs: Any) -> Self:
|
||||||
|
|||||||
@@ -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)
|
|
||||||
Reference in new issue
Block a user