stouputils 1.14.0__py3-none-any.whl → 1.14.1__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.
- stouputils/__init__.pyi +15 -0
- stouputils/_deprecated.pyi +12 -0
- stouputils/all_doctests.pyi +46 -0
- stouputils/applications/__init__.pyi +2 -0
- stouputils/applications/automatic_docs.py +3 -0
- stouputils/applications/automatic_docs.pyi +106 -0
- stouputils/applications/upscaler/__init__.pyi +3 -0
- stouputils/applications/upscaler/config.pyi +18 -0
- stouputils/applications/upscaler/image.pyi +109 -0
- stouputils/applications/upscaler/video.pyi +60 -0
- stouputils/archive.pyi +67 -0
- stouputils/backup.pyi +109 -0
- stouputils/collections.pyi +86 -0
- stouputils/continuous_delivery/__init__.pyi +5 -0
- stouputils/continuous_delivery/cd_utils.pyi +129 -0
- stouputils/continuous_delivery/github.pyi +162 -0
- stouputils/continuous_delivery/pypi.pyi +52 -0
- stouputils/continuous_delivery/pyproject.pyi +67 -0
- stouputils/continuous_delivery/stubs.pyi +39 -0
- stouputils/ctx.pyi +211 -0
- stouputils/data_science/config/get.py +51 -51
- stouputils/data_science/data_processing/image/__init__.py +66 -66
- stouputils/data_science/data_processing/image/auto_contrast.py +79 -79
- stouputils/data_science/data_processing/image/axis_flip.py +58 -58
- stouputils/data_science/data_processing/image/bias_field_correction.py +74 -74
- stouputils/data_science/data_processing/image/binary_threshold.py +73 -73
- stouputils/data_science/data_processing/image/blur.py +59 -59
- stouputils/data_science/data_processing/image/brightness.py +54 -54
- stouputils/data_science/data_processing/image/canny.py +110 -110
- stouputils/data_science/data_processing/image/clahe.py +92 -92
- stouputils/data_science/data_processing/image/common.py +30 -30
- stouputils/data_science/data_processing/image/contrast.py +53 -53
- stouputils/data_science/data_processing/image/curvature_flow_filter.py +74 -74
- stouputils/data_science/data_processing/image/denoise.py +378 -378
- stouputils/data_science/data_processing/image/histogram_equalization.py +123 -123
- stouputils/data_science/data_processing/image/invert.py +64 -64
- stouputils/data_science/data_processing/image/laplacian.py +60 -60
- stouputils/data_science/data_processing/image/median_blur.py +52 -52
- stouputils/data_science/data_processing/image/noise.py +59 -59
- stouputils/data_science/data_processing/image/normalize.py +65 -65
- stouputils/data_science/data_processing/image/random_erase.py +66 -66
- stouputils/data_science/data_processing/image/resize.py +69 -69
- stouputils/data_science/data_processing/image/rotation.py +80 -80
- stouputils/data_science/data_processing/image/salt_pepper.py +68 -68
- stouputils/data_science/data_processing/image/sharpening.py +55 -55
- stouputils/data_science/data_processing/image/shearing.py +64 -64
- stouputils/data_science/data_processing/image/threshold.py +64 -64
- stouputils/data_science/data_processing/image/translation.py +71 -71
- stouputils/data_science/data_processing/image/zoom.py +83 -83
- stouputils/data_science/data_processing/image_augmentation.py +118 -118
- stouputils/data_science/data_processing/image_preprocess.py +183 -183
- stouputils/data_science/data_processing/prosthesis_detection.py +359 -359
- stouputils/data_science/data_processing/technique.py +481 -481
- stouputils/data_science/dataset/__init__.py +45 -45
- stouputils/data_science/dataset/dataset.py +292 -292
- stouputils/data_science/dataset/dataset_loader.py +135 -135
- stouputils/data_science/dataset/grouping_strategy.py +296 -296
- stouputils/data_science/dataset/image_loader.py +100 -100
- stouputils/data_science/dataset/xy_tuple.py +696 -696
- stouputils/data_science/metric_dictionnary.py +106 -106
- stouputils/data_science/mlflow_utils.py +206 -206
- stouputils/data_science/models/abstract_model.py +149 -149
- stouputils/data_science/models/all.py +85 -85
- stouputils/data_science/models/keras/all.py +38 -38
- stouputils/data_science/models/keras/convnext.py +62 -62
- stouputils/data_science/models/keras/densenet.py +50 -50
- stouputils/data_science/models/keras/efficientnet.py +60 -60
- stouputils/data_science/models/keras/mobilenet.py +56 -56
- stouputils/data_science/models/keras/resnet.py +52 -52
- stouputils/data_science/models/keras/squeezenet.py +233 -233
- stouputils/data_science/models/keras/vgg.py +42 -42
- stouputils/data_science/models/keras/xception.py +38 -38
- stouputils/data_science/models/keras_utils/callbacks/__init__.py +20 -20
- stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +219 -219
- stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +148 -148
- stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +31 -31
- stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +249 -249
- stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +66 -66
- stouputils/data_science/models/keras_utils/losses/__init__.py +12 -12
- stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +56 -56
- stouputils/data_science/models/keras_utils/visualizations.py +416 -416
- stouputils/data_science/models/sandbox.py +116 -116
- stouputils/data_science/range_tuple.py +234 -234
- stouputils/data_science/utils.py +285 -285
- stouputils/decorators.pyi +242 -0
- stouputils/image.pyi +172 -0
- stouputils/installer/__init__.py +18 -18
- stouputils/installer/__init__.pyi +5 -0
- stouputils/installer/common.pyi +39 -0
- stouputils/installer/downloader.pyi +24 -0
- stouputils/installer/linux.py +144 -144
- stouputils/installer/linux.pyi +39 -0
- stouputils/installer/main.py +223 -223
- stouputils/installer/main.pyi +57 -0
- stouputils/installer/windows.py +136 -136
- stouputils/installer/windows.pyi +31 -0
- stouputils/io.pyi +213 -0
- stouputils/parallel.py +13 -10
- stouputils/parallel.pyi +211 -0
- stouputils/print.pyi +136 -0
- stouputils/py.typed +1 -1
- stouputils/stouputils/parallel.pyi +4 -4
- stouputils/version_pkg.pyi +15 -0
- {stouputils-1.14.0.dist-info → stouputils-1.14.1.dist-info}/METADATA +1 -1
- stouputils-1.14.1.dist-info/RECORD +171 -0
- stouputils-1.14.0.dist-info/RECORD +0 -140
- {stouputils-1.14.0.dist-info → stouputils-1.14.1.dist-info}/WHEEL +0 -0
- {stouputils-1.14.0.dist-info → stouputils-1.14.1.dist-info}/entry_points.txt +0 -0
stouputils/installer/windows.py
CHANGED
|
@@ -1,136 +1,136 @@
|
|
|
1
|
-
""" Installer module for Windows specific functions.
|
|
2
|
-
|
|
3
|
-
Provides Windows specific implementations for checking administrator privileges,
|
|
4
|
-
determining appropriate installation paths (global/local), and modifying
|
|
5
|
-
the user's PATH environment variable.
|
|
6
|
-
"""
|
|
7
|
-
# Imports
|
|
8
|
-
import os
|
|
9
|
-
|
|
10
|
-
from ..decorators import LogLevels, handle_error
|
|
11
|
-
from ..io import clean_path
|
|
12
|
-
from ..print import debug, info, warning
|
|
13
|
-
from .common import ask_install_type, prompt_for_path
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
# Functions
|
|
17
|
-
@handle_error(message="Failed to add to PATH (Windows)", error_log=LogLevels.WARNING_TRACEBACK)
|
|
18
|
-
def add_to_path_windows(install_path: str) -> bool | None:
|
|
19
|
-
""" Add install_path to the User PATH environment variable on Windows.
|
|
20
|
-
|
|
21
|
-
Args:
|
|
22
|
-
install_path (str): The path to add to the User PATH environment variable.
|
|
23
|
-
|
|
24
|
-
Returns:
|
|
25
|
-
bool | None: True if the path was added to the User PATH environment variable, None otherwise.
|
|
26
|
-
"""
|
|
27
|
-
# Convert install_path to a Windows path if it's not already
|
|
28
|
-
install_path = install_path.replace("/", "\\")
|
|
29
|
-
os.makedirs(install_path, exist_ok=True)
|
|
30
|
-
|
|
31
|
-
# Get current user PATH
|
|
32
|
-
import winreg
|
|
33
|
-
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Environment", 0, winreg.KEY_READ | winreg.KEY_WRITE) as key:
|
|
34
|
-
|
|
35
|
-
# Get the number of values in the registry key
|
|
36
|
-
num_values = winreg.QueryInfoKey(key)[1]
|
|
37
|
-
|
|
38
|
-
# Find the index of the 'Path' value
|
|
39
|
-
path_index = -1
|
|
40
|
-
for i in range(num_values):
|
|
41
|
-
if winreg.EnumValue(key, i)[0] == 'Path':
|
|
42
|
-
path_index = i
|
|
43
|
-
break
|
|
44
|
-
|
|
45
|
-
# Get the current path value
|
|
46
|
-
current_path: str = winreg.EnumValue(key, path_index)[1]
|
|
47
|
-
|
|
48
|
-
# Check if path is already present
|
|
49
|
-
if install_path not in current_path.split(';'):
|
|
50
|
-
new_path: str = f"{current_path};{install_path}"
|
|
51
|
-
winreg.SetValueEx(key, "Path", 0, winreg.REG_EXPAND_SZ, new_path)
|
|
52
|
-
debug(f"Added '{install_path}' to user PATH. Please restart your terminal for changes to take effect.")
|
|
53
|
-
else:
|
|
54
|
-
debug(f"'{install_path}' is already in user PATH.")
|
|
55
|
-
return True
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def check_admin_windows() -> bool:
|
|
59
|
-
""" Check if the script is running with administrator privileges on Windows. """
|
|
60
|
-
try:
|
|
61
|
-
import ctypes
|
|
62
|
-
return ctypes.windll.shell32.IsUserAnAdmin() != 0
|
|
63
|
-
except Exception:
|
|
64
|
-
return False
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
@handle_error(message="Failed to get installation path (Windows)", error_log=LogLevels.ERROR_TRACEBACK)
|
|
68
|
-
def get_install_path_windows(
|
|
69
|
-
program_name: str,
|
|
70
|
-
ask_global: int = 0,
|
|
71
|
-
add_path: bool = True,
|
|
72
|
-
append_to_path: str = "",
|
|
73
|
-
default_global: str = os.environ.get("ProgramFiles", "C:\\Program Files")
|
|
74
|
-
) -> str:
|
|
75
|
-
""" Get the installation path for the program
|
|
76
|
-
|
|
77
|
-
Args:
|
|
78
|
-
program_name (str): The name of the program to install.
|
|
79
|
-
ask_global (int): 0 = ask for anything, 1 = install globally, 2 = install locally
|
|
80
|
-
add_path (bool): Whether to add the program to the PATH environment variable. (Only if installed globally)
|
|
81
|
-
append_to_path (str): String to append to the installation path when adding to PATH.
|
|
82
|
-
(ex: "bin" if executables are in the bin folder)
|
|
83
|
-
default_global (str): The default global installation path.
|
|
84
|
-
(Default is "C:\\Program Files" which is the most common location for executables on Windows)
|
|
85
|
-
|
|
86
|
-
Returns:
|
|
87
|
-
str: The installation path.
|
|
88
|
-
"""
|
|
89
|
-
# Default path is located in the current working directory
|
|
90
|
-
default_local_path: str = clean_path(os.path.join(os.getcwd(), program_name))
|
|
91
|
-
|
|
92
|
-
# Define default global path (used in prompt even if not chosen initially)
|
|
93
|
-
default_global_path: str = clean_path(os.path.join(default_global, program_name))
|
|
94
|
-
|
|
95
|
-
# Ask user for installation type (global/local)
|
|
96
|
-
install_type: str = ask_install_type(ask_global, default_local_path, default_global_path)
|
|
97
|
-
|
|
98
|
-
# If the user wants to install globally,
|
|
99
|
-
if install_type == 'g':
|
|
100
|
-
|
|
101
|
-
# Check if the user has admin privileges,
|
|
102
|
-
if not check_admin_windows():
|
|
103
|
-
|
|
104
|
-
# If the user doesn't have admin privileges, fallback to local
|
|
105
|
-
warning(
|
|
106
|
-
f"Global installation requires administrator privileges. Please re-run as administrator.\n"
|
|
107
|
-
f"Install locally instead to '{default_local_path}'? (Y/n): "
|
|
108
|
-
)
|
|
109
|
-
if input().lower() == 'n':
|
|
110
|
-
info("Installation cancelled.")
|
|
111
|
-
return ""
|
|
112
|
-
else:
|
|
113
|
-
# Fallback to local path if user agrees
|
|
114
|
-
return prompt_for_path(
|
|
115
|
-
f"Falling back to local installation path: {default_local_path}.",
|
|
116
|
-
default_local_path
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
# If the user has admin privileges,
|
|
120
|
-
else:
|
|
121
|
-
# Ask it user wants to override the default global install path
|
|
122
|
-
install_path: str = prompt_for_path(
|
|
123
|
-
f"Default global installation path is {default_global_path}.",
|
|
124
|
-
default_global_path
|
|
125
|
-
)
|
|
126
|
-
if add_path:
|
|
127
|
-
add_to_path_windows(os.path.join(install_path, append_to_path))
|
|
128
|
-
return install_path
|
|
129
|
-
|
|
130
|
-
# Local install
|
|
131
|
-
else: # install_type == 'l'
|
|
132
|
-
return prompt_for_path(
|
|
133
|
-
f"Default local installation path is {default_local_path}.",
|
|
134
|
-
default_local_path
|
|
135
|
-
)
|
|
136
|
-
|
|
1
|
+
""" Installer module for Windows specific functions.
|
|
2
|
+
|
|
3
|
+
Provides Windows specific implementations for checking administrator privileges,
|
|
4
|
+
determining appropriate installation paths (global/local), and modifying
|
|
5
|
+
the user's PATH environment variable.
|
|
6
|
+
"""
|
|
7
|
+
# Imports
|
|
8
|
+
import os
|
|
9
|
+
|
|
10
|
+
from ..decorators import LogLevels, handle_error
|
|
11
|
+
from ..io import clean_path
|
|
12
|
+
from ..print import debug, info, warning
|
|
13
|
+
from .common import ask_install_type, prompt_for_path
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Functions
|
|
17
|
+
@handle_error(message="Failed to add to PATH (Windows)", error_log=LogLevels.WARNING_TRACEBACK)
|
|
18
|
+
def add_to_path_windows(install_path: str) -> bool | None:
|
|
19
|
+
""" Add install_path to the User PATH environment variable on Windows.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
install_path (str): The path to add to the User PATH environment variable.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
bool | None: True if the path was added to the User PATH environment variable, None otherwise.
|
|
26
|
+
"""
|
|
27
|
+
# Convert install_path to a Windows path if it's not already
|
|
28
|
+
install_path = install_path.replace("/", "\\")
|
|
29
|
+
os.makedirs(install_path, exist_ok=True)
|
|
30
|
+
|
|
31
|
+
# Get current user PATH
|
|
32
|
+
import winreg
|
|
33
|
+
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Environment", 0, winreg.KEY_READ | winreg.KEY_WRITE) as key:
|
|
34
|
+
|
|
35
|
+
# Get the number of values in the registry key
|
|
36
|
+
num_values = winreg.QueryInfoKey(key)[1]
|
|
37
|
+
|
|
38
|
+
# Find the index of the 'Path' value
|
|
39
|
+
path_index = -1
|
|
40
|
+
for i in range(num_values):
|
|
41
|
+
if winreg.EnumValue(key, i)[0] == 'Path':
|
|
42
|
+
path_index = i
|
|
43
|
+
break
|
|
44
|
+
|
|
45
|
+
# Get the current path value
|
|
46
|
+
current_path: str = winreg.EnumValue(key, path_index)[1]
|
|
47
|
+
|
|
48
|
+
# Check if path is already present
|
|
49
|
+
if install_path not in current_path.split(';'):
|
|
50
|
+
new_path: str = f"{current_path};{install_path}"
|
|
51
|
+
winreg.SetValueEx(key, "Path", 0, winreg.REG_EXPAND_SZ, new_path)
|
|
52
|
+
debug(f"Added '{install_path}' to user PATH. Please restart your terminal for changes to take effect.")
|
|
53
|
+
else:
|
|
54
|
+
debug(f"'{install_path}' is already in user PATH.")
|
|
55
|
+
return True
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def check_admin_windows() -> bool:
|
|
59
|
+
""" Check if the script is running with administrator privileges on Windows. """
|
|
60
|
+
try:
|
|
61
|
+
import ctypes
|
|
62
|
+
return ctypes.windll.shell32.IsUserAnAdmin() != 0
|
|
63
|
+
except Exception:
|
|
64
|
+
return False
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@handle_error(message="Failed to get installation path (Windows)", error_log=LogLevels.ERROR_TRACEBACK)
|
|
68
|
+
def get_install_path_windows(
|
|
69
|
+
program_name: str,
|
|
70
|
+
ask_global: int = 0,
|
|
71
|
+
add_path: bool = True,
|
|
72
|
+
append_to_path: str = "",
|
|
73
|
+
default_global: str = os.environ.get("ProgramFiles", "C:\\Program Files")
|
|
74
|
+
) -> str:
|
|
75
|
+
""" Get the installation path for the program
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
program_name (str): The name of the program to install.
|
|
79
|
+
ask_global (int): 0 = ask for anything, 1 = install globally, 2 = install locally
|
|
80
|
+
add_path (bool): Whether to add the program to the PATH environment variable. (Only if installed globally)
|
|
81
|
+
append_to_path (str): String to append to the installation path when adding to PATH.
|
|
82
|
+
(ex: "bin" if executables are in the bin folder)
|
|
83
|
+
default_global (str): The default global installation path.
|
|
84
|
+
(Default is "C:\\Program Files" which is the most common location for executables on Windows)
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
str: The installation path.
|
|
88
|
+
"""
|
|
89
|
+
# Default path is located in the current working directory
|
|
90
|
+
default_local_path: str = clean_path(os.path.join(os.getcwd(), program_name))
|
|
91
|
+
|
|
92
|
+
# Define default global path (used in prompt even if not chosen initially)
|
|
93
|
+
default_global_path: str = clean_path(os.path.join(default_global, program_name))
|
|
94
|
+
|
|
95
|
+
# Ask user for installation type (global/local)
|
|
96
|
+
install_type: str = ask_install_type(ask_global, default_local_path, default_global_path)
|
|
97
|
+
|
|
98
|
+
# If the user wants to install globally,
|
|
99
|
+
if install_type == 'g':
|
|
100
|
+
|
|
101
|
+
# Check if the user has admin privileges,
|
|
102
|
+
if not check_admin_windows():
|
|
103
|
+
|
|
104
|
+
# If the user doesn't have admin privileges, fallback to local
|
|
105
|
+
warning(
|
|
106
|
+
f"Global installation requires administrator privileges. Please re-run as administrator.\n"
|
|
107
|
+
f"Install locally instead to '{default_local_path}'? (Y/n): "
|
|
108
|
+
)
|
|
109
|
+
if input().lower() == 'n':
|
|
110
|
+
info("Installation cancelled.")
|
|
111
|
+
return ""
|
|
112
|
+
else:
|
|
113
|
+
# Fallback to local path if user agrees
|
|
114
|
+
return prompt_for_path(
|
|
115
|
+
f"Falling back to local installation path: {default_local_path}.",
|
|
116
|
+
default_local_path
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# If the user has admin privileges,
|
|
120
|
+
else:
|
|
121
|
+
# Ask it user wants to override the default global install path
|
|
122
|
+
install_path: str = prompt_for_path(
|
|
123
|
+
f"Default global installation path is {default_global_path}.",
|
|
124
|
+
default_global_path
|
|
125
|
+
)
|
|
126
|
+
if add_path:
|
|
127
|
+
add_to_path_windows(os.path.join(install_path, append_to_path))
|
|
128
|
+
return install_path
|
|
129
|
+
|
|
130
|
+
# Local install
|
|
131
|
+
else: # install_type == 'l'
|
|
132
|
+
return prompt_for_path(
|
|
133
|
+
f"Default local installation path is {default_local_path}.",
|
|
134
|
+
default_local_path
|
|
135
|
+
)
|
|
136
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from ..decorators import LogLevels as LogLevels, handle_error as handle_error
|
|
2
|
+
from ..io import clean_path as clean_path
|
|
3
|
+
from ..print import debug as debug, info as info, warning as warning
|
|
4
|
+
from .common import ask_install_type as ask_install_type, prompt_for_path as prompt_for_path
|
|
5
|
+
|
|
6
|
+
def add_to_path_windows(install_path: str) -> bool | None:
|
|
7
|
+
""" Add install_path to the User PATH environment variable on Windows.
|
|
8
|
+
|
|
9
|
+
\tArgs:
|
|
10
|
+
\t\tinstall_path (str): The path to add to the User PATH environment variable.
|
|
11
|
+
|
|
12
|
+
\tReturns:
|
|
13
|
+
\t\tbool | None: True if the path was added to the User PATH environment variable, None otherwise.
|
|
14
|
+
\t"""
|
|
15
|
+
def check_admin_windows() -> bool:
|
|
16
|
+
""" Check if the script is running with administrator privileges on Windows. """
|
|
17
|
+
def get_install_path_windows(program_name: str, ask_global: int = 0, add_path: bool = True, append_to_path: str = '', default_global: str = ...) -> str:
|
|
18
|
+
''' Get the installation path for the program
|
|
19
|
+
|
|
20
|
+
\tArgs:
|
|
21
|
+
\t\tprogram_name (str): The name of the program to install.
|
|
22
|
+
\t\task_global (int): 0 = ask for anything, 1 = install globally, 2 = install locally
|
|
23
|
+
\t\tadd_path (bool): Whether to add the program to the PATH environment variable. (Only if installed globally)
|
|
24
|
+
\t\tappend_to_path (str): String to append to the installation path when adding to PATH.
|
|
25
|
+
\t\t\t(ex: "bin" if executables are in the bin folder)
|
|
26
|
+
\t\tdefault_global (str): The default global installation path.
|
|
27
|
+
\t\t\t(Default is "C:\\Program Files" which is the most common location for executables on Windows)
|
|
28
|
+
|
|
29
|
+
\tReturns:
|
|
30
|
+
\t\tstr: The installation path.
|
|
31
|
+
\t'''
|
stouputils/io.pyi
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
from typing import Any, IO
|
|
2
|
+
|
|
3
|
+
def get_root_path(relative_path: str, go_up: int = 0) -> str:
|
|
4
|
+
""" Get the absolute path of the directory.
|
|
5
|
+
\tUsually used to get the root path of the project using the __file__ variable.
|
|
6
|
+
|
|
7
|
+
\tArgs:
|
|
8
|
+
\t\trelative_path (str): The path to get the absolute directory path from
|
|
9
|
+
\t\tgo_up (int): Number of parent directories to go up (default: 0)
|
|
10
|
+
\tReturns:
|
|
11
|
+
\t\tstr: The absolute path of the directory
|
|
12
|
+
|
|
13
|
+
\tExamples:
|
|
14
|
+
|
|
15
|
+
\t\t.. code-block:: python
|
|
16
|
+
|
|
17
|
+
\t\t\t> get_root_path(__file__)
|
|
18
|
+
\t\t\t'C:/Users/Alexandre-PC/AppData/Local/Programs/Python/Python310/lib/site-packages/stouputils'
|
|
19
|
+
|
|
20
|
+
\t\t\t> get_root_path(__file__, 3)
|
|
21
|
+
\t\t\t'C:/Users/Alexandre-PC/AppData/Local/Programs/Python/Python310'
|
|
22
|
+
\t"""
|
|
23
|
+
def relative_path(file_path: str, relative_to: str = '') -> str:
|
|
24
|
+
''' Get the relative path of a file relative to a given directory.
|
|
25
|
+
|
|
26
|
+
\tArgs:
|
|
27
|
+
\t\tfile_path (str): The path to get the relative path from
|
|
28
|
+
\t\trelative_to (str): The path to get the relative path to (default: current working directory -> os.getcwd())
|
|
29
|
+
\tReturns:
|
|
30
|
+
\t\tstr: The relative path of the file
|
|
31
|
+
\tExamples:
|
|
32
|
+
|
|
33
|
+
\t\t>>> relative_path("D:/some/random/path/stouputils/io.py", "D:\\\\some")
|
|
34
|
+
\t\t\'random/path/stouputils/io.py\'
|
|
35
|
+
\t\t>>> relative_path("D:/some/random/path/stouputils/io.py", "D:\\\\some\\\\")
|
|
36
|
+
\t\t\'random/path/stouputils/io.py\'
|
|
37
|
+
\t'''
|
|
38
|
+
def json_dump(data: Any, file: IO[Any] | str | None = None, max_level: int | None = 2, indent: str | int = '\t', suffix: str = '\n', ensure_ascii: bool = False) -> str:
|
|
39
|
+
''' Writes the provided data to a JSON file with a specified indentation depth.
|
|
40
|
+
\tFor instance, setting max_level to 2 will limit the indentation to 2 levels.
|
|
41
|
+
|
|
42
|
+
\tArgs:
|
|
43
|
+
\t\tdata\t\t(Any): \t\t\t\tThe data to dump (usually a dict or a list)
|
|
44
|
+
\t\tfile\t\t(IO[Any] | str): \tThe file object or path to dump the data to
|
|
45
|
+
\t\tmax_level\t(int | None):\t\tThe depth of indentation to stop at (-1 for infinite), None will default to 2
|
|
46
|
+
\t\tindent\t\t(str | int):\t\tThe indentation character (default: \'\\t\')
|
|
47
|
+
\t\tsuffix\t\t(str):\t\t\t\tThe suffix to add at the end of the string (default: \'\\n\')
|
|
48
|
+
\t\tensure_ascii (bool):\t\t\tWhether to escape non-ASCII characters (default: False)
|
|
49
|
+
\tReturns:
|
|
50
|
+
\t\tstr: The content of the file in every case
|
|
51
|
+
|
|
52
|
+
\t>>> json_dump({"a": [[1,2,3]], "b": 2}, max_level = 0)
|
|
53
|
+
\t\'{"a": [[1,2,3]],"b": 2}\\n\'
|
|
54
|
+
\t>>> json_dump({"a": [[1,2,3]], "b": 2}, max_level = 1)
|
|
55
|
+
\t\'{\\n\\t"a": [[1,2,3]],\\n\\t"b": 2\\n}\\n\'
|
|
56
|
+
\t>>> json_dump({"a": [[1,2,3]], "b": 2}, max_level = 2)
|
|
57
|
+
\t\'{\\n\\t"a": [\\n\\t\\t[1,2,3]\\n\\t],\\n\\t"b": 2\\n}\\n\'
|
|
58
|
+
\t>>> json_dump({"a": [[1,2,3]], "b": 2}, max_level = 3)
|
|
59
|
+
\t\'{\\n\\t"a": [\\n\\t\\t[\\n\\t\\t\\t1,\\n\\t\\t\\t2,\\n\\t\\t\\t3\\n\\t\\t]\\n\\t],\\n\\t"b": 2\\n}\\n\'
|
|
60
|
+
\t>>> json_dump({"éà": "üñ"}, ensure_ascii = True, max_level = 0)
|
|
61
|
+
\t\'{"\\\\u00e9\\\\u00e0": "\\\\u00fc\\\\u00f1"}\\n\'
|
|
62
|
+
\t>>> json_dump({"éà": "üñ"}, ensure_ascii = False, max_level = 0)
|
|
63
|
+
\t\'{"éà": "üñ"}\\n\'
|
|
64
|
+
\t'''
|
|
65
|
+
def json_load(file_path: str) -> Any:
|
|
66
|
+
""" Load a JSON file from the given path
|
|
67
|
+
|
|
68
|
+
\tArgs:
|
|
69
|
+
\t\tfile_path (str): The path to the JSON file
|
|
70
|
+
\tReturns:
|
|
71
|
+
\t\tAny: The content of the JSON file
|
|
72
|
+
\t"""
|
|
73
|
+
def csv_dump(data: Any, file: IO[Any] | str | None = None, delimiter: str = ',', has_header: bool = True, index: bool = False, *args: Any, **kwargs: Any) -> str:
|
|
74
|
+
''' Writes data to a CSV file with customizable options and returns the CSV content as a string.
|
|
75
|
+
|
|
76
|
+
\tArgs:
|
|
77
|
+
\t\tdata\t\t(list[list[Any]] | list[dict[str, Any]] | pd.DataFrame | pl.DataFrame):
|
|
78
|
+
\t\t\t\t\t\tThe data to write, either a list of lists, list of dicts, pandas DataFrame, or Polars DataFrame
|
|
79
|
+
\t\tfile\t\t(IO[Any] | str): The file object or path to dump the data to
|
|
80
|
+
\t\tdelimiter\t(str): The delimiter to use (default: \',\')
|
|
81
|
+
\t\thas_header\t(bool): Whether to include headers (default: True, applies to dict and DataFrame data)
|
|
82
|
+
\t\tindex\t\t(bool): Whether to include the index (default: False, only applies to pandas DataFrame)
|
|
83
|
+
\t\t*args\t\t(Any): Additional positional arguments to pass to the underlying CSV writer or DataFrame method
|
|
84
|
+
\t\t**kwargs\t(Any): Additional keyword arguments to pass to the underlying CSV writer or DataFrame method
|
|
85
|
+
\tReturns:
|
|
86
|
+
\t\tstr: The CSV content as a string
|
|
87
|
+
|
|
88
|
+
\tExamples:
|
|
89
|
+
|
|
90
|
+
\t\t>>> csv_dump([["a", "b", "c"], [1, 2, 3], [4, 5, 6]])
|
|
91
|
+
\t\t\'a,b,c\\r\\n1,2,3\\r\\n4,5,6\\r\\n\'
|
|
92
|
+
|
|
93
|
+
\t\t>>> csv_dump([{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}])
|
|
94
|
+
\t\t\'name,age\\r\\nAlice,30\\r\\nBob,25\\r\\n\'
|
|
95
|
+
\t'''
|
|
96
|
+
def csv_load(file_path: str, delimiter: str = ',', has_header: bool = True, as_dict: bool = False, as_dataframe: bool = False, use_polars: bool = False, *args: Any, **kwargs: Any) -> Any:
|
|
97
|
+
''' Load a CSV file from the given path
|
|
98
|
+
|
|
99
|
+
\tArgs:
|
|
100
|
+
\t\tfile_path (str): The path to the CSV file
|
|
101
|
+
\t\tdelimiter (str): The delimiter used in the CSV (default: \',\')
|
|
102
|
+
\t\thas_header (bool): Whether the CSV has a header row (default: True)
|
|
103
|
+
\t\tas_dict (bool): Whether to return data as list of dicts (default: False)
|
|
104
|
+
\t\tas_dataframe (bool): Whether to return data as a DataFrame (default: False)
|
|
105
|
+
\t\tuse_polars (bool): Whether to use Polars instead of pandas for DataFrame (default: False, requires polars)
|
|
106
|
+
\t\t*args: Additional positional arguments to pass to the underlying CSV reader or DataFrame method
|
|
107
|
+
\t\t**kwargs: Additional keyword arguments to pass to the underlying CSV reader or DataFrame method
|
|
108
|
+
\tReturns:
|
|
109
|
+
\t\tlist[list[str]] | list[dict[str, str]] | pd.DataFrame | pl.DataFrame: The content of the CSV file
|
|
110
|
+
|
|
111
|
+
\tExamples:
|
|
112
|
+
|
|
113
|
+
\t\t.. code-block:: python
|
|
114
|
+
|
|
115
|
+
\t\t\t> Assuming "test.csv" contains: a,b,c\\n1,2,3\\n4,5,6
|
|
116
|
+
\t\t\t> csv_load("test.csv")
|
|
117
|
+
\t\t\t[[\'1\', \'2\', \'3\'], [\'4\', \'5\', \'6\']]
|
|
118
|
+
|
|
119
|
+
\t\t\t> csv_load("test.csv", as_dict=True)
|
|
120
|
+
\t\t\t[{\'a\': \'1\', \'b\': \'2\', \'c\': \'3\'}, {\'a\': \'4\', \'b\': \'5\', \'c\': \'6\'}]
|
|
121
|
+
|
|
122
|
+
\t\t\t> csv_load("test.csv", as_dataframe=True)
|
|
123
|
+
\t\t\t a b c
|
|
124
|
+
\t\t\t0 1 2 3
|
|
125
|
+
\t\t\t1 4 5 6
|
|
126
|
+
|
|
127
|
+
\t\t.. code-block:: console
|
|
128
|
+
|
|
129
|
+
\t\t\t> csv_load("test.csv", as_dataframe=True, use_polars=True)
|
|
130
|
+
\t\t\tshape: (2, 3)
|
|
131
|
+
\t\t\t┌─────┬─────┬─────┐
|
|
132
|
+
\t\t\t│ a ┆ b ┆ c │
|
|
133
|
+
\t\t\t│ --- ┆ --- ┆ --- │
|
|
134
|
+
\t\t\t│ i64 ┆ i64 ┆ i64 │
|
|
135
|
+
\t\t\t╞═════╪═════╪═════╡
|
|
136
|
+
\t\t\t│ 1 ┆ 2 ┆ 3 │
|
|
137
|
+
\t\t\t│ 4 ┆ 5 ┆ 6 │
|
|
138
|
+
\t\t\t└─────┴─────┴─────┘
|
|
139
|
+
\t'''
|
|
140
|
+
def super_copy(src: str, dst: str, create_dir: bool = True, symlink: bool = False) -> str:
|
|
141
|
+
""" Copy a file (or a folder) from the source to the destination
|
|
142
|
+
|
|
143
|
+
\tArgs:
|
|
144
|
+
\t\tsrc (str): The source path
|
|
145
|
+
\t\tdst (str): The destination path
|
|
146
|
+
\t\tcreate_dir (bool): Whether to create the directory if it doesn't exist (default: True)
|
|
147
|
+
\t\tsymlink (bool): Whether to create a symlink instead of copying (Linux only, default: True)
|
|
148
|
+
\tReturns:
|
|
149
|
+
\t\tstr: The destination path
|
|
150
|
+
\t"""
|
|
151
|
+
def super_open(file_path: str, mode: str, encoding: str = 'utf-8') -> IO[Any]:
|
|
152
|
+
''' Open a file with the given mode, creating the directory if it doesn\'t exist (only if writing)
|
|
153
|
+
|
|
154
|
+
\tArgs:
|
|
155
|
+
\t\tfile_path\t(str): The path to the file
|
|
156
|
+
\t\tmode\t\t(str): The mode to open the file with, ex: "w", "r", "a", "wb", "rb", "ab"
|
|
157
|
+
\t\tencoding\t(str): The encoding to use when opening the file (default: "utf-8")
|
|
158
|
+
\tReturns:
|
|
159
|
+
\t\topen: The file object, ready to be used
|
|
160
|
+
\t'''
|
|
161
|
+
def read_file(file_path: str, encoding: str = 'utf-8') -> str:
|
|
162
|
+
''' Read the content of a file and return it as a string
|
|
163
|
+
|
|
164
|
+
\tArgs:
|
|
165
|
+
\t\tfile_path (str): The path to the file
|
|
166
|
+
\t\tencoding (str): The encoding to use when opening the file (default: "utf-8")
|
|
167
|
+
\tReturns:
|
|
168
|
+
\t\tstr: The content of the file
|
|
169
|
+
\t'''
|
|
170
|
+
def replace_tilde(path: str) -> str:
|
|
171
|
+
''' Replace the "~" by the user\'s home directory
|
|
172
|
+
|
|
173
|
+
\tArgs:
|
|
174
|
+
\t\tpath (str): The path to replace the "~" by the user\'s home directory
|
|
175
|
+
\tReturns:
|
|
176
|
+
\t\tstr: The path with the "~" replaced by the user\'s home directory
|
|
177
|
+
\tExamples:
|
|
178
|
+
|
|
179
|
+
\t\t.. code-block:: python
|
|
180
|
+
|
|
181
|
+
\t\t\t> replace_tilde("~/Documents/test.txt")
|
|
182
|
+
\t\t\t\'/home/user/Documents/test.txt\'
|
|
183
|
+
\t'''
|
|
184
|
+
def clean_path(file_path: str, trailing_slash: bool = True) -> str:
|
|
185
|
+
''' Clean the path by replacing backslashes with forward slashes and simplifying the path
|
|
186
|
+
|
|
187
|
+
\tArgs:
|
|
188
|
+
\t\tfile_path (str): The path to clean
|
|
189
|
+
\t\ttrailing_slash (bool): Whether to keep the trailing slash, ex: "test/" -> "test/"
|
|
190
|
+
\tReturns:
|
|
191
|
+
\t\tstr: The cleaned path
|
|
192
|
+
\tExamples:
|
|
193
|
+
\t\t>>> clean_path("C:\\\\Users\\\\Stoupy\\\\Documents\\\\test.txt")
|
|
194
|
+
\t\t\'C:/Users/Stoupy/Documents/test.txt\'
|
|
195
|
+
|
|
196
|
+
\t\t>>> clean_path("Some Folder////")
|
|
197
|
+
\t\t\'Some Folder/\'
|
|
198
|
+
|
|
199
|
+
\t\t>>> clean_path("test/uwu/1/../../")
|
|
200
|
+
\t\t\'test/\'
|
|
201
|
+
|
|
202
|
+
\t\t>>> clean_path("some/./folder/../")
|
|
203
|
+
\t\t\'some/\'
|
|
204
|
+
|
|
205
|
+
\t\t>>> clean_path("folder1/folder2/../../folder3")
|
|
206
|
+
\t\t\'folder3\'
|
|
207
|
+
|
|
208
|
+
\t\t>>> clean_path("./test/./folder/")
|
|
209
|
+
\t\t\'test/folder/\'
|
|
210
|
+
|
|
211
|
+
\t\t>>> clean_path("C:/folder1\\\\folder2")
|
|
212
|
+
\t\t\'C:/folder1/folder2\'
|
|
213
|
+
\t'''
|
stouputils/parallel.py
CHANGED
|
@@ -335,8 +335,8 @@ def run_in_subprocess[R](
|
|
|
335
335
|
import multiprocessing as mp
|
|
336
336
|
from multiprocessing import Queue
|
|
337
337
|
|
|
338
|
-
# Create a queue to get the result from the subprocess
|
|
339
|
-
result_queue: Queue[R | Exception] = Queue()
|
|
338
|
+
# Create a queue to get the result from the subprocess (only if we need to wait)
|
|
339
|
+
result_queue: Queue[R | Exception] | None = None if no_join else Queue()
|
|
340
340
|
|
|
341
341
|
# Create and start the subprocess using the module-level wrapper
|
|
342
342
|
process: mp.Process = mp.Process(
|
|
@@ -345,8 +345,9 @@ def run_in_subprocess[R](
|
|
|
345
345
|
)
|
|
346
346
|
process.start()
|
|
347
347
|
|
|
348
|
-
#
|
|
349
|
-
if
|
|
348
|
+
# Detach process if no_join (fire-and-forget)
|
|
349
|
+
if result_queue is None:
|
|
350
|
+
process.close() # Detach the process
|
|
350
351
|
return None # type: ignore
|
|
351
352
|
process.join(timeout=timeout)
|
|
352
353
|
|
|
@@ -394,16 +395,18 @@ def _subprocess_wrapper[R](
|
|
|
394
395
|
Must be at module level to be pickable on Windows (spawn context).
|
|
395
396
|
|
|
396
397
|
Args:
|
|
397
|
-
result_queue (multiprocessing.Queue): Queue to store the result or exception.
|
|
398
|
-
func (Callable):
|
|
399
|
-
args (tuple):
|
|
400
|
-
kwargs (dict):
|
|
398
|
+
result_queue (multiprocessing.Queue | None): Queue to store the result or exception (None if detached).
|
|
399
|
+
func (Callable): The target function to execute.
|
|
400
|
+
args (tuple): Positional arguments for the function.
|
|
401
|
+
kwargs (dict): Keyword arguments for the function.
|
|
401
402
|
"""
|
|
402
403
|
try:
|
|
403
404
|
result: R = func(*args, **kwargs)
|
|
404
|
-
result_queue
|
|
405
|
+
if result_queue is not None:
|
|
406
|
+
result_queue.put(result)
|
|
405
407
|
except Exception as e:
|
|
406
|
-
result_queue
|
|
408
|
+
if result_queue is not None:
|
|
409
|
+
result_queue.put(e)
|
|
407
410
|
|
|
408
411
|
# "Private" function to use starmap
|
|
409
412
|
def _starmap[T, R](args: tuple[Callable[[T], R], list[T]]) -> R:
|