osbot-utils 2.59.0__py3-none-any.whl → 2.60.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.
- osbot_utils/helpers/html/Html__To__Html_Document.py +1 -2
- osbot_utils/helpers/html/schemas/Schema__Html_Node.py +2 -2
- osbot_utils/helpers/safe_float/Safe_Float.py +155 -0
- osbot_utils/helpers/safe_float/Safe_Float__Engineering.py +7 -0
- osbot_utils/helpers/safe_float/Safe_Float__Money.py +11 -0
- osbot_utils/helpers/safe_float/Safe_Float__Percentage_Exact.py +9 -0
- osbot_utils/helpers/safe_float/__init__.py +0 -0
- osbot_utils/helpers/safe_int/Safe_Int.py +77 -0
- osbot_utils/helpers/safe_int/Safe_Int__Byte.py +11 -0
- osbot_utils/helpers/safe_int/Safe_Int__FileSize.py +19 -0
- osbot_utils/helpers/safe_int/Safe_Int__Percentage.py +10 -0
- osbot_utils/helpers/safe_int/Safe_Int__Port.py +11 -0
- osbot_utils/helpers/safe_int/Safe_Int__UInt.py +7 -0
- osbot_utils/helpers/safe_int/__init__.py +10 -0
- osbot_utils/helpers/safe_str/Safe_Str.py +1 -1
- osbot_utils/helpers/safe_str/http/__init__.py +0 -0
- osbot_utils/type_safe/shared/Type_Safe__Validation.py +1 -1
- osbot_utils/version +1 -1
- {osbot_utils-2.59.0.dist-info → osbot_utils-2.60.0.dist-info}/METADATA +2 -2
- {osbot_utils-2.59.0.dist-info → osbot_utils-2.60.0.dist-info}/RECORD +22 -9
- {osbot_utils-2.59.0.dist-info → osbot_utils-2.60.0.dist-info}/LICENSE +0 -0
- {osbot_utils-2.59.0.dist-info → osbot_utils-2.60.0.dist-info}/WHEEL +0 -0
@@ -3,13 +3,12 @@ from osbot_utils.helpers.html.Html__To__Html_Dict import Html__To__Htm
|
|
3
3
|
from osbot_utils.helpers.html.schemas.Schema__Html_Document import Schema__Html_Document
|
4
4
|
from osbot_utils.type_safe.Type_Safe import Type_Safe
|
5
5
|
|
6
|
-
|
7
6
|
class Html__To__Html_Document(Type_Safe):
|
8
7
|
html: str
|
9
8
|
html__dict : dict
|
10
9
|
html__document: Schema__Html_Document
|
11
10
|
|
12
|
-
def convert(self):
|
11
|
+
def convert(self) -> Schema__Html_Document:
|
13
12
|
if self.html:
|
14
13
|
html__dict = Html__To__Html_Dict(self.html).convert()
|
15
14
|
if html__dict:
|
@@ -4,7 +4,7 @@ from osbot_utils.type_safe.Type_Safe import Type_Safe
|
|
4
4
|
|
5
5
|
|
6
6
|
class Schema__Html_Node(Type_Safe):
|
7
|
-
attrs : Dict[str, Optional[str]]
|
7
|
+
attrs : Dict[str, Optional[str]] # HTML attributes (e.g., {'class': 'container'}) # todo: see what Safe_Ster we can use for these name attrs
|
8
8
|
nodes : List[Union['Schema__Html_Node', Schema__Html_Node__Data]] # Child nodes (recursive structure)
|
9
|
-
tag : str # HTML tag name (e.g., 'div', 'meta', 'title')
|
9
|
+
tag : str # HTML tag name (e.g., 'div', 'meta', 'title') # todo: see what Safe_Ster we can use for the tag
|
10
10
|
|
@@ -0,0 +1,155 @@
|
|
1
|
+
import math
|
2
|
+
from decimal import Decimal, ROUND_HALF_UP, InvalidOperation
|
3
|
+
from typing import Optional, Union
|
4
|
+
|
5
|
+
class Safe_Float(float): # Base class for type-safe floats with validation rules
|
6
|
+
|
7
|
+
min_value : Optional[float] = None
|
8
|
+
max_value : Optional[float] = None
|
9
|
+
allow_none : bool = True
|
10
|
+
allow_bool : bool = False
|
11
|
+
allow_str : bool = True
|
12
|
+
allow_int : bool = True
|
13
|
+
strict_type : bool = False
|
14
|
+
decimal_places : Optional[int] = None
|
15
|
+
|
16
|
+
# Precision handling options
|
17
|
+
use_decimal : bool = False
|
18
|
+
epsilon : float = 1e-9
|
19
|
+
round_output : bool = True
|
20
|
+
clamp_to_range : bool = False
|
21
|
+
|
22
|
+
def __new__(cls, value: Optional[Union[float, int, str]] = None) -> 'Safe_Float':
|
23
|
+
if value is None:
|
24
|
+
if cls.allow_none:
|
25
|
+
return super().__new__(cls, 0.0)
|
26
|
+
else:
|
27
|
+
raise ValueError(f"{cls.__name__} does not allow None values")
|
28
|
+
|
29
|
+
# Store original value for range checking
|
30
|
+
original_value = value
|
31
|
+
|
32
|
+
# Convert to float
|
33
|
+
if isinstance(value, str):
|
34
|
+
if not cls.allow_str:
|
35
|
+
raise TypeError(f"{cls.__name__} does not allow string conversion")
|
36
|
+
try:
|
37
|
+
if cls.use_decimal:
|
38
|
+
value = Decimal(value)
|
39
|
+
else:
|
40
|
+
value = float(value)
|
41
|
+
except (ValueError, InvalidOperation):
|
42
|
+
raise ValueError(f"Cannot convert '{value}' to float")
|
43
|
+
elif isinstance(value, bool):
|
44
|
+
if not cls.allow_bool:
|
45
|
+
raise TypeError(f"{cls.__name__} does not allow boolean values")
|
46
|
+
value = float(value)
|
47
|
+
elif isinstance(value, int):
|
48
|
+
if not cls.allow_int:
|
49
|
+
raise TypeError(f"{cls.__name__} does not allow integer conversion")
|
50
|
+
if cls.use_decimal:
|
51
|
+
value = Decimal(value)
|
52
|
+
else:
|
53
|
+
value = float(value)
|
54
|
+
elif isinstance(value, float):
|
55
|
+
if math.isinf(value):
|
56
|
+
raise ValueError(f"{cls.__name__} does not allow infinite values")
|
57
|
+
if math.isnan(value):
|
58
|
+
raise ValueError(f"{cls.__name__} does not allow NaN values")
|
59
|
+
|
60
|
+
if cls.use_decimal:
|
61
|
+
value = Decimal(str(value))
|
62
|
+
elif not isinstance(value, (float, Decimal)):
|
63
|
+
raise TypeError(f"{cls.__name__} requires a float value, got {type(value).__name__}")
|
64
|
+
|
65
|
+
# Get numeric value for range checking (before rounding)
|
66
|
+
check_value = float(value) if isinstance(value, Decimal) else value
|
67
|
+
|
68
|
+
# Range validation BEFORE rounding (unless clamping)
|
69
|
+
if not cls.clamp_to_range:
|
70
|
+
if cls.min_value is not None and check_value < cls.min_value:
|
71
|
+
raise ValueError(f"{cls.__name__} must be >= {cls.min_value}, got {check_value}")
|
72
|
+
if cls.max_value is not None and check_value > cls.max_value:
|
73
|
+
raise ValueError(f"{cls.__name__} must be <= {cls.max_value}, got {check_value}")
|
74
|
+
|
75
|
+
# NOW do rounding
|
76
|
+
if isinstance(value, Decimal) and cls.decimal_places is not None:
|
77
|
+
value = value.quantize(Decimal(f'0.{"0" * cls.decimal_places}'), rounding=ROUND_HALF_UP)
|
78
|
+
|
79
|
+
if isinstance(value, Decimal):
|
80
|
+
value = float(value)
|
81
|
+
|
82
|
+
# Check again for special values
|
83
|
+
if math.isinf(value):
|
84
|
+
raise ValueError(f"{cls.__name__} does not allow infinite values")
|
85
|
+
if math.isnan(value):
|
86
|
+
raise ValueError(f"{cls.__name__} does not allow NaN values")
|
87
|
+
|
88
|
+
# Clean up floating point errors (only if not already handled by Decimal)
|
89
|
+
if cls.round_output and cls.decimal_places is not None and not cls.use_decimal:
|
90
|
+
value = cls.__clean_float(value, cls.decimal_places)
|
91
|
+
|
92
|
+
# Handle clamping AFTER rounding
|
93
|
+
if cls.clamp_to_range:
|
94
|
+
if cls.min_value is not None and value < cls.min_value:
|
95
|
+
value = cls.min_value
|
96
|
+
if cls.max_value is not None and value > cls.max_value:
|
97
|
+
value = cls.max_value
|
98
|
+
|
99
|
+
return super().__new__(cls, value)
|
100
|
+
|
101
|
+
def __truediv__(self, other):
|
102
|
+
# Simple and safe - no special handling for infinity
|
103
|
+
if float(other) == 0:
|
104
|
+
raise ZeroDivisionError(f"{self.__class__.__name__} division by zero")
|
105
|
+
|
106
|
+
if self.use_decimal:
|
107
|
+
result = float(Decimal(str(float(self))) / Decimal(str(float(other))))
|
108
|
+
else:
|
109
|
+
result = float(self) / float(other)
|
110
|
+
|
111
|
+
# Check for overflow/underflow
|
112
|
+
if math.isinf(result) or math.isnan(result):
|
113
|
+
raise OverflowError(f"Division resulted in {result}")
|
114
|
+
|
115
|
+
if self.round_output and self.decimal_places is not None:
|
116
|
+
result = self.__clean_float(result, self.decimal_places)
|
117
|
+
|
118
|
+
try:
|
119
|
+
return self.__class__(result)
|
120
|
+
except (ValueError, TypeError):
|
121
|
+
return result
|
122
|
+
|
123
|
+
@classmethod
|
124
|
+
def __clean_float(cls, value: float, decimal_places: int) -> float: # Clean up floating point representation errors
|
125
|
+
rounded = round(value, decimal_places + 2) # First, round to eliminate tiny errors
|
126
|
+
|
127
|
+
# Check if very close to a clean decimal
|
128
|
+
str_val = f"{rounded:.{decimal_places + 2}f}"
|
129
|
+
if str_val.endswith('999999') or str_val.endswith('000001'):
|
130
|
+
# Use Decimal for exact rounding
|
131
|
+
d = Decimal(str(value))
|
132
|
+
return float(d.quantize(Decimal(f'0.{"0" * decimal_places}'), rounding=ROUND_HALF_UP))
|
133
|
+
|
134
|
+
return round(value, decimal_places) if decimal_places else value
|
135
|
+
|
136
|
+
def __mul__(self, other):
|
137
|
+
if self.use_decimal:
|
138
|
+
result = float(Decimal(str(float(self))) * Decimal(str(float(other))))
|
139
|
+
else:
|
140
|
+
result = float(self) * float(other)
|
141
|
+
|
142
|
+
if self.round_output and self.decimal_places is not None:
|
143
|
+
if not (math.isinf(result) or math.isnan(result)):
|
144
|
+
result = self.__clean_float(result, self.decimal_places)
|
145
|
+
|
146
|
+
try:
|
147
|
+
return self.__class__(result)
|
148
|
+
except (ValueError, TypeError):
|
149
|
+
return result
|
150
|
+
|
151
|
+
def __eq__(self, other):
|
152
|
+
"""Equality with epsilon tolerance"""
|
153
|
+
if isinstance(other, (int, float)):
|
154
|
+
return abs(float(self) - float(other)) < self.epsilon
|
155
|
+
return super().__eq__(other)
|
@@ -0,0 +1,7 @@
|
|
1
|
+
from osbot_utils.helpers.safe_float.Safe_Float import Safe_Float
|
2
|
+
|
3
|
+
class Safe_Float__Engineering(Safe_Float): # Engineering calculations with controlled precision
|
4
|
+
#decimal_places = 6
|
5
|
+
epsilon = 1e-6
|
6
|
+
round_output = True
|
7
|
+
use_decimal = False # Performance over exactness
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Safe_Float__Money.py
|
2
|
+
from osbot_utils.helpers.safe_float.Safe_Float import Safe_Float
|
3
|
+
|
4
|
+
|
5
|
+
class Safe_Float__Money(Safe_Float): # Money calculations with exact decimal arithmetic
|
6
|
+
decimal_places = 2
|
7
|
+
use_decimal = True # Use Decimal internally
|
8
|
+
allow_inf = False
|
9
|
+
allow_nan = False
|
10
|
+
min_value = 0.0
|
11
|
+
round_output = True
|
File without changes
|
@@ -0,0 +1,77 @@
|
|
1
|
+
from typing import Optional, Union
|
2
|
+
|
3
|
+
from osbot_utils.helpers.safe_float.Safe_Float import Safe_Float
|
4
|
+
|
5
|
+
|
6
|
+
class Safe_Int(int): # Base class for type-safe integers with validation rules
|
7
|
+
|
8
|
+
min_value : Optional[int] = None # Minimum allowed value (inclusive)
|
9
|
+
max_value : Optional[int] = None # Maximum allowed value (inclusive)
|
10
|
+
allow_none : bool = True # Whether None is allowed as input
|
11
|
+
allow_bool : bool = False # Whether bool is allowed as input
|
12
|
+
allow_str : bool = True # Whether string conversion is allowed
|
13
|
+
strict_type : bool = False # If True, only accept int type (no conversions)
|
14
|
+
|
15
|
+
def __new__(cls, value: Optional[Union[int, str]] = None) -> 'Safe_Int':
|
16
|
+
# Handle None input
|
17
|
+
if value is None:
|
18
|
+
if cls.allow_none:
|
19
|
+
return super().__new__(cls, 0) # Default to 0 for None
|
20
|
+
else:
|
21
|
+
raise ValueError(f"{cls.__name__} does not allow None values")
|
22
|
+
|
23
|
+
# Strict type checking
|
24
|
+
if cls.strict_type and not isinstance(value, int):
|
25
|
+
raise TypeError(f"{cls.__name__} requires int type, got {type(value).__name__}")
|
26
|
+
|
27
|
+
# Type conversion
|
28
|
+
if isinstance(value, str):
|
29
|
+
if not cls.allow_str:
|
30
|
+
raise TypeError(f"{cls.__name__} does not allow string conversion")
|
31
|
+
try:
|
32
|
+
value = int(value)
|
33
|
+
except ValueError:
|
34
|
+
raise ValueError(f"Cannot convert '{value}' to integer")
|
35
|
+
|
36
|
+
elif isinstance(value, bool):
|
37
|
+
if not cls.allow_bool:
|
38
|
+
raise TypeError(f"{cls.__name__} does not allow boolean values")
|
39
|
+
value = int(value)
|
40
|
+
|
41
|
+
elif not isinstance(value, int):
|
42
|
+
raise TypeError(f"{cls.__name__} requires an integer value, got {type(value).__name__}")
|
43
|
+
|
44
|
+
# Range validation
|
45
|
+
if cls.min_value is not None and value < cls.min_value:
|
46
|
+
raise ValueError(f"{cls.__name__} must be >= {cls.min_value}, got {value}")
|
47
|
+
|
48
|
+
if cls.max_value is not None and value > cls.max_value:
|
49
|
+
raise ValueError(f"{cls.__name__} must be <= {cls.max_value}, got {value}")
|
50
|
+
|
51
|
+
return super().__new__(cls, value)
|
52
|
+
|
53
|
+
# Arithmetic operations that maintain type safety
|
54
|
+
def __add__(self, other):
|
55
|
+
result = super().__add__(other)
|
56
|
+
try:
|
57
|
+
return self.__class__(result)
|
58
|
+
except (ValueError, TypeError):
|
59
|
+
return result # Return plain int if validation fails
|
60
|
+
|
61
|
+
def __sub__(self, other):
|
62
|
+
result = super().__sub__(other)
|
63
|
+
try:
|
64
|
+
return self.__class__(result)
|
65
|
+
except (ValueError, TypeError):
|
66
|
+
return result
|
67
|
+
|
68
|
+
def __mul__(self, other):
|
69
|
+
result = super().__mul__(other)
|
70
|
+
try:
|
71
|
+
return self.__class__(result)
|
72
|
+
except (ValueError, TypeError):
|
73
|
+
return result
|
74
|
+
|
75
|
+
def __truediv__(self, other):
|
76
|
+
result = super().__truediv__(other)
|
77
|
+
return Safe_Float(result)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from osbot_utils.helpers.safe_int.Safe_Int import Safe_Int
|
2
|
+
|
3
|
+
TYPE_SAFE_INT__BYTE__MIN_VALUE = 0
|
4
|
+
TYPE_SAFE_INT__BYTE__MAX_VALUE = 255
|
5
|
+
|
6
|
+
class Safe_Int__Byte(Safe_Int):
|
7
|
+
"""Single byte value (0-255)"""
|
8
|
+
|
9
|
+
min_value = TYPE_SAFE_INT__BYTE__MIN_VALUE
|
10
|
+
max_value = TYPE_SAFE_INT__BYTE__MAX_VALUE
|
11
|
+
allow_bool = False
|
@@ -0,0 +1,19 @@
|
|
1
|
+
from osbot_utils.helpers.safe_int.Safe_Int import Safe_Int
|
2
|
+
|
3
|
+
TYPE_SAFE_INT__FILE_SIZE__MIN_VALUE = 0
|
4
|
+
TYPE_SAFE_INT__FILE_SIZE__MAX_VALUE = 2**63 - 1 # Max file size on most systems
|
5
|
+
|
6
|
+
class Safe_Int__FileSize(Safe_Int): # File size in bytes
|
7
|
+
|
8
|
+
min_value = TYPE_SAFE_INT__FILE_SIZE__MIN_VALUE
|
9
|
+
max_value = TYPE_SAFE_INT__FILE_SIZE__MAX_VALUE
|
10
|
+
allow_bool = False
|
11
|
+
|
12
|
+
def to_kb(self) -> float:
|
13
|
+
return self / 1024
|
14
|
+
|
15
|
+
def to_mb(self) -> float:
|
16
|
+
return self / (1024 * 1024)
|
17
|
+
|
18
|
+
def to_gb(self) -> float:
|
19
|
+
return self / (1024 * 1024 * 1024)
|
@@ -0,0 +1,10 @@
|
|
1
|
+
from osbot_utils.helpers.safe_int.Safe_Int import Safe_Int
|
2
|
+
|
3
|
+
TYPE_SAFE_INT__PERCENTAGE__MIN_VALUE = 0
|
4
|
+
TYPE_SAFE_INT__PERCENTAGE__MAX_VALUE = 100
|
5
|
+
|
6
|
+
class Safe_Int__Percentage(Safe_Int): # Percentage value (0-100)
|
7
|
+
|
8
|
+
min_value = TYPE_SAFE_INT__PERCENTAGE__MIN_VALUE
|
9
|
+
max_value = TYPE_SAFE_INT__PERCENTAGE__MAX_VALUE
|
10
|
+
allow_bool = False
|
@@ -0,0 +1,11 @@
|
|
1
|
+
from osbot_utils.helpers.safe_int.Safe_Int import Safe_Int
|
2
|
+
|
3
|
+
TYPE_SAFE_INT__PORT__MIN_VALUE = 0
|
4
|
+
TYPE_SAFE_INT__PORT__MAX_VALUE = 65535
|
5
|
+
|
6
|
+
class Safe_Int__Port(Safe_Int): # Network port number (0-65535)
|
7
|
+
|
8
|
+
min_value = TYPE_SAFE_INT__PORT__MIN_VALUE
|
9
|
+
max_value = TYPE_SAFE_INT__PORT__MAX_VALUE
|
10
|
+
allow_bool = False
|
11
|
+
allow_none = False # don't allow 0 as port value since that is a really weird value for a port
|
@@ -0,0 +1,7 @@
|
|
1
|
+
from osbot_utils.helpers.safe_int.Safe_Int import Safe_Int
|
2
|
+
|
3
|
+
class Safe_Int__UInt(Safe_Int): # Unsigned Integer - only accepts non-negative integer values
|
4
|
+
|
5
|
+
min_value = 0 # Unsigned means >= 0
|
6
|
+
max_value = None # No upper limit by default
|
7
|
+
allow_bool = False # Don't allow True/False as 1/0
|
@@ -0,0 +1,10 @@
|
|
1
|
+
from osbot_utils.helpers.safe_int.Safe_Int import Safe_Int
|
2
|
+
|
3
|
+
TYPE_SAFE_INT__BYTE__MIN_VALUE = 0
|
4
|
+
TYPE_SAFE_INT__BYTE__MAX_VALUE = 255
|
5
|
+
|
6
|
+
class Safe_Int__Byte(Safe_Int): # Single byte value (0-255)
|
7
|
+
|
8
|
+
min_value = TYPE_SAFE_INT__BYTE__MIN_VALUE
|
9
|
+
max_value = TYPE_SAFE_INT__BYTE__MAX_VALUE
|
10
|
+
allow_bool = False
|
@@ -21,7 +21,7 @@ class Safe_Str(str):
|
|
21
21
|
if cls.allow_empty:
|
22
22
|
value = ""
|
23
23
|
else:
|
24
|
-
raise ValueError("
|
24
|
+
raise ValueError(f"in {cls.__name__}, value cannot be None when allow_empty is False") from None
|
25
25
|
|
26
26
|
if not isinstance(value, str): # Convert to string if not already
|
27
27
|
value = str(value)
|
File without changes
|
@@ -285,7 +285,7 @@ class Type_Safe__Validation:
|
|
285
285
|
if self.obj_is_type_union_compatible(var_type, IMMUTABLE_TYPES) is False: # if var_type is not something like Optional[Union[int, str]]
|
286
286
|
if var_type not in IMMUTABLE_TYPES or type(var_type) not in IMMUTABLE_TYPES:
|
287
287
|
if not isinstance(var_type, EnumMeta):
|
288
|
-
if not issubclass(var_type, str):
|
288
|
+
if not issubclass(var_type, (int,str, float)):
|
289
289
|
type_safe_raise_exception.immutable_type_error(var_name, var_type)
|
290
290
|
|
291
291
|
def validate_variable_type(self, var_name, var_type, var_value): # Validate type compatibility
|
osbot_utils/version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
v2.
|
1
|
+
v2.60.0
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: osbot_utils
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.60.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
|
-

|
27
27
|
[](https://codecov.io/gh/owasp-sbot/OSBot-Utils)
|
28
28
|
|
29
29
|
|
@@ -179,7 +179,7 @@ osbot_utils/helpers/html/Html_Dict__To__Html.py,sha256=jLizQHHfSLkOkdzbfSyPuHFys
|
|
179
179
|
osbot_utils/helpers/html/Html_Dict__To__Html_Document.py,sha256=hpN-3IJjYNly1tcCWp5JuLsE_idawgcYpMpXcwFnqHI,2135
|
180
180
|
osbot_utils/helpers/html/Html_Dict__To__Html_Tags.py,sha256=MfXW-tfTBA7DiGJfUX1HB4-Y1F1kxdIhTyglYHUblOs,5425
|
181
181
|
osbot_utils/helpers/html/Html__To__Html_Dict.py,sha256=VDaTOkrsidhLUj2Uuj7YdP0VYlLm6inFaRKybeC8ppg,4340
|
182
|
-
osbot_utils/helpers/html/Html__To__Html_Document.py,sha256=
|
182
|
+
osbot_utils/helpers/html/Html__To__Html_Document.py,sha256=xVbIT3TaxZPt4cz3lO4WvSru7FyWI1p36qdXp6HGC8o,886
|
183
183
|
osbot_utils/helpers/html/Html__To__Html_Tag.py,sha256=Qz6he08DwfYkYM_krt_FCVtEWgw6_9bs5j5CoC1FCQQ,566
|
184
184
|
osbot_utils/helpers/html/Tag__Base.py,sha256=geD7TpA3lHrSiaoLsViH2rcjrqZkMxNpDOhLx3HYbSk,4470
|
185
185
|
osbot_utils/helpers/html/Tag__Body.py,sha256=U3UNVs1mNBsJ_kG_-OtwYPi-YzFb4Y2w4vIsvAn0W3g,109
|
@@ -193,7 +193,7 @@ osbot_utils/helpers/html/Tag__Style.py,sha256=wRZ8DN1HVCtrnL4Flz82oByqJOy8Th40Eh
|
|
193
193
|
osbot_utils/helpers/html/Tag__Text.py,sha256=Pqf96QGwX9wdGqlwBvWYHWz9Qqi-oZrkgEzHQm6LzdY,241
|
194
194
|
osbot_utils/helpers/html/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
195
195
|
osbot_utils/helpers/html/schemas/Schema__Html_Document.py,sha256=227IP9kfQ7FH7bhd-LsPsppPo-mhwC58BcGYWsy0WwQ,381
|
196
|
-
osbot_utils/helpers/html/schemas/Schema__Html_Node.py,sha256=
|
196
|
+
osbot_utils/helpers/html/schemas/Schema__Html_Node.py,sha256=dz_LI9xzoz6_Gfh6aQbGBeN3IHZLlWVjESIegNz9vxY,728
|
197
197
|
osbot_utils/helpers/html/schemas/Schema__Html_Node__Data.py,sha256=T0S-MF-aw91fZCoU0vkDH0Ni_4oAyiXGdIMsHXdt4fs,449
|
198
198
|
osbot_utils/helpers/html/schemas/Schema__Html_Node__Data__Type.py,sha256=mbYivcm6BfN5-oeCyl6gjbnSKs_b_t-G2H1rpSK6nUY,90
|
199
199
|
osbot_utils/helpers/html/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -241,7 +241,19 @@ osbot_utils/helpers/pubsub/schemas/Schema__PubSub__Client.py,sha256=yOQSn4o1bIsE
|
|
241
241
|
osbot_utils/helpers/pubsub/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
242
242
|
osbot_utils/helpers/python_compatibility/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
243
243
|
osbot_utils/helpers/python_compatibility/python_3_8.py,sha256=kh846vs3ir8xD0RSARJBOL0xufnt3L_Td3K45lDfqng,161
|
244
|
-
osbot_utils/helpers/
|
244
|
+
osbot_utils/helpers/safe_float/Safe_Float.py,sha256=p0To2jrseu4xN4EhhgIR-1ncpJ21X6pxchTI-iHakOQ,6517
|
245
|
+
osbot_utils/helpers/safe_float/Safe_Float__Engineering.py,sha256=2XLh8sLs49WXqyRUzPbZnTQGok-CKR6jjxZCXi5py2A,330
|
246
|
+
osbot_utils/helpers/safe_float/Safe_Float__Money.py,sha256=Abh_CX8849rtKgAu-hCxwVxBytb7-I9-chkbYXpQr74,378
|
247
|
+
osbot_utils/helpers/safe_float/Safe_Float__Percentage_Exact.py,sha256=l_nGfa2-VCgdBeUXYQAR2wawc4362A9GsCOpWZ3Sdd4,286
|
248
|
+
osbot_utils/helpers/safe_float/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
249
|
+
osbot_utils/helpers/safe_int/Safe_Int.py,sha256=eXOJjZ8CgXshFQcPVwL1lOdemF8X65Jy0NFJTlt6QG8,3034
|
250
|
+
osbot_utils/helpers/safe_int/Safe_Int__Byte.py,sha256=D95ZDydTOxMt3FAnUq5llND__3Loju_G3Ge1dVhGMck,318
|
251
|
+
osbot_utils/helpers/safe_int/Safe_Int__FileSize.py,sha256=mqYoyM2lTUMM4PzkjyXBpsA9dFQY53roNf2649dK1DA,592
|
252
|
+
osbot_utils/helpers/safe_int/Safe_Int__Percentage.py,sha256=hkOhv4kkEYs3xExYv2fQfkPi4lbYG6cTHxz-2wiSqL8,349
|
253
|
+
osbot_utils/helpers/safe_int/Safe_Int__Port.py,sha256=2mXh5QM_aqzPLgqT88v6R3CLG4E6K5EmqtGStIKRLmo,474
|
254
|
+
osbot_utils/helpers/safe_int/Safe_Int__UInt.py,sha256=3S4k3Jw6PIIgWw6i6Dmhg25VnsEvAL_7tPCQEvkOKR4,322
|
255
|
+
osbot_utils/helpers/safe_int/__init__.py,sha256=kMU2WMsdQmayBEZugxnJV_wRW3O90bc118sx6iIm_mQ,310
|
256
|
+
osbot_utils/helpers/safe_str/Safe_Str.py,sha256=qc_wO1okHamcOOtv6-cvmPvF1Eh1A7-Pk4P4MSzOb24,3375
|
245
257
|
osbot_utils/helpers/safe_str/Safe_Str__File__Name.py,sha256=ncjkQ2hAhw0a3UulrCuQsA9ytrFwg5CT1XRJIGChMpY,289
|
246
258
|
osbot_utils/helpers/safe_str/Safe_Str__File__Path.py,sha256=K0yBcvH_Ncqiw7tMqjGqaNyWQh1Zs9qxZ-TR8nEIAow,550
|
247
259
|
osbot_utils/helpers/safe_str/Safe_Str__Hash.py,sha256=Tb2QeVpVDNWpCJGHNFjZPCQ_ZTaI7Z5BDzi19LiO_cI,952
|
@@ -254,6 +266,7 @@ osbot_utils/helpers/safe_str/http/Safe_Str__Http__Content_Type.py,sha256=HURT4n1
|
|
254
266
|
osbot_utils/helpers/safe_str/http/Safe_Str__Http__ETag.py,sha256=5cAfIqebraUnVKZJq3CzXzsFdHGy06TznO36Dc6b5A0,477
|
255
267
|
osbot_utils/helpers/safe_str/http/Safe_Str__Http__Last_Modified.py,sha256=FBcPM4h3ldN0F_cSISGZgdidWpjKLCOOPq9sWVGUCzg,438
|
256
268
|
osbot_utils/helpers/safe_str/http/Safe_Str__Http__Text.py,sha256=w0UPkVnQz41BN9asgDUZ4q6pSQUtzNa-4Sjcl56WTCM,1788
|
269
|
+
osbot_utils/helpers/safe_str/http/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
257
270
|
osbot_utils/helpers/sqlite/Capture_Sqlite_Error.py,sha256=GSuRYgs1yKQjxMszPoaI7fsfMfuUqhb64AaIysRE6Cs,1747
|
258
271
|
osbot_utils/helpers/sqlite/Sqlite__Cursor.py,sha256=4Im0pCOiERX6Nnf6iagRlSvTR3CPjyPVkdx4NMQV0P0,3342
|
259
272
|
osbot_utils/helpers/sqlite/Sqlite__Database.py,sha256=ORjRUD-xSvf89kDMQ70q7wBlbV5pdKtDerjE6gDN_fg,5616
|
@@ -371,7 +384,7 @@ osbot_utils/type_safe/shared/Type_Safe__Json_Compressor__Type_Registry.py,sha256
|
|
371
384
|
osbot_utils/type_safe/shared/Type_Safe__Not_Cached.py,sha256=25FAl6SOLxdStco_rm9tgOYLfuKyBWheGdl7vVa56UU,800
|
372
385
|
osbot_utils/type_safe/shared/Type_Safe__Raise_Exception.py,sha256=pbru8k8CTQMNUfmFBndiJhg2KkqEYzFvJAPcNZHeHfQ,829
|
373
386
|
osbot_utils/type_safe/shared/Type_Safe__Shared__Variables.py,sha256=SuZGl9LryQX6IpOE0I_lbzClT-h17UNylC__-M8ltTY,129
|
374
|
-
osbot_utils/type_safe/shared/Type_Safe__Validation.py,sha256=
|
387
|
+
osbot_utils/type_safe/shared/Type_Safe__Validation.py,sha256=zAQHly65XeOCfASOdlCmkYIgh_MYh-dyPzavF-Pua60,19240
|
375
388
|
osbot_utils/type_safe/shared/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
376
389
|
osbot_utils/type_safe/steps/Type_Safe__Step__Class_Kwargs.py,sha256=snoyJKvZ1crgF2fp0zexwNPnV_E63RfyRIsMAZdrKNY,6995
|
377
390
|
osbot_utils/type_safe/steps/Type_Safe__Step__Default_Kwargs.py,sha256=tzKXDUc0HVP5QvCWsmcPuuZodNvQZ9FeMDNI2x00Ngw,1943
|
@@ -412,8 +425,8 @@ osbot_utils/utils/Toml.py,sha256=Rxl8gx7mni5CvBAK-Ai02EKw-GwtJdd3yeHT2kMloik,166
|
|
412
425
|
osbot_utils/utils/Version.py,sha256=Ww6ChwTxqp1QAcxOnztkTicShlcx6fbNsWX5xausHrg,422
|
413
426
|
osbot_utils/utils/Zip.py,sha256=pR6sKliUY0KZXmqNzKY2frfW-YVQEVbLKiyqQX_lc-8,14052
|
414
427
|
osbot_utils/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
415
|
-
osbot_utils/version,sha256=
|
416
|
-
osbot_utils-2.
|
417
|
-
osbot_utils-2.
|
418
|
-
osbot_utils-2.
|
419
|
-
osbot_utils-2.
|
428
|
+
osbot_utils/version,sha256=D9uXwX3FHdetilkBF7SobVFVi0hZtTHmuPxn_3li-ms,8
|
429
|
+
osbot_utils-2.60.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
430
|
+
osbot_utils-2.60.0.dist-info/METADATA,sha256=fllKiqMg4tuh-o1z-XbK-BRcd5ydmtaYAGRy8F-Qv_4,1329
|
431
|
+
osbot_utils-2.60.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
432
|
+
osbot_utils-2.60.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|