aldict 1.0.3__tar.gz → 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aldict-1.0.3 → aldict-1.1.0}/PKG-INFO +71 -16
- aldict-1.0.3/aldict.egg-info/PKG-INFO → aldict-1.1.0/README.md +67 -23
- {aldict-1.0.3 → aldict-1.1.0}/aldict/__init__.py +3 -0
- aldict-1.1.0/aldict/alias_dict.py +180 -0
- aldict-1.1.0/pyproject.toml +42 -0
- aldict-1.0.3/README.md +0 -97
- aldict-1.0.3/aldict/alias_dict.py +0 -105
- aldict-1.0.3/aldict.egg-info/SOURCES.txt +0 -12
- aldict-1.0.3/aldict.egg-info/dependency_links.txt +0 -1
- aldict-1.0.3/aldict.egg-info/requires.txt +0 -6
- aldict-1.0.3/aldict.egg-info/top_level.txt +0 -1
- aldict-1.0.3/pyproject.toml +0 -27
- aldict-1.0.3/setup.cfg +0 -4
- aldict-1.0.3/tests/test_alias_dict.py +0 -251
- {aldict-1.0.3 → aldict-1.1.0}/LICENSE +0 -0
- {aldict-1.0.3 → aldict-1.1.0}/aldict/exception.py +0 -0
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aldict
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Multi-key dictionary, supports adding and manipulating key-aliases pointing to shared values
|
|
5
|
-
Author-email: Kaloyan Ivanov <kaloyan.ivanov88@gmail.com>
|
|
6
|
-
Project-URL: repository, https://github.com/kaliv0/aldict
|
|
7
5
|
Keywords: multi-key dictionary,multidict,alias-dict
|
|
6
|
+
Author-Email: kaliv0 <kaloyan.ivanov88@gmail.com>
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Project-URL: repository, https://github.com/kaliv0/aldict
|
|
8
9
|
Requires-Python: >=3.10
|
|
9
10
|
Description-Content-Type: text/markdown
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
Provides-Extra: dev
|
|
12
|
-
Requires-Dist: pytest>=8.3.4; extra == "dev"
|
|
13
|
-
Requires-Dist: ruff>=0.8.3; extra == "dev"
|
|
14
|
-
Requires-Dist: build>=1.2.2; extra == "dev"
|
|
15
|
-
Requires-Dist: twine>=6.0.1; extra == "dev"
|
|
16
|
-
Dynamic: license-file
|
|
17
11
|
|
|
18
12
|
<p align="center">
|
|
19
13
|
<img src="https://github.com/kaliv0/aldict/blob/main/assets/alter-ego.jpg?raw=true" width="250" alt="Alter Ego">
|
|
@@ -33,20 +27,32 @@ Multi-key dictionary, supports adding and manipulating key-aliases pointing to s
|
|
|
33
27
|
---
|
|
34
28
|
## How to use
|
|
35
29
|
|
|
30
|
+
- initialize with aliases
|
|
31
|
+
<br>(one-liner with <i>aliases</i> dict mapping <i>key</i> to list of <i>aliases</i>)
|
|
32
|
+
```python
|
|
33
|
+
ad = AliasDict({"a": 1, "b": 2}, aliases={"a": ["aa", "aaa"], "b": ["bb"]})
|
|
34
|
+
assert ad["a"] == ad["aa"] == ad["aaa"] == 1
|
|
35
|
+
assert ad["b"] == ad["bb"] == 2
|
|
36
|
+
```
|
|
36
37
|
- add_alias
|
|
37
|
-
<br>(pass <i>key</i> as first parameter and <i>alias(es)</i> as variadic params)
|
|
38
|
+
<br>(pass <i>key</i> as first parameter and <i>alias(es)</i> as variadic params, list or tuple)
|
|
38
39
|
```python
|
|
39
40
|
ad = AliasDict({"a": 1, "b": 2})
|
|
40
41
|
ad.add_alias("a", "aa")
|
|
41
42
|
ad.add_alias("b", "bb", "Bbb")
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
ad.add_alias("a", ["aaa", "aaaa"])
|
|
44
|
+
ad.add_alias("b", ("bbb",))
|
|
45
|
+
|
|
46
|
+
assert ad["a"] == ad["aa"] == ad["aaa"] == ad["aaaa"] == 1
|
|
47
|
+
assert ad["b"] == ad["bb"] == ad["Bbb"] == ad["bbb"] == 2
|
|
44
48
|
```
|
|
45
49
|
- remove_alias
|
|
46
|
-
<br>(pass <i>alias(es)</i> to be removed as variadic
|
|
50
|
+
<br>(pass <i>alias(es)</i> to be removed as variadic params, list or tuple)
|
|
47
51
|
```python
|
|
48
52
|
ad.remove_alias("aa")
|
|
49
53
|
ad.remove_alias("bb", "Bbb")
|
|
54
|
+
ad.remove_alias(["aaa", "aaaa"])
|
|
55
|
+
ad.remove_alias(("bbb",))
|
|
50
56
|
assert len(ad.aliases()) == 0
|
|
51
57
|
```
|
|
52
58
|
- clear_aliases
|
|
@@ -73,10 +79,10 @@ ad.add_alias("b", "bb", "B")
|
|
|
73
79
|
ad.add_alias("a", "ab", "A")
|
|
74
80
|
assert list(ad.aliases()) == ['aa', 'bb', 'B', 'ab', 'A']
|
|
75
81
|
```
|
|
76
|
-
-
|
|
82
|
+
- keys_with_aliases
|
|
77
83
|
<br>(read <i>keys</i> with corresponding <i>alias(es)</i>)
|
|
78
84
|
```python
|
|
79
|
-
assert dict(ad.
|
|
85
|
+
assert dict(ad.keys_with_aliases()) == {'a': ['aa', 'ab', 'A'], 'b': ['bb', 'B']}
|
|
80
86
|
```
|
|
81
87
|
- read dictviews
|
|
82
88
|
<br>(<i>dict.keys()</i> and <i>dict.items()</i> include <i>aliased</i> versions)
|
|
@@ -112,3 +118,52 @@ assert list(ad.keys()) == ["a", "b", "aa"]
|
|
|
112
118
|
assert len(ad) == 3
|
|
113
119
|
assert ad.origin_len() == 2
|
|
114
120
|
```
|
|
121
|
+
- copy
|
|
122
|
+
```python
|
|
123
|
+
ad = AliasDict({"a": 1, "b": 2})
|
|
124
|
+
ad.add_alias("a", "aa")
|
|
125
|
+
ad_copy = ad.copy()
|
|
126
|
+
assert ad_copy == ad
|
|
127
|
+
assert ad_copy is not ad
|
|
128
|
+
```
|
|
129
|
+
- merge with | and |= operators
|
|
130
|
+
```python
|
|
131
|
+
ad1 = AliasDict({"a": 1}, aliases={"a": ["aa"]})
|
|
132
|
+
ad2 = AliasDict({"b": 2}, aliases={"b": ["bb"]})
|
|
133
|
+
|
|
134
|
+
merged = ad1 | ad2
|
|
135
|
+
assert merged["aa"] == 1
|
|
136
|
+
assert merged["bb"] == 2
|
|
137
|
+
|
|
138
|
+
ad1 |= {"c": 3}
|
|
139
|
+
assert ad1["c"] == 3
|
|
140
|
+
```
|
|
141
|
+
- fromkeys
|
|
142
|
+
```python
|
|
143
|
+
ad = AliasDict.fromkeys(["a", "b", "c"], 0, aliases={"a": ["aa"]})
|
|
144
|
+
assert ad["a"] == ad["aa"] == 0
|
|
145
|
+
```
|
|
146
|
+
- origin_key
|
|
147
|
+
<br>(get original <i>key</i> for an <i>alias</i>)
|
|
148
|
+
```python
|
|
149
|
+
ad = AliasDict({"a": 1, "b": 2})
|
|
150
|
+
ad.add_alias("a", "aa")
|
|
151
|
+
assert ad.origin_key("aa") == "a"
|
|
152
|
+
assert ad.origin_key("a") is None # not an alias
|
|
153
|
+
```
|
|
154
|
+
- is_alias
|
|
155
|
+
<br>(check if <i>key</i> is an <i>alias</i>)
|
|
156
|
+
```python
|
|
157
|
+
ad = AliasDict({"a": 1, "b": 2})
|
|
158
|
+
ad.add_alias("a", "aa")
|
|
159
|
+
assert ad.is_alias("aa") is True
|
|
160
|
+
assert ad.is_alias("a") is False
|
|
161
|
+
```
|
|
162
|
+
- has_aliases
|
|
163
|
+
<br>(check if <i>key</i> has any <i>aliases</i>)
|
|
164
|
+
```python
|
|
165
|
+
ad = AliasDict({"a": 1, "b": 2})
|
|
166
|
+
ad.add_alias("a", "aa")
|
|
167
|
+
assert ad.has_aliases("a") is True
|
|
168
|
+
assert ad.has_aliases("b") is False
|
|
169
|
+
```
|
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: aldict
|
|
3
|
-
Version: 1.0.3
|
|
4
|
-
Summary: Multi-key dictionary, supports adding and manipulating key-aliases pointing to shared values
|
|
5
|
-
Author-email: Kaloyan Ivanov <kaloyan.ivanov88@gmail.com>
|
|
6
|
-
Project-URL: repository, https://github.com/kaliv0/aldict
|
|
7
|
-
Keywords: multi-key dictionary,multidict,alias-dict
|
|
8
|
-
Requires-Python: >=3.10
|
|
9
|
-
Description-Content-Type: text/markdown
|
|
10
|
-
License-File: LICENSE
|
|
11
|
-
Provides-Extra: dev
|
|
12
|
-
Requires-Dist: pytest>=8.3.4; extra == "dev"
|
|
13
|
-
Requires-Dist: ruff>=0.8.3; extra == "dev"
|
|
14
|
-
Requires-Dist: build>=1.2.2; extra == "dev"
|
|
15
|
-
Requires-Dist: twine>=6.0.1; extra == "dev"
|
|
16
|
-
Dynamic: license-file
|
|
17
|
-
|
|
18
1
|
<p align="center">
|
|
19
2
|
<img src="https://github.com/kaliv0/aldict/blob/main/assets/alter-ego.jpg?raw=true" width="250" alt="Alter Ego">
|
|
20
3
|
</p>
|
|
@@ -33,20 +16,32 @@ Multi-key dictionary, supports adding and manipulating key-aliases pointing to s
|
|
|
33
16
|
---
|
|
34
17
|
## How to use
|
|
35
18
|
|
|
19
|
+
- initialize with aliases
|
|
20
|
+
<br>(one-liner with <i>aliases</i> dict mapping <i>key</i> to list of <i>aliases</i>)
|
|
21
|
+
```python
|
|
22
|
+
ad = AliasDict({"a": 1, "b": 2}, aliases={"a": ["aa", "aaa"], "b": ["bb"]})
|
|
23
|
+
assert ad["a"] == ad["aa"] == ad["aaa"] == 1
|
|
24
|
+
assert ad["b"] == ad["bb"] == 2
|
|
25
|
+
```
|
|
36
26
|
- add_alias
|
|
37
|
-
<br>(pass <i>key</i> as first parameter and <i>alias(es)</i> as variadic params)
|
|
27
|
+
<br>(pass <i>key</i> as first parameter and <i>alias(es)</i> as variadic params, list or tuple)
|
|
38
28
|
```python
|
|
39
29
|
ad = AliasDict({"a": 1, "b": 2})
|
|
40
30
|
ad.add_alias("a", "aa")
|
|
41
31
|
ad.add_alias("b", "bb", "Bbb")
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
ad.add_alias("a", ["aaa", "aaaa"])
|
|
33
|
+
ad.add_alias("b", ("bbb",))
|
|
34
|
+
|
|
35
|
+
assert ad["a"] == ad["aa"] == ad["aaa"] == ad["aaaa"] == 1
|
|
36
|
+
assert ad["b"] == ad["bb"] == ad["Bbb"] == ad["bbb"] == 2
|
|
44
37
|
```
|
|
45
38
|
- remove_alias
|
|
46
|
-
<br>(pass <i>alias(es)</i> to be removed as variadic
|
|
39
|
+
<br>(pass <i>alias(es)</i> to be removed as variadic params, list or tuple)
|
|
47
40
|
```python
|
|
48
41
|
ad.remove_alias("aa")
|
|
49
42
|
ad.remove_alias("bb", "Bbb")
|
|
43
|
+
ad.remove_alias(["aaa", "aaaa"])
|
|
44
|
+
ad.remove_alias(("bbb",))
|
|
50
45
|
assert len(ad.aliases()) == 0
|
|
51
46
|
```
|
|
52
47
|
- clear_aliases
|
|
@@ -73,10 +68,10 @@ ad.add_alias("b", "bb", "B")
|
|
|
73
68
|
ad.add_alias("a", "ab", "A")
|
|
74
69
|
assert list(ad.aliases()) == ['aa', 'bb', 'B', 'ab', 'A']
|
|
75
70
|
```
|
|
76
|
-
-
|
|
71
|
+
- keys_with_aliases
|
|
77
72
|
<br>(read <i>keys</i> with corresponding <i>alias(es)</i>)
|
|
78
73
|
```python
|
|
79
|
-
assert dict(ad.
|
|
74
|
+
assert dict(ad.keys_with_aliases()) == {'a': ['aa', 'ab', 'A'], 'b': ['bb', 'B']}
|
|
80
75
|
```
|
|
81
76
|
- read dictviews
|
|
82
77
|
<br>(<i>dict.keys()</i> and <i>dict.items()</i> include <i>aliased</i> versions)
|
|
@@ -112,3 +107,52 @@ assert list(ad.keys()) == ["a", "b", "aa"]
|
|
|
112
107
|
assert len(ad) == 3
|
|
113
108
|
assert ad.origin_len() == 2
|
|
114
109
|
```
|
|
110
|
+
- copy
|
|
111
|
+
```python
|
|
112
|
+
ad = AliasDict({"a": 1, "b": 2})
|
|
113
|
+
ad.add_alias("a", "aa")
|
|
114
|
+
ad_copy = ad.copy()
|
|
115
|
+
assert ad_copy == ad
|
|
116
|
+
assert ad_copy is not ad
|
|
117
|
+
```
|
|
118
|
+
- merge with | and |= operators
|
|
119
|
+
```python
|
|
120
|
+
ad1 = AliasDict({"a": 1}, aliases={"a": ["aa"]})
|
|
121
|
+
ad2 = AliasDict({"b": 2}, aliases={"b": ["bb"]})
|
|
122
|
+
|
|
123
|
+
merged = ad1 | ad2
|
|
124
|
+
assert merged["aa"] == 1
|
|
125
|
+
assert merged["bb"] == 2
|
|
126
|
+
|
|
127
|
+
ad1 |= {"c": 3}
|
|
128
|
+
assert ad1["c"] == 3
|
|
129
|
+
```
|
|
130
|
+
- fromkeys
|
|
131
|
+
```python
|
|
132
|
+
ad = AliasDict.fromkeys(["a", "b", "c"], 0, aliases={"a": ["aa"]})
|
|
133
|
+
assert ad["a"] == ad["aa"] == 0
|
|
134
|
+
```
|
|
135
|
+
- origin_key
|
|
136
|
+
<br>(get original <i>key</i> for an <i>alias</i>)
|
|
137
|
+
```python
|
|
138
|
+
ad = AliasDict({"a": 1, "b": 2})
|
|
139
|
+
ad.add_alias("a", "aa")
|
|
140
|
+
assert ad.origin_key("aa") == "a"
|
|
141
|
+
assert ad.origin_key("a") is None # not an alias
|
|
142
|
+
```
|
|
143
|
+
- is_alias
|
|
144
|
+
<br>(check if <i>key</i> is an <i>alias</i>)
|
|
145
|
+
```python
|
|
146
|
+
ad = AliasDict({"a": 1, "b": 2})
|
|
147
|
+
ad.add_alias("a", "aa")
|
|
148
|
+
assert ad.is_alias("aa") is True
|
|
149
|
+
assert ad.is_alias("a") is False
|
|
150
|
+
```
|
|
151
|
+
- has_aliases
|
|
152
|
+
<br>(check if <i>key</i> has any <i>aliases</i>)
|
|
153
|
+
```python
|
|
154
|
+
ad = AliasDict({"a": 1, "b": 2})
|
|
155
|
+
ad.add_alias("a", "aa")
|
|
156
|
+
assert ad.has_aliases("a") is True
|
|
157
|
+
assert ad.has_aliases("b") is False
|
|
158
|
+
```
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
from collections import UserDict, defaultdict
|
|
2
|
+
from collections.abc import Mapping
|
|
3
|
+
from itertools import chain
|
|
4
|
+
|
|
5
|
+
from aldict.exception import AliasError, AliasValueError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AliasDict(UserDict):
|
|
9
|
+
"""Dict with key-aliases pointing to shared values."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, dict_=None, /, aliases=None):
|
|
12
|
+
self._alias_dict = {}
|
|
13
|
+
if isinstance(dict_, AliasDict):
|
|
14
|
+
super().__init__(dict_.data)
|
|
15
|
+
self._alias_dict = dict(dict_._alias_dict)
|
|
16
|
+
else:
|
|
17
|
+
super().__init__(dict_)
|
|
18
|
+
|
|
19
|
+
if aliases:
|
|
20
|
+
for key, alias_list in aliases.items():
|
|
21
|
+
self.add_alias(key, alias_list)
|
|
22
|
+
|
|
23
|
+
def add_alias(self, key, *aliases):
|
|
24
|
+
"""Add one or more aliases to a key. Accepts *args or a list/tuple."""
|
|
25
|
+
if key not in self.data:
|
|
26
|
+
raise KeyError(key)
|
|
27
|
+
|
|
28
|
+
for alias in self._unpack(aliases):
|
|
29
|
+
if alias == key:
|
|
30
|
+
raise AliasValueError(f"Key and corresponding alias cannot be equal: '{key}'")
|
|
31
|
+
if alias in self.data:
|
|
32
|
+
raise AliasValueError(f"Alias '{alias}' already exists as a key in the dictionary")
|
|
33
|
+
self._alias_dict[alias] = key
|
|
34
|
+
|
|
35
|
+
def remove_alias(self, *aliases):
|
|
36
|
+
"""Remove one or more aliases. Accepts *args or a list/tuple."""
|
|
37
|
+
for alias in self._unpack(aliases):
|
|
38
|
+
try:
|
|
39
|
+
self._alias_dict.__delitem__(alias)
|
|
40
|
+
except KeyError as e:
|
|
41
|
+
raise AliasError(f"Alias '{alias}' not found") from e
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
def _unpack(args):
|
|
45
|
+
return args[0] if len(args) == 1 and isinstance(args[0], (list, tuple)) else args
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def fromkeys(cls, iterable, value=None, aliases=None):
|
|
49
|
+
"""Create an AliasDict from an iterable of keys with optional aliases."""
|
|
50
|
+
return cls(dict.fromkeys(iterable, value), aliases=aliases)
|
|
51
|
+
|
|
52
|
+
def clear(self):
|
|
53
|
+
"""Clear all data and aliases."""
|
|
54
|
+
super().clear()
|
|
55
|
+
self._alias_dict.clear()
|
|
56
|
+
|
|
57
|
+
def clear_aliases(self):
|
|
58
|
+
"""Remove all aliases."""
|
|
59
|
+
self._alias_dict.clear()
|
|
60
|
+
|
|
61
|
+
def aliases(self):
|
|
62
|
+
"""Return all aliases."""
|
|
63
|
+
return self._alias_dict.keys()
|
|
64
|
+
|
|
65
|
+
def is_alias(self, key):
|
|
66
|
+
"""Return True if the key is an alias, False otherwise."""
|
|
67
|
+
return key in self._alias_dict
|
|
68
|
+
|
|
69
|
+
def has_aliases(self, key):
|
|
70
|
+
"""Return True if the key has any aliases, False otherwise."""
|
|
71
|
+
return key in self._alias_dict.values()
|
|
72
|
+
|
|
73
|
+
def keys_with_aliases(self):
|
|
74
|
+
"""Return keys with their aliases."""
|
|
75
|
+
result = defaultdict(list)
|
|
76
|
+
for alias, key in self._alias_dict.items():
|
|
77
|
+
result[key].append(alias)
|
|
78
|
+
return result.items()
|
|
79
|
+
|
|
80
|
+
def origin_keys(self):
|
|
81
|
+
"""Return original keys (without aliases)."""
|
|
82
|
+
return self.data.keys()
|
|
83
|
+
|
|
84
|
+
def origin_key(self, alias):
|
|
85
|
+
"""Return the original key for an alias, or None if not an alias."""
|
|
86
|
+
return self._alias_dict.get(alias)
|
|
87
|
+
|
|
88
|
+
def keys(self):
|
|
89
|
+
"""Return all keys and aliases."""
|
|
90
|
+
return dict(**self.data, **self._alias_dict).keys()
|
|
91
|
+
# NB: could be optimized as 'return iter(self)' but we won't be able to call e.g. len(alias_dict.keys())
|
|
92
|
+
|
|
93
|
+
def values(self):
|
|
94
|
+
"""Return all values."""
|
|
95
|
+
return self.data.values()
|
|
96
|
+
|
|
97
|
+
def items(self):
|
|
98
|
+
"""Return all items (including alias/value pairs)."""
|
|
99
|
+
return dict(**self.data, **{k: self.data[v] for k, v in self._alias_dict.items()}).items()
|
|
100
|
+
# NB: could be optimized as
|
|
101
|
+
# 'return chain(self.data.items(), ((k, self.data[v]) for k, v in self._alias_dict.items()))'
|
|
102
|
+
# (same as .keys() above)
|
|
103
|
+
|
|
104
|
+
def origin_len(self):
|
|
105
|
+
"""Return count of original keys (without aliases)."""
|
|
106
|
+
return len(self.data)
|
|
107
|
+
|
|
108
|
+
def __len__(self):
|
|
109
|
+
return len(self.data) + len(self._alias_dict)
|
|
110
|
+
|
|
111
|
+
def __missing__(self, key):
|
|
112
|
+
try:
|
|
113
|
+
return super().__getitem__(self._alias_dict[key])
|
|
114
|
+
except KeyError:
|
|
115
|
+
raise KeyError(key) from None
|
|
116
|
+
|
|
117
|
+
def __setitem__(self, key, value):
|
|
118
|
+
try:
|
|
119
|
+
key = self._alias_dict[key]
|
|
120
|
+
except KeyError:
|
|
121
|
+
pass
|
|
122
|
+
super().__setitem__(key, value)
|
|
123
|
+
|
|
124
|
+
def __delitem__(self, key):
|
|
125
|
+
try:
|
|
126
|
+
self.data.__delitem__(key)
|
|
127
|
+
for alias in [k for k, v in self._alias_dict.items() if v == key]:
|
|
128
|
+
del self._alias_dict[alias]
|
|
129
|
+
except KeyError:
|
|
130
|
+
return self.remove_alias(key)
|
|
131
|
+
|
|
132
|
+
def __contains__(self, item):
|
|
133
|
+
return item in self.data or item in self._alias_dict
|
|
134
|
+
|
|
135
|
+
def __iter__(self):
|
|
136
|
+
return chain(self.data, self._alias_dict)
|
|
137
|
+
|
|
138
|
+
def __reversed__(self):
|
|
139
|
+
return chain(reversed(self._alias_dict), reversed(self.data))
|
|
140
|
+
|
|
141
|
+
def copy(self):
|
|
142
|
+
"""Return a shallow copy of the AliasDict."""
|
|
143
|
+
return type(self)(self)
|
|
144
|
+
|
|
145
|
+
def __repr__(self):
|
|
146
|
+
return f"AliasDict({dict(self.items())})"
|
|
147
|
+
|
|
148
|
+
def __eq__(self, other):
|
|
149
|
+
if not isinstance(other, AliasDict):
|
|
150
|
+
return NotImplemented
|
|
151
|
+
return self.data == other.data and self._alias_dict == other._alias_dict
|
|
152
|
+
|
|
153
|
+
def __or__(self, other):
|
|
154
|
+
if not isinstance(other, Mapping):
|
|
155
|
+
return NotImplemented
|
|
156
|
+
new = self.copy()
|
|
157
|
+
if isinstance(other, AliasDict):
|
|
158
|
+
new.update(other.data)
|
|
159
|
+
new._alias_dict.update(other._alias_dict)
|
|
160
|
+
else:
|
|
161
|
+
new.update(other)
|
|
162
|
+
return new
|
|
163
|
+
|
|
164
|
+
def __ror__(self, other):
|
|
165
|
+
if not isinstance(other, Mapping):
|
|
166
|
+
return NotImplemented
|
|
167
|
+
new = AliasDict(other)
|
|
168
|
+
new.update(self.data)
|
|
169
|
+
new._alias_dict.update(self._alias_dict)
|
|
170
|
+
return new
|
|
171
|
+
|
|
172
|
+
def __ior__(self, other):
|
|
173
|
+
if isinstance(other, AliasDict):
|
|
174
|
+
self.update(other.data)
|
|
175
|
+
self._alias_dict.update(other._alias_dict)
|
|
176
|
+
else:
|
|
177
|
+
self.update(other)
|
|
178
|
+
return self
|
|
179
|
+
|
|
180
|
+
__hash__ = None
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "aldict"
|
|
3
|
+
version = "1.1.0"
|
|
4
|
+
requires-python = ">=3.10"
|
|
5
|
+
authors = [
|
|
6
|
+
{ name = "kaliv0", email = "kaloyan.ivanov88@gmail.com" },
|
|
7
|
+
]
|
|
8
|
+
description = "Multi-key dictionary, supports adding and manipulating key-aliases pointing to shared values"
|
|
9
|
+
keywords = [
|
|
10
|
+
"multi-key dictionary",
|
|
11
|
+
"multidict",
|
|
12
|
+
"alias-dict",
|
|
13
|
+
]
|
|
14
|
+
readme = "README.md"
|
|
15
|
+
license-files = [
|
|
16
|
+
"LICENSE",
|
|
17
|
+
]
|
|
18
|
+
dependencies = []
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
repository = "https://github.com/kaliv0/aldict"
|
|
22
|
+
|
|
23
|
+
[dependency-groups]
|
|
24
|
+
dev = [
|
|
25
|
+
"ruff>=0.12.4",
|
|
26
|
+
"pytest>=8.3.2",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[build-system]
|
|
30
|
+
requires = [
|
|
31
|
+
"pdm-backend",
|
|
32
|
+
]
|
|
33
|
+
build-backend = "pdm.backend"
|
|
34
|
+
|
|
35
|
+
[tool.pdm.build]
|
|
36
|
+
excludes = [
|
|
37
|
+
"tests/",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[tool.ruff]
|
|
41
|
+
fix = true
|
|
42
|
+
line-length = 100
|
aldict-1.0.3/README.md
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<img src="https://github.com/kaliv0/aldict/blob/main/assets/alter-ego.jpg?raw=true" width="250" alt="Alter Ego">
|
|
3
|
-
</p>
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
# Aldict
|
|
7
|
-
|
|
8
|
-
[](https://github.com/kaliv0/aldict/actions/workflows/ci.yml)
|
|
9
|
-

|
|
10
|
-
[](https://pypi.org/project/aldict/)
|
|
11
|
-
[](https://github.com/kaliv0/aldict/blob/main/LICENSE)
|
|
12
|
-
[](https://pepy.tech/projects/aldict)
|
|
13
|
-
|
|
14
|
-
Multi-key dictionary, supports adding and manipulating key-aliases pointing to shared values
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
## How to use
|
|
18
|
-
|
|
19
|
-
- add_alias
|
|
20
|
-
<br>(pass <i>key</i> as first parameter and <i>alias(es)</i> as variadic params)
|
|
21
|
-
```python
|
|
22
|
-
ad = AliasDict({"a": 1, "b": 2})
|
|
23
|
-
ad.add_alias("a", "aa")
|
|
24
|
-
ad.add_alias("b", "bb", "Bbb")
|
|
25
|
-
assert ad["a"] == ad["aa"] == 1
|
|
26
|
-
assert ad["b"] == ad["bb"] == ad["Bbb"] == 2
|
|
27
|
-
```
|
|
28
|
-
- remove_alias
|
|
29
|
-
<br>(pass <i>alias(es)</i> to be removed as variadic parameters)
|
|
30
|
-
```python
|
|
31
|
-
ad.remove_alias("aa")
|
|
32
|
-
ad.remove_alias("bb", "Bbb")
|
|
33
|
-
assert len(ad.aliases()) == 0
|
|
34
|
-
```
|
|
35
|
-
- clear_aliases
|
|
36
|
-
<br>(remove all <i>aliases</i> at once)
|
|
37
|
-
```python
|
|
38
|
-
ad.clear_aliases()
|
|
39
|
-
assert len(ad.aliases()) == 0
|
|
40
|
-
```
|
|
41
|
-
- update alias
|
|
42
|
-
<br>(point <i>alias</i> to different <i>key</i>)
|
|
43
|
-
```python
|
|
44
|
-
ad = AliasDict({"a": 1, "b": 2})
|
|
45
|
-
ad.add_alias("a", "ab")
|
|
46
|
-
assert list(ad.items()) == [('a', 1), ('b', 2), ('ab', 1)]
|
|
47
|
-
|
|
48
|
-
ad.add_alias("b", "ab")
|
|
49
|
-
assert list(ad.items()) == [('a', 1), ('b', 2), ('ab', 2)]
|
|
50
|
-
```
|
|
51
|
-
- read all aliases
|
|
52
|
-
```python
|
|
53
|
-
ad = AliasDict({"a": 1, "b": 2})
|
|
54
|
-
ad.add_alias("a", "aa")
|
|
55
|
-
ad.add_alias("b", "bb", "B")
|
|
56
|
-
ad.add_alias("a", "ab", "A")
|
|
57
|
-
assert list(ad.aliases()) == ['aa', 'bb', 'B', 'ab', 'A']
|
|
58
|
-
```
|
|
59
|
-
- aliased_keys
|
|
60
|
-
<br>(read <i>keys</i> with corresponding <i>alias(es)</i>)
|
|
61
|
-
```python
|
|
62
|
-
assert dict(ad.aliased_keys()) == {'a': ['aa', 'ab', 'A'], 'b': ['bb', 'B']}
|
|
63
|
-
```
|
|
64
|
-
- read dictviews
|
|
65
|
-
<br>(<i>dict.keys()</i> and <i>dict.items()</i> include <i>aliased</i> versions)
|
|
66
|
-
```python
|
|
67
|
-
ad = AliasDict({"x": 10, "y": 20})
|
|
68
|
-
ad.add_alias("x", "Xx")
|
|
69
|
-
ad.add_alias("y", "Yy", "xyz")
|
|
70
|
-
|
|
71
|
-
ad.keys()
|
|
72
|
-
ad.values()
|
|
73
|
-
ad.items()
|
|
74
|
-
|
|
75
|
-
# dict_keys(['x', 'y', 'Xx', 'Yy', 'xyz'])
|
|
76
|
-
# dict_values([10, 20])
|
|
77
|
-
# dict_items([('x', 10), ('y', 20), ('Xx', 10), ('Yy', 20), ('xyz', 20)])
|
|
78
|
-
```
|
|
79
|
-
- remove key and aliases
|
|
80
|
-
```python
|
|
81
|
-
ad.pop("y")
|
|
82
|
-
assert list(ad.items()) == [('x', 10), ('Xx', 10)]
|
|
83
|
-
```
|
|
84
|
-
- origin_keys
|
|
85
|
-
<br>(get original <i>keys</i> only)
|
|
86
|
-
```python
|
|
87
|
-
assert list(ad.origin_keys()) == ['x', 'y']
|
|
88
|
-
```
|
|
89
|
-
- origin_len
|
|
90
|
-
<br>(get original dict <i>length</i> without aliases)
|
|
91
|
-
```python
|
|
92
|
-
ad = AliasDict({"a": 1, "b": 2})
|
|
93
|
-
ad.add_alias("a", "aa")
|
|
94
|
-
assert list(ad.keys()) == ["a", "b", "aa"]
|
|
95
|
-
assert len(ad) == 3
|
|
96
|
-
assert ad.origin_len() == 2
|
|
97
|
-
```
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
from collections import UserDict, defaultdict
|
|
2
|
-
|
|
3
|
-
from aldict.exception import AliasError, AliasValueError
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class AliasDict(UserDict):
|
|
7
|
-
"""Custom Dict class supporting key-aliases pointing to shared values"""
|
|
8
|
-
|
|
9
|
-
def __init__(self, dict_):
|
|
10
|
-
self._alias_dict = {}
|
|
11
|
-
super().__init__(**dict_)
|
|
12
|
-
|
|
13
|
-
def add_alias(self, key, *aliases):
|
|
14
|
-
"""Adds one or more aliases to specified key in the dictionary"""
|
|
15
|
-
if key not in self.data.keys():
|
|
16
|
-
raise KeyError(key)
|
|
17
|
-
for alias in aliases:
|
|
18
|
-
if alias == key:
|
|
19
|
-
raise AliasValueError(f"Key and corresponding alias cannot be equal: '{key}'")
|
|
20
|
-
self._alias_dict[alias] = key
|
|
21
|
-
|
|
22
|
-
def remove_alias(self, *aliases):
|
|
23
|
-
"""Removes one or more aliases"""
|
|
24
|
-
for alias in aliases:
|
|
25
|
-
try:
|
|
26
|
-
self._alias_dict.__delitem__(alias)
|
|
27
|
-
except KeyError as e:
|
|
28
|
-
raise AliasError(alias) from e
|
|
29
|
-
|
|
30
|
-
def clear_aliases(self):
|
|
31
|
-
"""Removes all aliases"""
|
|
32
|
-
self._alias_dict.clear()
|
|
33
|
-
|
|
34
|
-
def aliases(self):
|
|
35
|
-
"""Returns all aliases present in the dictionary"""
|
|
36
|
-
return self._alias_dict.keys()
|
|
37
|
-
|
|
38
|
-
def aliased_keys(self):
|
|
39
|
-
"""Returns a dictview of all keys with their corresponding aliases"""
|
|
40
|
-
result = defaultdict(list)
|
|
41
|
-
for alias, key in self._alias_dict.items():
|
|
42
|
-
result[key].append(alias)
|
|
43
|
-
return result.items()
|
|
44
|
-
|
|
45
|
-
def origin_keys(self):
|
|
46
|
-
"""Returns all keys"""
|
|
47
|
-
return self.data.keys()
|
|
48
|
-
|
|
49
|
-
def keys(self):
|
|
50
|
-
"""Returns all keys and aliases"""
|
|
51
|
-
return dict(**self.data, **self._alias_dict).keys()
|
|
52
|
-
|
|
53
|
-
def values(self):
|
|
54
|
-
"""Returns all values"""
|
|
55
|
-
return self.data.values()
|
|
56
|
-
|
|
57
|
-
def items(self):
|
|
58
|
-
"""Returns a dictview with all items (including alias/value tuples)"""
|
|
59
|
-
return dict(**self.data, **{k: self.data[v] for k, v in self._alias_dict.items()}).items()
|
|
60
|
-
|
|
61
|
-
def origin_len(self):
|
|
62
|
-
"""Returns the length of the original dictionary (without aliases)"""
|
|
63
|
-
return len(self.data)
|
|
64
|
-
|
|
65
|
-
def __len__(self):
|
|
66
|
-
return len(self.keys())
|
|
67
|
-
|
|
68
|
-
def __missing__(self, key):
|
|
69
|
-
try:
|
|
70
|
-
return super().__getitem__(self._alias_dict[key])
|
|
71
|
-
except AttributeError as e:
|
|
72
|
-
raise KeyError(key) from e
|
|
73
|
-
|
|
74
|
-
def __setitem__(self, key, value):
|
|
75
|
-
try:
|
|
76
|
-
key = self._alias_dict[key]
|
|
77
|
-
except KeyError:
|
|
78
|
-
pass
|
|
79
|
-
super().__setitem__(key, value)
|
|
80
|
-
|
|
81
|
-
def __delitem__(self, key):
|
|
82
|
-
try:
|
|
83
|
-
self.data.__delitem__(key)
|
|
84
|
-
self._alias_dict = {k: v for k, v in self._alias_dict.items() if v != key}
|
|
85
|
-
except KeyError:
|
|
86
|
-
# in case we try to delete alias via pop() or del
|
|
87
|
-
return self.remove_alias(key)
|
|
88
|
-
|
|
89
|
-
def __contains__(self, item):
|
|
90
|
-
return item in set(self.keys())
|
|
91
|
-
|
|
92
|
-
def __iter__(self):
|
|
93
|
-
for item in self.keys():
|
|
94
|
-
yield item
|
|
95
|
-
|
|
96
|
-
def __repr__(self):
|
|
97
|
-
return f"AliasDict({self.items()})"
|
|
98
|
-
|
|
99
|
-
def __eq__(self, other):
|
|
100
|
-
if not isinstance(other, AliasDict):
|
|
101
|
-
raise TypeError(f"{other} is not an AliasDict")
|
|
102
|
-
return self.data == other.data and self._alias_dict == other._alias_dict
|
|
103
|
-
|
|
104
|
-
def __hash__(self):
|
|
105
|
-
return hash((self.data, self._alias_dict))
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
LICENSE
|
|
2
|
-
README.md
|
|
3
|
-
pyproject.toml
|
|
4
|
-
aldict/__init__.py
|
|
5
|
-
aldict/alias_dict.py
|
|
6
|
-
aldict/exception.py
|
|
7
|
-
aldict.egg-info/PKG-INFO
|
|
8
|
-
aldict.egg-info/SOURCES.txt
|
|
9
|
-
aldict.egg-info/dependency_links.txt
|
|
10
|
-
aldict.egg-info/requires.txt
|
|
11
|
-
aldict.egg-info/top_level.txt
|
|
12
|
-
tests/test_alias_dict.py
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
aldict
|
aldict-1.0.3/pyproject.toml
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=75.6.0", "wheel"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "aldict"
|
|
7
|
-
version = "1.0.3"
|
|
8
|
-
readme = "README.md"
|
|
9
|
-
authors = [{ name = "Kaloyan Ivanov", email = "kaloyan.ivanov88@gmail.com" }]
|
|
10
|
-
description = "Multi-key dictionary, supports adding and manipulating key-aliases pointing to shared values"
|
|
11
|
-
keywords = ["multi-key dictionary", "multidict", "alias-dict"]
|
|
12
|
-
urls = { repository = "https://github.com/kaliv0/aldict" }
|
|
13
|
-
|
|
14
|
-
requires-python = ">= 3.10"
|
|
15
|
-
|
|
16
|
-
[project.optional-dependencies]
|
|
17
|
-
dev = [
|
|
18
|
-
"pytest>=8.3.4",
|
|
19
|
-
"ruff>=0.8.3",
|
|
20
|
-
"build>=1.2.2",
|
|
21
|
-
"twine>=6.0.1",
|
|
22
|
-
]
|
|
23
|
-
|
|
24
|
-
[tool.setuptools.packages.find]
|
|
25
|
-
where = ["."]
|
|
26
|
-
include = ["aldict"]
|
|
27
|
-
exclude = ["tests"]
|
aldict-1.0.3/setup.cfg
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
import pytest
|
|
2
|
-
|
|
3
|
-
from aldict import AliasDict, AliasValueError, AliasError
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def test_alias_dict(alias_dict):
|
|
7
|
-
assert alias_dict[".toml"] == {
|
|
8
|
-
"callable": "load",
|
|
9
|
-
"import_mod": "tomli",
|
|
10
|
-
"read_mode": "r",
|
|
11
|
-
}
|
|
12
|
-
assert (
|
|
13
|
-
alias_dict[".yml"]
|
|
14
|
-
== alias_dict[".yaml"]
|
|
15
|
-
== {"callable": "safe_load", "import_mod": "yaml", "read_mode": "r"}
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def test_add_alias(alias_dict):
|
|
20
|
-
alias_dict.add_alias(".toml", ".tml")
|
|
21
|
-
assert (
|
|
22
|
-
alias_dict[".toml"]
|
|
23
|
-
== alias_dict[".tml"]
|
|
24
|
-
== {"callable": "load", "import_mod": "tomli", "read_mode": "r"}
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def test_add_multiple_aliases(alias_dict):
|
|
29
|
-
alias_dict.add_alias(".json", ".jsn", ".joojoo", ".jazz")
|
|
30
|
-
assert list(alias_dict.keys()) == [
|
|
31
|
-
".json",
|
|
32
|
-
".yaml",
|
|
33
|
-
".toml",
|
|
34
|
-
".yml",
|
|
35
|
-
".jsn",
|
|
36
|
-
".joojoo",
|
|
37
|
-
".jazz",
|
|
38
|
-
]
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def test_add_alias_raises(alias_dict):
|
|
42
|
-
with pytest.raises(
|
|
43
|
-
AliasValueError, match="Key and corresponding alias cannot be equal: '.toml'"
|
|
44
|
-
):
|
|
45
|
-
alias_dict.add_alias(".toml", ".toml")
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def test_update_alias(alias_dict):
|
|
49
|
-
# redirect ".yml" to point to ".toml"
|
|
50
|
-
alias_dict.add_alias(".toml", ".yml")
|
|
51
|
-
assert list(alias_dict.items()) == [
|
|
52
|
-
(".json", {"callable": "load", "import_mod": "json", "read_mode": "r"}),
|
|
53
|
-
(".yaml", {"callable": "safe_load", "import_mod": "yaml", "read_mode": "r"}),
|
|
54
|
-
(".toml", {"callable": "load", "import_mod": "tomli", "read_mode": "r"}),
|
|
55
|
-
(".yml", {"callable": "load", "import_mod": "tomli", "read_mode": "r"}),
|
|
56
|
-
]
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def test_update_alias_raises(alias_dict):
|
|
60
|
-
with pytest.raises(KeyError, match=".foo"):
|
|
61
|
-
alias_dict.add_alias(".foo", ".bar")
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def test_remove_alias(alias_dict):
|
|
65
|
-
assert list(alias_dict.keys()) == [".json", ".yaml", ".toml", ".yml"]
|
|
66
|
-
|
|
67
|
-
alias_dict.remove_alias(".yml")
|
|
68
|
-
assert list(alias_dict.keys()) == [".json", ".yaml", ".toml"]
|
|
69
|
-
assert list(alias_dict.items()) == [
|
|
70
|
-
(".json", {"callable": "load", "import_mod": "json", "read_mode": "r"}),
|
|
71
|
-
(".yaml", {"callable": "safe_load", "import_mod": "yaml", "read_mode": "r"}),
|
|
72
|
-
(".toml", {"callable": "load", "import_mod": "tomli", "read_mode": "r"}),
|
|
73
|
-
]
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def test_remove_alias_raises(alias_dict):
|
|
77
|
-
assert list(alias_dict.keys()) == [".json", ".yaml", ".toml", ".yml"]
|
|
78
|
-
with pytest.raises(AliasError, match=".foo"):
|
|
79
|
-
alias_dict.remove_alias(".foo")
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def test_remove_multiple_aliases(alias_dict):
|
|
83
|
-
alias_dict.add_alias(".json", ".jsn")
|
|
84
|
-
assert list(alias_dict.keys()) == [".json", ".yaml", ".toml", ".yml", ".jsn"]
|
|
85
|
-
|
|
86
|
-
alias_dict.remove_alias(".yml", ".jsn")
|
|
87
|
-
assert list(alias_dict.keys()) == [".json", ".yaml", ".toml"]
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def test_read_aliases(alias_dict):
|
|
91
|
-
alias_dict.add_alias(".toml", ".tml")
|
|
92
|
-
alias_dict.add_alias(".json", ".jsn")
|
|
93
|
-
alias_dict.add_alias(".json", ".whaaaaat!")
|
|
94
|
-
assert list(alias_dict.aliases()) == [".yml", ".tml", ".jsn", ".whaaaaat!"]
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
def test_dictviews(alias_dict):
|
|
98
|
-
assert list(alias_dict.keys()) == [".json", ".yaml", ".toml", ".yml"]
|
|
99
|
-
assert list(alias_dict.values()) == [
|
|
100
|
-
{"import_mod": "json", "callable": "load", "read_mode": "r"},
|
|
101
|
-
{"import_mod": "yaml", "callable": "safe_load", "read_mode": "r"},
|
|
102
|
-
{"import_mod": "tomli", "callable": "load", "read_mode": "r"},
|
|
103
|
-
]
|
|
104
|
-
assert list(alias_dict.items()) == [
|
|
105
|
-
(".json", {"callable": "load", "import_mod": "json", "read_mode": "r"}),
|
|
106
|
-
(".yaml", {"callable": "safe_load", "import_mod": "yaml", "read_mode": "r"}),
|
|
107
|
-
(".toml", {"callable": "load", "import_mod": "tomli", "read_mode": "r"}),
|
|
108
|
-
(".yml", {"callable": "safe_load", "import_mod": "yaml", "read_mode": "r"}),
|
|
109
|
-
]
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def test_remove_key_and_aliases(alias_dict):
|
|
113
|
-
assert list(alias_dict.keys()) == [".json", ".yaml", ".toml", ".yml"]
|
|
114
|
-
alias_dict.pop(".yaml")
|
|
115
|
-
assert list(alias_dict.keys()) == [".json", ".toml"]
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def test_contains(alias_dict):
|
|
119
|
-
alias_dict.add_alias(".toml", ".tml")
|
|
120
|
-
assert (".toml" in alias_dict) is True
|
|
121
|
-
assert (".tml" in alias_dict) is True
|
|
122
|
-
assert (".foo" in alias_dict) is False
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def test_get(alias_dict):
|
|
126
|
-
assert alias_dict.get(".yaml") == {
|
|
127
|
-
"callable": "safe_load",
|
|
128
|
-
"import_mod": "yaml",
|
|
129
|
-
"read_mode": "r",
|
|
130
|
-
}
|
|
131
|
-
assert alias_dict.get(".yml") == {
|
|
132
|
-
"callable": "safe_load",
|
|
133
|
-
"import_mod": "yaml",
|
|
134
|
-
"read_mode": "r",
|
|
135
|
-
}
|
|
136
|
-
assert alias_dict.get(".foo") is None
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def test_pop_alias_doesnt_remove_key(alias_dict):
|
|
140
|
-
assert alias_dict.pop(".yml") == {
|
|
141
|
-
"callable": "safe_load",
|
|
142
|
-
"import_mod": "yaml",
|
|
143
|
-
"read_mode": "r",
|
|
144
|
-
}
|
|
145
|
-
assert list(alias_dict.keys()) == [".json", ".yaml", ".toml"]
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
def test_iter(alias_dict):
|
|
149
|
-
assert [k for k in alias_dict] == [".json", ".yaml", ".toml", ".yml"]
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
def test_origin_keys(alias_dict):
|
|
153
|
-
assert list(alias_dict.origin_keys()) == [".json", ".yaml", ".toml"]
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
def test_aliased_keys(alias_dict):
|
|
157
|
-
assert list(alias_dict.aliased_keys()) == [(".yaml", [".yml"])]
|
|
158
|
-
alias_dict.add_alias(".toml", ".tml", ".tommy", ".tomograph")
|
|
159
|
-
assert list(alias_dict.aliased_keys()) == [
|
|
160
|
-
(".yaml", [".yml"]),
|
|
161
|
-
(".toml", [".tml", ".tommy", ".tomograph"]),
|
|
162
|
-
]
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
def test_repr(alias_dict):
|
|
166
|
-
assert str(alias_dict) == (
|
|
167
|
-
"AliasDict(dict_items(["
|
|
168
|
-
"('.json', {'import_mod': 'json', 'callable': 'load', 'read_mode': 'r'}), "
|
|
169
|
-
"('.yaml', {'import_mod': 'yaml', 'callable': 'safe_load', 'read_mode': 'r'}), "
|
|
170
|
-
"('.toml', {'import_mod': 'tomli', 'callable': 'load', 'read_mode': 'r'}), "
|
|
171
|
-
"('.yml', {'import_mod': 'yaml', 'callable': 'safe_load', 'read_mode': 'r'})"
|
|
172
|
-
"]))"
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
def test_eq():
|
|
177
|
-
ad_0 = {"a": 1, "b": 2}
|
|
178
|
-
ad_1 = AliasDict(ad_0)
|
|
179
|
-
ad_1.add_alias("a", "aa", "aaa")
|
|
180
|
-
|
|
181
|
-
ad_2 = AliasDict(ad_0)
|
|
182
|
-
ad_2.add_alias("a", "aa", "aaa")
|
|
183
|
-
|
|
184
|
-
ad_3 = AliasDict(ad_0)
|
|
185
|
-
ad_3.add_alias("a", "abc")
|
|
186
|
-
|
|
187
|
-
assert ad_1 == ad_2
|
|
188
|
-
assert ad_1 != ad_3
|
|
189
|
-
assert ad_2 != ad_3
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
def test_dict_len_includes_aliases(alias_dict):
|
|
193
|
-
assert list(alias_dict.keys()) == [".json", ".yaml", ".toml", ".yml"]
|
|
194
|
-
assert len(alias_dict) == 4
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
def test_dict_origin_len_excludes_aliases(alias_dict):
|
|
198
|
-
assert list(alias_dict.keys()) == [".json", ".yaml", ".toml", ".yml"]
|
|
199
|
-
assert alias_dict.origin_len() == 3
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
def test_popitem(alias_dict):
|
|
203
|
-
# pops first item -> MutableMapping.popitem()
|
|
204
|
-
assert alias_dict.popitem() == (
|
|
205
|
-
".json",
|
|
206
|
-
{"callable": "load", "import_mod": "json", "read_mode": "r"},
|
|
207
|
-
)
|
|
208
|
-
assert alias_dict.popitem() == (
|
|
209
|
-
".yaml",
|
|
210
|
-
{"callable": "safe_load", "import_mod": "yaml", "read_mode": "r"},
|
|
211
|
-
)
|
|
212
|
-
assert len(alias_dict.aliased_keys()) == 0
|
|
213
|
-
assert list(alias_dict.keys()) == [".toml"]
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
def test_clear(alias_dict):
|
|
217
|
-
alias_dict.clear()
|
|
218
|
-
assert len(alias_dict.items()) == 0
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
def test_clear_aliases(alias_dict):
|
|
222
|
-
alias_dict.clear_aliases()
|
|
223
|
-
assert len(alias_dict.aliases()) == 0
|
|
224
|
-
assert list(alias_dict.items()) == [
|
|
225
|
-
(".json", {"callable": "load", "import_mod": "json", "read_mode": "r"}),
|
|
226
|
-
(".yaml", {"callable": "safe_load", "import_mod": "yaml", "read_mode": "r"}),
|
|
227
|
-
(".toml", {"callable": "load", "import_mod": "tomli", "read_mode": "r"}),
|
|
228
|
-
]
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
def test_setdefault():
|
|
232
|
-
ad = AliasDict({"a": 1, "b": 2})
|
|
233
|
-
ad.setdefault("foo", "bar")
|
|
234
|
-
ad.add_alias("foo", "fizz")
|
|
235
|
-
assert ad["foo"] == "bar"
|
|
236
|
-
assert ad["fizz"] == "bar"
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
def test_setdefault_on_existing_aliased_key():
|
|
240
|
-
ad = AliasDict({"a": 1, "b": 2})
|
|
241
|
-
ad.setdefault("a", 42)
|
|
242
|
-
ad.add_alias("a", "aa")
|
|
243
|
-
assert ad["a"] == 1
|
|
244
|
-
assert ad["aa"] == 1
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
def test_update_modifies_aliases():
|
|
248
|
-
ad = AliasDict({"a": 1, "b": 2})
|
|
249
|
-
ad.add_alias("a", "aa", "aaa")
|
|
250
|
-
ad.update(**{"a": 40, "y": 50})
|
|
251
|
-
assert list(ad.items()) == [("a", 40), ("b", 2), ("y", 50), ("aa", 40), ("aaa", 40)]
|
|
File without changes
|
|
File without changes
|