stouputils 1.14.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.
Files changed (140) hide show
  1. stouputils/__init__.py +40 -0
  2. stouputils/__main__.py +86 -0
  3. stouputils/_deprecated.py +37 -0
  4. stouputils/all_doctests.py +160 -0
  5. stouputils/applications/__init__.py +22 -0
  6. stouputils/applications/automatic_docs.py +634 -0
  7. stouputils/applications/upscaler/__init__.py +39 -0
  8. stouputils/applications/upscaler/config.py +128 -0
  9. stouputils/applications/upscaler/image.py +247 -0
  10. stouputils/applications/upscaler/video.py +287 -0
  11. stouputils/archive.py +344 -0
  12. stouputils/backup.py +488 -0
  13. stouputils/collections.py +244 -0
  14. stouputils/continuous_delivery/__init__.py +27 -0
  15. stouputils/continuous_delivery/cd_utils.py +243 -0
  16. stouputils/continuous_delivery/github.py +522 -0
  17. stouputils/continuous_delivery/pypi.py +130 -0
  18. stouputils/continuous_delivery/pyproject.py +147 -0
  19. stouputils/continuous_delivery/stubs.py +86 -0
  20. stouputils/ctx.py +408 -0
  21. stouputils/data_science/config/get.py +51 -0
  22. stouputils/data_science/config/set.py +125 -0
  23. stouputils/data_science/data_processing/image/__init__.py +66 -0
  24. stouputils/data_science/data_processing/image/auto_contrast.py +79 -0
  25. stouputils/data_science/data_processing/image/axis_flip.py +58 -0
  26. stouputils/data_science/data_processing/image/bias_field_correction.py +74 -0
  27. stouputils/data_science/data_processing/image/binary_threshold.py +73 -0
  28. stouputils/data_science/data_processing/image/blur.py +59 -0
  29. stouputils/data_science/data_processing/image/brightness.py +54 -0
  30. stouputils/data_science/data_processing/image/canny.py +110 -0
  31. stouputils/data_science/data_processing/image/clahe.py +92 -0
  32. stouputils/data_science/data_processing/image/common.py +30 -0
  33. stouputils/data_science/data_processing/image/contrast.py +53 -0
  34. stouputils/data_science/data_processing/image/curvature_flow_filter.py +74 -0
  35. stouputils/data_science/data_processing/image/denoise.py +378 -0
  36. stouputils/data_science/data_processing/image/histogram_equalization.py +123 -0
  37. stouputils/data_science/data_processing/image/invert.py +64 -0
  38. stouputils/data_science/data_processing/image/laplacian.py +60 -0
  39. stouputils/data_science/data_processing/image/median_blur.py +52 -0
  40. stouputils/data_science/data_processing/image/noise.py +59 -0
  41. stouputils/data_science/data_processing/image/normalize.py +65 -0
  42. stouputils/data_science/data_processing/image/random_erase.py +66 -0
  43. stouputils/data_science/data_processing/image/resize.py +69 -0
  44. stouputils/data_science/data_processing/image/rotation.py +80 -0
  45. stouputils/data_science/data_processing/image/salt_pepper.py +68 -0
  46. stouputils/data_science/data_processing/image/sharpening.py +55 -0
  47. stouputils/data_science/data_processing/image/shearing.py +64 -0
  48. stouputils/data_science/data_processing/image/threshold.py +64 -0
  49. stouputils/data_science/data_processing/image/translation.py +71 -0
  50. stouputils/data_science/data_processing/image/zoom.py +83 -0
  51. stouputils/data_science/data_processing/image_augmentation.py +118 -0
  52. stouputils/data_science/data_processing/image_preprocess.py +183 -0
  53. stouputils/data_science/data_processing/prosthesis_detection.py +359 -0
  54. stouputils/data_science/data_processing/technique.py +481 -0
  55. stouputils/data_science/dataset/__init__.py +45 -0
  56. stouputils/data_science/dataset/dataset.py +292 -0
  57. stouputils/data_science/dataset/dataset_loader.py +135 -0
  58. stouputils/data_science/dataset/grouping_strategy.py +296 -0
  59. stouputils/data_science/dataset/image_loader.py +100 -0
  60. stouputils/data_science/dataset/xy_tuple.py +696 -0
  61. stouputils/data_science/metric_dictionnary.py +106 -0
  62. stouputils/data_science/metric_utils.py +847 -0
  63. stouputils/data_science/mlflow_utils.py +206 -0
  64. stouputils/data_science/models/abstract_model.py +149 -0
  65. stouputils/data_science/models/all.py +85 -0
  66. stouputils/data_science/models/base_keras.py +765 -0
  67. stouputils/data_science/models/keras/all.py +38 -0
  68. stouputils/data_science/models/keras/convnext.py +62 -0
  69. stouputils/data_science/models/keras/densenet.py +50 -0
  70. stouputils/data_science/models/keras/efficientnet.py +60 -0
  71. stouputils/data_science/models/keras/mobilenet.py +56 -0
  72. stouputils/data_science/models/keras/resnet.py +52 -0
  73. stouputils/data_science/models/keras/squeezenet.py +233 -0
  74. stouputils/data_science/models/keras/vgg.py +42 -0
  75. stouputils/data_science/models/keras/xception.py +38 -0
  76. stouputils/data_science/models/keras_utils/callbacks/__init__.py +20 -0
  77. stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +219 -0
  78. stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +148 -0
  79. stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +31 -0
  80. stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +249 -0
  81. stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +66 -0
  82. stouputils/data_science/models/keras_utils/losses/__init__.py +12 -0
  83. stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +56 -0
  84. stouputils/data_science/models/keras_utils/visualizations.py +416 -0
  85. stouputils/data_science/models/model_interface.py +939 -0
  86. stouputils/data_science/models/sandbox.py +116 -0
  87. stouputils/data_science/range_tuple.py +234 -0
  88. stouputils/data_science/scripts/augment_dataset.py +77 -0
  89. stouputils/data_science/scripts/exhaustive_process.py +133 -0
  90. stouputils/data_science/scripts/preprocess_dataset.py +70 -0
  91. stouputils/data_science/scripts/routine.py +168 -0
  92. stouputils/data_science/utils.py +285 -0
  93. stouputils/decorators.py +605 -0
  94. stouputils/image.py +441 -0
  95. stouputils/installer/__init__.py +18 -0
  96. stouputils/installer/common.py +67 -0
  97. stouputils/installer/downloader.py +101 -0
  98. stouputils/installer/linux.py +144 -0
  99. stouputils/installer/main.py +223 -0
  100. stouputils/installer/windows.py +136 -0
  101. stouputils/io.py +486 -0
  102. stouputils/parallel.py +483 -0
  103. stouputils/print.py +482 -0
  104. stouputils/py.typed +1 -0
  105. stouputils/stouputils/__init__.pyi +15 -0
  106. stouputils/stouputils/_deprecated.pyi +12 -0
  107. stouputils/stouputils/all_doctests.pyi +46 -0
  108. stouputils/stouputils/applications/__init__.pyi +2 -0
  109. stouputils/stouputils/applications/automatic_docs.pyi +106 -0
  110. stouputils/stouputils/applications/upscaler/__init__.pyi +3 -0
  111. stouputils/stouputils/applications/upscaler/config.pyi +18 -0
  112. stouputils/stouputils/applications/upscaler/image.pyi +109 -0
  113. stouputils/stouputils/applications/upscaler/video.pyi +60 -0
  114. stouputils/stouputils/archive.pyi +67 -0
  115. stouputils/stouputils/backup.pyi +109 -0
  116. stouputils/stouputils/collections.pyi +86 -0
  117. stouputils/stouputils/continuous_delivery/__init__.pyi +5 -0
  118. stouputils/stouputils/continuous_delivery/cd_utils.pyi +129 -0
  119. stouputils/stouputils/continuous_delivery/github.pyi +162 -0
  120. stouputils/stouputils/continuous_delivery/pypi.pyi +53 -0
  121. stouputils/stouputils/continuous_delivery/pyproject.pyi +67 -0
  122. stouputils/stouputils/continuous_delivery/stubs.pyi +39 -0
  123. stouputils/stouputils/ctx.pyi +211 -0
  124. stouputils/stouputils/decorators.pyi +252 -0
  125. stouputils/stouputils/image.pyi +172 -0
  126. stouputils/stouputils/installer/__init__.pyi +5 -0
  127. stouputils/stouputils/installer/common.pyi +39 -0
  128. stouputils/stouputils/installer/downloader.pyi +24 -0
  129. stouputils/stouputils/installer/linux.pyi +39 -0
  130. stouputils/stouputils/installer/main.pyi +57 -0
  131. stouputils/stouputils/installer/windows.pyi +31 -0
  132. stouputils/stouputils/io.pyi +213 -0
  133. stouputils/stouputils/parallel.pyi +216 -0
  134. stouputils/stouputils/print.pyi +136 -0
  135. stouputils/stouputils/version_pkg.pyi +15 -0
  136. stouputils/version_pkg.py +189 -0
  137. stouputils-1.14.0.dist-info/METADATA +178 -0
  138. stouputils-1.14.0.dist-info/RECORD +140 -0
  139. stouputils-1.14.0.dist-info/WHEEL +4 -0
  140. stouputils-1.14.0.dist-info/entry_points.txt +3 -0
@@ -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'''
@@ -0,0 +1,216 @@
1
+ from .ctx import SetMPStartMethod as SetMPStartMethod
2
+ from .print import BAR_FORMAT as BAR_FORMAT, MAGENTA as MAGENTA
3
+ from collections.abc import Callable, Iterable
4
+ from typing import Any, TypeVar
5
+
6
+ def doctest_square(x: int) -> int: ...
7
+ def doctest_slow(x: int) -> int: ...
8
+
9
+ CPU_COUNT: int
10
+ T = TypeVar('T')
11
+ R = TypeVar('R')
12
+
13
+ def multiprocessing[T, R](func: Callable[..., R] | list[Callable[..., R]], args: Iterable[T], use_starmap: bool = False, chunksize: int = 1, desc: str = '', max_workers: int | float = ..., delay_first_calls: float = 0, color: str = ..., bar_format: str = ..., ascii: bool = False, smooth_tqdm: bool = True, **tqdm_kwargs: Any) -> list[R]:
14
+ ''' Method to execute a function in parallel using multiprocessing
15
+
16
+ \t- For CPU-bound operations where the GIL (Global Interpreter Lock) is a bottleneck.
17
+ \t- When the task can be divided into smaller, independent sub-tasks that can be executed concurrently.
18
+ \t- For computationally intensive tasks like scientific simulations, data analysis, or machine learning workloads.
19
+
20
+ \tArgs:
21
+ \t\tfunc\t\t\t\t(Callable | list[Callable]):\tFunction to execute, or list of functions (one per argument)
22
+ \t\targs\t\t\t\t(Iterable):\t\t\tIterable of arguments to pass to the function(s)
23
+ \t\tuse_starmap\t\t\t(bool):\t\t\t\tWhether to use starmap or not (Defaults to False):
24
+ \t\t\tTrue means the function will be called like func(\\*args[i]) instead of func(args[i])
25
+ \t\tchunksize\t\t\t(int):\t\t\t\tNumber of arguments to process at a time
26
+ \t\t\t(Defaults to 1 for proper progress bar display)
27
+ \t\tdesc\t\t\t\t(str):\t\t\t\tDescription displayed in the progress bar
28
+ \t\t\t(if not provided no progress bar will be displayed)
29
+ \t\tmax_workers\t\t\t(int | float):\t\tNumber of workers to use (Defaults to CPU_COUNT), -1 means CPU_COUNT.
30
+ \t\t\tIf float between 0 and 1, it\'s treated as a percentage of CPU_COUNT.
31
+ \t\t\tIf negative float between -1 and 0, it\'s treated as a percentage of len(args).
32
+ \t\tdelay_first_calls\t(float):\t\t\tApply i*delay_first_calls seconds delay to the first "max_workers" calls.
33
+ \t\t\tFor instance, the first process will be delayed by 0 seconds, the second by 1 second, etc.
34
+ \t\t\t(Defaults to 0): This can be useful to avoid functions being called in the same second.
35
+ \t\tcolor\t\t\t\t(str):\t\t\t\tColor of the progress bar (Defaults to MAGENTA)
36
+ \t\tbar_format\t\t\t(str):\t\t\t\tFormat of the progress bar (Defaults to BAR_FORMAT)
37
+ \t\tascii\t\t\t\t(bool):\t\t\t\tWhether to use ASCII or Unicode characters for the progress bar
38
+ \t\tsmooth_tqdm\t\t\t(bool):\t\t\t\tWhether to enable smooth progress bar updates by setting miniters and mininterval (Defaults to True)
39
+ \t\t**tqdm_kwargs\t\t(Any):\t\t\t\tAdditional keyword arguments to pass to tqdm
40
+
41
+ \tReturns:
42
+ \t\tlist[object]:\tResults of the function execution
43
+
44
+ \tExamples:
45
+ \t\t.. code-block:: python
46
+
47
+ \t\t\t> multiprocessing(doctest_square, args=[1, 2, 3])
48
+ \t\t\t[1, 4, 9]
49
+
50
+ \t\t\t> multiprocessing(int.__mul__, [(1,2), (3,4), (5,6)], use_starmap=True)
51
+ \t\t\t[2, 12, 30]
52
+
53
+ \t\t\t> # Using a list of functions (one per argument)
54
+ \t\t\t> multiprocessing([doctest_square, doctest_square, doctest_square], [1, 2, 3])
55
+ \t\t\t[1, 4, 9]
56
+
57
+ \t\t\t> # Will process in parallel with progress bar
58
+ \t\t\t> multiprocessing(doctest_slow, range(10), desc="Processing")
59
+ \t\t\t[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
60
+
61
+ \t\t\t> # Will process in parallel with progress bar and delay the first threads
62
+ \t\t\t> multiprocessing(
63
+ \t\t\t. doctest_slow,
64
+ \t\t\t. range(10),
65
+ \t\t\t. desc="Processing with delay",
66
+ \t\t\t. max_workers=2,
67
+ \t\t\t. delay_first_calls=0.6
68
+ \t\t\t. )
69
+ \t\t\t[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
70
+ \t'''
71
+ def multithreading[T, R](func: Callable[..., R] | list[Callable[..., R]], args: Iterable[T], use_starmap: bool = False, desc: str = '', max_workers: int | float = ..., delay_first_calls: float = 0, color: str = ..., bar_format: str = ..., ascii: bool = False, smooth_tqdm: bool = True, **tqdm_kwargs: Any) -> list[R]:
72
+ ''' Method to execute a function in parallel using multithreading, you should use it:
73
+
74
+ \t- For I/O-bound operations where the GIL is not a bottleneck, such as network requests or disk operations.
75
+ \t- When the task involves waiting for external resources, such as network responses or user input.
76
+ \t- For operations that involve a lot of waiting, such as GUI event handling or handling user input.
77
+
78
+ \tArgs:
79
+ \t\tfunc\t\t\t\t(Callable | list[Callable]):\tFunction to execute, or list of functions (one per argument)
80
+ \t\targs\t\t\t\t(Iterable):\t\t\tIterable of arguments to pass to the function(s)
81
+ \t\tuse_starmap\t\t\t(bool):\t\t\t\tWhether to use starmap or not (Defaults to False):
82
+ \t\t\tTrue means the function will be called like func(\\*args[i]) instead of func(args[i])
83
+ \t\tdesc\t\t\t\t(str):\t\t\t\tDescription displayed in the progress bar
84
+ \t\t\t(if not provided no progress bar will be displayed)
85
+ \t\tmax_workers\t\t\t(int | float):\t\tNumber of workers to use (Defaults to CPU_COUNT), -1 means CPU_COUNT.
86
+ \t\t\tIf float between 0 and 1, it\'s treated as a percentage of CPU_COUNT.
87
+ \t\t\tIf negative float between -1 and 0, it\'s treated as a percentage of len(args).
88
+ \t\tdelay_first_calls\t(float):\t\t\tApply i*delay_first_calls seconds delay to the first "max_workers" calls.
89
+ \t\t\tFor instance with value to 1, the first thread will be delayed by 0 seconds, the second by 1 second, etc.
90
+ \t\t\t(Defaults to 0): This can be useful to avoid functions being called in the same second.
91
+ \t\tcolor\t\t\t\t(str):\t\t\t\tColor of the progress bar (Defaults to MAGENTA)
92
+ \t\tbar_format\t\t\t(str):\t\t\t\tFormat of the progress bar (Defaults to BAR_FORMAT)
93
+ \t\tascii\t\t\t\t(bool):\t\t\t\tWhether to use ASCII or Unicode characters for the progress bar
94
+ \t\tsmooth_tqdm\t\t\t(bool):\t\t\t\tWhether to enable smooth progress bar updates by setting miniters and mininterval (Defaults to True)
95
+ \t\t**tqdm_kwargs\t\t(Any):\t\t\t\tAdditional keyword arguments to pass to tqdm
96
+
97
+ \tReturns:
98
+ \t\tlist[object]:\tResults of the function execution
99
+
100
+ \tExamples:
101
+ \t\t.. code-block:: python
102
+
103
+ \t\t\t> multithreading(doctest_square, args=[1, 2, 3])
104
+ \t\t\t[1, 4, 9]
105
+
106
+ \t\t\t> multithreading(int.__mul__, [(1,2), (3,4), (5,6)], use_starmap=True)
107
+ \t\t\t[2, 12, 30]
108
+
109
+ \t\t\t> # Using a list of functions (one per argument)
110
+ \t\t\t> multithreading([doctest_square, doctest_square, doctest_square], [1, 2, 3])
111
+ \t\t\t[1, 4, 9]
112
+
113
+ \t\t\t> # Will process in parallel with progress bar
114
+ \t\t\t> multithreading(doctest_slow, range(10), desc="Threading")
115
+ \t\t\t[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
116
+
117
+ \t\t\t> # Will process in parallel with progress bar and delay the first threads
118
+ \t\t\t> multithreading(
119
+ \t\t\t. doctest_slow,
120
+ \t\t\t. range(10),
121
+ \t\t\t. desc="Threading with delay",
122
+ \t\t\t. max_workers=2,
123
+ \t\t\t. delay_first_calls=0.6
124
+ \t\t\t. )
125
+ \t\t\t[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
126
+ \t'''
127
+ def run_in_subprocess[R](func: Callable[..., R], *args: Any, timeout: float | None = None, no_join: bool = False, **kwargs: Any) -> R:
128
+ ''' Execute a function in a subprocess with positional and keyword arguments.
129
+
130
+ \tThis is useful when you need to run a function in isolation to avoid memory leaks,
131
+ \tresource conflicts, or to ensure a clean execution environment. The subprocess will
132
+ \tbe created, run the function with the provided arguments, and return the result.
133
+
134
+ \tArgs:
135
+ \t\tfunc (Callable): The function to execute in a subprocess.
136
+ \t\t\t(SHOULD BE A TOP-LEVEL FUNCTION TO BE PICKLABLE)
137
+ \t\t*args (Any): Positional arguments to pass to the function.
138
+ \t\ttimeout (float | None): Maximum time in seconds to wait for the subprocess.
139
+ \t\t\tIf None, wait indefinitely. If the subprocess exceeds this time, it will be terminated.
140
+ \t\tno_join (bool): If True, do not wait for the subprocess to finish (fire-and-forget).
141
+ \t\t**kwargs (Any): Keyword arguments to pass to the function.
142
+
143
+ \tReturns:
144
+ \t\tR: The return value of the function.
145
+
146
+ \tRaises:
147
+ \t\tRuntimeError: If the subprocess exits with a non-zero exit code or times out.
148
+ \t\tTimeoutError: If the subprocess exceeds the specified timeout.
149
+
150
+ \tExamples:
151
+ \t\t.. code-block:: python
152
+
153
+ \t\t\t> # Simple function execution
154
+ \t\t\t> run_in_subprocess(doctest_square, 5)
155
+ \t\t\t25
156
+
157
+ \t\t\t> # Function with multiple arguments
158
+ \t\t\t> def add(a: int, b: int) -> int:
159
+ \t\t\t. return a + b
160
+ \t\t\t> run_in_subprocess(add, 10, 20)
161
+ \t\t\t30
162
+
163
+ \t\t\t> # Function with keyword arguments
164
+ \t\t\t> def greet(name: str, greeting: str = "Hello") -> str:
165
+ \t\t\t. return f"{greeting}, {name}!"
166
+ \t\t\t> run_in_subprocess(greet, "World", greeting="Hi")
167
+ \t\t\t\'Hi, World!\'
168
+
169
+ \t\t\t> # With timeout to prevent hanging
170
+ \t\t\t> run_in_subprocess(some_gpu_func, data, timeout=300.0)
171
+ \t'''
172
+ def _subprocess_wrapper[R](result_queue: Any, func: Callable[..., R], args: tuple[Any, ...], kwargs: dict[str, Any]) -> None:
173
+ """ Wrapper function to execute the target function and store the result in the queue.
174
+
175
+ \tMust be at module level to be pickable on Windows (spawn context).
176
+
177
+ \tArgs:
178
+ \t\tresult_queue (multiprocessing.Queue): Queue to store the result or exception.
179
+ \t\tfunc (Callable): The target function to execute.
180
+ \t\targs (tuple): Positional arguments for the function.
181
+ \t\tkwargs (dict): Keyword arguments for the function.
182
+ \t"""
183
+ def _starmap[T, R](args: tuple[Callable[[T], R], list[T]]) -> R:
184
+ """ Private function to use starmap using args[0](\\*args[1])
185
+
186
+ \tArgs:
187
+ \t\targs (tuple): Tuple containing the function and the arguments list to pass to the function
188
+ \tReturns:
189
+ \t\tobject: Result of the function execution
190
+ \t"""
191
+ def _delayed_call[T, R](args: tuple[Callable[[T], R], float, T]) -> R:
192
+ """ Private function to apply delay before calling the target function
193
+
194
+ \tArgs:
195
+ \t\targs (tuple): Tuple containing the function, delay in seconds, and the argument to pass to the function
196
+ \tReturns:
197
+ \t\tobject: Result of the function execution
198
+ \t"""
199
+ def _handle_parameters[T, R](func: Callable[[T], R] | list[Callable[[T], R]], args: list[T], use_starmap: bool, delay_first_calls: float, max_workers: int, desc: str, color: str) -> tuple[str, Callable[[T], R], list[T]]:
200
+ ''' Private function to handle the parameters for multiprocessing or multithreading functions
201
+
202
+ \tArgs:
203
+ \t\tfunc\t\t\t\t(Callable | list[Callable]):\tFunction to execute, or list of functions (one per argument)
204
+ \t\targs\t\t\t\t(list):\t\t\t\tList of arguments to pass to the function(s)
205
+ \t\tuse_starmap\t\t\t(bool):\t\t\t\tWhether to use starmap or not (Defaults to False):
206
+ \t\t\tTrue means the function will be called like func(\\*args[i]) instead of func(args[i])
207
+ \t\tdelay_first_calls\t(int):\t\t\t\tApply i*delay_first_calls seconds delay to the first "max_workers" calls.
208
+ \t\t\tFor instance, the first process will be delayed by 0 seconds, the second by 1 second, etc. (Defaults to 0):
209
+ \t\t\tThis can be useful to avoid functions being called in the same second.
210
+ \t\tmax_workers\t\t\t(int):\t\t\t\tNumber of workers to use (Defaults to CPU_COUNT)
211
+ \t\tdesc\t\t\t\t(str):\t\t\t\tDescription of the function execution displayed in the progress bar
212
+ \t\tcolor\t\t\t\t(str):\t\t\t\tColor of the progress bar
213
+
214
+ \tReturns:
215
+ \t\ttuple[str, Callable[[T], R], list[T]]:\tTuple containing the description, function, and arguments
216
+ \t'''
@@ -0,0 +1,136 @@
1
+ from collections.abc import Callable as Callable, Iterable, Iterator
2
+ from typing import Any, IO, TextIO, TypeVar
3
+
4
+ RESET: str
5
+ RED: str
6
+ GREEN: str
7
+ YELLOW: str
8
+ BLUE: str
9
+ MAGENTA: str
10
+ CYAN: str
11
+ LINE_UP: str
12
+ BAR_FORMAT: str
13
+ T = TypeVar('T')
14
+ previous_args_kwards: tuple[Any, Any]
15
+ nb_values: int
16
+ import_time: float
17
+
18
+ def colored_for_loop[T](iterable: Iterable[T], desc: str = 'Processing', color: str = ..., bar_format: str = ..., ascii: bool = False, smooth_tqdm: bool = True, **kwargs: Any) -> Iterator[T]:
19
+ ''' Function to iterate over a list with a colored TQDM progress bar like the other functions in this module.
20
+
21
+ \tArgs:
22
+ \t\titerable\t(Iterable):\t\t\tList to iterate over
23
+ \t\tdesc\t\t(str):\t\t\t\tDescription of the function execution displayed in the progress bar
24
+ \t\tcolor\t\t(str):\t\t\t\tColor of the progress bar (Defaults to MAGENTA)
25
+ \t\tbar_format\t(str):\t\t\t\tFormat of the progress bar (Defaults to BAR_FORMAT)
26
+ \t\tascii\t\t(bool):\t\t\t\tWhether to use ASCII or Unicode characters for the progress bar (Defaults to False)
27
+ \t\tsmooth_tqdm\t(bool):\t\t\t\tWhether to enable smooth progress bar updates by setting miniters=1 and mininterval=0.0 (Defaults to True)
28
+ \t\t**kwargs:\t\t\t\t\t\tAdditional arguments to pass to the TQDM progress bar
29
+
30
+ \tYields:
31
+ \t\tT: Each item of the iterable
32
+
33
+ \tExamples:
34
+ \t\t>>> for i in colored_for_loop(range(10), desc="Time sleeping loop"):
35
+ \t\t... time.sleep(0.01)
36
+ \t\t>>> # Time sleeping loop: 100%|██████████████████| 10/10 [ 95.72it/s, 00:00<00:00]
37
+ \t'''
38
+ def info(*values: Any, color: str = ..., text: str = 'INFO ', prefix: str = '', file: TextIO | list[TextIO] | None = None, **print_kwargs: Any) -> None:
39
+ ''' Print an information message looking like "[INFO HH:MM:SS] message" in green by default.
40
+
41
+ \tArgs:
42
+ \t\tvalues\t\t\t(Any):\t\t\t\t\tValues to print (like the print function)
43
+ \t\tcolor\t\t\t(str):\t\t\t\t\tColor of the message (default: GREEN)
44
+ \t\ttext\t\t\t(str):\t\t\t\t\tText of the message (default: "INFO ")
45
+ \t\tprefix\t\t\t(str):\t\t\t\t\tPrefix to add to the values
46
+ \t\tfile\t\t\t(TextIO|list[TextIO]):\tFile(s) to write the message to (default: sys.stdout)
47
+ \t\tprint_kwargs\t(dict):\t\t\t\t\tKeyword arguments to pass to the print function
48
+ \t'''
49
+ def debug(*values: Any, **print_kwargs: Any) -> None:
50
+ ''' Print a debug message looking like "[DEBUG HH:MM:SS] message" in cyan by default. '''
51
+ def alt_debug(*values: Any, **print_kwargs: Any) -> None:
52
+ ''' Print a debug message looking like "[DEBUG HH:MM:SS] message" in blue by default. '''
53
+ def suggestion(*values: Any, **print_kwargs: Any) -> None:
54
+ ''' Print a suggestion message looking like "[SUGGESTION HH:MM:SS] message" in cyan by default. '''
55
+ def progress(*values: Any, **print_kwargs: Any) -> None:
56
+ ''' Print a progress message looking like "[PROGRESS HH:MM:SS] message" in magenta by default. '''
57
+ def warning(*values: Any, **print_kwargs: Any) -> None:
58
+ ''' Print a warning message looking like "[WARNING HH:MM:SS] message" in yellow by default and in sys.stderr. '''
59
+ def error(*values: Any, exit: bool = False, **print_kwargs: Any) -> None:
60
+ """ Print an error message (in sys.stderr and in red by default)
61
+ \tand optionally ask the user to continue or stop the program.
62
+
63
+ \tArgs:
64
+ \t\tvalues\t\t\t(Any):\t\tValues to print (like the print function)
65
+ \t\texit\t\t\t(bool):\t\tWhether to ask the user to continue or stop the program,
66
+ \t\t\tfalse to ignore the error automatically and continue
67
+ \t\tprint_kwargs\t(dict):\t\tKeyword arguments to pass to the print function
68
+ \t"""
69
+ def whatisit(*values: Any, print_function: Callable[..., None] = ..., max_length: int = 250, color: str = ..., **print_kwargs: Any) -> None:
70
+ ''' Print the type of each value and the value itself, with its id and length/shape.
71
+
72
+ \tThe output format is: "type, <id id_number>:\t(length/shape) value"
73
+
74
+ \tArgs:
75
+ \t\tvalues\t\t\t(Any):\t\tValues to print
76
+ \t\tprint_function\t(Callable):\tFunction to use to print the values (default: debug())
77
+ \t\tmax_length\t\t(int):\t\tMaximum length of the value string to print (default: 250)
78
+ \t\tcolor\t\t\t(str):\t\tColor of the message (default: CYAN)
79
+ \t\tprint_kwargs\t(dict):\t\tKeyword arguments to pass to the print function
80
+ \t'''
81
+ def breakpoint(*values: Any, print_function: Callable[..., None] = ..., **print_kwargs: Any) -> None:
82
+ """ Breakpoint function, pause the program and print the values.
83
+
84
+ \tArgs:
85
+ \t\tvalues\t\t\t(Any):\t\tValues to print
86
+ \t\tprint_function\t(Callable):\tFunction to use to print the values (default: warning())
87
+ \t\tprint_kwargs\t(dict):\t\tKeyword arguments to pass to the print function
88
+ \t"""
89
+
90
+ class TeeMultiOutput:
91
+ ''' File-like object that duplicates output to multiple file-like objects.
92
+
93
+ \tArgs:
94
+ \t\t*files (IO[Any]): One or more file-like objects that have write and flush methods
95
+ \t\tstrip_colors (bool): Strip ANSI color codes from output sent to non-stdout/stderr files
96
+ \t\tascii_only (bool): Replace non-ASCII characters with their ASCII equivalents for non-stdout/stderr files
97
+ \t\tignore_lineup (bool): Ignore lines containing LINE_UP escape sequence in non-terminal outputs
98
+
99
+ \tExamples:
100
+ \t\t>>> f = open("logfile.txt", "w")
101
+ \t\t>>> sys.stdout = TeeMultiOutput(sys.stdout, f)
102
+ \t\t>>> print("Hello World") # Output goes to both console and file
103
+ \t\tHello World
104
+ \t\t>>> f.close()\t# TeeMultiOutput will handle any future writes to closed files gracefully
105
+ \t'''
106
+ files: tuple[IO[Any], ...]
107
+ strip_colors: bool
108
+ ascii_only: bool
109
+ ignore_lineup: bool
110
+ def __init__(self, *files: IO[Any], strip_colors: bool = True, ascii_only: bool = True, ignore_lineup: bool = True) -> None: ...
111
+ @property
112
+ def encoding(self) -> str:
113
+ ''' Get the encoding of the first file, or "utf-8" as fallback.
114
+
115
+ \t\tReturns:
116
+ \t\t\tstr: The encoding, ex: "utf-8", "ascii", "latin1", etc.
117
+ \t\t'''
118
+ def write(self, obj: str) -> int:
119
+ """ Write the object to all files while stripping colors if needed.
120
+
121
+ \t\tArgs:
122
+ \t\t\tobj (str): String to write
123
+ \t\tReturns:
124
+ \t\t\tint: Number of characters written to the first file
125
+ \t\t"""
126
+ def flush(self) -> None:
127
+ """ Flush all files. """
128
+ def fileno(self) -> int:
129
+ """ Return the file descriptor of the first file. """
130
+
131
+ def remove_colors(text: str) -> str:
132
+ """ Remove the colors from a text """
133
+ def is_same_print(*args: Any, **kwargs: Any) -> bool:
134
+ """ Checks if the current print call is the same as the previous one. """
135
+ def current_time() -> str:
136
+ ''' Get the current time as "HH:MM:SS" if less than 24 hours since import, else "YYYY-MM-DD HH:MM:SS" '''
@@ -0,0 +1,15 @@
1
+ from .print import CYAN as CYAN, GREEN as GREEN, RESET as RESET, YELLOW as YELLOW
2
+
3
+ def show_version(main_package: str = 'stouputils', primary_color: str = ..., secondary_color: str = ..., max_depth: int = 2) -> None:
4
+ ''' Print the version of the main package and its dependencies.
5
+
6
+ \tUsed by the "stouputils --version" command.
7
+
8
+ \tArgs:
9
+ \t\tmain_package\t(str):\tName of the main package to show version for
10
+ \t\tprimary_color\t(str):\tColor to use for the primary package name
11
+ \t\tsecondary_color\t(str):\tColor to use for the secondary package names
12
+ \t\tmax_depth\t\t(int):\tMaximum depth for dependency tree (<= 2 for flat, >=3 for tree)
13
+ \t'''
14
+ def show_version_cli() -> None:
15
+ ''' Handle the "stouputils --version" CLI command '''