osbot-utils 1.70.0__py3-none-any.whl → 1.73.1__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.
@@ -12,6 +12,7 @@ from typing import List
12
12
  from osbot_utils.base_classes.Type_Safe__List import Type_Safe__List
13
13
  from osbot_utils.helpers.Random_Guid import Random_Guid
14
14
  from osbot_utils.helpers.Random_Guid_Short import Random_Guid_Short
15
+ from osbot_utils.helpers.Safe_Id import Safe_Id
15
16
  from osbot_utils.helpers.Timestamp_Now import Timestamp_Now
16
17
  from osbot_utils.utils.Dev import pprint
17
18
  from osbot_utils.utils.Json import json_parse, json_to_bytes, json_to_gz
@@ -248,28 +249,63 @@ class Type_Safe:
248
249
  setattr(self, key, value)
249
250
  return self
250
251
 
252
+ def deserialize_dict__using_key_value_annotations(self, key, value):
253
+ dict_annotations_tuple = get_args(self.__annotations__[key])
254
+ if not dict_annotations_tuple: # happens when the value is a dict/Dict with no annotations
255
+ return value
256
+ if not type(value) is dict:
257
+ return value
258
+ #key_class = get_args(self.__annotations__[key])[0]
259
+ #value_class = get_args(self.__annotations__[key])[1]
260
+ key_class = dict_annotations_tuple[0]
261
+ value_class = dict_annotations_tuple[1]
262
+ new_value = {}
263
+
264
+ for dict_key, dict_value in value.items():
265
+ if issubclass(key_class, Type_Safe):
266
+ new__dict_key = key_class().deserialize_from_dict(dict_key)
267
+ else:
268
+ new__dict_key = key_class(dict_key)
269
+
270
+ if issubclass(value_class, Type_Safe):
271
+ new__dict_value = value_class().deserialize_from_dict(dict_value)
272
+ else:
273
+ new__dict_value = value_class(dict_value)
274
+ new_value[new__dict_key] = new__dict_value
251
275
 
276
+ return new_value
277
+
278
+ # todo: this needs refactoring, since the logic and code is getting quite complex (to be inside methods like this)
252
279
  def deserialize_from_dict(self, data):
280
+
253
281
  for key, value in data.items():
254
282
  if hasattr(self, key) and isinstance(getattr(self, key), Type_Safe):
255
- getattr(self, key).deserialize_from_dict(value) # Recursive call for complex nested objects
283
+ getattr(self, key).deserialize_from_dict(value) # if the attribute is a Type_Safe object, then also deserialize it
256
284
  else:
257
- if hasattr(self, '__annotations__'): # can only do type safety checks if the class does not have annotations
258
- if obj_is_attribute_annotation_of_type(self, key, EnumMeta): # Handle the case when the value is an Enum
259
- enum_type = getattr(self, '__annotations__').get(key)
260
- if type(value) is not enum_type: # If the value is not already of the target type
261
- value = enum_from_value(enum_type, value) # Try to resolve the value into the enum
262
-
263
- # todo: refactor these special cases into a separate method to class
264
- elif obj_is_attribute_annotation_of_type(self, key, Decimal): # handle Decimals
265
- value = Decimal(value)
266
- elif obj_is_attribute_annotation_of_type(self, key, Random_Guid): # handle Random_Guid
267
- value = Random_Guid(value)
268
- elif obj_is_attribute_annotation_of_type(self, key, Random_Guid_Short): # handle Random_Guid_Short
269
- value = Random_Guid_Short(value)
270
- elif obj_is_attribute_annotation_of_type(self, key, Timestamp_Now): # handle Timestamp_Now
271
- value = Timestamp_Now(value)
272
- setattr(self, key, value) # Direct assignment for primitive types and other structures
285
+ if hasattr(self, '__annotations__'): # can only do type safety checks if the class does not have annotations
286
+ if hasattr(self, key) is False: # make sure we are now adding new attributes to the class
287
+ raise ValueError(f"Attribute '{key}' not found in '{self.__class__.__name__}'")
288
+ if obj_is_attribute_annotation_of_type(self, key, dict): # handle the case when the value is a dict
289
+ value = self.deserialize_dict__using_key_value_annotations(key, value)
290
+ else:
291
+ if value is not None:
292
+ if obj_is_attribute_annotation_of_type(self, key, EnumMeta): # Handle the case when the value is an Enum
293
+ enum_type = getattr(self, '__annotations__').get(key)
294
+ if type(value) is not enum_type: # If the value is not already of the target type
295
+ value = enum_from_value(enum_type, value) # Try to resolve the value into the enum
296
+
297
+ # todo: refactor these special cases into a separate method to class
298
+ elif obj_is_attribute_annotation_of_type(self, key, Decimal): # handle Decimals
299
+ value = Decimal(value)
300
+ elif obj_is_attribute_annotation_of_type(self, key, Safe_Id): # handle Safe_Id
301
+ value = Safe_Id(value)
302
+ elif obj_is_attribute_annotation_of_type(self, key, Random_Guid): # handle Random_Guid
303
+ value = Random_Guid(value)
304
+ elif obj_is_attribute_annotation_of_type(self, key, Random_Guid_Short): # handle Random_Guid_Short
305
+ value = Random_Guid_Short(value)
306
+ elif obj_is_attribute_annotation_of_type(self, key, Timestamp_Now): # handle Timestamp_Now
307
+ value = Timestamp_Now(value)
308
+ setattr(self, key, value) # Direct assignment for primitive types and other structures
273
309
 
274
310
  return self
275
311
 
@@ -1,7 +1,10 @@
1
- from osbot_utils.utils.Str import safe_id
1
+ from osbot_utils.utils.Misc import random_id_short
2
+ from osbot_utils.utils.Str import safe_id
2
3
 
3
4
  class Safe_Id(str):
4
- def __new__(cls, value):
5
+ def __new__(cls, value=None):
6
+ if value is None:
7
+ value = safe_id(random_id_short('safe-id'))
5
8
  sanitized_value = safe_id(value)
6
9
  return str.__new__(cls, sanitized_value)
7
10
 
osbot_utils/utils/Misc.py CHANGED
@@ -379,6 +379,9 @@ def random_string(length:int=8, prefix:str='', postfix:str=''):
379
379
  value = '_' + ''.join(random.choices(string.ascii_uppercase, k=length)).lower()
380
380
  return f"{prefix}{value}{postfix}"
381
381
 
382
+ def random_string_short(prefix:str = None):
383
+ return random_id(prefix=prefix, length=6).lower()
384
+
382
385
  def random_string_and_numbers(length:int=6,prefix:str=''):
383
386
  return prefix + ''.join(random.choices(string.ascii_uppercase + string.digits, k=length))
384
387
 
@@ -508,6 +511,7 @@ str_lines = split_lines
508
511
  str_remove = remove
509
512
 
510
513
  random_id = random_string
514
+ random_id_short = random_string_short
511
515
  random_int = random_number
512
516
  random_guid = random_uuid
513
517
  random_guid_short = random_uuid_short
@@ -8,12 +8,13 @@ import typing
8
8
  from collections.abc import Mapping
9
9
  from typing import Union
10
10
  from types import SimpleNamespace
11
+ from osbot_utils.helpers.Safe_Id import Safe_Id
11
12
  from osbot_utils.helpers.Timestamp_Now import Timestamp_Now
12
13
  from osbot_utils.helpers.Random_Guid import Random_Guid
13
14
  from osbot_utils.utils.Misc import list_set
14
15
  from osbot_utils.utils.Str import str_unicode_escape, str_max_width
15
16
 
16
- TYPE_SAFE__CONVERT_VALUE__SUPPORTED_TYPES = [Random_Guid, Timestamp_Now]
17
+ TYPE_SAFE__CONVERT_VALUE__SUPPORTED_TYPES = [Safe_Id, Random_Guid, Timestamp_Now]
17
18
 
18
19
  # Backport implementations of get_origin and get_args for Python 3.7
19
20
  if sys.version_info < (3, 8):
@@ -352,6 +353,8 @@ def obj_is_attribute_annotation_of_type(target, attr_name, expected_type):
352
353
  return True
353
354
  if expected_type is type(attribute_annotation):
354
355
  return True
356
+ if expected_type is get_origin(attribute_annotation): # handle genericAlias
357
+ return True
355
358
  return False
356
359
 
357
360
  def obj_is_type_union_compatible(var_type, compatible_types):
osbot_utils/version CHANGED
@@ -1 +1 @@
1
- v1.70.0
1
+ v1.73.1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: osbot_utils
3
- Version: 1.70.0
3
+ Version: 1.73.1
4
4
  Summary: OWASP Security Bot - Utils
5
5
  Home-page: https://github.com/owasp-sbot/OSBot-Utils
6
6
  License: MIT
@@ -23,7 +23,7 @@ Description-Content-Type: text/markdown
23
23
 
24
24
  Powerful Python util methods and classes that simplify common apis and tasks.
25
25
 
26
- ![Current Release](https://img.shields.io/badge/release-v1.70.0-blue)
26
+ ![Current Release](https://img.shields.io/badge/release-v1.73.1-blue)
27
27
  [![codecov](https://codecov.io/gh/owasp-sbot/OSBot-Utils/graph/badge.svg?token=GNVW0COX1N)](https://codecov.io/gh/owasp-sbot/OSBot-Utils)
28
28
 
29
29
 
@@ -2,7 +2,7 @@ osbot_utils/__init__.py,sha256=DdJDmQc9zbQUlPVyTJOww6Ixrn9n4bD3ami5ItQfzJI,16
2
2
  osbot_utils/base_classes/Cache_Pickle.py,sha256=kPCwrgUbf_dEdxUz7vW1GuvIPwlNXxuRhb-H3AbSpII,5884
3
3
  osbot_utils/base_classes/Kwargs_To_Disk.py,sha256=HHoy05NC_w35WcT-OnSKoSIV_cLqaU9rdjH0_KNTM0E,1096
4
4
  osbot_utils/base_classes/Kwargs_To_Self.py,sha256=weFNsBfBNV9W_qBkN-IdBD4yYcJV_zgTxBRO-ZlcPS4,141
5
- osbot_utils/base_classes/Type_Safe.py,sha256=2cQ5qxJV2Ow3YQCkm_VwK7LoVet3pLjfShdgsBUkFt4,18261
5
+ osbot_utils/base_classes/Type_Safe.py,sha256=-sqoyhkBKmS9XbZLBn_v1Gp_G48Sj8pTAfeIsOjqhFY,20515
6
6
  osbot_utils/base_classes/Type_Safe__List.py,sha256=-80C9OhsK6iDR2dAG8yNLAZV0qg5x3faqvSUigFCMJw,517
7
7
  osbot_utils/base_classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  osbot_utils/context_managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -68,7 +68,7 @@ osbot_utils/helpers/Python_Audit.py,sha256=shpZlluJwqJBAlad6xN01FkgC1TsQ48RLvR5Z
68
68
  osbot_utils/helpers/Random_Guid.py,sha256=hBBcjetZMYgdagWbkS1j7AYAQ5k6JFbDpbPBi9gTj1A,373
69
69
  osbot_utils/helpers/Random_Guid_Short.py,sha256=YP_k5OLuYvXWGU2OEnQHk_OGViBQofTWKm3pUdQaJao,404
70
70
  osbot_utils/helpers/Random_Seed.py,sha256=14btja8LDN9cMGWaz4fCNcMRU_eyx49gas-_PQvHgy4,634
71
- osbot_utils/helpers/Safe_Id.py,sha256=k9GbZ_0ZNTJ5LIWGiEk9Rd-zjo2OPudDn6u9cezWNOk,225
71
+ osbot_utils/helpers/Safe_Id.py,sha256=JbpBWF57Inoq8MgSx1NUy_fjQdpXDjYEp00_MrS5yjs,364
72
72
  osbot_utils/helpers/Timestamp_Now.py,sha256=Vmdsm-pgvxkkQ_Qj_9Watr8rXXSvc-aBxWMPFGQx8Z0,371
73
73
  osbot_utils/helpers/Type_Registry.py,sha256=Ajk3SyMSKDi2g9SJYUtTgg7PZkAgydaHcpbGuEN3S94,311
74
74
  osbot_utils/helpers/Zip_Bytes.py,sha256=KB5zWfCf6ET4alNfqNrSp5DxZ3Jp9oDHpc6tK2iO_qg,4320
@@ -293,8 +293,8 @@ osbot_utils/utils/Int.py,sha256=PmlUdU4lSwf4gJdmTVdqclulkEp7KPCVUDO6AcISMF4,116
293
293
  osbot_utils/utils/Json.py,sha256=8fpYFXzNPSrwYfXMt3eGKpe-lhxh1kEaCRae1X1943A,6662
294
294
  osbot_utils/utils/Json_Cache.py,sha256=mLPkkDZN-3ZVJiDvV1KBJXILtKkTZ4OepzOsDoBPhWg,2006
295
295
  osbot_utils/utils/Lists.py,sha256=tPz5x5s3sRO97WZ_nsxREBPC5cwaHrhgaYBhsrffTT8,5599
296
- osbot_utils/utils/Misc.py,sha256=4MkG2BE1VzZfV4KPzYZ4jVAoUwoA3pTTVPi609ldLGA,16961
297
- osbot_utils/utils/Objects.py,sha256=6Gdph2A6cv1mVrADLjaCopDQIHxqZf8p1yfnXuDU6iQ,18798
296
+ osbot_utils/utils/Misc.py,sha256=A8AzI1M912NDxNpPRrW1lPrwIIjVOoGUQHzyyRCEMFU,17102
297
+ osbot_utils/utils/Objects.py,sha256=fqDy8AFimxkUxGAMQBkqYCvQnT_TDcR8EwHOMWPxorc,18992
298
298
  osbot_utils/utils/Png.py,sha256=V1juGp6wkpPigMJ8HcxrPDIP4bSwu51oNkLI8YqP76Y,1172
299
299
  osbot_utils/utils/Process.py,sha256=lr3CTiEkN3EiBx3ZmzYmTKlQoPdkgZBRjPulMxG-zdo,2357
300
300
  osbot_utils/utils/Python_Logger.py,sha256=tx8N6wRKL3RDHboDRKZn8SirSJdSAE9cACyJkxrThZ8,12792
@@ -306,8 +306,8 @@ osbot_utils/utils/Toml.py,sha256=-_Yv5T8ZhGGoDSSoNEdFhSsXiK_JPjGkPijm4JoeHSk,166
306
306
  osbot_utils/utils/Version.py,sha256=Ww6ChwTxqp1QAcxOnztkTicShlcx6fbNsWX5xausHrg,422
307
307
  osbot_utils/utils/Zip.py,sha256=pR6sKliUY0KZXmqNzKY2frfW-YVQEVbLKiyqQX_lc-8,14052
308
308
  osbot_utils/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
309
- osbot_utils/version,sha256=WI_wFg4NBrE5c9MJt5exrOXrSfHGB8Bq2u9jyP_mFJ0,8
310
- osbot_utils-1.70.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
311
- osbot_utils-1.70.0.dist-info/METADATA,sha256=1IuNEeFqJOaJkhPGjdqafVMeccaKvSLuY6ZIBEp1rRE,1317
312
- osbot_utils-1.70.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
313
- osbot_utils-1.70.0.dist-info/RECORD,,
309
+ osbot_utils/version,sha256=XQZP76Xm8wvpQXHErcX4x4a-cHx37c7KYvzRU9kBOOE,8
310
+ osbot_utils-1.73.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
311
+ osbot_utils-1.73.1.dist-info/METADATA,sha256=4LIQAlshrHhnOLEnRZS9h8V4T_V2GrX131jsOI0FISI,1317
312
+ osbot_utils-1.73.1.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
313
+ osbot_utils-1.73.1.dist-info/RECORD,,