osbot-utils 2.64.0__py3-none-any.whl → 2.65.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.
@@ -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,20 @@
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
+
5
11
  @functools.wraps(func) # Preserve function metadata
6
12
  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
13
+ if direct_execution:
14
+ return func(*args, **kwargs)
15
+ else:
16
+ bound_args = type_checker.handle_type_safety(args, kwargs) # Validate type safety
17
+ return func(**bound_args.arguments) # Call original function
10
18
 
11
19
  return wrapper # Return wrapped function
12
20
 
osbot_utils/version CHANGED
@@ -1 +1 @@
1
- v2.64.0
1
+ v2.65.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: osbot_utils
3
- Version: 2.64.0
3
+ Version: 2.65.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.65.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
 
@@ -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=pghmcxZp-L3E3yQMSPOyC-inVO1KU1aql_naEqWLt-8,1507
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=oCkmaExem5YihngZUO4qUVW6DPLlhdxUDeJF0raydEg,8
436
+ osbot_utils-2.65.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
437
+ osbot_utils-2.65.0.dist-info/METADATA,sha256=kWWFHflY8D1c-M9vqnraZaziAIrgTpG9r8teABngWrY,1329
438
+ osbot_utils-2.65.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
439
+ osbot_utils-2.65.0.dist-info/RECORD,,