osbot-utils 2.68.0__py3-none-any.whl → 2.70.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.
@@ -1,5 +1,6 @@
1
1
  from typing import Dict, Any, Type
2
2
  from osbot_utils.helpers.llms.actions.Type_Safe__Schema_For__LLMs import Type_Safe__Schema_For__LLMs
3
+ from osbot_utils.helpers.llms.schemas.Safe_Str__LLM__Model_Name import Safe_Str__LLM__Model_Name
3
4
  from osbot_utils.helpers.llms.schemas.Schema__LLM_Request import Schema__LLM_Request
4
5
  from osbot_utils.helpers.llms.schemas.Schema__LLM_Request__Data import Schema__LLM_Request__Data
5
6
  from osbot_utils.helpers.llms.schemas.Schema__LLM_Request__Function_Call import Schema__LLM_Request__Function_Call
@@ -40,14 +41,14 @@ class LLM_Request__Builder(Type_Safe):
40
41
  self.llm_request_data.function_call = function_call
41
42
  return self
42
43
 
43
- def set__model (self, model : Safe_Str__Text): self.llm_request_data.model = model ; return self
44
- def set__platform (self, platform: Safe_Str__Text): self.llm_request_data.platform = platform; return self
45
- def set__provider (self, provider: Safe_Str__Text): self.llm_request_data.provider = provider; return self
46
- def set__model__gpt_4o (self ): return self.set__model('gpt-4o' )
47
- def set__model__gpt_4o_mini (self ): return self.set__model('gpt-4o-mini' )
48
- def set__model__gpt_4_1 (self ): return self.set__model('gpt-4.1' )
49
- def set__model__gpt_4_1_mini(self ): return self.set__model('gpt-4.1-mini')
50
- def set__model__gpt_4_1_nano(self ): return self.set__model('gpt-4.1-nano')
44
+ def set__model (self, model : Safe_Str__LLM__Model_Name): self.llm_request_data.model = model ; return self
45
+ def set__platform (self, platform: Safe_Str__Text ): self.llm_request_data.platform = platform; return self
46
+ def set__provider (self, provider: Safe_Str__Text ): self.llm_request_data.provider = provider; return self
47
+ def set__model__gpt_4o (self ): return self.set__model('gpt-4o' )
48
+ def set__model__gpt_4o_mini (self ): return self.set__model('gpt-4o-mini' )
49
+ def set__model__gpt_4_1 (self ): return self.set__model('gpt-4.1' )
50
+ def set__model__gpt_4_1_mini(self ): return self.set__model('gpt-4.1-mini')
51
+ def set__model__gpt_4_1_nano(self ): return self.set__model('gpt-4.1-nano')
51
52
 
52
53
 
53
54
  @type_safe
@@ -0,0 +1,10 @@
1
+ import re
2
+
3
+ from osbot_utils.helpers.safe_str.Safe_Str import Safe_Str
4
+
5
+ TYPE_SAFE_STR__LLM__MODEL_NAME__MAX_LENGTH = 256
6
+ TYPE_SAFE_STR__LLM__MODEL_NAME__REGEX = r'[^a-zA-Z0-9/_\-.:]'
7
+
8
+ class Safe_Str__LLM__Model_Name(Safe_Str):
9
+ regex = re.compile(TYPE_SAFE_STR__LLM__MODEL_NAME__REGEX)
10
+ max_length = TYPE_SAFE_STR__LLM__MODEL_NAME__MAX_LENGTH
@@ -1,11 +1,12 @@
1
1
  from typing import List, Optional
2
+ from osbot_utils.helpers.llms.schemas.Safe_Str__LLM__Model_Name import Safe_Str__LLM__Model_Name
2
3
  from osbot_utils.helpers.llms.schemas.Schema__LLM_Request__Function_Call import Schema__LLM_Request__Function_Call
3
4
  from osbot_utils.helpers.llms.schemas.Schema__LLM_Request__Message__Content import Schema__LLM_Request__Message__Content
4
5
  from osbot_utils.helpers.safe_str.Safe_Str__Text import Safe_Str__Text
5
6
  from osbot_utils.type_safe.Type_Safe import Type_Safe
6
7
 
7
8
  class Schema__LLM_Request__Data(Type_Safe): # Schema for LLM API request data
8
- model : Safe_Str__Text # LLM model identifier
9
+ model : Safe_Str__LLM__Model_Name # LLM model identifier
9
10
  platform : Safe_Str__Text
10
11
  provider : Safe_Str__Text
11
12
  messages : List [Schema__LLM_Request__Message__Content] # Message content entries
@@ -1,8 +1,10 @@
1
1
  import re
2
2
  from osbot_utils.helpers.safe_str.Safe_Str import Safe_Str
3
3
 
4
+ TYPE_SAFE_STR__FILE__NAME__REGEX = re.compile(r'[^a-zA-Z0-9_\-. ]')
5
+
4
6
  class Safe_Str__File__Name(Safe_Str):
5
- regex = re.compile(r'[^a-zA-Z0-9_\-. ]')
7
+ regex = TYPE_SAFE_STR__FILE__NAME__REGEX
6
8
  allow_empty = False
7
9
  trim_whitespace = True
8
10
  allow_all_replacement_char = False
@@ -29,6 +29,12 @@ class Type_Safe__Primitive:
29
29
  return super().__eq__(other)
30
30
  return False # Different types → not equal
31
31
 
32
+ def __enter__(self): # support context manager
33
+ return self
34
+
35
+ def __exit__(self, exc_type, exc_val, exc_tb):
36
+ return
37
+
32
38
  def __ne__(self, other):
33
39
  return not self.__eq__(other)
34
40
 
@@ -1,5 +1,8 @@
1
1
  import os
2
- from typing import Union
2
+ from typing import Union, List
3
+
4
+ from osbot_utils.helpers.safe_str.Safe_Str__File__Path import Safe_Str__File__Path
5
+
3
6
 
4
7
  class Files:
5
8
  @staticmethod
@@ -72,16 +75,25 @@ class Files:
72
75
  return glob.glob(path_pattern, recursive=recursive)
73
76
 
74
77
  @staticmethod
75
- def files(path, pattern= '*', only_files=True):
78
+ def files(path, pattern= '*', only_files=True, include_path=True) -> List[Safe_Str__File__Path]:
79
+
76
80
  from pathlib import Path
77
81
 
78
- result = []
82
+ result = []
79
83
  for file in Path(path).rglob(pattern):
80
84
  if only_files and is_not_file(file):
81
85
  continue
82
- result.append(str(file)) # todo: see if there is a better way to do this conversion to string
86
+ file_path = file.as_posix()
87
+ if include_path is False:
88
+ file_path = str(file.relative_to(path))
89
+ result.append(Safe_Str__File__Path(file_path))
90
+
83
91
  return sorted(result)
84
92
 
93
+ @staticmethod
94
+ def files__virtual_paths(path, pattern='*', only_files=True):
95
+ return Files.files(path, pattern=pattern, only_files=only_files, include_path=False)
96
+
85
97
  @staticmethod
86
98
  def files_names(files : list, check_if_exists=True):
87
99
  result = []
@@ -628,6 +640,7 @@ filter_parent_folder = Files.filter_parent_folder
628
640
  files_find = Files.find
629
641
  files_recursive = Files.files_recursive
630
642
  files_list = Files.files
643
+ files_list__virtual_paths = Files.files__virtual_paths
631
644
  files_names = Files.files_names
632
645
 
633
646
  find_files = Files.files
osbot_utils/utils/Zip.py CHANGED
@@ -79,6 +79,8 @@ def zip_bytes__add_files(zip_bytes, files_to_add):
79
79
  file_contents = file_contents.encode('utf-8')
80
80
  elif not isinstance(file_contents, bytes):
81
81
  continue
82
+ if file_path.startswith(('/', '\\')): # Strip leading slash or backslash to make the path relative
83
+ file_path = file_path.lstrip('/\\')
82
84
  zf.writestr(file_path, file_contents)
83
85
 
84
86
  return zip_buffer.getvalue()
@@ -135,7 +137,7 @@ def zip_bytes__replace_files(zip_bytes, files_to_replace):
135
137
  def zip_bytes__unzip(zip_bytes, target_folder=None):
136
138
  target_folder = target_folder or temp_folder() # Use the provided target folder or create a temporary one
137
139
  zip_buffer = io.BytesIO(zip_bytes) # Create a BytesIO buffer from the zip bytes
138
- with zipfile.ZipFile(zip_buffer, 'r') as zf: # Open the zip file from the buffer
140
+ with zipfile.ZipFile(zip_buffer, 'r') as zf: # Open the zip file from the buffer
139
141
  zf.extractall(target_folder) # Extract all files to the target folder
140
142
  return target_folder # Return the path of the target folder
141
143
 
@@ -200,16 +202,18 @@ def zip_folder_to_file (root_dir, target_file):
200
202
  zip_file = zip_folder(root_dir)
201
203
  return file_move(zip_file, target_file)
202
204
 
203
- def zip_folder_to_bytes(root_dir): # todo add unit test
205
+ def zip_folder_to_bytes(root_dir, files_to_ignore:list=None): # todo add unit test
204
206
  zip_buffer = io.BytesIO() # Create a BytesIO buffer to hold the zipped file
205
207
  with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zf: # Create a ZipFile object with the buffer as the target
206
208
  for foldername, subfolders, filenames in os.walk(root_dir): # Walk the root_dir and add all files and folders to the zip file
207
209
  for filename in filenames:
210
+ if files_to_ignore and filename in files_to_ignore:
211
+ continue
208
212
  absolute_path = os.path.join(foldername, filename) # Create the complete filepath
209
213
  arcname = os.path.relpath(absolute_path, root_dir) # Define the arcname, which is the name inside the zip file
210
214
  zf.write(absolute_path, arcname) # Add the file to the zip file
211
215
  zip_buffer.seek(0) # Reset buffer position
212
- return zip_buffer
216
+ return zip_buffer.getvalue()
213
217
 
214
218
  def zip_files(base_folder, file_pattern="*.*", target_file=None):
215
219
  base_folder = abspath(base_folder)
osbot_utils/version CHANGED
@@ -1 +1 @@
1
- v2.68.0
1
+ v2.70.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: osbot_utils
3
- Version: 2.68.0
3
+ Version: 2.70.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.68.0-blue)
26
+ ![Current Release](https://img.shields.io/badge/release-v2.70.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
 
@@ -208,7 +208,7 @@ osbot_utils/helpers/llms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
208
208
  osbot_utils/helpers/llms/actions/LLM_Request__Execute.py,sha256=IsC5gzQXG__j5M2dSWVCmV77Kf133pKbZRvbiQyeihU,2453
209
209
  osbot_utils/helpers/llms/actions/Type_Safe__Schema_For__LLMs.py,sha256=em9RoSZqSSo6BQBZvEKH8Qv8f8f8oubNpy0LIDsak-E,12024
210
210
  osbot_utils/helpers/llms/actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
211
- osbot_utils/helpers/llms/builders/LLM_Request__Builder.py,sha256=2Zp4Ka4q2XcZNUuR47kP7iyhfLsY2A_rxOME3i6olgE,3811
211
+ osbot_utils/helpers/llms/builders/LLM_Request__Builder.py,sha256=d9TnJmA1KbEypvCdgFXWcg684n-TGIrumxigsTOMECE,4008
212
212
  osbot_utils/helpers/llms/builders/LLM_Request__Builder__Open_AI.py,sha256=JwyPDeBUQd70Ltm801y5qvS883IIC7TcfG04D3LWdGI,3430
213
213
  osbot_utils/helpers/llms/builders/LLM_Request__Factory.py,sha256=bpFXVTKpalBL7ZONjaHU5c0-2Rwzzd2vgdD1FpYxfGw,6291
214
214
  osbot_utils/helpers/llms/builders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -222,9 +222,10 @@ osbot_utils/helpers/llms/cache/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
222
222
  osbot_utils/helpers/llms/platforms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
223
223
  osbot_utils/helpers/llms/platforms/open_ai/API__LLM__Open_AI.py,sha256=Yyy2ZnIS6CfxXepP9pZNsOYx02d-5EnK1IFeFf8myyk,2148
224
224
  osbot_utils/helpers/llms/platforms/open_ai/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
225
+ osbot_utils/helpers/llms/schemas/Safe_Str__LLM__Model_Name.py,sha256=AKLfBv65ELl6XvSsLKMVS-y9LefSVNf8GNrEWKVd_TY,358
225
226
  osbot_utils/helpers/llms/schemas/Schema__LLM_Cache__Index.py,sha256=12dUUSFhWRZvqEkNivqajqMPApPWhfSI7jWnHyBuxNw,717
226
227
  osbot_utils/helpers/llms/schemas/Schema__LLM_Request.py,sha256=UUiqZQ5mj16SPdlzef7_j3myLaKKCZdAUjsWUJnK1Ag,378
227
- osbot_utils/helpers/llms/schemas/Schema__LLM_Request__Data.py,sha256=EpII6ZMkWACkoHYn-TNowppbIskyoaCovefPA5Q5qtA,1380
228
+ osbot_utils/helpers/llms/schemas/Schema__LLM_Request__Data.py,sha256=oLrvmngkDVX2KB2gVR1DwvJQcxWMbBxomjs_IBFQtzc,1489
228
229
  osbot_utils/helpers/llms/schemas/Schema__LLM_Request__Function_Call.py,sha256=VJgWi4aK-DJmuJvfY2qZUZuLkrLlmu5lgyzxZrrp3hM,440
229
230
  osbot_utils/helpers/llms/schemas/Schema__LLM_Request__Message__Content.py,sha256=nl-16yz4G_72ViACKE9CvGStrKxw2Gm_JcaU8wVcJXI,521
230
231
  osbot_utils/helpers/llms/schemas/Schema__LLM_Request__Message__Role.py,sha256=T99w0cRrDPXQqPT-Nw7_14tMr4vKpUlhw74UJZL6w6w,168
@@ -261,7 +262,7 @@ osbot_utils/helpers/safe_int/Safe_UInt__Percentage.py,sha256=Ck-jiu6NK57Y3ruAjIJ
261
262
  osbot_utils/helpers/safe_int/Safe_UInt__Port.py,sha256=uISrh8VKXiEQULQ1POU9YK8Di6z_vr0HWjCTpjA0YaY,482
262
263
  osbot_utils/helpers/safe_int/__init__.py,sha256=kMU2WMsdQmayBEZugxnJV_wRW3O90bc118sx6iIm_mQ,310
263
264
  osbot_utils/helpers/safe_str/Safe_Str.py,sha256=qR2RDh5cehP_wDDeV5TQahNBwmfcizPFyStALBKD5dw,3509
264
- osbot_utils/helpers/safe_str/Safe_Str__File__Name.py,sha256=ncjkQ2hAhw0a3UulrCuQsA9ytrFwg5CT1XRJIGChMpY,289
265
+ osbot_utils/helpers/safe_str/Safe_Str__File__Name.py,sha256=9Evl4P45GCyyR2ywze29GzmqWhyTCcgI-o2CItMsOHo,358
265
266
  osbot_utils/helpers/safe_str/Safe_Str__File__Path.py,sha256=K0yBcvH_Ncqiw7tMqjGqaNyWQh1Zs9qxZ-TR8nEIAow,550
266
267
  osbot_utils/helpers/safe_str/Safe_Str__Hash.py,sha256=IpYdYwXey5WZWa6QfysmsiDP-4L-wP-_EKbkeXhFRH4,1252
267
268
  osbot_utils/helpers/safe_str/Safe_Str__Text.py,sha256=QxuWqF8hNYdOPDn3Yac86h_1ZaX-THbTBDakberiJcs,313
@@ -376,7 +377,7 @@ osbot_utils/type_safe/Type_Safe__Base.py,sha256=UTMipTL6mXoetAEUCI5hs8RqXp4NDYOv
376
377
  osbot_utils/type_safe/Type_Safe__Dict.py,sha256=QB200L5eNWT3FnUv8sm5kncj1wXJsJ9uRycNFl9xb6Y,3077
377
378
  osbot_utils/type_safe/Type_Safe__List.py,sha256=y_lp7Ai0HfQCqC8Bxn0g6_M9MP5lPOXy5Dhkuj2fJvQ,1891
378
379
  osbot_utils/type_safe/Type_Safe__Method.py,sha256=K100jAq1wmskuXcTd_9vt-XodSKJkDowJselmnDFCN8,16643
379
- osbot_utils/type_safe/Type_Safe__Primitive.py,sha256=CJ4LP2W5i9utSSzuiiJrwqvwdMv1DeQ6dIZICtYfLTY,3635
380
+ osbot_utils/type_safe/Type_Safe__Primitive.py,sha256=-GBUcuFBBBKrVRSf7cmjPRbAxo7vnL4tOvr9ktmbVj4,3829
380
381
  osbot_utils/type_safe/Type_Safe__Set.py,sha256=j12fc8cbd9-s_a13ysaz723rNEW4Dt6hObCd0S-AjIg,1432
381
382
  osbot_utils/type_safe/Type_Safe__Tuple.py,sha256=Kx7C4YfHybRbMmVMcmV6yFLi4T48pb592vEZfjjyLxo,1710
382
383
  osbot_utils/type_safe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -413,7 +414,7 @@ osbot_utils/utils/Csv.py,sha256=oHLVpjRJqrLMz9lubMCNEoThXWju5rNTprcwHc1zq2c,1012
413
414
  osbot_utils/utils/Dev.py,sha256=eaQ87ZcMRRcxgzA-f7OO8HjjWhbE6L_edwvXiwFZvIQ,1291
414
415
  osbot_utils/utils/Env.py,sha256=rBksAy6k-J5oAJp-S_JedVlcj1b2VK8V3zsQbacopMc,6076
415
416
  osbot_utils/utils/Exceptions.py,sha256=KyOUHkXQ_6jDTq04Xm261dbEZuRidtsM4dgzNwSG8-8,389
416
- osbot_utils/utils/Files.py,sha256=YwfXMeU1jfDzYvZJGy0bWHvvduTuTnftBNlAnpsXDzw,23013
417
+ osbot_utils/utils/Files.py,sha256=Zg8TV8RpKv3ytnZvvT17DWeEJCisSkO8zzyP_Twhcww,23449
417
418
  osbot_utils/utils/Functions.py,sha256=VoTrAbCHt6hulz6hVz3co8w2xoOS8wE04wyHc5_cC1c,3671
418
419
  osbot_utils/utils/Http.py,sha256=pLDwq0Jd4Zmpps0gEzXTbeycSFRXMN8W-DprNpYq9A0,8189
419
420
  osbot_utils/utils/Int.py,sha256=PmlUdU4lSwf4gJdmTVdqclulkEp7KPCVUDO6AcISMF4,116
@@ -431,10 +432,10 @@ osbot_utils/utils/Str.py,sha256=KQVfh0o3BxJKVm24yhAhgIGH5QYfzpP1G-siVv2zQws,3301
431
432
  osbot_utils/utils/Threads.py,sha256=YI1T382AtJpHVsa-BK7SycmEYhnkqHIiYyK_5HSmUtw,4329
432
433
  osbot_utils/utils/Toml.py,sha256=Rxl8gx7mni5CvBAK-Ai02EKw-GwtJdd3yeHT2kMloik,1667
433
434
  osbot_utils/utils/Version.py,sha256=Ww6ChwTxqp1QAcxOnztkTicShlcx6fbNsWX5xausHrg,422
434
- osbot_utils/utils/Zip.py,sha256=pR6sKliUY0KZXmqNzKY2frfW-YVQEVbLKiyqQX_lc-8,14052
435
+ osbot_utils/utils/Zip.py,sha256=mG42lgTY0tnm14T3P1-DSAIZKkTiYoO3odZ1aOUdc1I,14394
435
436
  osbot_utils/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
436
- osbot_utils/version,sha256=tz0YZbPbxI1MZny2uz5JYHas4qH1U1J4ERBX9mZthgM,8
437
- osbot_utils-2.68.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
438
- osbot_utils-2.68.0.dist-info/METADATA,sha256=PmGNC4TeAdIIv85WIzFoLzG2qgxZJF8qjytG1mVYNIY,1329
439
- osbot_utils-2.68.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
440
- osbot_utils-2.68.0.dist-info/RECORD,,
437
+ osbot_utils/version,sha256=0cHMv8cBSyT1AgEUuKq6G2WmqYGDEd5ktNMn-AhcMBI,8
438
+ osbot_utils-2.70.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
439
+ osbot_utils-2.70.0.dist-info/METADATA,sha256=-9hKyVUnDUX9X8z-OuMG0sETWVC4RPkILyfo93EC5fQ,1329
440
+ osbot_utils-2.70.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
441
+ osbot_utils-2.70.0.dist-info/RECORD,,