osbot-utils 1.94.0__py3-none-any.whl → 1.95.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.
@@ -3,7 +3,8 @@
3
3
 
4
4
  import sys
5
5
  import types
6
- from osbot_utils.utils.Objects import default_value # todo: remove test mocking requirement for this to be here (instead of on the respective method)
6
+ from osbot_utils.utils.Objects import default_value # todo: remove test mocking requirement for this to be here (instead of on the respective method)
7
+ from osbot_utils.utils.Objects import all_annotations
7
8
 
8
9
  # Backport implementations of get_origin and get_args for Python 3.7
9
10
  if sys.version_info < (3, 8): # pragma: no cover
@@ -89,7 +90,8 @@ class Type_Safe:
89
90
  from osbot_utils.utils.Objects import value_type_matches_obj_annotation_for_union_and_annotated
90
91
  from osbot_utils.helpers.type_safe.Type_Safe__Validator import Type_Safe__Validator
91
92
 
92
- if not hasattr(self, '__annotations__'): # can't do type safety checks if the class does not have annotations
93
+ annotations = all_annotations(self)
94
+ if not annotations: # can't do type safety checks if the class does not have annotations
93
95
  return super().__setattr__(name, value)
94
96
 
95
97
  if value is not None:
@@ -101,20 +103,20 @@ class Type_Safe:
101
103
  origin = get_origin(value)
102
104
  if origin is not None:
103
105
  value = origin
104
- check_1 = value_type_matches_obj_annotation_for_attr (self, name, value)
106
+ check_1 = value_type_matches_obj_annotation_for_attr (self, name, value)
105
107
  check_2 = value_type_matches_obj_annotation_for_union_and_annotated(self, name, value)
106
108
  if (check_1 is False and check_2 is None or
107
109
  check_1 is None and check_2 is False or
108
110
  check_1 is False and check_2 is False ): # fix for type safety assigment on Union vars
109
- raise ValueError(f"Invalid type for attribute '{name}'. Expected '{self.__annotations__.get(name)}' but got '{type(value)}'")
111
+ raise ValueError(f"Invalid type for attribute '{name}'. Expected '{annotations.get(name)}' but got '{type(value)}'")
110
112
  else:
111
- if hasattr(self, name) and self.__annotations__.get(name) : # don't allow previously set variables to be set to None
113
+ if hasattr(self, name) and annotations.get(name) : # don't allow previously set variables to be set to None
112
114
  if getattr(self, name) is not None: # unless it is already set to None
113
115
  raise ValueError(f"Can't set None, to a variable that is already set. Invalid type for attribute '{name}'. Expected '{self.__annotations__.get(name)}' but got '{type(value)}'")
114
116
 
115
117
  # todo: refactor this to separate method
116
- if hasattr(self.__annotations__, 'get'):
117
- annotation = self.__annotations__.get(name)
118
+ if hasattr(annotations, 'get'):
119
+ annotation = annotations.get(name)
118
120
  if annotation and get_origin(annotation) is Annotated:
119
121
  annotation_args = get_args(annotation)
120
122
  target_type = annotation_args[0]
@@ -19,4 +19,4 @@ class Type_Safe__Dict(Type_Safe__Base, dict):
19
19
  def __repr__(self):
20
20
  key_type_name = type_str(self.expected_key_type)
21
21
  value_type_name = type_str(self.expected_value_type)
22
- return f"dict[{key_type_name}, {value_type_name}] with {len(self)} entries"
22
+ return f"dict[{key_type_name}, {value_type_name}] with {len(self)} entries"
@@ -11,7 +11,7 @@ class Guid(str):
11
11
  if is_guid(value):
12
12
  guid = value
13
13
  else:
14
- guid = uuid.uuid5(GUID__NAMESPACE, value) # Generate a UUID5 using the namespace and value
14
+ guid = uuid.uuid5(GUID__NAMESPACE, value) # Generate a UUID5 using the namespace and value
15
15
  return super().__new__(cls, str(guid)) # Return a new instance of Guid initialized with the string version of the UUID
16
16
 
17
17
  def __str__(self):
@@ -12,6 +12,7 @@ GLOBAL_FUNCTIONS_TO_IGNORE = ['value_type_matches_obj_annotation_for_attr'
12
12
  'value_type_matches_obj_annotation_for_union_and_annotated' , # todo: map out and document why exactly these methods are ignore (and what is the side effect)
13
13
  'are_types_compatible_for_assigment' ,
14
14
  'obj_attribute_annotation' ,
15
+ 'all_annotations' ,
15
16
  'get_origin' ,
16
17
  'getmro' ,
17
18
  'default_value' ,
@@ -1,6 +1,8 @@
1
1
  # todo add tests
2
2
  import sys
3
- from types import SimpleNamespace
3
+ from types import SimpleNamespace
4
+ from osbot_utils.helpers.python_compatibility.python_3_8 import Annotated
5
+
4
6
 
5
7
  class __(SimpleNamespace):
6
8
  pass
@@ -439,29 +441,38 @@ def pickle_load_from_bytes(pickled_data: bytes):
439
441
  except Exception:
440
442
  return {}
441
443
 
444
+ def all_annotations(target):
445
+ annotations = {}
446
+ if hasattr(target.__class__, '__mro__'):
447
+ for base in reversed(target.__class__.__mro__):
448
+ if hasattr(base, '__annotations__'):
449
+ annotations.update(base.__annotations__)
450
+ return annotations
451
+
442
452
  def value_type_matches_obj_annotation_for_attr(target, attr_name, value):
443
453
  import typing
444
-
445
- if hasattr(target, '__annotations__'):
446
- obj_annotations = target.__annotations__
447
- if hasattr(obj_annotations,'get'):
448
- attr_type = obj_annotations.get(attr_name)
449
- if attr_type:
450
- origin_attr_type = get_origin(attr_type) # to handle when type definion contains an generic
451
- if origin_attr_type is typing.Union:
452
- args = get_args(attr_type)
453
- if len(args)==2 and args[1] is type(None): # todo: find a better way to do this, since this is handling an edge case when origin_attr_type is Optional (which is an shorthand for Union[X, None] )
454
- attr_type = args[0]
455
- origin_attr_type = get_origin(attr_type)
456
-
457
- if origin_attr_type:
458
- attr_type = origin_attr_type
459
- value_type = type(value)
460
- if are_types_compatible_for_assigment(source_type=value_type, target_type=attr_type):
461
- return True
462
- if are_types_magic_mock(source_type=value_type, target_type=attr_type):
463
- return True
464
- return value_type is attr_type
454
+ annotations = all_annotations(target)
455
+ attr_type = annotations.get(attr_name)
456
+ if attr_type:
457
+ origin_attr_type = get_origin(attr_type) # to handle when type definition contains a generic
458
+ if origin_attr_type is Annotated: # if the type is Annotated
459
+ args = get_args(attr_type)
460
+ origin_attr_type = args[0]
461
+
462
+ elif origin_attr_type is typing.Union:
463
+ args = get_args(attr_type)
464
+ if len(args)==2 and args[1] is type(None): # todo: find a better way to do this, since this is handling an edge case when origin_attr_type is Optional (which is an shorthand for Union[X, None] )
465
+ attr_type = args[0]
466
+ origin_attr_type = get_origin(attr_type)
467
+
468
+ if origin_attr_type:
469
+ attr_type = origin_attr_type
470
+ value_type = type(value)
471
+ if are_types_compatible_for_assigment(source_type=value_type, target_type=attr_type):
472
+ return True
473
+ if are_types_magic_mock(source_type=value_type, target_type=attr_type):
474
+ return True
475
+ return value_type is attr_type
465
476
  return None
466
477
 
467
478
 
osbot_utils/version CHANGED
@@ -1 +1 @@
1
- v1.94.0
1
+ v1.95.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: osbot_utils
3
- Version: 1.94.0
3
+ Version: 1.95.0
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.94.0-blue)
26
+ ![Current Release](https://img.shields.io/badge/release-v1.95.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
 
@@ -2,9 +2,9 @@ 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=XzJd1tOEFFT67ycg5QaiXv5pFeWD8Fq4YDVQGGVYAjc,28990
5
+ osbot_utils/base_classes/Type_Safe.py,sha256=cfpLk3x0TQNeRMSRda91_DAO_m14_QtYcRrGMWZ8dmU,29076
6
6
  osbot_utils/base_classes/Type_Safe__Base.py,sha256=CFPYe8_i5vvTLyc7s8CXbY4n_dY6sqVfBY8w9Vo77ZA,5468
7
- osbot_utils/base_classes/Type_Safe__Dict.py,sha256=sfZcukhXUd9TS0PQpAk-gGLfZUJSC6BtMh6jF4Fn8Jw,1107
7
+ osbot_utils/base_classes/Type_Safe__Dict.py,sha256=yB9dSNPh_PARqXhNLg1HBFXgMsB-o-PC7h-BUE8njg0,1106
8
8
  osbot_utils/base_classes/Type_Safe__List.py,sha256=pXDzJJttpEQQ9oTdsw7BykMB4VIX2rZzi1ZrnCzMZ8M,650
9
9
  osbot_utils/base_classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  osbot_utils/context_managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -41,7 +41,7 @@ osbot_utils/helpers/CFormat.py,sha256=1_XvqGwgU6qC97MbzcKF0o7s9mCXpU5Kq9Yf-1ixUw
41
41
  osbot_utils/helpers/CPrint.py,sha256=ztKPNmT8BGxeyPXSQKRs63PqqbgxKDz_BiZmzFMup9g,1413
42
42
  osbot_utils/helpers/Dependency_Manager.py,sha256=79YRYnVfchewq8iSMJ5dzwW2D5u8chWcIqYE-G9YrSo,1337
43
43
  osbot_utils/helpers/Dict_To_Attr.py,sha256=NdhXl5mJH7-NaBk213amzc5Nfy3tJgW-N_uYIRE4hoc,208
44
- osbot_utils/helpers/Guid.py,sha256=22oNPpugnzOkc7swHzw6_duc3PyzXQg5f5mnBXLC-Jw,832
44
+ osbot_utils/helpers/Guid.py,sha256=fqiCYHrYff3yZ_Df-WJdXHl1RQtJHb4oCmDkJpcGN_k,828
45
45
  osbot_utils/helpers/Hashicorp_Secrets.py,sha256=zjXa_dQvfR9L1uoulWJ8nYYaDvznV6o_QPPS4zmb6mo,4235
46
46
  osbot_utils/helpers/Local_Cache.py,sha256=0JZZX3fFImcwtbBvxAQl-EbBegSNJRhRMYF6ovTH6zY,3141
47
47
  osbot_utils/helpers/Local_Caches.py,sha256=aQmi1HSM0TH6WQPedG2fbz4KCCJ3DQTU9d18rB1jR0M,1885
@@ -239,7 +239,7 @@ osbot_utils/helpers/ssh/TestCase__SSH.py,sha256=MD8sq0_kI4f6pEmEO0cLq2mQOhIqbP45
239
239
  osbot_utils/helpers/ssh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
240
240
  osbot_utils/helpers/trace/Trace_Call.py,sha256=O_y6cncgneYrj3ARDMz-o9Yi1LjsESibUqkGFAg0Jk0,8886
241
241
  osbot_utils/helpers/trace/Trace_Call__Config.py,sha256=UAjdsDEqsPBBsu-h4_QKYL4UMukJmQYBBWGYTmSKS40,3361
242
- osbot_utils/helpers/trace/Trace_Call__Handler.py,sha256=9EQyIiGB6r3UURyNgEXHPOCmZNOejM0UJNW9c_MjpNU,12650
242
+ osbot_utils/helpers/trace/Trace_Call__Handler.py,sha256=lXMk_7M9SK7s13qNpLuk5qx9CJJ3lzMJGdI8tB-nO-c,12744
243
243
  osbot_utils/helpers/trace/Trace_Call__Print_Lines.py,sha256=cy7zLv0_JNxdOIQPfZk6J9bv6AkIW6O643w0ykClXbw,4820
244
244
  osbot_utils/helpers/trace/Trace_Call__Print_Traces.py,sha256=2LGeWMGP1uhSojGMmJmL3bH2B5LFIlfYEqEPNqoyKJw,8628
245
245
  osbot_utils/helpers/trace/Trace_Call__Stack.py,sha256=pIvZ2yP4tymOQraUR2N5R-qlmg5QijyLxt85zmMajUs,7462
@@ -304,7 +304,7 @@ osbot_utils/utils/Json.py,sha256=0t7Hwefx8bg4JiZVr-xIbWP3BAk6_ZsnY7iV5pnRLDQ,713
304
304
  osbot_utils/utils/Json_Cache.py,sha256=mLPkkDZN-3ZVJiDvV1KBJXILtKkTZ4OepzOsDoBPhWg,2006
305
305
  osbot_utils/utils/Lists.py,sha256=tPz5x5s3sRO97WZ_nsxREBPC5cwaHrhgaYBhsrffTT8,5599
306
306
  osbot_utils/utils/Misc.py,sha256=H_xexJgiTxB3jDeDiW8efGQbO0Zuy8MM0iQ7qXC92JI,17363
307
- osbot_utils/utils/Objects.py,sha256=nsheXk2t4sRQVJStsKYDgCj8wF3knQ8X1AtLO1M4SlM,21614
307
+ osbot_utils/utils/Objects.py,sha256=7QS_rBiLMLiD28be_br-7NrLfR7LtxFImjUGko8MqXM,21933
308
308
  osbot_utils/utils/Png.py,sha256=V1juGp6wkpPigMJ8HcxrPDIP4bSwu51oNkLI8YqP76Y,1172
309
309
  osbot_utils/utils/Process.py,sha256=lr3CTiEkN3EiBx3ZmzYmTKlQoPdkgZBRjPulMxG-zdo,2357
310
310
  osbot_utils/utils/Python_Logger.py,sha256=tx8N6wRKL3RDHboDRKZn8SirSJdSAE9cACyJkxrThZ8,12792
@@ -316,8 +316,8 @@ osbot_utils/utils/Toml.py,sha256=Rxl8gx7mni5CvBAK-Ai02EKw-GwtJdd3yeHT2kMloik,166
316
316
  osbot_utils/utils/Version.py,sha256=Ww6ChwTxqp1QAcxOnztkTicShlcx6fbNsWX5xausHrg,422
317
317
  osbot_utils/utils/Zip.py,sha256=pR6sKliUY0KZXmqNzKY2frfW-YVQEVbLKiyqQX_lc-8,14052
318
318
  osbot_utils/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
319
- osbot_utils/version,sha256=_0FgKn2Budr8baj8RE7pf68-C8Yvew0utOg1014PVtc,8
320
- osbot_utils-1.94.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
321
- osbot_utils-1.94.0.dist-info/METADATA,sha256=v3Ivesk54q4PsxGFrjpS-7clJ6b6tkX_-vhJkZ-ZZp4,1317
322
- osbot_utils-1.94.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
323
- osbot_utils-1.94.0.dist-info/RECORD,,
319
+ osbot_utils/version,sha256=hj792tBZ6NCLSnkj5lttcLXORlnd4_1CyyedSRJmqaU,8
320
+ osbot_utils-1.95.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
321
+ osbot_utils-1.95.0.dist-info/METADATA,sha256=erJLyJM0vNgo9YzaCaN6X99UyNcYPlgv1mh9enE0HyE,1317
322
+ osbot_utils-1.95.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
323
+ osbot_utils-1.95.0.dist-info/RECORD,,