From 4014dbfe0faad96555e738060f1128fb445f4de7 Mon Sep 17 00:00:00 2001 From: kaliv0 Date: Sat, 14 Dec 2024 15:59:16 +0200 Subject: [PATCH 1/3] added clear_aliases() and more test cases --- aldict/alias_dict.py | 3 ++ tests/test_alias_dict.py | 59 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/aldict/alias_dict.py b/aldict/alias_dict.py index e22fc81..a9c5700 100644 --- a/aldict/alias_dict.py +++ b/aldict/alias_dict.py @@ -25,6 +25,9 @@ def remove_alias(self, *aliases): except KeyError: raise AliasError(alias) + def clear_aliases(self): + self._alias_dict.clear() + def aliases(self): return self._alias_dict.keys() diff --git a/tests/test_alias_dict.py b/tests/test_alias_dict.py index a9ca699..d5aa87c 100644 --- a/tests/test_alias_dict.py +++ b/tests/test_alias_dict.py @@ -136,13 +136,12 @@ def test_get(alias_dict): assert alias_dict.get(".foo") is None -def test_pop(alias_dict): +def test_pop_alias_doesnt_remove_key(alias_dict): assert alias_dict.pop(".yml") == { "callable": "safe_load", "import_mod": "yaml", "read_mode": "r", } - # removing the alias doesn't remove the key assert ".yaml" in alias_dict @@ -175,15 +174,65 @@ def test_repr(alias_dict): def test_eq(): - ad_1 = AliasDict({"a": 1, "b": 2}) + ad_0 = {"a": 1, "b": 2} + ad_1 = AliasDict(ad_0) ad_1.add_alias("a", "aa", "aaa") - ad_2 = AliasDict({"a": 1, "b": 2}) + ad_2 = AliasDict(ad_0) ad_2.add_alias("a", "aa", "aaa") - ad_3 = AliasDict({"a": 1, "b": 2}) + ad_3 = AliasDict(ad_0) ad_3.add_alias("a", "abc") assert ad_1 == ad_2 assert ad_1 != ad_3 assert ad_2 != ad_3 + + +def test_dict_len_doesnt_include_aliases(alias_dict): + assert list(alias_dict.keys()) == [".json", ".yaml", ".toml", ".yml"] + assert len(alias_dict) == 3 + + +def test_popitem(alias_dict): + # pops first item -> MutableMapping.popitem() + assert alias_dict.popitem() == ( + ".json", + {"callable": "load", "import_mod": "json", "read_mode": "r"}, + ) + assert alias_dict.popitem() == ( + ".yaml", + {"callable": "safe_load", "import_mod": "yaml", "read_mode": "r"}, + ) + assert list(alias_dict.aliased_keys()) == [] + assert list(alias_dict.keys()) == [".toml"] + + +def test_clear(alias_dict): + alias_dict.clear() + assert len(alias_dict.items()) == 0 + + +def test_clear_aliases(alias_dict): + alias_dict.clear_aliases() + assert len(alias_dict.aliases()) == 0 + assert list(alias_dict.items()) == [ + (".json", {"callable": "load", "import_mod": "json", "read_mode": "r"}), + (".yaml", {"callable": "safe_load", "import_mod": "yaml", "read_mode": "r"}), + (".toml", {"callable": "load", "import_mod": "tomli", "read_mode": "r"}), + ] + + +def test_setdefault(): + ad = AliasDict({"a": 1, "b": 2}) + ad.setdefault("foo", "bar") + ad.add_alias("foo", "fizz") + assert ad["foo"] == "bar" + assert ad["fizz"] == "bar" + + +def test_update_modifies_aliases(): + ad = AliasDict({"a": 1, "b": 2}) + ad.add_alias("a", "aa", "aaa") + ad.update(**{"a": 40, "y": 50}) + assert list(ad.items()) == [("a", 40), ("b", 2), ("y", 50), ("aa", 40), ("aaa", 40)] From ec9b0ddbc4ea21e4952f96dd1d02fabc38436db3 Mon Sep 17 00:00:00 2001 From: kaliv0 Date: Sat, 14 Dec 2024 16:05:28 +0200 Subject: [PATCH 2/3] tested setdefault on existing key --- tests/test_alias_dict.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/test_alias_dict.py b/tests/test_alias_dict.py index d5aa87c..765ce8e 100644 --- a/tests/test_alias_dict.py +++ b/tests/test_alias_dict.py @@ -204,7 +204,7 @@ def test_popitem(alias_dict): ".yaml", {"callable": "safe_load", "import_mod": "yaml", "read_mode": "r"}, ) - assert list(alias_dict.aliased_keys()) == [] + assert len(alias_dict.aliased_keys()) == 0 assert list(alias_dict.keys()) == [".toml"] @@ -231,6 +231,14 @@ def test_setdefault(): assert ad["fizz"] == "bar" +def test_setdefault_on_existing_aliased_key(): + ad = AliasDict({"a": 1, "b": 2}) + ad.setdefault("a", 42) + ad.add_alias("a", "aa") + assert ad["a"] == 1 + assert ad["aa"] == 1 + + def test_update_modifies_aliases(): ad = AliasDict({"a": 1, "b": 2}) ad.add_alias("a", "aa", "aaa") From 51408bddb320be84aca509bcc20261260b244f1d Mon Sep 17 00:00:00 2001 From: kaliv0 Date: Sun, 15 Dec 2024 12:47:45 +0200 Subject: [PATCH 3/3] expanded readme --- README.md | 78 ++++++++++++++++++++++++++++++++++++++-- aldict/alias_dict.py | 11 +++--- pyproject.toml | 2 +- tests/test_alias_dict.py | 4 +-- 4 files changed, 86 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 987a8bd..7f3afd8 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@

--- - # Aldict [![tests](https://img.shields.io/github/actions/workflow/status/kaliv0/aldict/ci.yml)](https://github.com/kaliv0/aldict/actions/workflows/ci.yml) @@ -11,4 +10,79 @@ [![PyPI](https://img.shields.io/pypi/v/aldict.svg)](https://pypi.org/project/aldict/) [![License](https://img.shields.io/badge/License-MIT-yellow?style=flat-square)](https://github.com/kaliv0/aldict/blob/main/LICENSE) -Multi-key dictionary, supports adding and manipulating key-aliases pointing to shared values \ No newline at end of file +Multi-key dictionary, supports adding and manipulating key-aliases pointing to shared values + +--- +## How to use + +- add_alias +
(pass key as first parameter and alias(es) as variadic params) +```python +ad = AliasDict({"a": 1, "b": 2}) +ad.add_alias("a", "aa") +ad.add_alias("b", "bb", "Bbb") +assert ad["a"] == ad["aa"] == 1 +assert ad["b"] == ad["bb"] == ad["Bbb"] == 2 +``` +- remove_alias +
(pass alias(es) to be removed as variadic parameters) +```python +ad.remove_alias("aa") +ad.remove_alias("bb", "Bbb") +assert len(ad.aliases()) == 0 +``` +- clear_aliases +
(remove all aliases at once) +```python +ad.clear_aliases() +assert len(ad.aliases()) == 0 +``` +- update alias +
(point alias to different key) +```python +ad = AliasDict({"a": 1, "b": 2}) +ad.add_alias("a", "ab") +assert list(ad.items()) == [('a', 1), ('b', 2), ('ab', 1)] + +ad.add_alias("b", "ab") +assert list(ad.items()) == [('a', 1), ('b', 2), ('ab', 2)] +``` +- read all aliases +```python +ad = AliasDict({"a": 1, "b": 2}) +ad.add_alias("a", "aa") +ad.add_alias("b", "bb", "B") +ad.add_alias("a", "ab", "A") +assert list(ad.aliases()) == ['aa', 'bb', 'B', 'ab', 'A'] +``` +- aliased_keys +
(read keys with corresponding alias(es)) +```python +assert dict(ad.aliased_keys()) == {'a': ['aa', 'ab', 'A'], 'b': ['bb', 'B']} +``` +- read dictviews +
(dict.keys() and dict.items() include aliased versions) +```python +ad = AliasDict({"x": 10, "y": 20}) +ad.add_alias("x", "Xx") +ad.add_alias("y", "Yy", "xyz") + +ad.keys() +ad.values() +ad.items() +``` +```shell +dict_keys(['x', 'y', 'Xx', 'Yy', 'xyz']) +dict_values([10, 20]) +dict_items([('x', 10), ('y', 20), ('Xx', 10), ('Yy', 20), ('xyz', 20)]) +``` +- remove key and aliases +```python +ad.pop("y") +assert list(ad.items()) == [('x', 10), ('Xx', 10)] +``` +- origin_keys +
(get original keys only) +```python +assert list(ad.origin_keys()) == ['x', 'y'] +``` \ No newline at end of file diff --git a/aldict/alias_dict.py b/aldict/alias_dict.py index a9c5700..1988f8d 100644 --- a/aldict/alias_dict.py +++ b/aldict/alias_dict.py @@ -22,8 +22,8 @@ def remove_alias(self, *aliases): for alias in aliases: try: self._alias_dict.__delitem__(alias) - except KeyError: - raise AliasError(alias) + except KeyError as e: + raise AliasError(alias) from e def clear_aliases(self): self._alias_dict.clear() @@ -52,8 +52,8 @@ def items(self): def __missing__(self, key): try: return super().__getitem__(self._alias_dict[key]) - except AttributeError: - raise KeyError(key) + except AttributeError as e: + raise KeyError(key) from e def __setitem__(self, key, value): try: @@ -77,6 +77,9 @@ def __iter__(self): for item in self.keys(): yield item + def __len__(self): + return len(self.keys()) + def __repr__(self): return f"AliasDict({self.items()})" diff --git a/pyproject.toml b/pyproject.toml index 6d63010..fd8d19d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "aldict" -version = "0.1.0" +version = "1.0.0" readme = "README.md" authors = [{ name = "Kaloyan Ivanov", email = "kaloyan.ivanov88@gmail.com" }] description = "Multi-key dictionary, supports adding and manipulating key-aliases pointing to shared values" diff --git a/tests/test_alias_dict.py b/tests/test_alias_dict.py index 765ce8e..f9b9af8 100644 --- a/tests/test_alias_dict.py +++ b/tests/test_alias_dict.py @@ -189,9 +189,9 @@ def test_eq(): assert ad_2 != ad_3 -def test_dict_len_doesnt_include_aliases(alias_dict): +def test_dict_len_includes_aliases(alias_dict): assert list(alias_dict.keys()) == [".json", ".yaml", ".toml", ".yml"] - assert len(alias_dict) == 3 + assert len(alias_dict) == 4 def test_popitem(alias_dict):