xulbux 1.6.0__py3-none-any.whl → 1.6.2__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.
Potentially problematic release.
This version of xulbux might be problematic. Click here for more details.
- xulbux/__init__.py +1 -1
- xulbux/_consts_.py +16 -16
- xulbux/xx_code.py +4 -4
- xulbux/xx_color.py +155 -144
- xulbux/xx_console.py +26 -41
- xulbux/xx_data.py +69 -66
- xulbux/xx_env_path.py +4 -4
- xulbux/xx_file.py +35 -26
- xulbux/xx_format_codes.py +122 -64
- xulbux/xx_json.py +27 -22
- xulbux/xx_path.py +2 -7
- xulbux/xx_regex.py +61 -61
- xulbux/xx_string.py +14 -13
- xulbux/xx_system.py +59 -8
- {xulbux-1.6.0.dist-info → xulbux-1.6.2.dist-info}/METADATA +3 -3
- xulbux-1.6.2.dist-info/RECORD +21 -0
- {xulbux-1.6.0.dist-info → xulbux-1.6.2.dist-info}/WHEEL +1 -1
- xulbux-1.6.0.dist-info/RECORD +0 -21
- {xulbux-1.6.0.dist-info → xulbux-1.6.2.dist-info}/LICENSE +0 -0
- {xulbux-1.6.0.dist-info → xulbux-1.6.2.dist-info}/entry_points.txt +0 -0
- {xulbux-1.6.0.dist-info → xulbux-1.6.2.dist-info}/top_level.txt +0 -0
xulbux/xx_console.py
CHANGED
|
@@ -15,8 +15,8 @@ Functions for logging and other small actions within the console:
|
|
|
15
15
|
- `Console.confirm()`
|
|
16
16
|
- `Console.restricted_input()`
|
|
17
17
|
- `Console.pwd_input()`\n
|
|
18
|
-
|
|
19
|
-
You can also use special formatting codes directly inside the log message to change their appearance
|
|
18
|
+
------------------------------------------------------------------------------------------------------
|
|
19
|
+
You can also use special formatting codes directly inside the log message to change their appearance.
|
|
20
20
|
For more detailed information about formatting codes, see the the `xx_format_codes` description.
|
|
21
21
|
"""
|
|
22
22
|
|
|
@@ -29,7 +29,6 @@ from contextlib import suppress
|
|
|
29
29
|
import pyperclip as _pyperclip
|
|
30
30
|
import keyboard as _keyboard
|
|
31
31
|
import getpass as _getpass
|
|
32
|
-
import ctypes as _ctypes
|
|
33
32
|
import shutil as _shutil
|
|
34
33
|
import mouse as _mouse
|
|
35
34
|
import sys as _sys
|
|
@@ -67,17 +66,6 @@ class Console:
|
|
|
67
66
|
def user() -> str:
|
|
68
67
|
return _os.getenv("USER") or _os.getenv("USERNAME") or _getpass.getuser()
|
|
69
68
|
|
|
70
|
-
def is_admin() -> bool:
|
|
71
|
-
try:
|
|
72
|
-
if _os.name == "nt":
|
|
73
|
-
return _ctypes.windll.shell32.IsUserAnAdmin() != 0
|
|
74
|
-
elif _os.name == "posix":
|
|
75
|
-
return _os.geteuid() == 0
|
|
76
|
-
else:
|
|
77
|
-
return False
|
|
78
|
-
except Exception:
|
|
79
|
-
return False
|
|
80
|
-
|
|
81
69
|
@staticmethod
|
|
82
70
|
def pause_exit(
|
|
83
71
|
pause: bool = False,
|
|
@@ -86,9 +74,8 @@ class Console:
|
|
|
86
74
|
exit_code: int = 0,
|
|
87
75
|
reset_ansi: bool = False,
|
|
88
76
|
) -> None:
|
|
89
|
-
"""Will print the `last_prompt` and then pause the program if `pause` is set
|
|
90
|
-
to `True` and after the pause, exit the program if `exit` is set to `True`.
|
|
91
|
-
"""
|
|
77
|
+
"""Will print the `last_prompt` and then pause the program if `pause` is set
|
|
78
|
+
to `True` and after the pause, exit the program if `exit` is set to `True`."""
|
|
92
79
|
print(prompt, end="", flush=True)
|
|
93
80
|
if reset_ansi:
|
|
94
81
|
FormatCodes.print("[_]", end="")
|
|
@@ -114,17 +101,16 @@ class Console:
|
|
|
114
101
|
title_bg_color: hexa | rgba = None,
|
|
115
102
|
default_color: hexa | rgba = None,
|
|
116
103
|
) -> None:
|
|
117
|
-
"""Will print a formatted log message
|
|
118
|
-
`title` -⠀the title of the log message (e.g. `DEBUG`, `WARN`, `FAIL`, etc.)
|
|
119
|
-
`prompt` -⠀the log message
|
|
120
|
-
`start` -⠀something to print before the log is printed
|
|
121
|
-
`end` -⠀something to print after the log is printed (e.g. `\\n\\n`)
|
|
122
|
-
`title_bg_color` -⠀the background color of the `title
|
|
123
|
-
`default_color` -⠀the default text color of the `prompt`\n
|
|
104
|
+
"""Will print a formatted log message:
|
|
105
|
+
- `title` -⠀the title of the log message (e.g. `DEBUG`, `WARN`, `FAIL`, etc.)
|
|
106
|
+
- `prompt` -⠀the log message
|
|
107
|
+
- `start` -⠀something to print before the log is printed
|
|
108
|
+
- `end` -⠀something to print after the log is printed (e.g. `\\n\\n`)
|
|
109
|
+
- `title_bg_color` -⠀the background color of the `title`
|
|
110
|
+
- `default_color` -⠀the default text color of the `prompt`\n
|
|
124
111
|
--------------------------------------------------------------------------------
|
|
125
|
-
The log message supports special formatting codes. For more detailed
|
|
126
|
-
information about formatting codes, see `xx_format_codes` class description.
|
|
127
|
-
"""
|
|
112
|
+
The log message supports special formatting codes. For more detailed
|
|
113
|
+
information about formatting codes, see `xx_format_codes` class description."""
|
|
128
114
|
title_color = "_color" if not title_bg_color else Color.text_color_for_on_bg(title_bg_color)
|
|
129
115
|
if title:
|
|
130
116
|
FormatCodes.print(
|
|
@@ -150,7 +136,7 @@ class Console:
|
|
|
150
136
|
pause: bool = False,
|
|
151
137
|
exit: bool = False,
|
|
152
138
|
) -> None:
|
|
153
|
-
"""A preset for `log()`: `DEBUG` log message with the options to pause
|
|
139
|
+
"""A preset for `log()`: `DEBUG` log message with the options to pause
|
|
154
140
|
at the message and exit the program after the message was printed."""
|
|
155
141
|
if active:
|
|
156
142
|
Console.log("DEBUG", prompt, start, end, title_bg_color, default_color)
|
|
@@ -166,7 +152,7 @@ class Console:
|
|
|
166
152
|
pause: bool = False,
|
|
167
153
|
exit: bool = False,
|
|
168
154
|
) -> None:
|
|
169
|
-
"""A preset for `log()`: `INFO` log message with the options to pause
|
|
155
|
+
"""A preset for `log()`: `INFO` log message with the options to pause
|
|
170
156
|
at the message and exit the program after the message was printed."""
|
|
171
157
|
Console.log("INFO", prompt, start, end, title_bg_color, default_color)
|
|
172
158
|
Console.pause_exit(pause, exit)
|
|
@@ -181,7 +167,7 @@ class Console:
|
|
|
181
167
|
pause: bool = False,
|
|
182
168
|
exit: bool = False,
|
|
183
169
|
) -> None:
|
|
184
|
-
"""A preset for `log()`: `DONE` log message with the options to pause
|
|
170
|
+
"""A preset for `log()`: `DONE` log message with the options to pause
|
|
185
171
|
at the message and exit the program after the message was printed."""
|
|
186
172
|
Console.log("DONE", prompt, start, end, title_bg_color, default_color)
|
|
187
173
|
Console.pause_exit(pause, exit)
|
|
@@ -196,7 +182,7 @@ class Console:
|
|
|
196
182
|
pause: bool = False,
|
|
197
183
|
exit: bool = False,
|
|
198
184
|
) -> None:
|
|
199
|
-
"""A preset for `log()`: `WARN` log message with the options to pause
|
|
185
|
+
"""A preset for `log()`: `WARN` log message with the options to pause
|
|
200
186
|
at the message and exit the program after the message was printed."""
|
|
201
187
|
Console.log("WARN", prompt, start, end, title_bg_color, default_color)
|
|
202
188
|
Console.pause_exit(pause, exit)
|
|
@@ -212,7 +198,7 @@ class Console:
|
|
|
212
198
|
exit: bool = True,
|
|
213
199
|
reset_ansi=True,
|
|
214
200
|
) -> None:
|
|
215
|
-
"""A preset for `log()`: `FAIL` log message with the options to pause
|
|
201
|
+
"""A preset for `log()`: `FAIL` log message with the options to pause
|
|
216
202
|
at the message and exit the program after the message was printed."""
|
|
217
203
|
Console.log("FAIL", prompt, start, end, title_bg_color, default_color)
|
|
218
204
|
Console.pause_exit(pause, exit, reset_ansi=reset_ansi)
|
|
@@ -228,7 +214,7 @@ class Console:
|
|
|
228
214
|
exit: bool = True,
|
|
229
215
|
reset_ansi=True,
|
|
230
216
|
) -> None:
|
|
231
|
-
"""A preset for `log()`: `EXIT` log message with the options to pause
|
|
217
|
+
"""A preset for `log()`: `EXIT` log message with the options to pause
|
|
232
218
|
at the message and exit the program after the message was printed."""
|
|
233
219
|
Console.log("EXIT", prompt, start, end, title_bg_color, default_color)
|
|
234
220
|
Console.pause_exit(pause, exit, reset_ansi=reset_ansi)
|
|
@@ -242,10 +228,9 @@ class Console:
|
|
|
242
228
|
default_is_yes: bool = True,
|
|
243
229
|
) -> bool:
|
|
244
230
|
"""Ask a yes/no question.\n
|
|
245
|
-
|
|
246
|
-
The question can be formatted with special formatting codes. For more detailed
|
|
247
|
-
information about formatting codes, see the `xx_format_codes` description.
|
|
248
|
-
"""
|
|
231
|
+
-------------------------------------------------------------------------------
|
|
232
|
+
The question can be formatted with special formatting codes. For more detailed
|
|
233
|
+
information about formatting codes, see the `xx_format_codes` description."""
|
|
249
234
|
confirmed = input(
|
|
250
235
|
FormatCodes.to_ansi(
|
|
251
236
|
f'{start} {str(prompt)} [_|dim](({"Y" if default_is_yes else "y"}/{"n" if default_is_yes else "N"}): )',
|
|
@@ -271,9 +256,8 @@ class Console:
|
|
|
271
256
|
- optional mask character (hide user input, e.g. for passwords)
|
|
272
257
|
- reset the ANSI formatting codes after the user continues\n
|
|
273
258
|
-----------------------------------------------------------------------------------
|
|
274
|
-
The input can be formatted with special formatting codes. For more detailed
|
|
275
|
-
information about formatting codes, see the `xx_format_codes` description.
|
|
276
|
-
"""
|
|
259
|
+
The input can be formatted with special formatting codes. For more detailed
|
|
260
|
+
information about formatting codes, see the `xx_format_codes` description."""
|
|
277
261
|
FormatCodes.print(prompt, end="", flush=True)
|
|
278
262
|
result = ""
|
|
279
263
|
select_all = False
|
|
@@ -377,5 +361,6 @@ class Console:
|
|
|
377
361
|
max_len: int = None,
|
|
378
362
|
_reset_ansi: bool = True,
|
|
379
363
|
) -> str:
|
|
380
|
-
"""Password input
|
|
364
|
+
"""Password input (preset for `Console.restricted_input()`)
|
|
365
|
+
that always masks the entered characters with asterisks."""
|
|
381
366
|
return Console.restricted_input(prompt, allowed_chars, min_len, max_len, "*", _reset_ansi)
|
xulbux/xx_data.py
CHANGED
|
@@ -26,7 +26,7 @@ class Data:
|
|
|
26
26
|
|
|
27
27
|
@staticmethod
|
|
28
28
|
def remove_empty_items(data: DataStructure, spaces_are_empty: bool = False) -> DataStructure:
|
|
29
|
-
"""Removes empty items from the data structure
|
|
29
|
+
"""Removes empty items from the data structure.
|
|
30
30
|
If `spaces_are_empty` is true, it will count items with only spaces as empty."""
|
|
31
31
|
if isinstance(data, dict):
|
|
32
32
|
return {
|
|
@@ -79,14 +79,15 @@ class Data:
|
|
|
79
79
|
comment_sep: str = "",
|
|
80
80
|
) -> DataStructure:
|
|
81
81
|
"""Remove comments from a list, tuple or dictionary.\n
|
|
82
|
-
|
|
83
|
-
The `data` parameter is your list, tuple or dictionary, where the comments should get removed from
|
|
84
|
-
The `comment_start` parameter is the string that marks the start of a comment inside `data`. (default: `>>`)
|
|
85
|
-
The `comment_end` parameter is the string that marks the end of a comment inside `data`. (default: `<<`)
|
|
86
|
-
The `comment_sep` parameter is a string with which a comment will be replaced, if it is in the middle of a value.\n
|
|
87
|
-
|
|
88
|
-
Examples
|
|
89
|
-
```python
|
|
82
|
+
----------------------------------------------------------------------------------------------------------------------
|
|
83
|
+
- The `data` parameter is your list, tuple or dictionary, where the comments should get removed from.
|
|
84
|
+
- The `comment_start` parameter is the string that marks the start of a comment inside `data`. (default: `>>`)
|
|
85
|
+
- The `comment_end` parameter is the string that marks the end of a comment inside `data`. (default: `<<`)
|
|
86
|
+
- The `comment_sep` parameter is a string with which a comment will be replaced, if it is in the middle of a value.\n
|
|
87
|
+
----------------------------------------------------------------------------------------------------------------------
|
|
88
|
+
Examples:
|
|
89
|
+
```python
|
|
90
|
+
data = {
|
|
90
91
|
"key1": [
|
|
91
92
|
">> COMMENT IN THE BEGINNING OF THE STRING << value1",
|
|
92
93
|
"value2 >> COMMENT IN THE END OF THE STRING",
|
|
@@ -106,24 +107,25 @@ class Data:
|
|
|
106
107
|
comment_start=">>",
|
|
107
108
|
comment_end="<<",
|
|
108
109
|
comment_sep="__"
|
|
109
|
-
)
|
|
110
|
-
|
|
110
|
+
)
|
|
111
|
+
```\n
|
|
112
|
+
----------------------------------------------------------------------------------------------------------------------
|
|
111
113
|
For this example, `processed_data` will be:
|
|
112
|
-
```python
|
|
114
|
+
```python
|
|
115
|
+
{
|
|
113
116
|
"key1": [
|
|
114
117
|
"value1",
|
|
115
118
|
"value2",
|
|
116
119
|
"val__ue3"
|
|
117
120
|
],
|
|
118
121
|
"key3": None
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
For `
|
|
125
|
-
"""
|
|
126
|
-
|
|
122
|
+
}
|
|
123
|
+
```\n
|
|
124
|
+
- For `key1`, all the comments will just be removed, except at `value3` and `value4`:
|
|
125
|
+
- `value3` The comment is removed and the parts left and right are joined through `comment_sep`.
|
|
126
|
+
- `value4` The whole value is removed, since the whole value was a comment.
|
|
127
|
+
- For `key2`, the key, including its whole values will be removed.
|
|
128
|
+
- For `key3`, since all its values are just comments, the key will still exist, but with a value of `None`."""
|
|
127
129
|
if comment_end:
|
|
128
130
|
pattern = _re.compile(
|
|
129
131
|
rf"^((?:(?!{_re.escape(comment_start)}).)*){_re.escape(comment_start)}(?:(?:(?!{_re.escape(comment_end)}).)*)(?:{_re.escape(comment_end)})?(.*?)$"
|
|
@@ -163,13 +165,13 @@ class Data:
|
|
|
163
165
|
comment_end: str = "<<",
|
|
164
166
|
) -> bool:
|
|
165
167
|
"""Compares two structures and returns `True` if they are equal and `False` otherwise.\n
|
|
166
|
-
⇾
|
|
167
|
-
|
|
168
|
-
Ignores the specified (found) key/s or item/s from `ignore_paths`. Comments are not ignored
|
|
169
|
-
when comparing. `comment_start` and `comment_end` are only used to correctly recognize the
|
|
168
|
+
⇾ Will not detect, if a key-name has changed, only if removed or added.\n
|
|
169
|
+
--------------------------------------------------------------------------------------------
|
|
170
|
+
Ignores the specified (found) key/s or item/s from `ignore_paths`. Comments are not ignored
|
|
171
|
+
when comparing. `comment_start` and `comment_end` are only used to correctly recognize the
|
|
170
172
|
keys in the `ignore_paths`.\n
|
|
171
|
-
|
|
172
|
-
The paths from `ignore_paths` and the `path_sep` parameter work exactly the same way as for
|
|
173
|
+
--------------------------------------------------------------------------------------------
|
|
174
|
+
The paths from `ignore_paths` and the `path_sep` parameter work exactly the same way as for
|
|
173
175
|
the function `Data.get_path_id()`. See its documentation for more details."""
|
|
174
176
|
|
|
175
177
|
def process_ignore_paths(
|
|
@@ -222,26 +224,28 @@ class Data:
|
|
|
222
224
|
-------------------------------------------------------------------------------------------------
|
|
223
225
|
The `data` parameter is the list, tuple, or dictionary, which the id should be generated for.\n
|
|
224
226
|
-------------------------------------------------------------------------------------------------
|
|
225
|
-
The param `value_path` is a sort of path (or a list of paths) to the value/s to be updated
|
|
227
|
+
The param `value_path` is a sort of path (or a list of paths) to the value/s to be updated.
|
|
226
228
|
In this example:
|
|
227
|
-
|
|
229
|
+
```python
|
|
230
|
+
{
|
|
228
231
|
"healthy": {
|
|
229
232
|
"fruit": ["apples", "bananas", "oranges"],
|
|
230
233
|
"vegetables": ["carrots", "broccoli", "celery"]
|
|
231
234
|
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
... if you want to change the value of `"apples"` to `"strawberries"`, the value path would be
|
|
238
|
+
`healthy->fruit->apples` or if you don't know that the value is `"apples"` you can also use the
|
|
239
|
+
index of the value, so `healthy->fruit->0`.\n
|
|
236
240
|
-------------------------------------------------------------------------------------------------
|
|
237
|
-
The comments marked with `comment_start` and `comment_end` will be removed
|
|
238
|
-
|
|
241
|
+
The comments marked with `comment_start` and `comment_end` will be removed, before trying to get
|
|
242
|
+
the path id.\n
|
|
239
243
|
-------------------------------------------------------------------------------------------------
|
|
240
|
-
The `path_sep` param is the separator between the keys/indexes in the path
|
|
241
|
-
|
|
244
|
+
The `path_sep` param is the separator between the keys/indexes in the path (default is `->` just
|
|
245
|
+
like in the example above).\n
|
|
242
246
|
-------------------------------------------------------------------------------------------------
|
|
243
|
-
If `ignore_not_found` is `True`, the function will return `None` if the value is not
|
|
244
|
-
|
|
247
|
+
If `ignore_not_found` is `True`, the function will return `None` if the value is not found
|
|
248
|
+
instead of raising an error."""
|
|
245
249
|
|
|
246
250
|
def process_path(path: str, data_obj: list | tuple | set | frozenset | dict) -> str | None:
|
|
247
251
|
keys = path.split(path_sep)
|
|
@@ -289,11 +293,11 @@ class Data:
|
|
|
289
293
|
@staticmethod
|
|
290
294
|
def get_value_by_path_id(data: DataStructure, path_id: str, get_key: bool = False) -> any:
|
|
291
295
|
"""Retrieves the value from `data` using the provided `path_id`.\n
|
|
292
|
-
|
|
293
|
-
Input your `data` along with a `path_id` that was created before using `Data.get_path_id()
|
|
296
|
+
-------------------------------------------------------------------------------------------------
|
|
297
|
+
Input your `data` along with a `path_id` that was created before using `Data.get_path_id()`.
|
|
294
298
|
If `get_key` is true and the final item is in a dict, it returns the key instead of the value.\n
|
|
295
|
-
|
|
296
|
-
The function will return the value (or key) from the path ID location, as long as the structure
|
|
299
|
+
-------------------------------------------------------------------------------------------------
|
|
300
|
+
The function will return the value (or key) from the path ID location, as long as the structure
|
|
297
301
|
of `data` hasn't changed since creating the path ID to that value."""
|
|
298
302
|
|
|
299
303
|
def get_nested(data: list | tuple | set | frozenset | dict, path: list[int], get_key: bool) -> any:
|
|
@@ -326,12 +330,12 @@ class Data:
|
|
|
326
330
|
) -> list | tuple | dict:
|
|
327
331
|
"""Updates the value/s from `update_values` in the `data`.\n
|
|
328
332
|
--------------------------------------------------------------------------------
|
|
329
|
-
Input a list, tuple or dict as `data`, along with `update_values`, which is
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
+
Input a list, tuple or dict as `data`, along with `update_values`, which is a
|
|
334
|
+
path ID that was created before using `Data.get_path_id()`, together with the
|
|
335
|
+
new value to be inserted where the path ID points to. The path ID and the new
|
|
336
|
+
value are separated by `sep`, which per default is `::`.\n
|
|
333
337
|
--------------------------------------------------------------------------------
|
|
334
|
-
The value from path ID will be changed to the new value, as long as the
|
|
338
|
+
The value from path ID will be changed to the new value, as long as the
|
|
335
339
|
structure of `data` hasn't changed since creating the path ID to that value."""
|
|
336
340
|
|
|
337
341
|
def update_nested(
|
|
@@ -383,16 +387,15 @@ class Data:
|
|
|
383
387
|
end: str = "\n",
|
|
384
388
|
) -> None:
|
|
385
389
|
"""Print nicely formatted data structures.\n
|
|
386
|
-
|
|
387
|
-
The indentation spaces-amount can be set with with `indent
|
|
388
|
-
There are three different levels of `compactness
|
|
389
|
-
`0` expands everything possible
|
|
390
|
-
`1` only expands if there's other lists, tuples or dicts inside of data or
|
|
391
|
-
|
|
392
|
-
`2` keeps everything collapsed (all on one line)\n
|
|
393
|
-
|
|
394
|
-
If `as_json` is set to `True`, the output will be in valid JSON format.
|
|
395
|
-
"""
|
|
390
|
+
------------------------------------------------------------------------------
|
|
391
|
+
The indentation spaces-amount can be set with with `indent`.
|
|
392
|
+
There are three different levels of `compactness`:
|
|
393
|
+
- `0` expands everything possible
|
|
394
|
+
- `1` only expands if there's other lists, tuples or dicts inside of data or,
|
|
395
|
+
if the data's content is longer than `max_width`
|
|
396
|
+
- `2` keeps everything collapsed (all on one line)\n
|
|
397
|
+
------------------------------------------------------------------------------
|
|
398
|
+
If `as_json` is set to `True`, the output will be in valid JSON format."""
|
|
396
399
|
print(
|
|
397
400
|
Data.to_str(data, indent, compactness, sep, max_width, as_json),
|
|
398
401
|
end=end,
|
|
@@ -409,14 +412,14 @@ class Data:
|
|
|
409
412
|
as_json: bool = False,
|
|
410
413
|
) -> str:
|
|
411
414
|
"""Get nicely formatted data structure-strings.\n
|
|
412
|
-
|
|
413
|
-
The indentation spaces-amount can be set with with `indent
|
|
414
|
-
There are three different levels of `compactness
|
|
415
|
-
`0` expands everything possible
|
|
416
|
-
`1` only expands if there's other lists, tuples or dicts inside of data or
|
|
417
|
-
|
|
418
|
-
`2` keeps everything collapsed (all on one line)\n
|
|
419
|
-
|
|
415
|
+
------------------------------------------------------------------------------
|
|
416
|
+
The indentation spaces-amount can be set with with `indent`.
|
|
417
|
+
There are three different levels of `compactness`:
|
|
418
|
+
- `0` expands everything possible
|
|
419
|
+
- `1` only expands if there's other lists, tuples or dicts inside of data or,
|
|
420
|
+
if the data's content is longer than `max_width`
|
|
421
|
+
- `2` keeps everything collapsed (all on one line)\n
|
|
422
|
+
------------------------------------------------------------------------------
|
|
420
423
|
If `as_json` is set to `True`, the output will be in valid JSON format."""
|
|
421
424
|
|
|
422
425
|
def format_value(value: any, current_indent: int) -> str:
|
|
@@ -495,7 +498,7 @@ class Data:
|
|
|
495
498
|
def _is_key(data: DataStructure, path_id: str) -> bool:
|
|
496
499
|
"""Returns `True` if the path ID points to a key in `data` and `False` otherwise.\n
|
|
497
500
|
------------------------------------------------------------------------------------
|
|
498
|
-
Input a list, tuple or dict as `data`, along with `path_id`, which is a path ID
|
|
501
|
+
Input a list, tuple or dict as `data`, along with `path_id`, which is a path ID
|
|
499
502
|
that was created before using `Data.get_path_id()`."""
|
|
500
503
|
|
|
501
504
|
def check_nested(data: list | tuple | set | frozenset | dict, path: list[int]) -> bool:
|
xulbux/xx_env_path.py
CHANGED
|
@@ -8,8 +8,8 @@ Functions for modifying and checking the systems environment-variables:
|
|
|
8
8
|
|
|
9
9
|
from .xx_path import Path
|
|
10
10
|
|
|
11
|
-
import os as _os
|
|
12
11
|
import sys as _sys
|
|
12
|
+
import os as _os
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class EnvPath:
|
|
@@ -60,9 +60,9 @@ class EnvPath:
|
|
|
60
60
|
cwd: bool = False,
|
|
61
61
|
base_dir: bool = False,
|
|
62
62
|
) -> list:
|
|
63
|
-
"""Get and/or normalize the paths
|
|
64
|
-
|
|
65
|
-
neither `cwd` or `base_dir` is `True`."""
|
|
63
|
+
"""Get and/or normalize the paths.\n
|
|
64
|
+
------------------------------------------------------------------------------------
|
|
65
|
+
Raise an error if no path is provided and neither `cwd` or `base_dir` is `True`."""
|
|
66
66
|
if cwd:
|
|
67
67
|
path = _os.getcwd()
|
|
68
68
|
elif base_dir:
|
xulbux/xx_file.py
CHANGED
|
@@ -7,20 +7,31 @@ import os as _os
|
|
|
7
7
|
class File:
|
|
8
8
|
|
|
9
9
|
@staticmethod
|
|
10
|
-
def rename_extension(
|
|
11
|
-
|
|
10
|
+
def rename_extension(
|
|
11
|
+
file: str,
|
|
12
|
+
new_extension: str,
|
|
13
|
+
camel_case_filename: bool = False,
|
|
14
|
+
) -> str:
|
|
15
|
+
"""Rename the extension of a file.\n
|
|
16
|
+
--------------------------------------------------------------------------
|
|
17
|
+
If the `camel_case_filename` parameter is true, the filename will be made
|
|
18
|
+
CamelCase in addition to changing the files extension."""
|
|
19
|
+
directory, filename_with_ext = _os.path.split(file)
|
|
12
20
|
filename = filename_with_ext.split(".")[0]
|
|
13
|
-
camel_case_filename
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return new_file_path
|
|
21
|
+
if camel_case_filename:
|
|
22
|
+
filename = String.to_camel_case(filename)
|
|
23
|
+
return _os.path.join(directory, f"{filename}{new_extension}")
|
|
17
24
|
|
|
18
25
|
@staticmethod
|
|
19
|
-
def create(
|
|
26
|
+
def create(
|
|
27
|
+
file: str,
|
|
28
|
+
content: str = "",
|
|
29
|
+
force: bool = False,
|
|
30
|
+
) -> str:
|
|
20
31
|
"""Create a file with ot without content.\n
|
|
21
|
-
|
|
22
|
-
The function will throw a `FileExistsError` if the file already exists
|
|
23
|
-
To overwrite the file, set the `force` parameter to `True`."""
|
|
32
|
+
------------------------------------------------------------------------
|
|
33
|
+
The function will throw a `FileExistsError` if the file already exists.
|
|
34
|
+
To always overwrite the file, set the `force` parameter to `True`."""
|
|
24
35
|
if _os.path.exists(file) and not force:
|
|
25
36
|
with open(file, "r", encoding="utf-8") as existing_file:
|
|
26
37
|
existing_content = existing_file.read()
|
|
@@ -33,24 +44,22 @@ class File:
|
|
|
33
44
|
return full_path
|
|
34
45
|
|
|
35
46
|
@staticmethod
|
|
36
|
-
def
|
|
37
|
-
|
|
38
|
-
filetype: str,
|
|
47
|
+
def extend_or_make_path(
|
|
48
|
+
file: str,
|
|
39
49
|
search_in: str | list[str] = None,
|
|
40
50
|
prefer_base_dir: bool = True,
|
|
41
|
-
|
|
51
|
+
correct_paths: bool = False,
|
|
42
52
|
) -> str:
|
|
43
|
-
"""
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
53
|
+
"""Tries to find the file and extend the path to be absolute and if the file was not found:\n
|
|
54
|
+
Generate the absolute path to the file in the CWD or the running program's base-directory.\n
|
|
55
|
+
----------------------------------------------------------------------------------------------
|
|
56
|
+
If the `file` is not found in the above directories, it will be searched in the `search_in`
|
|
57
|
+
directory/directories. If the file is still not found, it will return the path to the file in
|
|
58
|
+
the base-dir per default or to the file in the CWD if `prefer_base_dir` is set to `False`.\n
|
|
59
|
+
----------------------------------------------------------------------------------------------
|
|
60
|
+
If `correct_paths` is true, it is possible to have typos in the `search_in` path/s and it
|
|
61
|
+
will still find the file if it is under one of those paths."""
|
|
51
62
|
try:
|
|
52
|
-
return Path.extend(
|
|
63
|
+
return Path.extend(file, search_in, raise_error=True, correct_path=correct_paths)
|
|
53
64
|
except FileNotFoundError:
|
|
54
|
-
return (
|
|
55
|
-
_os.path.join(Path.get(base_dir=True), filename) if prefer_base_dir else _os.path.join(_os.getcwd(), filename)
|
|
56
|
-
)
|
|
65
|
+
return _os.path.join(Path.get(base_dir=True), file) if prefer_base_dir else _os.path.join(_os.getcwd(), file)
|