batutils 2.0.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.
Files changed (79) hide show
  1. {batutils-2.0.0 → batutils-2.2.0}/LICENSE +1 -1
  2. {batutils-2.0.0 → batutils-2.2.0}/PKG-INFO +6 -5
  3. batutils-2.2.0/batutils/__init__.py +5 -0
  4. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/casting/_any.py +1 -1
  5. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/casting/_instant.py +6 -1
  6. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/casting/_timestamp.py +5 -12
  7. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/casting/_evals.py +63 -8
  8. {batutils-2.0.0 → batutils-2.2.0}/batutils.egg-info/PKG-INFO +6 -5
  9. {batutils-2.0.0 → batutils-2.2.0}/pyproject.toml +2 -2
  10. batutils-2.0.0/batutils/__init__.py +0 -5
  11. {batutils-2.0.0 → batutils-2.2.0}/README.md +0 -0
  12. {batutils-2.0.0 → batutils-2.2.0}/batutils/_common/__init__.py +0 -0
  13. {batutils-2.0.0 → batutils-2.2.0}/batutils/_common/_decode.py +0 -0
  14. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/__init__.py +0 -0
  15. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/casting/__init__.py +0 -0
  16. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/casting/_filetime.py +0 -0
  17. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/casting/_string.py +0 -0
  18. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/formatting/__init__.py +0 -0
  19. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/formatting/_delta.py +0 -0
  20. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/formatting/_serialize.py +0 -0
  21. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/parsers/__init__.py +0 -0
  22. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/parsers/_string.py +0 -0
  23. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/parsers/_timedelta.py +0 -0
  24. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/shortcuts/__init__.py +0 -0
  25. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/shortcuts/_aliases.py +0 -0
  26. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/shortcuts/_checkers.py +0 -0
  27. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/shortcuts/_finders.py +0 -0
  28. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/structs/__init__.py +0 -0
  29. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/structs/_base.py +0 -0
  30. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/structs/_deltasplit.py +0 -0
  31. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/structs/_types.py +0 -0
  32. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/structs/aliases.py +0 -0
  33. {batutils-2.0.0 → batutils-2.2.0}/batutils/dtu/structs/consts.py +0 -0
  34. {batutils-2.0.0 → batutils-2.2.0}/batutils/structs/__init__.py +0 -0
  35. {batutils-2.0.0 → batutils-2.2.0}/batutils/structs/_base.py +0 -0
  36. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/__init__.py +0 -0
  37. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/casting/__init__.py +0 -0
  38. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/casting/_currency.py +0 -0
  39. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/casting/_ip.py +0 -0
  40. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/casting/_mask.py +0 -0
  41. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/casting/_params.py +0 -0
  42. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/casting/_serialize.py +0 -0
  43. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/comparison/__init__.py +0 -0
  44. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/comparison/_mixin.py +0 -0
  45. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/insp/__init__.py +0 -0
  46. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/insp/_insp_old.py +0 -0
  47. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/insp/_typecheck.py +0 -0
  48. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/iters/__init__.py +0 -0
  49. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/iters/_attrs.py +0 -0
  50. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/iters/_dicts.py +0 -0
  51. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/iters/_group.py +0 -0
  52. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/iters/_lists.py +0 -0
  53. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/size/__init__.py +0 -0
  54. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/size/_total.py +0 -0
  55. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/strimp/__init__.py +0 -0
  56. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/strimp/_getters.py +0 -0
  57. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/string/__init__.py +0 -0
  58. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/string/_string.py +0 -0
  59. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/__init__.py +0 -0
  60. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/_base.py +0 -0
  61. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/empty/__init__.py +0 -0
  62. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/empty/_empty.py +0 -0
  63. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/enumex/__init__.py +0 -0
  64. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/enumex/_enumextra.py +0 -0
  65. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/fluid/__init__.py +0 -0
  66. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/fluid/_attrfluid.py +0 -0
  67. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/sentience/__init__.py +0 -0
  68. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/sentience/_builder.py +0 -0
  69. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/serializers/__init__.py +0 -0
  70. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/serializers/_json.py +0 -0
  71. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/serializers/_jsonsafe.py +0 -0
  72. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/serializers/_universal.py +0 -0
  73. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/singleton/__init__.py +0 -0
  74. {batutils-2.0.0 → batutils-2.2.0}/batutils/tpu/structs/singleton/_singleton.py +0 -0
  75. {batutils-2.0.0 → batutils-2.2.0}/batutils.egg-info/SOURCES.txt +0 -0
  76. {batutils-2.0.0 → batutils-2.2.0}/batutils.egg-info/dependency_links.txt +0 -0
  77. {batutils-2.0.0 → batutils-2.2.0}/batutils.egg-info/top_level.txt +0 -0
  78. {batutils-2.0.0 → batutils-2.2.0}/setup.cfg +0 -0
  79. {batutils-2.0.0 → batutils-2.2.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 Thordur Matthiasson
3
+ Copyright (c) 2024-2026 Thordur Matthiasson
4
4
  Copyright (c) 2013-2024 CCP Games
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -1,11 +1,11 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: batutils
3
- Version: 2.0.0
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 Thordur Matthiasson
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
 
@@ -0,0 +1,5 @@
1
+ __version__ = '2.2.0'
2
+
3
+ __author__ = 'Thordur Matthiasson <doddi79@gmail.com>'
4
+ __license__ = 'MIT License'
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 timestamp_to_datetime(temporal_object)
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
- return timestamp_to_datetime(milliseconds_since_epoch / 1000., minmax_on_fail)
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.fromtimestamp(seconds_since_epoch)
21
- except OSError:
22
- try:
23
- return Datetime(1970, 1, 1, 0, 0, 0, 0) + TimeDelta(seconds=seconds_since_epoch)
24
- except OverflowError:
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):
226
- hit = {o.name.lower(): o for o in enum_class}.get(value.strip().lower(), None)
228
+ # First we check the member name (normalized)
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
- if isinstance(value, int):
237
- try:
238
- return enum_class(value)
239
- except ValueError:
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
1
+ Metadata-Version: 2.4
2
2
  Name: batutils
3
- Version: 2.0.0
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 Thordur Matthiasson
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",
@@ -1,5 +0,0 @@
1
- __version__ = '2.0.0'
2
-
3
- __author__ = 'Thordur Matthiasson <doddi79@gmail.com>'
4
- __license__ = 'MIT License'
5
- __copyright__ = 'Copyright 2024 - Thordur Matthiasson, Copyright 2013-2024 - CCP Games ehf'
File without changes
File without changes
File without changes