osbot-utils 2.64.0__py3-none-any.whl → 2.66.0__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.
@@ -20,7 +20,7 @@ class Kwargs_To_Disk:
20
20
  else:
21
21
  self._local_cache.set(key, value)
22
22
 
23
- def _cache_create (self): return self._local_cache.create ()
23
+ def _cache_create (self): return self._local_cache.create()
24
24
  def _cache_delete (self): return self._local_cache.cache_delete ()
25
25
  def _cache_data (self): return self._local_cache.data ()
26
26
  def _cache_exists (self): return self._local_cache.cache_exists ()
@@ -15,7 +15,7 @@ class PubSub__Sqlite(Sqlite__Database):
15
15
  with self.table_clients() as _:
16
16
  _.row_schema = TABLE_SCHEMA__PUB_SUB__CLIENTS
17
17
  if _.exists() is False:
18
- _.create() # create if it doesn't exist
18
+ _.create() # create if it doesn't exist
19
19
  return True
20
20
  return False
21
21
 
@@ -1,6 +1,7 @@
1
1
  import re
2
+ from typing import Any
2
3
  from osbot_utils.helpers.safe_str.Safe_Str import Safe_Str
3
- from osbot_utils.utils.Misc import str_md5
4
+ from osbot_utils.utils.Misc import bytes_md5
4
5
 
5
6
  # Constants for hash validation
6
7
  SIZE__VALUE_HASH = 10
@@ -14,5 +15,11 @@ class Safe_Str__Hash(Safe_Str):
14
15
  strict_validation = True # Enable strict validation - new attribute
15
16
  exact_length = True # Require exact length match - new attribute
16
17
 
17
- def safe_str_hash(value : str):
18
- return str_md5(value)[0:SIZE__VALUE_HASH]
18
+ def safe_str_hash(value: Any) -> Safe_Str__Hash:
19
+ if isinstance(value, str):
20
+ value = value.encode()
21
+ elif not isinstance(value, bytes):
22
+ raise ValueError('In safe_str_hash, value must be a string or bytes')
23
+
24
+ hash_value = bytes_md5(value)[0:SIZE__VALUE_HASH]
25
+ return Safe_Str__Hash(hash_value)
@@ -26,7 +26,7 @@ class Sqlite__DB__Requests(Sqlite__DB__Local):
26
26
  with self.table_requests() as _:
27
27
  _.row_schema = self.table_schema # set the table_class
28
28
  if _.exists() is False:
29
- _.create() # create if it doesn't exist
29
+ _.create() # create if it doesn't exist
30
30
  _.index_create('request_hash') # add index to the request_hash field
31
31
  return True
32
32
  return False
@@ -10,12 +10,13 @@ class Type_Safe__Method:
10
10
  self.func = func # Store original function
11
11
  self.sig = inspect.signature(func) # Get function signature
12
12
  self.annotations = func.__annotations__ # Get function annotations
13
+ self.params = list(self.sig.parameters.keys())
13
14
 
14
15
  def check_for_any_use(self):
15
16
  for param_name, type_hint in self.annotations.items():
16
17
  if type_hint is any: # Detect incorrect usage of lowercase any
17
18
  raise ValueError(f"Parameter '{param_name}' uses lowercase 'any' instead of 'Any' from typing module. "
18
- f"Please use 'from typing import Any' and annotate as '{param_name}: Any'")
19
+ f"Please use 'from typing import Any' and annotate as '{param_name}: Any'")
19
20
 
20
21
  def handle_type_safety(self, args: tuple, kwargs: dict): # Main method to handle type safety
21
22
  self.check_for_any_use()
@@ -80,10 +81,6 @@ class Type_Safe__Method:
80
81
  self.validate_union_type(param_name, param_value, expected_type) # Validate union
81
82
  return # Exit early
82
83
 
83
- # if self.try_basic_type_conversion(param_value, expected_type, param_name, # Try basic type conversion
84
- # bound_args): # Pass bound args
85
- # return # Exit if conversion successful
86
-
87
84
  self.validate_direct_type(param_name, param_value, expected_type) # Direct type validation
88
85
 
89
86
  def is_optional_type(self, type_hint: Any) -> bool: # Check if type is Optional
@@ -108,9 +105,13 @@ class Type_Safe__Method:
108
105
  if not isinstance(param_value, list): # Check if value is a list
109
106
  raise ValueError(f"Parameter '{param_name}' expected a list but got {type(param_value)}") # Raise error if not list
110
107
 
111
- item_type = get_args(expected_type)[0] # Get list item type
112
- for i, item in enumerate(param_value): # Check each list item
113
- if not isinstance(item, item_type): # Validate item type
108
+ item_type = get_args(expected_type)[0] # Get list item type
109
+ if get_origin(item_type) is not None: # Handle the case when item_type is a subscripted type (which is not supported at the moment)
110
+ raise NotImplementedError(f"Validation for list items with subscripted type"
111
+ f" '{item_type}' is not yet supported "
112
+ f"in parameter '{param_name}'.") # todo: add support for checking for subscripted types
113
+ for i, item in enumerate(param_value): # Check each list item
114
+ if not isinstance(item, item_type): # Validate item type
114
115
  raise ValueError(f"List item at index {i} expected type {item_type}, but got {type(item)}") # Raise error for invalid item
115
116
 
116
117
  def validate_type_parameter(self, param_name: str, param_value: Any, expected_type: Any): # Validate a Type[T] parameter
@@ -163,6 +164,7 @@ class Type_Safe__Method:
163
164
  is_optional = self.is_optional_type(expected_type) # Check if type is optional
164
165
  has_default = self.has_default_value(param_name) # Check if has default value
165
166
  self.validate_none_value(param_name, is_optional, has_default) # Validate None value
167
+ return True
166
168
 
167
169
  origin = get_origin(expected_type)
168
170
 
@@ -174,11 +176,20 @@ class Type_Safe__Method:
174
176
  if not isinstance(param_value, dict):
175
177
  raise ValueError(f"Parameter '{param_name}' expected dict but got {type(param_value)}")
176
178
  key_type, value_type = get_args(expected_type)
179
+ if value_type is Any: # if value type is Any, we don't need to do any checks since they will all match
180
+ return True
177
181
  for k, v in param_value.items():
178
- if not isinstance(k, key_type):
179
- raise ValueError(f"Dict key '{k}' expected type {key_type}, but got {type(k)}")
180
- if not isinstance(v, value_type):
181
- raise ValueError(f"Dict value for key '{k}' expected type {value_type}, but got {type(v)}")
182
+ if get_origin(key_type) is None:
183
+ if not isinstance(k, key_type):
184
+ raise ValueError(f"Dict key '{k}' expected type {key_type}, but got {type(k)}")
185
+ else:
186
+ raise NotImplementedError(f"Validation for subscripted key type '{key_type}' not yet supported in parameter '{param_name}'")
187
+
188
+ if get_origin(value_type) is None:
189
+ if not isinstance(v, value_type):
190
+ raise ValueError(f"Dict value for key '{k}' expected type {value_type}, but got {type(v)}")
191
+ elif value_type is not Any:
192
+ raise NotImplementedError(f"Validation for subscripted value type '{value_type}' not yet supported in parameter '{param_name}'")
182
193
  return True
183
194
  base_type = origin
184
195
  else:
@@ -1,12 +1,22 @@
1
1
  import functools # For wrapping functions
2
2
  from osbot_utils.type_safe.Type_Safe__Method import Type_Safe__Method
3
3
 
4
- def type_safe(func): # Main decorator function
4
+ def type_safe(func): # Main decorator function
5
+ type_checker = Type_Safe__Method(func) # Create type checker instance
6
+
7
+ has_only_self = len(type_checker.params) == 1 and type_checker.params[0] == 'self' # Check if method has only 'self' parameter or no parameters
8
+ has_no_params = len(type_checker.params) == 0
9
+ direct_execution = has_no_params or has_only_self # these are major performance optimisation where this @type_safe had an overhead of 250x (even on methods with no params) to now having an over head of ~5x
10
+ if direct_execution: # todo: review if we really need to do this, since although it is an optimisation, the idea of the type_safe attribute is to check when there are params
11
+ return func
12
+
5
13
  @functools.wraps(func) # Preserve function metadata
6
14
  def wrapper(*args, **kwargs): # Wrapper function
7
- type_checker = Type_Safe__Method(func) # Create type checker instance
8
- bound_args = type_checker.handle_type_safety(args, kwargs) # Validate type safety
9
- return func(**bound_args.arguments) # Call original function
15
+ if direct_execution:
16
+ return func(*args, **kwargs)
17
+ else:
18
+ bound_args = type_checker.handle_type_safety(args, kwargs) # Validate type safety
19
+ return func(**bound_args.arguments) # Call original function
10
20
 
11
21
  return wrapper # Return wrapped function
12
22
 
osbot_utils/version CHANGED
@@ -1 +1 @@
1
- v2.64.0
1
+ v2.66.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: osbot_utils
3
- Version: 2.64.0
3
+ Version: 2.66.0
4
4
  Summary: OWASP Security Bot - Utils
5
5
  License: MIT
6
6
  Author: Dinis Cruz
@@ -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-v2.64.0-blue)
26
+ ![Current Release](https://img.shields.io/badge/release-v2.66.0-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
 
@@ -1,6 +1,6 @@
1
1
  osbot_utils/__init__.py,sha256=DdJDmQc9zbQUlPVyTJOww6Ixrn9n4bD3ami5ItQfzJI,16
2
2
  osbot_utils/base_classes/Cache_Pickle.py,sha256=kPCwrgUbf_dEdxUz7vW1GuvIPwlNXxuRhb-H3AbSpII,5884
3
- osbot_utils/base_classes/Kwargs_To_Disk.py,sha256=HHoy05NC_w35WcT-OnSKoSIV_cLqaU9rdjH0_KNTM0E,1096
3
+ osbot_utils/base_classes/Kwargs_To_Disk.py,sha256=jrm_L3xgh7bfKmDyxCcUJ9-DLzZ6n6YZlmCtHqmd0aY,1087
4
4
  osbot_utils/base_classes/Kwargs_To_Self.py,sha256=3LRFpxdg9RBuUlIacF1Bwq014NXtJmB4U2dy9a69uY8,138
5
5
  osbot_utils/base_classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  osbot_utils/context_managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -234,7 +234,7 @@ osbot_utils/helpers/pubsub/Event__Queue.py,sha256=bCtIdVlAuG-jvFEnz14oNhgRScEUrd
234
234
  osbot_utils/helpers/pubsub/PubSub__Client.py,sha256=6K3l4H-Tc0DhktrxpYzLVur1uZ532pQsHWprLNRXFJE,2316
235
235
  osbot_utils/helpers/pubsub/PubSub__Room.py,sha256=3drJIAVSAzXB_0Q9dXxwhYWxNaEUaMiWiXLY9Mh02DM,481
236
236
  osbot_utils/helpers/pubsub/PubSub__Server.py,sha256=DjQ6PsNGmULdFodspdNktADcoIN3FbdvAitE52m89-w,3548
237
- osbot_utils/helpers/pubsub/PubSub__Sqlite.py,sha256=3u1Gbpq22JDgDEexdyMzGvkQAHe97l8_Kuhr_SHFAR8,868
237
+ osbot_utils/helpers/pubsub/PubSub__Sqlite.py,sha256=BXDZEz0r7NO1PLt8Y7Wa6Yok0iKNp5bnegCMxm_2xMg,848
238
238
  osbot_utils/helpers/pubsub/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
239
239
  osbot_utils/helpers/pubsub/schemas/Schema__Event.py,sha256=si12mqRRROI3HYGvjQvzPZ_NGw3TpmVZxGhzuWq5cus,402
240
240
  osbot_utils/helpers/pubsub/schemas/Schema__Event__Connect.py,sha256=fgq0G3_zx3UFk5knsotmEXvP1YvZwOLBtT9gow1U-qM,269
@@ -262,7 +262,7 @@ osbot_utils/helpers/safe_int/__init__.py,sha256=kMU2WMsdQmayBEZugxnJV_wRW3O90bc1
262
262
  osbot_utils/helpers/safe_str/Safe_Str.py,sha256=qR2RDh5cehP_wDDeV5TQahNBwmfcizPFyStALBKD5dw,3509
263
263
  osbot_utils/helpers/safe_str/Safe_Str__File__Name.py,sha256=ncjkQ2hAhw0a3UulrCuQsA9ytrFwg5CT1XRJIGChMpY,289
264
264
  osbot_utils/helpers/safe_str/Safe_Str__File__Path.py,sha256=K0yBcvH_Ncqiw7tMqjGqaNyWQh1Zs9qxZ-TR8nEIAow,550
265
- osbot_utils/helpers/safe_str/Safe_Str__Hash.py,sha256=Tb2QeVpVDNWpCJGHNFjZPCQ_ZTaI7Z5BDzi19LiO_cI,952
265
+ osbot_utils/helpers/safe_str/Safe_Str__Hash.py,sha256=IpYdYwXey5WZWa6QfysmsiDP-4L-wP-_EKbkeXhFRH4,1252
266
266
  osbot_utils/helpers/safe_str/Safe_Str__Text.py,sha256=QxuWqF8hNYdOPDn3Yac86h_1ZaX-THbTBDakberiJcs,313
267
267
  osbot_utils/helpers/safe_str/Safe_Str__Text__Dangerous.py,sha256=6-fkXBuWgjz70eQicD07f38eEuKqNzJzaFFY6hozhNQ,388
268
268
  osbot_utils/helpers/safe_str/Safe_Str__Url.py,sha256=4l46AAe5Dy_P_W6d-_3pwtXuehG_Wczq1dC5sOOzg_g,549
@@ -288,7 +288,7 @@ osbot_utils/helpers/sqlite/cache/Sqlite__Cache__Requests.py,sha256=SC-NBsj-wsAcv
288
288
  osbot_utils/helpers/sqlite/cache/Sqlite__Cache__Requests__Patch.py,sha256=HB-LbZQ0VHi9cJm0647WJKUZIjesMppKQ3ZbTOsMgCI,2474
289
289
  osbot_utils/helpers/sqlite/cache/Sqlite__Cache__Requests__Sqlite.py,sha256=vaijPsoQU2_2uQEBa_ukeA6o-EhJkn2KmhKJ3_hse3o,779
290
290
  osbot_utils/helpers/sqlite/cache/Sqlite__Cache__Requests__Table.py,sha256=77uO-8WLmzBh5A4Y2VVclKlp2kn1aZ6iJVCtOr4zYFo,2830
291
- osbot_utils/helpers/sqlite/cache/Sqlite__DB__Requests.py,sha256=CWB-hTcgly2T_7HOZM5gUgfdsvgMus5nX2M_wpjVLZs,1643
291
+ osbot_utils/helpers/sqlite/cache/Sqlite__DB__Requests.py,sha256=VWprEbbSWTy5VPBe0XVHdZ3yD9-Zlb-344-QfzDD_wA,1603
292
292
  osbot_utils/helpers/sqlite/cache/TestCase__Sqlite__Cache__Requests.py,sha256=TLUdQC6vsf5BcDP15CCeoYkipVG30bzqFcqEJpH4dWg,1645
293
293
  osbot_utils/helpers/sqlite/cache/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
294
294
  osbot_utils/helpers/sqlite/domains/Sqlite__DB.py,sha256=xyXnt4-GLYqMEPBZrNPI0dZnkl61KwLEIuYjebO20Jc,1210
@@ -374,13 +374,13 @@ osbot_utils/type_safe/Type_Safe.py,sha256=LOWRGOGpnRU2iTRLP47vUoyalK0vjFrWlnaghB
374
374
  osbot_utils/type_safe/Type_Safe__Base.py,sha256=UTMipTL6mXoetAEUCI5hs8RqXp4NDYOvoAiYoFOt5jg,8807
375
375
  osbot_utils/type_safe/Type_Safe__Dict.py,sha256=QB200L5eNWT3FnUv8sm5kncj1wXJsJ9uRycNFl9xb6Y,3077
376
376
  osbot_utils/type_safe/Type_Safe__List.py,sha256=y_lp7Ai0HfQCqC8Bxn0g6_M9MP5lPOXy5Dhkuj2fJvQ,1891
377
- osbot_utils/type_safe/Type_Safe__Method.py,sha256=lHBCpW5nf2ikybm9oucvq6L67VXNO4qEvzGskJ1hGHs,15697
377
+ osbot_utils/type_safe/Type_Safe__Method.py,sha256=cvFYoR42SPU4qQPG45CCHQw7i-sq7R6gHECcsncGGL4,16653
378
378
  osbot_utils/type_safe/Type_Safe__Primitive.py,sha256=CJ4LP2W5i9utSSzuiiJrwqvwdMv1DeQ6dIZICtYfLTY,3635
379
379
  osbot_utils/type_safe/Type_Safe__Set.py,sha256=j12fc8cbd9-s_a13ysaz723rNEW4Dt6hObCd0S-AjIg,1432
380
380
  osbot_utils/type_safe/Type_Safe__Tuple.py,sha256=Kx7C4YfHybRbMmVMcmV6yFLi4T48pb592vEZfjjyLxo,1710
381
381
  osbot_utils/type_safe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
382
382
  osbot_utils/type_safe/decorators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
383
- osbot_utils/type_safe/decorators/type_safe.py,sha256=ERFfJuAIo5qLp03YEDu2zu5wxu65OhR7hOybwuTfLlc,1006
383
+ osbot_utils/type_safe/decorators/type_safe.py,sha256=3jVwrO46s6xpS1Uc4gTrbWc2TnrHCfWJUZ8FIS8mwEo,1772
384
384
  osbot_utils/type_safe/methods/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
385
385
  osbot_utils/type_safe/methods/type_safe_property.py,sha256=DcJkOIs6swJtkglsZVKLyFSczCGSJISOVwAmvjCOQvo,1425
386
386
  osbot_utils/type_safe/shared/Type_Safe__Annotations.py,sha256=nmVqCbhk4kUYrw_mdYqugxQlv4gM3NUUH89FYTHUg-c,1133
@@ -432,8 +432,8 @@ osbot_utils/utils/Toml.py,sha256=Rxl8gx7mni5CvBAK-Ai02EKw-GwtJdd3yeHT2kMloik,166
432
432
  osbot_utils/utils/Version.py,sha256=Ww6ChwTxqp1QAcxOnztkTicShlcx6fbNsWX5xausHrg,422
433
433
  osbot_utils/utils/Zip.py,sha256=pR6sKliUY0KZXmqNzKY2frfW-YVQEVbLKiyqQX_lc-8,14052
434
434
  osbot_utils/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
435
- osbot_utils/version,sha256=Ik_Z1_68qStKaUrjNMdT-_2K34-svwqhzWn_iKWEiAM,8
436
- osbot_utils-2.64.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
437
- osbot_utils-2.64.0.dist-info/METADATA,sha256=NVqO8V4OXl0l6YXdNQCbsspZ4wle5_jgH97qimTST9M,1329
438
- osbot_utils-2.64.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
439
- osbot_utils-2.64.0.dist-info/RECORD,,
435
+ osbot_utils/version,sha256=I-tXq-4G9hvb1JqQfc9x8xB8ZmzgFoAtCtq_ER_YmZE,8
436
+ osbot_utils-2.66.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
437
+ osbot_utils-2.66.0.dist-info/METADATA,sha256=00ICakDJcjSd_dw6IXnHIY4Uvc3o_kVtbfV0Z25XN54,1329
438
+ osbot_utils-2.66.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
439
+ osbot_utils-2.66.0.dist-info/RECORD,,