Skip to content

Commit

Permalink
Fix dict compatibility making keylist feature working only with lis…
Browse files Browse the repository at this point in the history
…ts. #412 #432
  • Loading branch information
fabiocaccamo committed Oct 18, 2024
1 parent 62089a7 commit 6d6de76
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 56 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ python-benedict is a dict subclass with **keylist/keypath/keyattr** support, **I
- [Usage](#usage)
- [Basics](#basics)
- [Keyattr](#keyattr) `my_dict.x.y.z`
- [Keylist](#keylist) `my_dict["x", "y", "z"]`
- [Keylist](#keylist) `my_dict[["x", "y", "z"]]`
- [Keypath](#keypath) `my_dict["x.y.z"]`
- [Custom keypath separator](#custom-keypath-separator)
- [Change keypath separator](#change-keypath-separator)
Expand Down Expand Up @@ -136,16 +136,16 @@ Wherever a **key** is used, it is possible to use also a **list (or a tuple) of
d = benedict()

# set values by keys list
d["profile", "firstname"] = "Fabio"
d["profile", "lastname"] = "Caccamo"
d[["profile", "firstname"]] = "Fabio"
d[["profile", "lastname"]] = "Caccamo"
print(d) # -> { "profile":{ "firstname":"Fabio", "lastname":"Caccamo" } }
print(d["profile"]) # -> { "firstname":"Fabio", "lastname":"Caccamo" }

# check if keypath exists in dict
print(["profile", "lastname"] in d) # -> True
print([["profile", "lastname"]] in d) # -> True

# delete value by keys list
del d["profile", "lastname"]
del d[["profile", "lastname"]]
print(d["profile"]) # -> { "firstname":"Fabio" }
```

Expand Down
12 changes: 6 additions & 6 deletions benedict/dicts/keylist/keylist_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def __contains__(self, key):
if type_util.is_list_or_tuple(key):
if type_util.is_list(key):
return self._contains_by_keys(key)
return super().__contains__(key)

Expand All @@ -19,7 +19,7 @@ def _contains_by_keys(self, keys):
return False

def __delitem__(self, key):
if type_util.is_list_or_tuple(key):
if type_util.is_list(key):
self._delitem_by_keys(key)
return
super().__delitem__(key)
Expand All @@ -35,7 +35,7 @@ def _delitem_by_keys(self, keys):
raise KeyError(f"Invalid keys: {keys!r}")

def __getitem__(self, key):
if type_util.is_list_or_tuple(key):
if type_util.is_list(key):
return self._getitem_by_keys(key)
return super().__getitem__(key)

Expand All @@ -46,7 +46,7 @@ def _getitem_by_keys(self, keys):
raise KeyError(f"Invalid keys: {keys!r}")

def __setitem__(self, key, value):
if type_util.is_list_or_tuple(key):
if type_util.is_list(key):
self._setitem_by_keys(key, value)
return
super().__setitem__(key, value)
Expand All @@ -55,7 +55,7 @@ def _setitem_by_keys(self, keys, value):
keylist_util.set_item(self, keys, value)

def get(self, key, default=None):
if type_util.is_list_or_tuple(key):
if type_util.is_list(key):
return self._get_by_keys(key, default)
return super().get(key, default)

Expand All @@ -68,7 +68,7 @@ def _get_by_keys(self, keys, default=None):
return default

def pop(self, key, *args):
if type_util.is_list_or_tuple(key):
if type_util.is_list(key):
return self._pop_by_keys(key, *args)
return super().pop(key, *args)

Expand Down
2 changes: 1 addition & 1 deletion benedict/dicts/keypath/keypath_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def parse_keys(keypath, separator):
"""
Parse keys from keylist or keypath using the given separator.
"""
if type_util.is_list_or_tuple(keypath):
if type_util.is_list(keypath):
keys = []
for key in keypath:
keys += parse_keys(key, separator)
Expand Down
17 changes: 0 additions & 17 deletions tests/dicts/keylist/test_keylist_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ def test_contains(self):
d["a"]["b"] = True
self.assertTrue(["a", "b"] in d)
self.assertFalse(["a", "b", "c"] in d)
# with keys as tuple
self.assertTrue(("a", "b") in d)
self.assertFalse(("a", "b", "c") in d)

def test_delitem(self):
d = KeylistDict()
Expand All @@ -27,30 +24,20 @@ def test_delitem(self):
del d[["a", "b", "c"]]
self.assertFalse(["a", "b", "c"] in d)
self.assertTrue(["a", "b"] in d)
# with keys as tuple
del d[("a", "b")]
self.assertFalse(["a", "b"] in d)
self.assertTrue(["a"] in d)

def test_get(self):
d = KeylistDict()
d["a"] = {}
d["a"]["b"] = True
self.assertEqual(d.get(["a", "b"]), True)
self.assertEqual(d.get(["a", "b"]), True)
# with keys as tuple
self.assertEqual(d.get(("a", "b")), True)
self.assertEqual(d.get(("a", "b")), True)

def test_getitem(self):
d = KeylistDict()
d["a"] = {}
d["a"]["b"] = True
self.assertEqual(d[["a", "b"]], True)
self.assertEqual(d[["a", "b"]], True)
# with keys as tuple
self.assertEqual(d[("a", "b")], True)
self.assertEqual(d[("a", "b")], True)

def test_pop(self):
d = KeylistDict()
Expand All @@ -61,10 +48,6 @@ def test_pop(self):
d.pop(["a", "b", "c"])
self.assertFalse(["a", "b", "c"] in d)
self.assertTrue(["a", "b"] in d)
# with keys as tuple
d.pop(("a", "b"))
self.assertFalse(["a", "b"] in d)
self.assertTrue(["a"] in d)

def test_set(self):
# TODO
Expand Down
44 changes: 17 additions & 27 deletions tests/dicts/keypath/test_keypath_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,17 +334,11 @@ def test_get_item_with_keys_list(self):
},
}
b = KeypathDict(d)
self.assertEqual(b["a", "b.c"], 1)
self.assertEqual(b[["a", "b.c"]], 1)
self.assertEqual(b[("a", "b.c")], 1)
self.assertEqual(b["a", "b", "c"], 1)
self.assertEqual(b[["a", "b", "c"]], 1)
self.assertEqual(b[("a", "b", "c")], 1)
self.assertEqual(b["a", "b", "d"], 2)
self.assertEqual(b[["a", "b", "d"]], 2)
self.assertEqual(b[("a", "b", "d")], 2)
with self.assertRaises(KeyError):
_ = b["a", "b", "e"]
_ = b[["a", "b", "e"]]

def test_get_item_with_keys_list_and_no_keypath_separator(self):
d = {
Expand All @@ -357,16 +351,12 @@ def test_get_item_with_keys_list_and_no_keypath_separator(self):
}
b = KeypathDict(d, keypath_separator=None)
with self.assertRaises(KeyError):
_ = b["a", "b.c"]
_ = b[["a", "b.c"]]

self.assertEqual(b["a", "b", "c"], 1)
self.assertEqual(b[["a", "b", "c"]], 1)
self.assertEqual(b[("a", "b", "c")], 1)
self.assertEqual(b["a", "b", "d"], 2)
self.assertEqual(b[["a", "b", "d"]], 2)
self.assertEqual(b[("a", "b", "d")], 2)
with self.assertRaises(KeyError):
_ = b["a", "b", "e"]
_ = b[["a", "b", "e"]]

def test_has_with_1_key(self):
d = {
Expand Down Expand Up @@ -516,13 +506,13 @@ def test_setitem_with_keys_list(self):
},
}
b = KeypathDict(d)
b["a", "b.c"] = 2
b[["a", "b.c"]] = 2
self.assertEqual(b["a.b.c"], 2)
b["a", "b", "c"] = 3
b[["a", "b", "c"]] = 3
self.assertEqual(b["a.b.c"], 3)
b["a", "b", "d"] = 4
b[["a", "b", "d"]] = 4
self.assertEqual(b["a.b.d"], 4)
b["a", "b", "e"] = 5
b[["a", "b", "e"]] = 5
self.assertEqual(b["a.b.e"], 5)

def test_setitem_with_keys_list_and_no_keypath_separator(self):
Expand All @@ -535,20 +525,20 @@ def test_setitem_with_keys_list_and_no_keypath_separator(self):
},
}
b = KeypathDict(d, keypath_separator=None)
b["a", "b", "c"] = 3
b[["a", "b", "c"]] = 3
with self.assertRaises(KeyError):
_ = b["a.b.c"]
self.assertEqual(b["a", "b", "c"], 3)
self.assertEqual(b[["a", "b", "c"]], 3)

b["a", "b", "d"] = 4
b[["a", "b", "d"]] = 4
with self.assertRaises(KeyError):
_ = b["a.b.d"]
self.assertEqual(b["a", "b", "d"], 4)
self.assertEqual(b[["a", "b", "d"]], 4)

b["a", "b", "e"] = 5
b[["a", "b", "e"]] = 5
with self.assertRaises(KeyError):
_ = b["a.b.e"]
self.assertEqual(b["a", "b", "e"], 5)
self.assertEqual(b[["a", "b", "e"]], 5)

def test_setitem_with_dict_value_with_separator_in_keys(self):
d = {
Expand Down Expand Up @@ -668,8 +658,8 @@ def test_delitem_with_keys_list(self):
}
b = KeypathDict(d)
with self.assertRaises(KeyError):
del b["a", "b", "c", "d"]
del b["a", "b", "c"]
del b[["a", "b", "c", "d"]]
del b[["a", "b", "c"]]
self.assertEqual(b.get("a.b.c", 3), 3)

def test_delitem_with_keys_list_and_no_keypath_separator(self):
Expand All @@ -683,8 +673,8 @@ def test_delitem_with_keys_list_and_no_keypath_separator(self):
}
b = KeypathDict(d, keypath_separator=None)
with self.assertRaises(KeyError):
del b["a", "b", "c", "d"]
del b["a", "b", "c"]
del b[["a", "b", "c", "d"]]
del b[["a", "b", "c"]]
self.assertEqual(b.get("a.b.c", 3), 3)

def test_pop_default(self):
Expand Down
31 changes: 31 additions & 0 deletions tests/github/test_issue_0432.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import unittest
from benedict import benedict


class github_issue_0432_test_case(unittest.TestCase):
"""
This class describes a github issue 0432 test case.
https://github.com/fabiocaccamo/python-benedict/issues/432
To run this specific test:
- Run python -m unittest tests.github.test_issue_0432
"""

def test_tuple_as_key_like_dict_432(self):
d1 = {}
d2 = benedict()
d1[(0, 0, 1)] = "a"
d2[(0, 0, 1)] = "a"
self.assertEqual(d1, d2)

def test_tuple_as_key_like_dict_412(self):
d = {}
d[("a", True)] = "test"

b1 = benedict()
b1[("a", True)] = "test"
self.assertEqual(d, b1)

b2 = benedict()
b2.update({("a", True): "test"})
self.assertEqual(d, b2)

0 comments on commit 6d6de76

Please sign in to comment.