osbot-utils 2.72.0__py3-none-any.whl → 2.74.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/flows/actions/Flow__Data.py +1 -1
- osbot_utils/helpers/flows/models/Flow_Run__Event.py +6 -5
- osbot_utils/helpers/flows/models/Schema__Flow__Artifact.py +1 -1
- osbot_utils/helpers/flows/models/Schema__Flow__Result.py +1 -1
- osbot_utils/helpers/flows/schemas/Schema__Flow__Data.py +1 -1
- osbot_utils/helpers/flows/schemas/Schema__Flow__Event.py +1 -1
- osbot_utils/helpers/flows/schemas/Schema__Flow__Log.py +1 -1
- osbot_utils/helpers/flows/schemas/Schema__Flow__Task__Data.py +1 -1
- osbot_utils/helpers/generators/Generator_Manager.py +1 -1
- osbot_utils/helpers/generators/Model__Generator_Target.py +1 -1
- osbot_utils/helpers/html/schemas/Schema__Html_Document.py +1 -1
- osbot_utils/helpers/llms/actions/LLM_Request__Execute.py +2 -1
- osbot_utils/helpers/llms/actions/Type_Safe__Schema_For__LLMs.py +10 -10
- osbot_utils/helpers/llms/builders/LLM_Request__Builder.py +3 -2
- osbot_utils/helpers/llms/builders/LLM_Request__Builder__Open_AI.py +2 -1
- osbot_utils/helpers/llms/builders/LLM_Request__Factory.py +1 -1
- osbot_utils/helpers/llms/cache/LLM_Cache__Path_Generator.py +7 -6
- osbot_utils/helpers/llms/cache/LLM_Request__Cache.py +10 -10
- osbot_utils/helpers/llms/cache/LLM_Request__Cache__File_System.py +5 -3
- osbot_utils/helpers/llms/cache/LLM_Request__Cache__Storage.py +2 -2
- osbot_utils/helpers/llms/cache/Virtual_Storage__Local__Folder.py +7 -7
- osbot_utils/helpers/llms/cache/Virtual_Storage__Sqlite.py +7 -7
- osbot_utils/helpers/llms/schemas/Safe_Str__LLM__Model_Name.py +1 -1
- osbot_utils/helpers/llms/schemas/Schema__LLM_Cache__Index.py +6 -5
- osbot_utils/helpers/llms/schemas/Schema__LLM_Request__Data.py +2 -1
- osbot_utils/helpers/llms/schemas/Schema__LLM_Response.py +1 -1
- osbot_utils/helpers/llms/schemas/Schema__LLM_Response__Cache.py +7 -6
- osbot_utils/helpers/xml/rss/RSS__Feed__Parser.py +1 -1
- osbot_utils/helpers/xml/rss/RSS__Item.py +1 -1
- osbot_utils/type_safe/Type_Safe.py +11 -10
- osbot_utils/type_safe/Type_Safe__Base.py +3 -3
- osbot_utils/{helpers → type_safe/primitives}/safe_float/Safe_Float__Engineering.py +2 -1
- osbot_utils/{helpers → type_safe/primitives}/safe_float/Safe_Float__Money.py +1 -2
- osbot_utils/{helpers → type_safe/primitives}/safe_float/Safe_Float__Percentage_Exact.py +1 -1
- osbot_utils/{helpers → type_safe/primitives}/safe_int/Safe_Int.py +3 -3
- osbot_utils/{helpers → type_safe/primitives}/safe_int/__init__.py +1 -1
- osbot_utils/{helpers → type_safe/primitives}/safe_str/Safe_Str.py +3 -3
- osbot_utils/{helpers/safe_str → type_safe/primitives/safe_str/cryptography/hashes}/Safe_Str__Hash.py +3 -3
- osbot_utils/type_safe/primitives/safe_str/cryptography/hashes/Safe_Str__SHA1.py +26 -0
- osbot_utils/type_safe/primitives/safe_str/cryptography/hashes/Safe_Str__SHA1__Short.py +24 -0
- osbot_utils/type_safe/primitives/safe_str/cryptography/nacl/Safe_Str__NaCl__Private_Key.py +27 -0
- osbot_utils/type_safe/primitives/safe_str/cryptography/nacl/Safe_Str__NaCl__Public_Key.py +28 -0
- osbot_utils/type_safe/primitives/safe_str/cryptography/nacl/Schema__NaCl__Keys.py +8 -0
- osbot_utils/{helpers/safe_str → type_safe/primitives/safe_str/filesystem}/Safe_Str__File__Name.py +1 -1
- osbot_utils/{helpers/safe_str → type_safe/primitives/safe_str/filesystem}/Safe_Str__File__Path.py +1 -1
- osbot_utils/type_safe/primitives/safe_str/git/Safe_Str__Git__Branch.py +27 -0
- osbot_utils/type_safe/primitives/safe_str/git/Safe_Str__Git__Ref.py +63 -0
- osbot_utils/type_safe/primitives/safe_str/git/Safe_Str__Git__Ref_Base.py +73 -0
- osbot_utils/type_safe/primitives/safe_str/git/Safe_Str__Git__Tag.py +17 -0
- osbot_utils/{helpers/safe_str → type_safe/primitives/safe_str/git}/Safe_Str__Version.py +2 -2
- osbot_utils/type_safe/primitives/safe_str/github/Safe_Str__GitHub__Repo.py +46 -0
- osbot_utils/type_safe/primitives/safe_str/github/Safe_Str__GitHub__Repo_Name.py +35 -0
- osbot_utils/type_safe/primitives/safe_str/github/Safe_Str__GitHub__Repo_Owner.py +39 -0
- osbot_utils/type_safe/primitives/safe_str/github/__init__.py +0 -0
- osbot_utils/{helpers → type_safe/primitives}/safe_str/http/Safe_Str__Http__Content_Type.py +1 -1
- osbot_utils/{helpers → type_safe/primitives}/safe_str/http/Safe_Str__Http__ETag.py +1 -1
- osbot_utils/{helpers → type_safe/primitives}/safe_str/http/Safe_Str__Http__Last_Modified.py +1 -1
- osbot_utils/{helpers → type_safe/primitives}/safe_str/http/Safe_Str__Http__Text.py +1 -1
- osbot_utils/type_safe/primitives/safe_str/http/__init__.py +0 -0
- osbot_utils/{helpers → type_safe/primitives/safe_str/identifiers}/Guid.py +3 -2
- osbot_utils/type_safe/primitives/safe_str/identifiers/__init__.py +0 -0
- osbot_utils/{helpers/safe_str → type_safe/primitives/safe_str/text}/Safe_Str__Text.py +1 -1
- osbot_utils/{helpers/safe_str → type_safe/primitives/safe_str/text}/Safe_Str__Text__Dangerous.py +1 -1
- osbot_utils/type_safe/primitives/safe_str/text/__init__.py +0 -0
- osbot_utils/{helpers/safe_str/http → type_safe/primitives/safe_str/web}/Safe_Str__Html.py +1 -1
- osbot_utils/{helpers/safe_str → type_safe/primitives/safe_str/web}/Safe_Str__Url.py +1 -1
- osbot_utils/type_safe/primitives/safe_str/web/__init__.py +0 -0
- osbot_utils/{helpers/safe_int → type_safe/primitives/safe_uint}/Safe_UInt.py +2 -1
- osbot_utils/{helpers/safe_int → type_safe/primitives/safe_uint}/Safe_UInt__Byte.py +1 -1
- osbot_utils/{helpers/safe_int → type_safe/primitives/safe_uint}/Safe_UInt__FileSize.py +1 -1
- osbot_utils/{helpers/safe_int → type_safe/primitives/safe_uint}/Safe_UInt__Percentage.py +1 -1
- osbot_utils/{helpers/safe_int → type_safe/primitives/safe_uint}/Safe_UInt__Port.py +1 -1
- osbot_utils/type_safe/primitives/safe_uint/__init__.py +0 -0
- osbot_utils/type_safe/type_safe_core/__init__.py +0 -0
- osbot_utils/type_safe/{Type_Safe__Dict.py → type_safe_core/collections/Type_Safe__Dict.py} +4 -3
- osbot_utils/type_safe/type_safe_core/collections/__init__.py +0 -0
- osbot_utils/type_safe/type_safe_core/decorators/__init__.py +0 -0
- osbot_utils/type_safe/{decorators → type_safe_core/decorators}/type_safe.py +2 -1
- osbot_utils/type_safe/{Type_Safe__Method.py → type_safe_core/methods/Type_Safe__Method.py} +4 -5
- osbot_utils/type_safe/type_safe_core/methods/__init__.py +0 -0
- osbot_utils/type_safe/{shared → type_safe_core/shared}/Type_Safe__Annotations.py +1 -1
- osbot_utils/type_safe/{shared → type_safe_core/shared}/Type_Safe__Cache.py +3 -3
- osbot_utils/type_safe/{shared → type_safe_core/shared}/Type_Safe__Convert.py +3 -3
- osbot_utils/type_safe/{shared → type_safe_core/shared}/Type_Safe__Json_Compressor.py +6 -6
- osbot_utils/type_safe/{shared → type_safe_core/shared}/Type_Safe__Raise_Exception.py +1 -1
- osbot_utils/type_safe/{shared → type_safe_core/shared}/Type_Safe__Validation.py +8 -7
- osbot_utils/type_safe/type_safe_core/shared/__init__.py +0 -0
- osbot_utils/type_safe/{steps → type_safe_core/steps}/Type_Safe__Step__Class_Kwargs.py +8 -7
- osbot_utils/type_safe/{steps → type_safe_core/steps}/Type_Safe__Step__Default_Value.py +6 -6
- osbot_utils/type_safe/{steps → type_safe_core/steps}/Type_Safe__Step__From_Json.py +16 -17
- osbot_utils/type_safe/{steps → type_safe_core/steps}/Type_Safe__Step__Init.py +7 -6
- osbot_utils/type_safe/{steps → type_safe_core/steps}/Type_Safe__Step__Set_Attr.py +7 -7
- osbot_utils/type_safe/type_safe_core/steps/__init__.py +0 -0
- osbot_utils/utils/Files.py +2 -3
- osbot_utils/version +1 -1
- osbot_utils-2.74.0.dist-info/METADATA +212 -0
- {osbot_utils-2.72.0.dist-info → osbot_utils-2.74.0.dist-info}/RECORD +122 -98
- osbot_utils-2.72.0.dist-info/METADATA +0 -44
- /osbot_utils/{helpers/safe_float → type_safe/primitives}/__init__.py +0 -0
- /osbot_utils/{helpers → type_safe/primitives}/safe_float/Safe_Float.py +0 -0
- /osbot_utils/{helpers/safe_str → type_safe/primitives/safe_float}/__init__.py +0 -0
- /osbot_utils/{helpers → type_safe/primitives/safe_int}/Timestamp_Now.py +0 -0
- /osbot_utils/{helpers/safe_str/schemas → type_safe/primitives/safe_str}/Enum__Safe_Str__Regex_Mode.py +0 -0
- /osbot_utils/{helpers/safe_str/http → type_safe/primitives/safe_str}/__init__.py +0 -0
- /osbot_utils/{helpers/safe_str/schemas → type_safe/primitives/safe_str/cryptography}/__init__.py +0 -0
- /osbot_utils/type_safe/{decorators → primitives/safe_str/cryptography/hashes}/__init__.py +0 -0
- /osbot_utils/type_safe/{methods → primitives/safe_str/cryptography/nacl}/__init__.py +0 -0
- /osbot_utils/type_safe/{shared → primitives/safe_str/filesystem}/__init__.py +0 -0
- /osbot_utils/type_safe/{steps → primitives/safe_str/git}/__init__.py +0 -0
- /osbot_utils/{helpers → type_safe/primitives/safe_str/identifiers}/Random_Guid.py +0 -0
- /osbot_utils/{helpers → type_safe/primitives/safe_str/identifiers}/Random_Guid_Short.py +0 -0
- /osbot_utils/{helpers → type_safe/primitives/safe_str/identifiers}/Safe_Id.py +0 -0
- /osbot_utils/{helpers/safe_str/http → type_safe/primitives/safe_str/web}/Safe_Str__IP_Address.py +0 -0
- /osbot_utils/type_safe/{Type_Safe__List.py → type_safe_core/collections/Type_Safe__List.py} +0 -0
- /osbot_utils/type_safe/{Type_Safe__Set.py → type_safe_core/collections/Type_Safe__Set.py} +0 -0
- /osbot_utils/type_safe/{Type_Safe__Tuple.py → type_safe_core/collections/Type_Safe__Tuple.py} +0 -0
- /osbot_utils/type_safe/{methods → type_safe_core/methods}/type_safe_property.py +0 -0
- /osbot_utils/type_safe/{shared → type_safe_core/shared}/Type_Safe__Json_Compressor__Type_Registry.py +0 -0
- /osbot_utils/type_safe/{shared → type_safe_core/shared}/Type_Safe__Not_Cached.py +0 -0
- /osbot_utils/type_safe/{shared → type_safe_core/shared}/Type_Safe__Shared__Variables.py +0 -0
- /osbot_utils/type_safe/{steps → type_safe_core/steps}/Type_Safe__Step__Default_Kwargs.py +0 -0
- {osbot_utils-2.72.0.dist-info → osbot_utils-2.74.0.dist-info}/LICENSE +0 -0
- {osbot_utils-2.72.0.dist-info → osbot_utils-2.74.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
import re
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
3
|
+
from osbot_utils.type_safe.primitives.safe_str.Enum__Safe_Str__Regex_Mode import Enum__Safe_Str__Regex_Mode
|
4
|
+
|
5
|
+
TYPE_SAFE_STR__NACL__PUBLIC_KEY__REGEX = re.compile(r'^[a-fA-F0-9]{64}$')
|
6
|
+
TYPE_SAFE_STR__NACL__PUBLIC_KEY__LENGTH = 64 # 32 bytes as hex = 64 characters
|
7
|
+
|
8
|
+
# todo: refactor this with Safe_Str__NaCl__Private_Key since the code is just about the same
|
9
|
+
class Safe_Str__NaCl__Public_Key(Safe_Str):
|
10
|
+
"""
|
11
|
+
Safe string class for NaCl (Curve25519) public keys in hexadecimal format.
|
12
|
+
|
13
|
+
NaCl public keys are 32 bytes (256 bits), represented as 64 hexadecimal characters.
|
14
|
+
These keys are used with libsodium/PyNaCl for asymmetric encryption using SealedBox.
|
15
|
+
|
16
|
+
Examples:
|
17
|
+
- "a1b2c3d4e5f6789012345678901234567890abcdefabcdefabcdefabcdefabcd"
|
18
|
+
- "fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"
|
19
|
+
|
20
|
+
Security Note: Public keys can be safely shared and transmitted.
|
21
|
+
"""
|
22
|
+
regex = TYPE_SAFE_STR__NACL__PUBLIC_KEY__REGEX
|
23
|
+
regex_mode = Enum__Safe_Str__Regex_Mode.MATCH
|
24
|
+
max_length = TYPE_SAFE_STR__NACL__PUBLIC_KEY__LENGTH
|
25
|
+
exact_length = True
|
26
|
+
allow_empty = False
|
27
|
+
trim_whitespace = True
|
28
|
+
strict_validation = True
|
@@ -0,0 +1,8 @@
|
|
1
|
+
from osbot_utils.type_safe.Type_Safe import Type_Safe
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.cryptography.nacl.Safe_Str__NaCl__Private_Key import Safe_Str__NaCl__Private_Key
|
3
|
+
from osbot_utils.type_safe.primitives.safe_str.cryptography.nacl.Safe_Str__NaCl__Public_Key import Safe_Str__NaCl__Public_Key
|
4
|
+
|
5
|
+
|
6
|
+
class Schema__NaCl__Keys(Type_Safe):
|
7
|
+
public_key : Safe_Str__NaCl__Public_Key = None
|
8
|
+
private_key: Safe_Str__NaCl__Private_Key = None
|
osbot_utils/{helpers/safe_str → type_safe/primitives/safe_str/filesystem}/Safe_Str__File__Path.py
RENAMED
@@ -1,5 +1,5 @@
|
|
1
1
|
import re
|
2
|
-
from osbot_utils.
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
3
3
|
|
4
4
|
TYPE_SAFE_STR__FILE_PATH__REGEX = re.compile(r'[^a-zA-Z0-9_\-./\\ ]') # Allow alphanumerics, underscores, hyphens, dots, slashes, and spaces
|
5
5
|
TYPE_SAFE_STR__FILE_PATH__MAX_LENGTH = 1024
|
@@ -0,0 +1,27 @@
|
|
1
|
+
from osbot_utils.type_safe.primitives.safe_str.git.Safe_Str__Git__Ref_Base import Safe_Str__Git__Ref_Base
|
2
|
+
|
3
|
+
|
4
|
+
class Safe_Str__Git__Branch(Safe_Str__Git__Ref_Base):
|
5
|
+
"""
|
6
|
+
Safe string class for GitHub branch names.
|
7
|
+
|
8
|
+
Follows git-check-ref-format rules with additional branch-specific restrictions:
|
9
|
+
- Cannot start with a dash '-' (branch-specific rule)
|
10
|
+
|
11
|
+
Examples:
|
12
|
+
- "main", "master", "develop"
|
13
|
+
- "feature/oauth-login"
|
14
|
+
- "bugfix/issue-123"
|
15
|
+
- "release/v2.0"
|
16
|
+
"""
|
17
|
+
|
18
|
+
def __new__(cls, value=None):
|
19
|
+
result = super().__new__(cls, value)
|
20
|
+
|
21
|
+
if result:
|
22
|
+
# Additional branch-specific rule: cannot start with dash
|
23
|
+
# (from git check-ref-format --branch documentation)
|
24
|
+
if result.startswith('-'):
|
25
|
+
raise ValueError(f"Branch name cannot start with dash: {result}")
|
26
|
+
|
27
|
+
return result
|
@@ -0,0 +1,63 @@
|
|
1
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.cryptography.hashes.Safe_Str__SHA1 import Safe_Str__SHA1
|
3
|
+
from osbot_utils.type_safe.primitives.safe_str.cryptography.hashes.Safe_Str__SHA1__Short import Safe_Str__SHA1__Short
|
4
|
+
from osbot_utils.type_safe.primitives.safe_str.git.Safe_Str__Git__Branch import Safe_Str__Git__Branch
|
5
|
+
from osbot_utils.type_safe.primitives.safe_str.git.Safe_Str__Git__Tag import Safe_Str__Git__Tag
|
6
|
+
|
7
|
+
|
8
|
+
class Safe_Str__Git__Ref(Safe_Str):
|
9
|
+
"""
|
10
|
+
Safe string class for any valid Git reference (branch, tag, or commit SHA).
|
11
|
+
|
12
|
+
This class validates that a string is a syntactically valid Git reference
|
13
|
+
without attempting to classify what type of reference it is.
|
14
|
+
|
15
|
+
A value is accepted if it passes validation as ANY of:
|
16
|
+
- A 40-character SHA (Safe_Str__SHA1)
|
17
|
+
- A 7-character short SHA (Safe_Str__SHA1__Short)
|
18
|
+
- A valid Git branch name (Safe_Str__Git__Branch)
|
19
|
+
- A valid Git tag name (Safe_Str__Git__Tag)
|
20
|
+
|
21
|
+
Used in GitHub API calls like:
|
22
|
+
- /repos/{owner}/{repo}/zipball/{ref}
|
23
|
+
- /repos/{owner}/{repo}/git/ref/{ref}
|
24
|
+
- /repos/{owner}/{repo}/commits/{ref}
|
25
|
+
"""
|
26
|
+
max_length = 255
|
27
|
+
allow_empty = False
|
28
|
+
trim_whitespace = True
|
29
|
+
|
30
|
+
def __new__(cls, value=None):
|
31
|
+
# First, do basic Safe_Str processing
|
32
|
+
if value is None:
|
33
|
+
if cls.allow_empty:
|
34
|
+
value = ""
|
35
|
+
else:
|
36
|
+
raise ValueError(f"in {cls.__name__}, value cannot be None when allow_empty is False")
|
37
|
+
|
38
|
+
if not isinstance(value, str):
|
39
|
+
value = str(value)
|
40
|
+
|
41
|
+
if cls.trim_whitespace:
|
42
|
+
value = value.strip()
|
43
|
+
|
44
|
+
if not cls.allow_empty and (value is None or value == ""):
|
45
|
+
raise ValueError("Value cannot be empty when allow_empty is False")
|
46
|
+
|
47
|
+
if len(value) > cls.max_length:
|
48
|
+
raise ValueError(f"Value exceeds maximum length of {cls.max_length} characters (was {len(value)})")
|
49
|
+
|
50
|
+
|
51
|
+
validators = [('SHA' , Safe_Str__SHA1 ), # we will try to validate as different ref types
|
52
|
+
('short SHA', Safe_Str__SHA1__Short ), # If ANY of these validation succeeds, accept the value
|
53
|
+
('branch' , Safe_Str__Git__Branch ),
|
54
|
+
('tag' , Safe_Str__Git__Tag )]
|
55
|
+
|
56
|
+
for validator_name, validator_class in validators:
|
57
|
+
try:
|
58
|
+
sanitized_value = validator_class(value) # Validation succeeded - use the sanitized value
|
59
|
+
return str.__new__(cls, sanitized_value) # return since it is a valid ref
|
60
|
+
except ValueError:
|
61
|
+
continue # This validator didn't accept it, try the next one
|
62
|
+
|
63
|
+
raise ValueError(f"Invalid Git ref: '{value}' is not a valid SHA, branch, or tag name") # None of the validators accepted it - it's not a valid ref
|
@@ -0,0 +1,73 @@
|
|
1
|
+
import re
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
3
|
+
|
4
|
+
|
5
|
+
TYPE_SAFE_STR__GIT_REF__REGEX = re.compile(r'[\x00-\x1f\x7f ~^:?*\[\]\\]')
|
6
|
+
TYPE_SAFE_STR__GIT_REF__MAX_LENGTH = 255
|
7
|
+
|
8
|
+
class Safe_Str__Git__Ref_Base(Safe_Str):
|
9
|
+
"""
|
10
|
+
Base class for Git references following git-check-ref-format rules.
|
11
|
+
|
12
|
+
Git reference rules (from git-check-ref-format https://git-scm.com/docs/git-check-ref-format):
|
13
|
+
1. Can include slash `/` for hierarchical grouping, but no slash-separated
|
14
|
+
component can begin with a dot `.` or end with `.lock`
|
15
|
+
2. Cannot have two consecutive dots `..` anywhere
|
16
|
+
3. Cannot have ASCII control characters, space, tilde `~`, caret `^`,
|
17
|
+
colon `:`, question-mark `?`, asterisk `*`, or open bracket `[`
|
18
|
+
4. Cannot begin or end with a slash `/` or contain multiple consecutive slashes
|
19
|
+
5. Cannot end with a dot `.`
|
20
|
+
6. Cannot contain a sequence `@{`
|
21
|
+
7. Cannot be the single character `@`
|
22
|
+
8. Cannot contain a backslash `\`
|
23
|
+
"""
|
24
|
+
regex = TYPE_SAFE_STR__GIT_REF__REGEX
|
25
|
+
max_length = TYPE_SAFE_STR__GIT_REF__MAX_LENGTH
|
26
|
+
allow_empty = False
|
27
|
+
trim_whitespace = True
|
28
|
+
allow_all_replacement_char = True
|
29
|
+
|
30
|
+
def __new__(cls, value=None):
|
31
|
+
result = super().__new__(cls, value)
|
32
|
+
|
33
|
+
if result:
|
34
|
+
# Rule: Cannot be the single character '@'
|
35
|
+
if result == '@':
|
36
|
+
raise ValueError(f"Reference cannot be the single character '@': {result}")
|
37
|
+
|
38
|
+
# Rule: Cannot have two consecutive dots '..'
|
39
|
+
if '..' in result:
|
40
|
+
raise ValueError(f"Reference cannot contain consecutive dots '..': {result}")
|
41
|
+
|
42
|
+
# Rule: Cannot contain sequence '@{'
|
43
|
+
if '@{' in result:
|
44
|
+
raise ValueError(f"Reference cannot contain '@{{': {result}")
|
45
|
+
|
46
|
+
# Rule: Cannot begin or end with a slash
|
47
|
+
if result.startswith('/') or result.endswith('/'):
|
48
|
+
raise ValueError(f"Reference cannot start or end with slash: {result}")
|
49
|
+
|
50
|
+
# Rule: Cannot contain multiple consecutive slashes
|
51
|
+
if '//' in result:
|
52
|
+
raise ValueError(f"Reference cannot contain consecutive slashes: {result}")
|
53
|
+
|
54
|
+
# Rule: Cannot end with a dot
|
55
|
+
if result.endswith('.'):
|
56
|
+
raise ValueError(f"Reference cannot end with dot: {result}")
|
57
|
+
|
58
|
+
# Rule: No slash-separated component can begin with '.' or end with '.lock'
|
59
|
+
if '/' in result:
|
60
|
+
components = result.split('/')
|
61
|
+
for component in components:
|
62
|
+
if component.startswith('.'):
|
63
|
+
raise ValueError(f"Path component cannot start with dot: {component}")
|
64
|
+
if component.endswith('.lock'):
|
65
|
+
raise ValueError(f"Path component cannot end with '.lock': {component}")
|
66
|
+
else:
|
67
|
+
# Single component (no slashes)
|
68
|
+
if result.startswith('.'):
|
69
|
+
raise ValueError(f"Reference cannot start with dot: {result}")
|
70
|
+
if result.endswith('.lock'):
|
71
|
+
raise ValueError(f"Reference cannot end with '.lock': {result}")
|
72
|
+
|
73
|
+
return result
|
@@ -0,0 +1,17 @@
|
|
1
|
+
from osbot_utils.type_safe.primitives.safe_str.git.Safe_Str__Git__Ref_Base import Safe_Str__Git__Ref_Base
|
2
|
+
|
3
|
+
class Safe_Str__Git__Tag(Safe_Str__Git__Ref_Base):
|
4
|
+
"""
|
5
|
+
Safe string class for GitHub tag names.
|
6
|
+
|
7
|
+
Follows git-check-ref-format rules for tags.
|
8
|
+
Tags have the same rules as general Git references.
|
9
|
+
|
10
|
+
Examples:
|
11
|
+
- "v1.0.0", "v2.3.4"
|
12
|
+
- "release-1.0.0"
|
13
|
+
- "2024.01.15"
|
14
|
+
- "stable", "latest"
|
15
|
+
"""
|
16
|
+
pass
|
17
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import re
|
2
|
-
from osbot_utils.
|
3
|
-
from osbot_utils.
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
3
|
+
from osbot_utils.type_safe.primitives.safe_str.Enum__Safe_Str__Regex_Mode import Enum__Safe_Str__Regex_Mode
|
4
4
|
|
5
5
|
TYPE_SAFE_STR__VERSION__REGEX = re.compile(r'^v(\d{1,3})\.(\d{1,3})\.(\d{1,3})$') # Regex to match versions like v0.1.1 or v999.999.999
|
6
6
|
TYPE_SAFE_STR__VERSION__MAX_LENGTH = 12 # Max length for 'v999.999.999'
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import re
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
3
|
+
from osbot_utils.type_safe.primitives.safe_str.github.Safe_Str__GitHub__Repo_Name import Safe_Str__GitHub__Repo_Name
|
4
|
+
from osbot_utils.type_safe.primitives.safe_str.github.Safe_Str__GitHub__Repo_Owner import Safe_Str__GitHub__Repo_Owner
|
5
|
+
|
6
|
+
TYPE_SAFE_STR__GITHUB__REPO__REGEX = re.compile(r'[^a-zA-Z0-9\-_./]')
|
7
|
+
TYPE_SAFE_STR__GITHUB__REPO__MAX_LENGTH = 140 # 39 (owner) + 1 (/) + 100 (repo)
|
8
|
+
|
9
|
+
class Safe_Str__GitHub__Repo(Safe_Str):
|
10
|
+
"""
|
11
|
+
Safe string class for full GitHub repository identifiers in owner/repo format.
|
12
|
+
|
13
|
+
Examples:
|
14
|
+
- "octocat/Hello-World"
|
15
|
+
- "microsoft/vscode"
|
16
|
+
- "owasp-sbot/OSBot-Utils"
|
17
|
+
|
18
|
+
This class leverages Safe_Str__GitHub__Repo_Owner and Safe_Str__GitHub__Repo_Name
|
19
|
+
for validation of the individual components.
|
20
|
+
"""
|
21
|
+
regex = TYPE_SAFE_STR__GITHUB__REPO__REGEX
|
22
|
+
max_length = TYPE_SAFE_STR__GITHUB__REPO__MAX_LENGTH
|
23
|
+
allow_empty = False
|
24
|
+
trim_whitespace = True
|
25
|
+
allow_all_replacement_char = False
|
26
|
+
repo_owner : Safe_Str__GitHub__Repo_Owner = None # note: due to the str override these will not show in the Pycharm code hints (but they will work)
|
27
|
+
repo_name : Safe_Str__GitHub__Repo_Name = None
|
28
|
+
|
29
|
+
def __new__(cls, value=None):
|
30
|
+
result = super().__new__(cls, value)
|
31
|
+
|
32
|
+
if result:
|
33
|
+
if '/' not in result: # Check for the required forward slash
|
34
|
+
raise ValueError(f"GitHub repository must be in 'owner/repo' format: {result}")
|
35
|
+
|
36
|
+
|
37
|
+
parts = result.split('/') # Split and validate components using the dedicated classes
|
38
|
+
if len(parts) != 2:
|
39
|
+
raise ValueError(f"GitHub repository must be in 'owner/repo' format: {result}")
|
40
|
+
|
41
|
+
owner_part, repo_part = parts
|
42
|
+
|
43
|
+
result.repo_owner = Safe_Str__GitHub__Repo_Owner(owner_part) # Validate using the dedicated classes (and store the references)
|
44
|
+
result.repo_name = Safe_Str__GitHub__Repo_Name(repo_part ) # This will raise appropriate errors if validation fails
|
45
|
+
|
46
|
+
return result
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import re
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
3
|
+
|
4
|
+
TYPE_SAFE_STR__GITHUB__REPO_NAME__REGEX = re.compile(r'[^a-zA-Z0-9\-_.]')
|
5
|
+
TYPE_SAFE_STR__GITHUB__REPO_NAME__MAX_LENGTH = 100
|
6
|
+
|
7
|
+
class Safe_Str__GitHub__Repo_Name(Safe_Str):
|
8
|
+
"""
|
9
|
+
Safe string class for GitHub repository names.
|
10
|
+
|
11
|
+
GitHub repository name rules:
|
12
|
+
- May contain alphanumeric characters, hyphens, underscores, and periods
|
13
|
+
- Maximum length of 100 characters
|
14
|
+
- Cannot be empty
|
15
|
+
"""
|
16
|
+
regex = TYPE_SAFE_STR__GITHUB__REPO_NAME__REGEX
|
17
|
+
max_length = TYPE_SAFE_STR__GITHUB__REPO_NAME__MAX_LENGTH
|
18
|
+
allow_empty = False
|
19
|
+
trim_whitespace = True
|
20
|
+
allow_all_replacement_char = False
|
21
|
+
|
22
|
+
def __new__(cls, value=None):
|
23
|
+
result = super().__new__(cls, value)
|
24
|
+
|
25
|
+
# Additional validation
|
26
|
+
if result:
|
27
|
+
# Check if it's just periods (reserved names)
|
28
|
+
if result in ['.', '..']:
|
29
|
+
raise ValueError(f"Invalid repository name: {result}")
|
30
|
+
|
31
|
+
# Check for all replacement characters
|
32
|
+
if set(result) == {'_'} and len(result) > 0:
|
33
|
+
raise ValueError(f"Invalid repository name: {result}")
|
34
|
+
|
35
|
+
return result
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import re
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
3
|
+
|
4
|
+
TYPE_SAFE_STR__GITHUB__REPO_OWNER__REGEX = re.compile(r'[^a-zA-Z0-9\-]')
|
5
|
+
TYPE_SAFE_STR__GITHUB__REPO_OWNER__MAX_LENGTH = 39
|
6
|
+
|
7
|
+
class Safe_Str__GitHub__Repo_Owner(Safe_Str):
|
8
|
+
"""
|
9
|
+
Safe string class for GitHub repository owners (users or organizations).
|
10
|
+
|
11
|
+
GitHub username/organization rules:
|
12
|
+
- May only contain alphanumeric characters or hyphens
|
13
|
+
- Cannot have multiple consecutive hyphens
|
14
|
+
- Cannot begin or end with a hyphen
|
15
|
+
- Maximum length of 39 characters
|
16
|
+
"""
|
17
|
+
regex = TYPE_SAFE_STR__GITHUB__REPO_OWNER__REGEX
|
18
|
+
max_length = TYPE_SAFE_STR__GITHUB__REPO_OWNER__MAX_LENGTH
|
19
|
+
allow_empty = False
|
20
|
+
trim_whitespace = True
|
21
|
+
allow_all_replacement_char = False
|
22
|
+
|
23
|
+
def __new__(cls, value=None):
|
24
|
+
result = super().__new__(cls, value)
|
25
|
+
|
26
|
+
|
27
|
+
if result: # Additional GitHub-specific validation
|
28
|
+
if result.startswith('-') or result.endswith('-'): # Check for leading/trailing hyphens
|
29
|
+
raise ValueError(f"GitHub owner name cannot start or end with a hyphen: {result}")
|
30
|
+
|
31
|
+
if '--' in result: # Check for consecutive hyphens
|
32
|
+
raise ValueError(f"GitHub owner name cannot contain consecutive hyphens: {result}")
|
33
|
+
|
34
|
+
if result.replace('_', '') == '': # Check for all underscores (sanitized invalid input)
|
35
|
+
raise ValueError(f"Invalid GitHub owner name: {result}")
|
36
|
+
|
37
|
+
return result
|
38
|
+
|
39
|
+
|
File without changes
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import re
|
2
|
-
from osbot_utils.
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
3
3
|
|
4
4
|
TYPE_SAFE_STR__HTTP__CONTENT_TYPE__REGEX = re.compile(r'[^a-zA-Z0-9/\-+.;= ]')
|
5
5
|
TYPE_SAFE_STR__HTTP__CONTENT_TYPE__MAX_LENGTH = 256
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import re
|
2
|
-
from osbot_utils.
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
3
3
|
|
4
4
|
TYPE_SAFE_STR__HTTP__ETAG__REGEX = re.compile(r'[^a-zA-Z0-9"\/\-_.:]') # Allow alphanumerics, quotes, slashes, hyphens, underscores, periods, colons
|
5
5
|
TYPE_SAFE_STR__HTTP__ETAG__MAX_LENGTH = 128
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import re
|
2
|
-
from osbot_utils.
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
3
3
|
|
4
4
|
TYPE_SAFE_STR__HTTP__LAST_MODIFIED__REGEX = re.compile(r'[^a-zA-Z0-9:, -]')
|
5
5
|
TYPE_SAFE_STR__HTTP__LAST_MODIFIED__MAX_LENGTH = 64
|
File without changes
|
@@ -1,9 +1,10 @@
|
|
1
1
|
import uuid
|
2
|
-
from osbot_utils.
|
2
|
+
from osbot_utils.type_safe.Type_Safe__Primitive import Type_Safe__Primitive
|
3
|
+
from osbot_utils.utils.Misc import is_guid
|
3
4
|
|
4
5
|
GUID__NAMESPACE = uuid.UUID('2cfec064-537a-4ff7-8fdc-2fc9e2606f3d')
|
5
6
|
|
6
|
-
class Guid(str):
|
7
|
+
class Guid(Type_Safe__Primitive, str):
|
7
8
|
def __new__(cls, value: str):
|
8
9
|
if not isinstance(value, str): # Check if the value is a string
|
9
10
|
raise ValueError(f'in Guid: value provided was not a string: {value}') # if not raise a ValueError
|
File without changes
|
osbot_utils/{helpers/safe_str → type_safe/primitives/safe_str/text}/Safe_Str__Text__Dangerous.py
RENAMED
@@ -1,5 +1,5 @@
|
|
1
1
|
import re
|
2
|
-
from osbot_utils.
|
2
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
3
3
|
|
4
4
|
TYPE_SAFE_STR__TEXT__DANGEROUS__MAX_LENGTH = 65536
|
5
5
|
TYPE_SAFE_STR__TEXT__DANGEROUS__REGEX = r'[^a-zA-Z0-9_\s!@#$%^&*()\[\]{}\-+=:;,.?"/\\<>\']'
|
File without changes
|
@@ -1,6 +1,6 @@
|
|
1
1
|
|
2
2
|
import re
|
3
|
-
from osbot_utils.
|
3
|
+
from osbot_utils.type_safe.primitives.safe_str.Safe_Str import Safe_Str
|
4
4
|
|
5
5
|
TYPE_SAFE_STR__URL__MAX_LENGTH = 2048 # Common maximum URL length
|
6
6
|
TYPE_SAFE_STR__URL__REGEX = re.compile(r'^(?!https?://).*|[^a-zA-Z0-9:/\-._~&=?#+%@]') # Allow characters valid in URLs
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,6 +1,7 @@
|
|
1
|
-
from typing
|
2
|
-
from osbot_utils.type_safe.
|
3
|
-
from osbot_utils.type_safe.
|
1
|
+
from typing import Type
|
2
|
+
from osbot_utils.type_safe.Type_Safe__Base import Type_Safe__Base
|
3
|
+
from osbot_utils.type_safe.type_safe_core.collections.Type_Safe__List import Type_Safe__List
|
4
|
+
|
4
5
|
|
5
6
|
class Type_Safe__Dict(Type_Safe__Base, dict):
|
6
7
|
def __init__(self, expected_key_type, expected_value_type, *args, **kwargs):
|
File without changes
|
File without changes
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import functools # For wrapping functions
|
2
|
-
from osbot_utils.type_safe.Type_Safe__Method import Type_Safe__Method
|
2
|
+
from osbot_utils.type_safe.type_safe_core.methods.Type_Safe__Method import Type_Safe__Method
|
3
|
+
|
3
4
|
|
4
5
|
def type_safe(func): # Main decorator function
|
5
6
|
type_checker = Type_Safe__Method(func) # Create type checker instance
|
@@ -1,8 +1,7 @@
|
|
1
|
-
import inspect
|
2
|
-
from enum
|
3
|
-
from typing
|
4
|
-
|
5
|
-
from osbot_utils.type_safe.shared.Type_Safe__Shared__Variables import IMMUTABLE_TYPES
|
1
|
+
import inspect # For function introspection
|
2
|
+
from enum import Enum
|
3
|
+
from typing import get_args, get_origin, Union, List, Any, Dict # For type hinting utilities
|
4
|
+
from osbot_utils.type_safe.type_safe_core.shared.Type_Safe__Shared__Variables import IMMUTABLE_TYPES
|
6
5
|
|
7
6
|
|
8
7
|
class Type_Safe__Method: # Class to handle method type safety validation
|
File without changes
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import inspect
|
2
|
-
from weakref
|
3
|
-
from osbot_utils.type_safe.shared.Type_Safe__Not_Cached
|
4
|
-
from osbot_utils.type_safe.shared.Type_Safe__Shared__Variables
|
2
|
+
from weakref import WeakKeyDictionary
|
3
|
+
from osbot_utils.type_safe.type_safe_core.shared.Type_Safe__Not_Cached import type_safe_not_cached
|
4
|
+
from osbot_utils.type_safe.type_safe_core.shared.Type_Safe__Shared__Variables import IMMUTABLE_TYPES
|
5
5
|
|
6
6
|
|
7
7
|
class Type_Safe__Cache:
|
@@ -1,6 +1,6 @@
|
|
1
|
-
from typing
|
2
|
-
from osbot_utils.type_safe.shared.Type_Safe__Cache
|
3
|
-
from osbot_utils.utils.Objects
|
1
|
+
from typing import get_args
|
2
|
+
from osbot_utils.type_safe.type_safe_core.shared.Type_Safe__Cache import type_safe_cache
|
3
|
+
from osbot_utils.utils.Objects import base_classes_names
|
4
4
|
|
5
5
|
|
6
6
|
class Type_Safe__Convert:
|
@@ -1,9 +1,9 @@
|
|
1
|
-
from typing
|
2
|
-
from osbot_utils.type_safe.Type_Safe__Base
|
3
|
-
from osbot_utils.type_safe.Type_Safe
|
4
|
-
from osbot_utils.type_safe.shared.Type_Safe__Cache
|
5
|
-
from osbot_utils.type_safe.shared.Type_Safe__Json_Compressor__Type_Registry
|
6
|
-
from osbot_utils.utils.Objects
|
1
|
+
from typing import Dict, Any, Type
|
2
|
+
from osbot_utils.type_safe.Type_Safe__Base import Type_Safe__Base
|
3
|
+
from osbot_utils.type_safe.Type_Safe import Type_Safe
|
4
|
+
from osbot_utils.type_safe.type_safe_core.shared.Type_Safe__Cache import type_safe_cache
|
5
|
+
from osbot_utils.type_safe.type_safe_core.shared.Type_Safe__Json_Compressor__Type_Registry import Type_Safe__Json_Compressor__Type_Registry
|
6
|
+
from osbot_utils.utils.Objects import class_full_name
|
7
7
|
|
8
8
|
class Type_Safe__Json_Compressor(Type_Safe__Base):
|
9
9
|
|
@@ -2,13 +2,14 @@ import collections
|
|
2
2
|
import inspect
|
3
3
|
import types
|
4
4
|
import typing
|
5
|
-
from enum
|
6
|
-
from typing
|
7
|
-
from osbot_utils.type_safe.Type_Safe__Primitive
|
8
|
-
from osbot_utils.type_safe.shared.Type_Safe__Annotations import type_safe_annotations
|
9
|
-
from osbot_utils.type_safe.shared.Type_Safe__Cache import type_safe_cache
|
10
|
-
from osbot_utils.type_safe.shared.
|
11
|
-
from osbot_utils.type_safe.shared.
|
5
|
+
from enum import EnumMeta
|
6
|
+
from typing import Any, Annotated, Optional, get_args, get_origin, ForwardRef, Type, Dict, _GenericAlias
|
7
|
+
from osbot_utils.type_safe.Type_Safe__Primitive import Type_Safe__Primitive
|
8
|
+
from osbot_utils.type_safe.type_safe_core.shared.Type_Safe__Annotations import type_safe_annotations
|
9
|
+
from osbot_utils.type_safe.type_safe_core.shared.Type_Safe__Cache import type_safe_cache
|
10
|
+
from osbot_utils.type_safe.type_safe_core.shared.Type_Safe__Raise_Exception import type_safe_raise_exception
|
11
|
+
from osbot_utils.type_safe.type_safe_core.shared.Type_Safe__Shared__Variables import IMMUTABLE_TYPES
|
12
|
+
|
12
13
|
|
13
14
|
class Type_Safe__Validation:
|
14
15
|
|