xloft 0.1.19__py3-none-any.whl → 0.10.10__py3-none-any.whl
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.
- xloft/__init__.py +35 -14
- xloft/converters/__init__.py +22 -0
- xloft/converters/human_size.py +42 -0
- xloft/converters/roman.py +119 -0
- xloft/errors.py +43 -24
- xloft/itis.py +63 -0
- xloft/types/__init__.py +20 -0
- xloft/types/alias_dict.py +359 -0
- xloft/{namedtuple.py → types/named_tuple.py} +240 -255
- xloft-0.10.10.dist-info/METADATA +281 -0
- xloft-0.10.10.dist-info/RECORD +14 -0
- {xloft-0.1.19.dist-info → xloft-0.10.10.dist-info}/WHEEL +1 -1
- {xloft-0.1.19.dist-info → xloft-0.10.10.dist-info}/licenses/LICENSE +21 -21
- xloft/humanism.py +0 -30
- xloft-0.1.19.dist-info/METADATA +0 -175
- xloft-0.1.19.dist-info/RECORD +0 -9
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# XLOFT - X-Library of tools.
|
|
2
|
+
# Copyright (c) 2025 Gennady Kostyunin
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
"""`AliasDict` - Pseudo dictionary with supports aliases for keys.
|
|
5
|
+
|
|
6
|
+
Class `AliasDict` contains the following methods:
|
|
7
|
+
|
|
8
|
+
- `get` - Get value by alias.
|
|
9
|
+
- `add` - Add a new key and value pair.
|
|
10
|
+
- `update` - Update the value of an existing key.
|
|
11
|
+
- `delete` - Delete the value associated with the key and all its aliases.
|
|
12
|
+
- `add_alias` - Add a new alias to an existing set.
|
|
13
|
+
- `delete_alias` - Remove the alias from the existing set.
|
|
14
|
+
- `has_key` - Check if the alias exists.
|
|
15
|
+
- `has_value` - Check if the value exists.
|
|
16
|
+
- `items` - Returns a generator of list of `AliasDict` elements grouped into tuples.
|
|
17
|
+
- `keys` - Get a generator of list of all aliases.
|
|
18
|
+
- `values` - Get a generator of list of all values.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
__all__ = ("AliasDict",)
|
|
24
|
+
|
|
25
|
+
import copy
|
|
26
|
+
import logging
|
|
27
|
+
from collections.abc import Generator
|
|
28
|
+
from typing import Any
|
|
29
|
+
|
|
30
|
+
from xloft.errors import (
|
|
31
|
+
AttributeCannotBeDeleteError,
|
|
32
|
+
AttributeDoesNotGetValueError,
|
|
33
|
+
AttributeDoesNotSetValueError,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class AliasDict:
|
|
38
|
+
"""Pseudo dictionary with supports aliases for keys."""
|
|
39
|
+
|
|
40
|
+
def __init__(self, data: list[tuple[set[str | int | float], Any]] | None = None) -> None: # noqa: D107
|
|
41
|
+
self.__dict__["_store"] = []
|
|
42
|
+
self.__dict__["all_alias_set"] = set() # for uniqueness check
|
|
43
|
+
if data is not None:
|
|
44
|
+
for item in data:
|
|
45
|
+
if not self.all_alias_set.isdisjoint(item[0]):
|
|
46
|
+
err_msg = "In some keys, aliases are repeated!"
|
|
47
|
+
logging.error(err_msg)
|
|
48
|
+
raise KeyError(err_msg)
|
|
49
|
+
self.all_alias_set.update(item[0])
|
|
50
|
+
self._store.append(list(item))
|
|
51
|
+
|
|
52
|
+
def __len__(self) -> int:
|
|
53
|
+
"""Get the number of elements in the dictionary.
|
|
54
|
+
|
|
55
|
+
Examples:
|
|
56
|
+
>>> from xloft import AliasDict
|
|
57
|
+
>>> ad = AliasDict([({"English", "en"}, "lemmatize_en_all")])
|
|
58
|
+
>>> len(ad)
|
|
59
|
+
1
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
The number of elements in the dictionary.
|
|
63
|
+
"""
|
|
64
|
+
return len(self.__dict__["_store"])
|
|
65
|
+
|
|
66
|
+
def __getattr__(self, name: str) -> None:
|
|
67
|
+
"""Blocked Getter."""
|
|
68
|
+
raise AttributeDoesNotGetValueError(name)
|
|
69
|
+
|
|
70
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
71
|
+
"""Blocked Setter."""
|
|
72
|
+
raise AttributeDoesNotSetValueError(name)
|
|
73
|
+
|
|
74
|
+
def __delattr__(self, name: str) -> None:
|
|
75
|
+
"""Blocked Deleter."""
|
|
76
|
+
raise AttributeCannotBeDeleteError(name)
|
|
77
|
+
|
|
78
|
+
def __getitem__(self, alias: str | int | float) -> Any:
|
|
79
|
+
"""Get value by [key_name].
|
|
80
|
+
|
|
81
|
+
Examples:
|
|
82
|
+
>>> from xloft import AliasDict
|
|
83
|
+
>>> ad = AliasDict([({"English", "en"}, "lemmatize_en_all")])
|
|
84
|
+
>>> ad["en"]
|
|
85
|
+
"lemmatize_en_all"
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
alias (str | int | float): Alias of key.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Deep copy of the value associated with the alias.
|
|
92
|
+
"""
|
|
93
|
+
for item in self.__dict__["_store"]:
|
|
94
|
+
if alias in item[0]:
|
|
95
|
+
return copy.deepcopy(item[1])
|
|
96
|
+
raise KeyError(f"Alias `{alias}` is missing!")
|
|
97
|
+
|
|
98
|
+
def get(self, alias: str | int | float, default: Any = None) -> Any:
|
|
99
|
+
"""Get value by alias.
|
|
100
|
+
|
|
101
|
+
If there is no alias, return the default value.
|
|
102
|
+
|
|
103
|
+
Examples:
|
|
104
|
+
>>> from xloft import AliasDict
|
|
105
|
+
>>> ad = AliasDict([({"English", "en"}, "lemmatize_en_all")])
|
|
106
|
+
>>> ad.get("en")
|
|
107
|
+
"lemmatize_en_all"
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
alias (str | int | float): Alias of key.
|
|
111
|
+
default (Any): Value by default.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Deep copy of the value associated with the alias or value by default.
|
|
115
|
+
"""
|
|
116
|
+
for item in self.__dict__["_store"]:
|
|
117
|
+
if alias in item[0]:
|
|
118
|
+
return copy.deepcopy(item[1])
|
|
119
|
+
|
|
120
|
+
return default
|
|
121
|
+
|
|
122
|
+
def add(self, aliases: set[str | int | float], value: Any) -> None:
|
|
123
|
+
"""Add a new key and value pair.
|
|
124
|
+
|
|
125
|
+
Examples:
|
|
126
|
+
>>> from xloft import AliasDict
|
|
127
|
+
>>> ad = AliasDict([({"English", "en"}, "lemmatize_en_all")])
|
|
128
|
+
>>> ad.add({"Russian", "ru"}, "lemmatize_ru_all")
|
|
129
|
+
>>> ad.get("ru")
|
|
130
|
+
"lemmatize_ru_all"
|
|
131
|
+
|
|
132
|
+
Args:
|
|
133
|
+
aliases (set[str | int | float]): List (set) aliases of key.
|
|
134
|
+
value (Any): Value associated with key.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
`None` or `KeyError` is missing.
|
|
138
|
+
"""
|
|
139
|
+
if not self.all_alias_set.isdisjoint(aliases):
|
|
140
|
+
err_msg = "In some keys, aliases are repeated."
|
|
141
|
+
logging.error(err_msg)
|
|
142
|
+
|
|
143
|
+
self._store.append([aliases, value])
|
|
144
|
+
self.all_alias_set.update(aliases)
|
|
145
|
+
|
|
146
|
+
def update(self, alias: str | int | float, value: Any) -> None:
|
|
147
|
+
"""Update the value of an existing key.
|
|
148
|
+
|
|
149
|
+
Examples:
|
|
150
|
+
>>> from xloft import AliasDict
|
|
151
|
+
>>> ad = AliasDict([({"English", "en"}, "lemmatize_en_all")])
|
|
152
|
+
>>> ad.update("en", "Hello world!")
|
|
153
|
+
>>> ad.get("English")
|
|
154
|
+
"Hello world!"
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
alias (str | int | float): Alias of key.
|
|
158
|
+
value (Any): Value associated with key.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
`None` or `KeyError` if alias is missing.
|
|
162
|
+
"""
|
|
163
|
+
for item in self.__dict__["_store"]:
|
|
164
|
+
if alias in item[0]:
|
|
165
|
+
item[1] = value
|
|
166
|
+
return
|
|
167
|
+
|
|
168
|
+
err_msg = f"Alias `{alias}` is missing!"
|
|
169
|
+
logging.error(err_msg)
|
|
170
|
+
raise KeyError(err_msg)
|
|
171
|
+
|
|
172
|
+
def delete(self, alias: str | int | float) -> None:
|
|
173
|
+
"""Delete the value associated with the key and all its aliases.
|
|
174
|
+
|
|
175
|
+
Examples:
|
|
176
|
+
>>> from xloft import AliasDict
|
|
177
|
+
>>> ad = AliasDict([({"English", "en"}, "lemmatize_en_all")])
|
|
178
|
+
>>> ad.delete("en")
|
|
179
|
+
>>> ad.get("English")
|
|
180
|
+
None
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
alias (str | int | float): Alias of key.
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
`None` or `KeyError` if alias is missing.
|
|
187
|
+
"""
|
|
188
|
+
for item in self.__dict__["_store"]:
|
|
189
|
+
if alias in item[0]:
|
|
190
|
+
self.__dict__["all_alias_set"] = {
|
|
191
|
+
alias for alias in self.__dict__["all_alias_set"] if alias not in item[0]
|
|
192
|
+
}
|
|
193
|
+
self.__dict__["_store"] = [item for item in self.__dict__["_store"] if alias not in item[0]]
|
|
194
|
+
return
|
|
195
|
+
|
|
196
|
+
err_msg = f"Alias `{alias}` is missing!"
|
|
197
|
+
logging.error(err_msg)
|
|
198
|
+
raise KeyError(err_msg)
|
|
199
|
+
|
|
200
|
+
def add_alias(
|
|
201
|
+
self,
|
|
202
|
+
alias: str | int | float,
|
|
203
|
+
new_alias: str | int | float,
|
|
204
|
+
) -> None:
|
|
205
|
+
"""Add a new alias to an existing set.
|
|
206
|
+
|
|
207
|
+
Examples:
|
|
208
|
+
>>> from xloft import AliasDict
|
|
209
|
+
>>> ad = AliasDict([({"English"}, "lemmatize_en_all")])
|
|
210
|
+
>>> ad.add_alias("English", "en")
|
|
211
|
+
>>> ad.get("en")
|
|
212
|
+
"lemmatize_en_all"
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
alias (str | int | float): Existing alias.
|
|
216
|
+
new_alias (str | int | float): The alias that needs to be added to the existing set.
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
`None` or `KeyError` if new alias is already exists.
|
|
220
|
+
"""
|
|
221
|
+
if new_alias in self.__dict__["all_alias_set"]:
|
|
222
|
+
err_msg = f"New Alias `{new_alias}` is already exists!"
|
|
223
|
+
logging.error(err_msg)
|
|
224
|
+
raise KeyError(err_msg)
|
|
225
|
+
|
|
226
|
+
for item in self.__dict__["_store"]:
|
|
227
|
+
if alias in item[0]:
|
|
228
|
+
item[0].add(new_alias)
|
|
229
|
+
self.all_alias_set.add(new_alias)
|
|
230
|
+
return
|
|
231
|
+
|
|
232
|
+
err_msg = f"Alias `{alias}` is missing!"
|
|
233
|
+
logging.error(err_msg)
|
|
234
|
+
raise KeyError(err_msg)
|
|
235
|
+
|
|
236
|
+
def delete_alias(self, alias: str | int | float) -> None:
|
|
237
|
+
"""Remove the alias from the existing set.
|
|
238
|
+
|
|
239
|
+
If the alias was the last one, then the value associated with it is deleted.
|
|
240
|
+
|
|
241
|
+
Examples:
|
|
242
|
+
>>> from xloft import AliasDict
|
|
243
|
+
>>> ad = AliasDict([({"English", "en"}, "lemmatize_en_all")])
|
|
244
|
+
>>> ad.delete_alias("en")
|
|
245
|
+
>>> ad.keys()
|
|
246
|
+
["English"]
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
alias (str | int | float): Existing alias.
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
`None` or `KeyError` if alias is missing.
|
|
253
|
+
"""
|
|
254
|
+
for item in self.__dict__["_store"]:
|
|
255
|
+
if alias in item[0]:
|
|
256
|
+
if len(item[0]) == 1:
|
|
257
|
+
self._store = [item for item in self._store if alias not in item[0]]
|
|
258
|
+
else:
|
|
259
|
+
item[0].remove(alias)
|
|
260
|
+
self.all_alias_set.remove(alias)
|
|
261
|
+
return
|
|
262
|
+
|
|
263
|
+
err_msg = f"Alias `{alias}` is missing!"
|
|
264
|
+
logging.error(err_msg)
|
|
265
|
+
raise KeyError(err_msg)
|
|
266
|
+
|
|
267
|
+
def has_key(self, alias: str | int | float) -> bool:
|
|
268
|
+
"""Check if the alias exists.
|
|
269
|
+
|
|
270
|
+
Examples:
|
|
271
|
+
>>> from xloft import AliasDict
|
|
272
|
+
>>> ad = AliasDict([({"English", "en"}, "lemmatize_en_all")])
|
|
273
|
+
>>> ad.has_key("en")
|
|
274
|
+
True
|
|
275
|
+
|
|
276
|
+
Args:
|
|
277
|
+
alias (str | int | float): Some alias.
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
True if the key exists, otherwise False.
|
|
281
|
+
"""
|
|
282
|
+
return alias in self.__dict__["all_alias_set"]
|
|
283
|
+
|
|
284
|
+
def has_value(self, value: Any) -> bool:
|
|
285
|
+
"""Check if the value exists.
|
|
286
|
+
|
|
287
|
+
Examples:
|
|
288
|
+
>>> from xloft import AliasDict
|
|
289
|
+
>>> ad = AliasDict([({"English", "en"}, "lemmatize_en_all")])
|
|
290
|
+
>>> ad.has_value("lemmatize_en_all")
|
|
291
|
+
True
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
value (Any): Value associated with key.
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
True if the value exists, otherwise False.
|
|
298
|
+
"""
|
|
299
|
+
is_exists = False
|
|
300
|
+
for item in self.__dict__["_store"]:
|
|
301
|
+
if value == item[1]:
|
|
302
|
+
is_exists = True
|
|
303
|
+
break
|
|
304
|
+
|
|
305
|
+
return is_exists
|
|
306
|
+
|
|
307
|
+
def items(self) -> Generator[tuple[list[str | int | float], Any]]:
|
|
308
|
+
"""Returns a generator of list containing a tuple for each key-value pair.
|
|
309
|
+
|
|
310
|
+
This is convenient for use in a `for` loop.
|
|
311
|
+
If you need to get a list, do it list(instance.items()).
|
|
312
|
+
|
|
313
|
+
Examples:
|
|
314
|
+
>>> from xloft import AliasDict
|
|
315
|
+
>>> ad = AliasDict([({"English", "en"}, "lemmatize_en_all")])
|
|
316
|
+
>>> for aliases, value in ad.items():
|
|
317
|
+
... print(f"Aliases: {aliases}, Value: {value}")
|
|
318
|
+
"Key: ['English', 'en'], Value: lemmatize_en_all"
|
|
319
|
+
|
|
320
|
+
Returns:
|
|
321
|
+
Returns a list containing a tuple for each key-value pair.
|
|
322
|
+
Type: `list[tuple[list[str | int | float], Any]]` or `[]`.
|
|
323
|
+
"""
|
|
324
|
+
store = self.__dict__["_store"]
|
|
325
|
+
return ((list(item[0]), item[1]) for item in store)
|
|
326
|
+
|
|
327
|
+
def keys(self) -> Generator[str | int | float]:
|
|
328
|
+
"""Get a generator of list of all aliases.
|
|
329
|
+
|
|
330
|
+
If you need to get a list, do it list(instance.keys()).
|
|
331
|
+
|
|
332
|
+
Examples:
|
|
333
|
+
>>> from xloft import AliasDict
|
|
334
|
+
>>> ad = AliasDict([({"English", "en"}, "lemmatize_en_all")])
|
|
335
|
+
>>> list(ad.keys())
|
|
336
|
+
["English", "en"]
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
List of all aliases.
|
|
340
|
+
"""
|
|
341
|
+
all_alias_set = self.__dict__["all_alias_set"]
|
|
342
|
+
return (item for item in all_alias_set)
|
|
343
|
+
|
|
344
|
+
def values(self) -> Generator[Any]:
|
|
345
|
+
"""Get a generator of list of all values.
|
|
346
|
+
|
|
347
|
+
If you need to get a list, do it list(instance.values()).
|
|
348
|
+
|
|
349
|
+
Examples:
|
|
350
|
+
>>> from xloft import AliasDict
|
|
351
|
+
>>> ad = AliasDict([({"English", "en"}, "lemmatize_en_all")])
|
|
352
|
+
>>> list(ad.values())
|
|
353
|
+
["lemmatize_en_all"]
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
List of all values.
|
|
357
|
+
"""
|
|
358
|
+
store = self.__dict__["_store"]
|
|
359
|
+
return (item[1] for item in store)
|