batutils 2.1.0__tar.gz → 2.2.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.
- {batutils-2.1.0 → batutils-2.2.0}/LICENSE +1 -1
- {batutils-2.1.0 → batutils-2.2.0}/PKG-INFO +6 -5
- {batutils-2.1.0 → batutils-2.2.0}/batutils/__init__.py +2 -2
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/casting/_any.py +1 -1
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/casting/_instant.py +6 -1
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/casting/_timestamp.py +5 -12
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/casting/_evals.py +62 -7
- {batutils-2.1.0 → batutils-2.2.0}/batutils.egg-info/PKG-INFO +6 -5
- {batutils-2.1.0 → batutils-2.2.0}/pyproject.toml +2 -2
- {batutils-2.1.0 → batutils-2.2.0}/README.md +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/_common/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/_common/_decode.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/casting/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/casting/_filetime.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/casting/_string.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/formatting/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/formatting/_delta.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/formatting/_serialize.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/parsers/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/parsers/_string.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/parsers/_timedelta.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/shortcuts/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/shortcuts/_aliases.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/shortcuts/_checkers.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/shortcuts/_finders.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/structs/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/structs/_base.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/structs/_deltasplit.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/structs/_types.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/structs/aliases.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/dtu/structs/consts.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/structs/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/structs/_base.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/casting/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/casting/_currency.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/casting/_ip.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/casting/_mask.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/casting/_params.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/casting/_serialize.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/comparison/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/comparison/_mixin.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/insp/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/insp/_insp_old.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/insp/_typecheck.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/iters/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/iters/_attrs.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/iters/_dicts.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/iters/_group.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/iters/_lists.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/size/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/size/_total.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/strimp/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/strimp/_getters.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/string/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/string/_string.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/_base.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/empty/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/empty/_empty.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/enumex/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/enumex/_enumextra.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/fluid/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/fluid/_attrfluid.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/sentience/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/sentience/_builder.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/serializers/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/serializers/_json.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/serializers/_jsonsafe.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/serializers/_universal.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/singleton/__init__.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils/tpu/structs/singleton/_singleton.py +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils.egg-info/SOURCES.txt +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils.egg-info/dependency_links.txt +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/batutils.egg-info/top_level.txt +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/setup.cfg +0 -0
- {batutils-2.1.0 → batutils-2.2.0}/setup.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: batutils
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Team Batcave's utilities for date and/or time objects and values and messing with types and so much more.
|
|
5
5
|
Author-email: Thordur Matthiasson <doddi79@gmail.com>, John Aldis <johnaldis@ccpgames.com>
|
|
6
6
|
License: MIT License
|
|
7
7
|
|
|
8
|
-
Copyright (c) 2024-
|
|
8
|
+
Copyright (c) 2024-2026 Thordur Matthiasson
|
|
9
9
|
Copyright (c) 2013-2024 CCP Games
|
|
10
10
|
|
|
11
11
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
@@ -37,17 +37,18 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
37
37
|
Classifier: Intended Audience :: Developers
|
|
38
38
|
Classifier: Programming Language :: Python
|
|
39
39
|
Classifier: Programming Language :: Python :: 3
|
|
40
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
41
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
42
40
|
Classifier: Programming Language :: Python :: 3.10
|
|
43
41
|
Classifier: Programming Language :: Python :: 3.11
|
|
44
42
|
Classifier: Programming Language :: Python :: 3.12
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
45
45
|
Classifier: Topic :: Software Development
|
|
46
46
|
Classifier: Topic :: Software Development :: Libraries
|
|
47
47
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
48
48
|
Classifier: Topic :: Utilities
|
|
49
49
|
Description-Content-Type: text/markdown
|
|
50
50
|
License-File: LICENSE
|
|
51
|
+
Dynamic: license-file
|
|
51
52
|
|
|
52
53
|
# Team Batcave Python Toolkit
|
|
53
54
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
__version__ = '2.
|
|
1
|
+
__version__ = '2.2.0'
|
|
2
2
|
|
|
3
3
|
__author__ = 'Thordur Matthiasson <doddi79@gmail.com>'
|
|
4
4
|
__license__ = 'MIT License'
|
|
5
|
-
__copyright__ = 'Copyright 2024-
|
|
5
|
+
__copyright__ = 'Copyright 2024-2026 - Thordur Matthiasson, Copyright 2013-2024 - CCP Games ehf'
|
|
@@ -90,7 +90,7 @@ def any_to_datetime(temporal_object: T_TEMPORAL_VALUE,
|
|
|
90
90
|
# This range means that the number, if treated as an instant,
|
|
91
91
|
# represents a datetime within 1000 years to/from now so it's the
|
|
92
92
|
# second most likely bet!
|
|
93
|
-
return
|
|
93
|
+
return instant_to_datetime(temporal_object)
|
|
94
94
|
|
|
95
95
|
# This number is so large that it's most likely a filetime!
|
|
96
96
|
return filetime_to_datetime(temporal_object)
|
|
@@ -16,7 +16,12 @@ def instant_to_datetime(milliseconds_since_epoch: T_NUMBER, minmax_on_fail: bool
|
|
|
16
16
|
negative)
|
|
17
17
|
:return: A Python Datetime
|
|
18
18
|
"""
|
|
19
|
-
|
|
19
|
+
try:
|
|
20
|
+
return Datetime(1970, 1, 1) + TimeDelta(milliseconds=milliseconds_since_epoch)
|
|
21
|
+
except OverflowError:
|
|
22
|
+
if minmax_on_fail:
|
|
23
|
+
return Datetime.max if milliseconds_since_epoch > 0 else Datetime.min
|
|
24
|
+
raise
|
|
20
25
|
|
|
21
26
|
|
|
22
27
|
def datetime_to_instant(dt: T_DATE_VALUE) -> int:
|
|
@@ -17,18 +17,11 @@ def timestamp_to_datetime(seconds_since_epoch: T_NUMBER, minmax_on_fail: bool =
|
|
|
17
17
|
:return: A Python Datetime
|
|
18
18
|
"""
|
|
19
19
|
try:
|
|
20
|
-
return Datetime
|
|
21
|
-
except
|
|
22
|
-
|
|
23
|
-
return Datetime
|
|
24
|
-
|
|
25
|
-
if minmax_on_fail:
|
|
26
|
-
if seconds_since_epoch > 0:
|
|
27
|
-
return Datetime.max
|
|
28
|
-
else:
|
|
29
|
-
return Datetime.min
|
|
30
|
-
else:
|
|
31
|
-
raise
|
|
20
|
+
return Datetime(1970, 1, 1) + TimeDelta(seconds=seconds_since_epoch)
|
|
21
|
+
except OverflowError:
|
|
22
|
+
if minmax_on_fail:
|
|
23
|
+
return Datetime.max if seconds_since_epoch > 0 else Datetime.min
|
|
24
|
+
raise
|
|
32
25
|
|
|
33
26
|
|
|
34
27
|
def datetime_to_timestamp(dt: T_DATE_VALUE) -> float:
|
|
@@ -4,6 +4,8 @@ __all__ = [
|
|
|
4
4
|
'bool_eval',
|
|
5
5
|
'enum_eval',
|
|
6
6
|
|
|
7
|
+
'enum_value_lookup_map',
|
|
8
|
+
|
|
7
9
|
'decode_bytes',
|
|
8
10
|
]
|
|
9
11
|
|
|
@@ -223,9 +225,24 @@ def enum_eval(value: Any,
|
|
|
223
225
|
return default
|
|
224
226
|
|
|
225
227
|
if isinstance(value, str):
|
|
228
|
+
# First we check the member name (normalized)
|
|
226
229
|
hit = {n.lower(): m for n, m in enum_class.__members__.items()}.get(value.strip().lower(), None)
|
|
227
230
|
if hit is not None:
|
|
228
231
|
return hit
|
|
232
|
+
|
|
233
|
+
try:
|
|
234
|
+
value_lookup = enum_value_lookup_map(enum_class, allow_collision=False)
|
|
235
|
+
except KeyError:
|
|
236
|
+
if raise_on_fail:
|
|
237
|
+
raise
|
|
238
|
+
return default
|
|
239
|
+
|
|
240
|
+
# This covers just about everything, except where a numeric value was given as a string
|
|
241
|
+
hit = value_lookup.get(value, None)
|
|
242
|
+
if hit is not None:
|
|
243
|
+
return hit
|
|
244
|
+
|
|
245
|
+
if isinstance(value, str):
|
|
229
246
|
try:
|
|
230
247
|
value = int(value, base=0)
|
|
231
248
|
except ValueError:
|
|
@@ -233,15 +250,53 @@ def enum_eval(value: Any,
|
|
|
233
250
|
raise ValueError(f'{value!r} is not a valid {enum_class.__name__}')
|
|
234
251
|
return default
|
|
235
252
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if raise_on_fail:
|
|
241
|
-
raise
|
|
242
|
-
return default
|
|
253
|
+
# Retry after casting
|
|
254
|
+
hit = value_lookup.get(value, None)
|
|
255
|
+
if hit is not None:
|
|
256
|
+
return hit
|
|
243
257
|
|
|
244
258
|
if raise_on_fail:
|
|
245
259
|
raise ValueError(f'{value!r} is not a valid {enum_class.__name__}')
|
|
246
260
|
|
|
247
261
|
return default
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def enum_value_lookup_map(enum_class: Type[_T_ENUM_CLASS], allow_collision: bool = False) -> Dict[Any, _T_ENUM_CLASS]:
|
|
265
|
+
"""Returns a dict of all the values of an enum class as keys and their respective members as values for reverse
|
|
266
|
+
value lookups.
|
|
267
|
+
|
|
268
|
+
This also breaks down the individual values in the value tuple of a multi-value enum and includes each of those as
|
|
269
|
+
a lookup key as well. By default, this will raise a `KeyError` if any individual value is repeated with a different
|
|
270
|
+
member as its target but this can be suppressed by setting `allow_collision=True`
|
|
271
|
+
|
|
272
|
+
Example:
|
|
273
|
+
```python
|
|
274
|
+
import enum
|
|
275
|
+
|
|
276
|
+
class MyGoodEnum(enum.Enum):
|
|
277
|
+
FOO = ('one', 'one'), # This is fine
|
|
278
|
+
BAR = ('something', 'else'),
|
|
279
|
+
|
|
280
|
+
class MyBadEnum(enum.Enum):
|
|
281
|
+
FOO = ('one', 'something'),
|
|
282
|
+
BAR = ('one', 'else'), # This will result in a collision with FOO's 'one' and raise a KeyError by default
|
|
283
|
+
```
|
|
284
|
+
"""
|
|
285
|
+
d = {}
|
|
286
|
+
|
|
287
|
+
def _collision_free_add(value: Any, enum_member: _T_ENUM_CLASS):
|
|
288
|
+
if allow_collision:
|
|
289
|
+
d[value] = enum_member
|
|
290
|
+
else:
|
|
291
|
+
if value in d:
|
|
292
|
+
if d[value] != enum_member:
|
|
293
|
+
raise KeyError(f'value lookup map for {enum_class.__name__} resulted in a collision between {d[value]} and {enum_member} for the value {value!r}')
|
|
294
|
+
else:
|
|
295
|
+
d[value] = enum_member
|
|
296
|
+
|
|
297
|
+
for _, member in enum_class.__members__.items():
|
|
298
|
+
_collision_free_add(member.value, member)
|
|
299
|
+
if isinstance(member.value, tuple):
|
|
300
|
+
for v in member.value:
|
|
301
|
+
_collision_free_add(v, member)
|
|
302
|
+
return d
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: batutils
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: Team Batcave's utilities for date and/or time objects and values and messing with types and so much more.
|
|
5
5
|
Author-email: Thordur Matthiasson <doddi79@gmail.com>, John Aldis <johnaldis@ccpgames.com>
|
|
6
6
|
License: MIT License
|
|
7
7
|
|
|
8
|
-
Copyright (c) 2024-
|
|
8
|
+
Copyright (c) 2024-2026 Thordur Matthiasson
|
|
9
9
|
Copyright (c) 2013-2024 CCP Games
|
|
10
10
|
|
|
11
11
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
@@ -37,17 +37,18 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
37
37
|
Classifier: Intended Audience :: Developers
|
|
38
38
|
Classifier: Programming Language :: Python
|
|
39
39
|
Classifier: Programming Language :: Python :: 3
|
|
40
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
41
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
42
40
|
Classifier: Programming Language :: Python :: 3.10
|
|
43
41
|
Classifier: Programming Language :: Python :: 3.11
|
|
44
42
|
Classifier: Programming Language :: Python :: 3.12
|
|
43
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
44
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
45
45
|
Classifier: Topic :: Software Development
|
|
46
46
|
Classifier: Topic :: Software Development :: Libraries
|
|
47
47
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
48
48
|
Classifier: Topic :: Utilities
|
|
49
49
|
Description-Content-Type: text/markdown
|
|
50
50
|
License-File: LICENSE
|
|
51
|
+
Dynamic: license-file
|
|
51
52
|
|
|
52
53
|
# Team Batcave Python Toolkit
|
|
53
54
|
|
|
@@ -22,11 +22,11 @@ classifiers = [
|
|
|
22
22
|
|
|
23
23
|
"Programming Language :: Python",
|
|
24
24
|
"Programming Language :: Python :: 3",
|
|
25
|
-
"Programming Language :: Python :: 3.8",
|
|
26
|
-
"Programming Language :: Python :: 3.9",
|
|
27
25
|
"Programming Language :: Python :: 3.10",
|
|
28
26
|
"Programming Language :: Python :: 3.11",
|
|
29
27
|
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Programming Language :: Python :: 3.14",
|
|
30
30
|
|
|
31
31
|
"Topic :: Software Development",
|
|
32
32
|
"Topic :: Software Development :: Libraries",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|