osbot-utils 2.78.0__py3-none-any.whl → 2.79.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/Dict_To_Attr.py +0 -3
- osbot_utils/helpers/transformers/Dict__To__Toml.py +211 -0
- osbot_utils/utils/Toml.py +7 -26
- osbot_utils/version +1 -1
- {osbot_utils-2.78.0.dist-info → osbot_utils-2.79.0.dist-info}/METADATA +2 -2
- {osbot_utils-2.78.0.dist-info → osbot_utils-2.79.0.dist-info}/RECORD +8 -7
- {osbot_utils-2.78.0.dist-info → osbot_utils-2.79.0.dist-info}/LICENSE +0 -0
- {osbot_utils-2.78.0.dist-info → osbot_utils-2.79.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,211 @@
|
|
1
|
+
from typing import Dict, Any, List, Set, Tuple, Union
|
2
|
+
from osbot_utils.type_safe.Type_Safe import Type_Safe
|
3
|
+
from osbot_utils.type_safe.type_safe_core.decorators.type_safe import type_safe
|
4
|
+
|
5
|
+
|
6
|
+
class Dict__To__Toml(Type_Safe):
|
7
|
+
|
8
|
+
@type_safe
|
9
|
+
def convert(self, data: Dict[str, Any] # Dictionary to convert to TOML
|
10
|
+
) -> str: # Returns TOML formatted string
|
11
|
+
toml_str = ""
|
12
|
+
|
13
|
+
# First, process top-level simple values
|
14
|
+
toml_str += self._process_simple_values(data, indent_level=0)
|
15
|
+
|
16
|
+
# Process top-level arrays of simple types
|
17
|
+
toml_str += self._process_simple_arrays(data, indent_level=0)
|
18
|
+
|
19
|
+
# Process top-level dictionaries as sections
|
20
|
+
toml_str += self._process_sections(data, parent_key="")
|
21
|
+
|
22
|
+
# Process arrays of tables
|
23
|
+
toml_str += self._process_array_of_tables(data, parent_key="")
|
24
|
+
|
25
|
+
return toml_str
|
26
|
+
|
27
|
+
@type_safe
|
28
|
+
def _format_string_value(self, value: str # String to format
|
29
|
+
) -> str: # Returns formatted TOML string
|
30
|
+
"""Format a string value for TOML output"""
|
31
|
+
# For TOML basic strings, we need to handle:
|
32
|
+
# 1. If string contains single quotes, use double quotes
|
33
|
+
# 2. If string contains double quotes but no single quotes, use single quotes
|
34
|
+
# 3. If string contains both, use triple quotes (multi-line literal)
|
35
|
+
|
36
|
+
has_single = "'" in value
|
37
|
+
has_double = '"' in value
|
38
|
+
has_newline = '\n' in value or '\r' in value
|
39
|
+
|
40
|
+
# Use triple quotes for complex strings (multilineelif has_single: or with both quote types)
|
41
|
+
if has_newline or (has_single and has_double):
|
42
|
+
# Use multi-line literal string (triple single quotes)
|
43
|
+
# This preserves the exact content without escaping
|
44
|
+
return f"'''\n{value}'''"
|
45
|
+
elif has_single:
|
46
|
+
# Use double quotes and escape any double quotes
|
47
|
+
escaped = value.replace('"', '\\"')
|
48
|
+
return f'"{escaped}"'
|
49
|
+
else:
|
50
|
+
# Use single quotes (default) - no escaping needed
|
51
|
+
return f"'{value}'"
|
52
|
+
|
53
|
+
@type_safe
|
54
|
+
def _process_simple_values(self, data : Dict[str, Any] , # Data to process
|
55
|
+
indent_level : int = 0 # Current indentation level
|
56
|
+
) -> str: # Returns TOML for simple values
|
57
|
+
toml_str = ""
|
58
|
+
indent = " " * indent_level
|
59
|
+
|
60
|
+
for key, value in data.items():
|
61
|
+
if not isinstance(value, (dict, list, tuple, set)):
|
62
|
+
if isinstance(value, str):
|
63
|
+
toml_str += f"{indent}{key} = {self._format_string_value(value)}\n"
|
64
|
+
elif isinstance(value, bool):
|
65
|
+
toml_str += f"{indent}{key} = {str(value).lower()}\n"
|
66
|
+
elif value is not None:
|
67
|
+
toml_str += f"{indent}{key} = {value}\n"
|
68
|
+
|
69
|
+
return toml_str
|
70
|
+
|
71
|
+
@type_safe
|
72
|
+
def _process_simple_arrays(self, data : Dict[str, Any] , # Data to process
|
73
|
+
indent_level : int = 0 # Current indentation level
|
74
|
+
) -> str: # Returns TOML for simple arrays
|
75
|
+
toml_str = ""
|
76
|
+
indent = " " * indent_level
|
77
|
+
|
78
|
+
for key, value in data.items():
|
79
|
+
if isinstance(value, (list, tuple, set)):
|
80
|
+
if not value: # Empty collection
|
81
|
+
toml_str += f"{indent}{key} = []\n"
|
82
|
+
elif not any(isinstance(item, dict) for item in value): # No dict items
|
83
|
+
toml_str += f"{indent}{key} = [\n"
|
84
|
+
for item in value:
|
85
|
+
if isinstance(item, str):
|
86
|
+
toml_str += f"{indent} {self._format_string_value(item)},\n"
|
87
|
+
elif isinstance(item, bool):
|
88
|
+
toml_str += f"{indent} {str(item).lower()},\n"
|
89
|
+
elif item is not None:
|
90
|
+
toml_str += f"{indent} {item},\n"
|
91
|
+
toml_str += f"{indent}]\n"
|
92
|
+
|
93
|
+
return toml_str
|
94
|
+
|
95
|
+
@type_safe
|
96
|
+
def _process_sections(self, data : Dict[str, Any] , # Data to process
|
97
|
+
parent_key : str = "" # Parent section key
|
98
|
+
) -> str: # Returns TOML sections
|
99
|
+
toml_str = ""
|
100
|
+
|
101
|
+
for key, value in data.items():
|
102
|
+
if isinstance(value, dict):
|
103
|
+
section_key = f"{parent_key}.{key}" if parent_key else key
|
104
|
+
toml_str += f"[{section_key}]\n"
|
105
|
+
toml_str += self._process_section_content(value, section_key)
|
106
|
+
|
107
|
+
return toml_str
|
108
|
+
|
109
|
+
@type_safe
|
110
|
+
def _process_section_content(self, section_data : Dict[str, Any] , # Section data to process
|
111
|
+
section_key : str # Current section key
|
112
|
+
) -> str: # Returns section content
|
113
|
+
toml_str = ""
|
114
|
+
indent = " "
|
115
|
+
|
116
|
+
# Process simple values in section
|
117
|
+
for key, value in section_data.items():
|
118
|
+
if isinstance(value, str):
|
119
|
+
toml_str += f"{indent}{key} = {self._format_string_value(value)}\n"
|
120
|
+
elif isinstance(value, bool):
|
121
|
+
toml_str += f"{indent}{key} = {str(value).lower()}\n"
|
122
|
+
elif isinstance(value, (int, float)) and value is not None:
|
123
|
+
toml_str += f"{indent}{key} = {value}\n"
|
124
|
+
elif isinstance(value, (list, tuple, set)) and not value:
|
125
|
+
toml_str += f"{indent}{key} = []\n"
|
126
|
+
elif isinstance(value, (list, tuple, set)):
|
127
|
+
if not any(isinstance(item, dict) for item in value):
|
128
|
+
toml_str += f"{indent}{key} = [\n"
|
129
|
+
for item in value:
|
130
|
+
if isinstance(item, str):
|
131
|
+
toml_str += f"{indent}{indent}{self._format_string_value(item)},\n"
|
132
|
+
elif isinstance(item, bool):
|
133
|
+
toml_str += f"{indent}{indent}{str(item).lower()},\n"
|
134
|
+
elif item is not None:
|
135
|
+
toml_str += f"{indent}{indent}{item},\n"
|
136
|
+
toml_str += f"{indent}]\n"
|
137
|
+
|
138
|
+
# Process arrays of tables within sections (NEW)
|
139
|
+
for key, value in section_data.items():
|
140
|
+
if isinstance(value, (list, tuple, set)):
|
141
|
+
if value and all(isinstance(item, dict) for item in value):
|
142
|
+
for item in value:
|
143
|
+
toml_str += f"[[{section_key}.{key}]]\n"
|
144
|
+
for item_key, item_value in item.items():
|
145
|
+
if isinstance(item_value, str):
|
146
|
+
toml_str += f"{indent}{item_key} = {self._format_string_value(item_value)}\n"
|
147
|
+
elif isinstance(item_value, bool):
|
148
|
+
toml_str += f"{indent}{item_key} = {str(item_value).lower()}\n"
|
149
|
+
elif isinstance(item_value, (int, float)) and item_value is not None:
|
150
|
+
toml_str += f"{indent}{item_key} = {item_value}\n"
|
151
|
+
|
152
|
+
# Process nested dictionaries
|
153
|
+
for key, value in section_data.items():
|
154
|
+
if isinstance(value, dict):
|
155
|
+
nested_key = f"{section_key}.{key}"
|
156
|
+
toml_str += f"[{nested_key}]\n"
|
157
|
+
toml_str += self._process_section_content(value, nested_key)
|
158
|
+
|
159
|
+
return toml_str
|
160
|
+
|
161
|
+
@type_safe
|
162
|
+
def _process_array_of_tables(self, data : Dict[str, Any] , # Data to process
|
163
|
+
parent_key : str = "" # Parent section key
|
164
|
+
) -> str: # Returns array of tables
|
165
|
+
toml_str = ""
|
166
|
+
|
167
|
+
for key, value in data.items():
|
168
|
+
if isinstance(value, (list, tuple, set)):
|
169
|
+
if value and all(isinstance(item, dict) for item in value):
|
170
|
+
for item in value:
|
171
|
+
section_key = f"{parent_key}.{key}" if parent_key else key
|
172
|
+
toml_str += f"[[{section_key}]]\n"
|
173
|
+
toml_str += self._process_table_item(item, section_key)
|
174
|
+
|
175
|
+
return toml_str
|
176
|
+
|
177
|
+
@type_safe
|
178
|
+
def _process_table_item(self, item : Dict[str, Any] , # Table item to process
|
179
|
+
section_key : str # Current section key
|
180
|
+
) -> str: # Returns formatted table item
|
181
|
+
toml_str = ""
|
182
|
+
indent = " "
|
183
|
+
|
184
|
+
# Process simple values in table item
|
185
|
+
for key, value in item.items():
|
186
|
+
if isinstance(value, str):
|
187
|
+
toml_str += f"{indent}{key} = {self._format_string_value(value)}\n"
|
188
|
+
elif isinstance(value, bool):
|
189
|
+
toml_str += f"{indent}{key} = {str(value).lower()}\n"
|
190
|
+
elif isinstance(value, (int, float)) and value is not None:
|
191
|
+
toml_str += f"{indent}{key} = {value}\n"
|
192
|
+
elif isinstance(value, (list, tuple, set)) and not value:
|
193
|
+
toml_str += f"{indent}{key} = []\n"
|
194
|
+
elif isinstance(value, (list, tuple, set)):
|
195
|
+
if not any(isinstance(sub_item, dict) for sub_item in value):
|
196
|
+
toml_str += f"{indent}{key} = [\n"
|
197
|
+
for sub_item in value:
|
198
|
+
if isinstance(sub_item, str):
|
199
|
+
toml_str += f"{indent}{indent}{self._format_string_value(sub_item)},\n"
|
200
|
+
else:
|
201
|
+
toml_str += f"{indent}{indent}{sub_item},\n"
|
202
|
+
toml_str += f"{indent}]\n"
|
203
|
+
|
204
|
+
# Process nested dicts in table items
|
205
|
+
for key, value in item.items():
|
206
|
+
if isinstance(value, dict):
|
207
|
+
nested_section = f"{section_key}.{key}"
|
208
|
+
toml_str += f"[{nested_section}]\n"
|
209
|
+
toml_str += self._process_section_content(value, nested_section)
|
210
|
+
|
211
|
+
return toml_str
|
osbot_utils/utils/Toml.py
CHANGED
@@ -1,29 +1,11 @@
|
|
1
1
|
import sys
|
2
|
-
from osbot_utils.
|
3
|
-
from osbot_utils.utils.
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
for key, value in data.items():
|
11
|
-
if isinstance(value, dict):
|
12
|
-
toml_str += f"{indent}[{key}]\n"
|
13
|
-
toml_str += dict_to_toml(value, indent_level + 1)
|
14
|
-
elif isinstance(value, (list, tuple, set)):
|
15
|
-
toml_str += f"{indent}{key} = [\n"
|
16
|
-
for item in value:
|
17
|
-
toml_str += f"{indent} {repr(item)},\n"
|
18
|
-
toml_str += f"{indent}]\n"
|
19
|
-
elif isinstance(value, str):
|
20
|
-
toml_str += f"{indent}{key} = '{value}'\n"
|
21
|
-
elif isinstance(value, bool):
|
22
|
-
toml_str += f"{indent}{key} = {str(value).lower()}\n"
|
23
|
-
else:
|
24
|
-
toml_str += f"{indent}{key} = {value}\n"
|
25
|
-
|
26
|
-
return toml_str
|
2
|
+
from osbot_utils.helpers.transformers.Dict__To__Toml import Dict__To__Toml
|
3
|
+
from osbot_utils.utils.Files import file_create, file_contents
|
4
|
+
from osbot_utils.utils.Objects import dict_to_obj
|
5
|
+
|
6
|
+
|
7
|
+
def dict_to_toml(data):
|
8
|
+
return Dict__To__Toml().convert(data) # Singleton instance for convenience
|
27
9
|
|
28
10
|
def toml_dict_to_file(toml_file, data):
|
29
11
|
str_toml = dict_to_toml(data)
|
@@ -33,7 +15,6 @@ def toml_dict_from_file(toml_file):
|
|
33
15
|
str_toml = file_contents(toml_file)
|
34
16
|
return toml_to_dict(str_toml)
|
35
17
|
|
36
|
-
|
37
18
|
def toml_to_dict(str_toml):
|
38
19
|
if sys.version_info >= (3, 11):
|
39
20
|
import tomllib
|
osbot_utils/version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
v2.
|
1
|
+
v2.79.0
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: osbot_utils
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.79.0
|
4
4
|
Summary: OWASP Security Bot - Utils
|
5
5
|
License: MIT
|
6
6
|
Author: Dinis Cruz
|
@@ -21,7 +21,7 @@ Description-Content-Type: text/markdown
|
|
21
21
|
|
22
22
|
# OSBot-Utils
|
23
23
|
|
24
|
-

|
25
25
|

|
26
26
|

|
27
27
|

|
@@ -33,7 +33,7 @@ osbot_utils/fluent/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVG
|
|
33
33
|
osbot_utils/helpers/CFormat.py,sha256=QviXlx3cQF7Wq6bNQmvWPHknDDMQXg5bh5dsRncrg-U,6805
|
34
34
|
osbot_utils/helpers/CPrint.py,sha256=8iCkLaPozi3anzLQ-kPfJTtfLZdOrgpGNJs5UNjGJ9g,1346
|
35
35
|
osbot_utils/helpers/Dependency_Manager.py,sha256=79YRYnVfchewq8iSMJ5dzwW2D5u8chWcIqYE-G9YrSo,1337
|
36
|
-
osbot_utils/helpers/Dict_To_Attr.py,sha256=
|
36
|
+
osbot_utils/helpers/Dict_To_Attr.py,sha256=OWAChOCTM03ECfL4ME7Y0026ZnfA7OmSTIWYKlW9Jmg,139
|
37
37
|
osbot_utils/helpers/Hashicorp_Secrets.py,sha256=e2fWWHK6bubpAm1sw5y8X5kh2Hk5d4JyZCnUovZip5A,4232
|
38
38
|
osbot_utils/helpers/Local_Cache.py,sha256=67qmeVXUBhfqLUQhjFBE9Pjt5dcjpQYhqCTGQNWgVSU,3232
|
39
39
|
osbot_utils/helpers/Local_Caches.py,sha256=LUeNJX07Ccnp1SIhYvhqqQFVF6r_Ez7bWha8ssomuvY,1957
|
@@ -306,6 +306,7 @@ osbot_utils/helpers/trace/Trace_Call__Stats.py,sha256=gmiotIrOXe2ssxodzQQ56t8eGT
|
|
306
306
|
osbot_utils/helpers/trace/Trace_Call__View_Model.py,sha256=a40nn6agCEMd2ecsJ93n8vXij0omh0D69QilqwmN_ao,4545
|
307
307
|
osbot_utils/helpers/trace/Trace_Files.py,sha256=SNpAmuBlSUS9NyVocgZ5vevzqVaIqoh622yZge3a53A,978
|
308
308
|
osbot_utils/helpers/trace/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
309
|
+
osbot_utils/helpers/transformers/Dict__To__Toml.py,sha256=x_5_9xwS6ytSVzpr74AJOjYTnrkTCLPb8MoHyRkWuvA,10791
|
309
310
|
osbot_utils/helpers/xml/Xml__Attribute.py,sha256=_dIVyp0WHfdv306vAj5bpEtiqKa83MLKRH925rjKa94,145
|
310
311
|
osbot_utils/helpers/xml/Xml__Element.py,sha256=NLRdiTsRhqRf0I0ScAdN-tHuSh2qNuKP_tldx7iiSv4,868
|
311
312
|
osbot_utils/helpers/xml/Xml__File.py,sha256=ECR4WD57ePyA88uioKVt5GVbWXddM_Y1OsWAJNzAg74,420
|
@@ -464,12 +465,12 @@ osbot_utils/utils/Regex.py,sha256=MtHhk69ax7Nwu4CQZK7y4KXHZ6VREwEpIchuioB168c,96
|
|
464
465
|
osbot_utils/utils/Status.py,sha256=OjqLwUhHqY-j-JeRN-hIaVZQHPRdyjR7y6i6ujsB-Yc,4287
|
465
466
|
osbot_utils/utils/Str.py,sha256=KQVfh0o3BxJKVm24yhAhgIGH5QYfzpP1G-siVv2zQws,3301
|
466
467
|
osbot_utils/utils/Threads.py,sha256=YI1T382AtJpHVsa-BK7SycmEYhnkqHIiYyK_5HSmUtw,4329
|
467
|
-
osbot_utils/utils/Toml.py,sha256=
|
468
|
+
osbot_utils/utils/Toml.py,sha256=grjWkVPIMVkawJ499FVIJKxQp8FJ2wcsd0Z3YIR4drM,1148
|
468
469
|
osbot_utils/utils/Version.py,sha256=Ww6ChwTxqp1QAcxOnztkTicShlcx6fbNsWX5xausHrg,422
|
469
470
|
osbot_utils/utils/Zip.py,sha256=mG42lgTY0tnm14T3P1-DSAIZKkTiYoO3odZ1aOUdc1I,14394
|
470
471
|
osbot_utils/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
471
|
-
osbot_utils/version,sha256=
|
472
|
-
osbot_utils-2.
|
473
|
-
osbot_utils-2.
|
474
|
-
osbot_utils-2.
|
475
|
-
osbot_utils-2.
|
472
|
+
osbot_utils/version,sha256=LBnSHfeuqdNUDCaJ0l1-HSUQy_-YezgRfKFIWsPg7Q4,8
|
473
|
+
osbot_utils-2.79.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
474
|
+
osbot_utils-2.79.0.dist-info/METADATA,sha256=EYa9xfe3-uAcOGHcGHDaX0LIrRtztORvnB_PJ8cS-G0,7918
|
475
|
+
osbot_utils-2.79.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
476
|
+
osbot_utils-2.79.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|