stouputils 1.9.0__tar.gz → 1.9.1__tar.gz

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 (139) hide show
  1. {stouputils-1.9.0 → stouputils-1.9.1}/PKG-INFO +1 -1
  2. {stouputils-1.9.0 → stouputils-1.9.1}/pyproject.toml +1 -1
  3. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/parallel.py +127 -14
  4. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/parallel.pyi +70 -13
  5. {stouputils-1.9.0 → stouputils-1.9.1}/.gitignore +0 -0
  6. {stouputils-1.9.0 → stouputils-1.9.1}/LICENSE +0 -0
  7. {stouputils-1.9.0 → stouputils-1.9.1}/README.md +0 -0
  8. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/__init__.py +0 -0
  9. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/__init__.pyi +0 -0
  10. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/__main__.py +0 -0
  11. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/_deprecated.py +0 -0
  12. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/_deprecated.pyi +0 -0
  13. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/all_doctests.py +0 -0
  14. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/all_doctests.pyi +0 -0
  15. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/applications/__init__.py +0 -0
  16. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/applications/__init__.pyi +0 -0
  17. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/applications/automatic_docs.py +0 -0
  18. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/applications/automatic_docs.pyi +0 -0
  19. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/applications/upscaler/__init__.py +0 -0
  20. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/applications/upscaler/__init__.pyi +0 -0
  21. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/applications/upscaler/config.py +0 -0
  22. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/applications/upscaler/config.pyi +0 -0
  23. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/applications/upscaler/image.py +0 -0
  24. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/applications/upscaler/image.pyi +0 -0
  25. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/applications/upscaler/video.py +0 -0
  26. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/applications/upscaler/video.pyi +0 -0
  27. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/archive.py +0 -0
  28. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/archive.pyi +0 -0
  29. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/backup.py +0 -0
  30. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/backup.pyi +0 -0
  31. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/collections.py +0 -0
  32. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/collections.pyi +0 -0
  33. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/continuous_delivery/__init__.py +0 -0
  34. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/continuous_delivery/__init__.pyi +0 -0
  35. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/continuous_delivery/cd_utils.py +0 -0
  36. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/continuous_delivery/cd_utils.pyi +0 -0
  37. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/continuous_delivery/github.py +0 -0
  38. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/continuous_delivery/github.pyi +0 -0
  39. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/continuous_delivery/pypi.py +0 -0
  40. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/continuous_delivery/pypi.pyi +0 -0
  41. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/continuous_delivery/pyproject.py +0 -0
  42. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/continuous_delivery/pyproject.pyi +0 -0
  43. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/continuous_delivery/stubs.py +0 -0
  44. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/continuous_delivery/stubs.pyi +0 -0
  45. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/ctx.py +0 -0
  46. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/ctx.pyi +0 -0
  47. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/config/get.py +0 -0
  48. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/config/set.py +0 -0
  49. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/__init__.py +0 -0
  50. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/auto_contrast.py +0 -0
  51. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/axis_flip.py +0 -0
  52. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/bias_field_correction.py +0 -0
  53. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/binary_threshold.py +0 -0
  54. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/blur.py +0 -0
  55. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/brightness.py +0 -0
  56. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/canny.py +0 -0
  57. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/clahe.py +0 -0
  58. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/common.py +0 -0
  59. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/contrast.py +0 -0
  60. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/curvature_flow_filter.py +0 -0
  61. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/denoise.py +0 -0
  62. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/histogram_equalization.py +0 -0
  63. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/invert.py +0 -0
  64. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/laplacian.py +0 -0
  65. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/median_blur.py +0 -0
  66. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/noise.py +0 -0
  67. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/normalize.py +0 -0
  68. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/random_erase.py +0 -0
  69. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/resize.py +0 -0
  70. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/rotation.py +0 -0
  71. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/salt_pepper.py +0 -0
  72. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/sharpening.py +0 -0
  73. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/shearing.py +0 -0
  74. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/threshold.py +0 -0
  75. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/translation.py +0 -0
  76. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image/zoom.py +0 -0
  77. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image_augmentation.py +0 -0
  78. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/image_preprocess.py +0 -0
  79. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/prosthesis_detection.py +0 -0
  80. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/data_processing/technique.py +0 -0
  81. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/dataset/__init__.py +0 -0
  82. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/dataset/dataset.py +0 -0
  83. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/dataset/dataset_loader.py +0 -0
  84. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/dataset/grouping_strategy.py +0 -0
  85. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/dataset/image_loader.py +0 -0
  86. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/dataset/xy_tuple.py +0 -0
  87. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/metric_dictionnary.py +0 -0
  88. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/metric_utils.py +0 -0
  89. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/mlflow_utils.py +0 -0
  90. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/abstract_model.py +0 -0
  91. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/all.py +0 -0
  92. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/base_keras.py +0 -0
  93. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras/all.py +0 -0
  94. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras/convnext.py +0 -0
  95. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras/densenet.py +0 -0
  96. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras/efficientnet.py +0 -0
  97. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras/mobilenet.py +0 -0
  98. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras/resnet.py +0 -0
  99. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras/squeezenet.py +0 -0
  100. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras/vgg.py +0 -0
  101. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras/xception.py +0 -0
  102. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras_utils/callbacks/__init__.py +0 -0
  103. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +0 -0
  104. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +0 -0
  105. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +0 -0
  106. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +0 -0
  107. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +0 -0
  108. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras_utils/losses/__init__.py +0 -0
  109. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +0 -0
  110. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/keras_utils/visualizations.py +0 -0
  111. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/model_interface.py +0 -0
  112. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/models/sandbox.py +0 -0
  113. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/range_tuple.py +0 -0
  114. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/scripts/augment_dataset.py +0 -0
  115. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/scripts/exhaustive_process.py +0 -0
  116. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/scripts/preprocess_dataset.py +0 -0
  117. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/scripts/routine.py +0 -0
  118. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/data_science/utils.py +0 -0
  119. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/decorators.py +0 -0
  120. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/decorators.pyi +0 -0
  121. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/image.py +0 -0
  122. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/image.pyi +0 -0
  123. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/installer/__init__.py +0 -0
  124. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/installer/__init__.pyi +0 -0
  125. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/installer/common.py +0 -0
  126. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/installer/common.pyi +0 -0
  127. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/installer/downloader.py +0 -0
  128. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/installer/downloader.pyi +0 -0
  129. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/installer/linux.py +0 -0
  130. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/installer/linux.pyi +0 -0
  131. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/installer/main.py +0 -0
  132. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/installer/main.pyi +0 -0
  133. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/installer/windows.py +0 -0
  134. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/installer/windows.pyi +0 -0
  135. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/io.py +0 -0
  136. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/io.pyi +0 -0
  137. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/print.py +0 -0
  138. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/print.pyi +0 -0
  139. {stouputils-1.9.0 → stouputils-1.9.1}/stouputils/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stouputils
3
- Version: 1.9.0
3
+ Version: 1.9.1
4
4
  Summary: Stouputils is a collection of utility modules designed to simplify and enhance the development process. It includes a range of tools for tasks such as execution of doctests, display utilities, decorators, as well as context managers, and many more.
5
5
  Project-URL: Homepage, https://github.com/Stoupy51/stouputils
6
6
  Project-URL: Issues, https://github.com/Stoupy51/stouputils/issues
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
5
5
 
6
6
  [project]
7
7
  name = "stouputils"
8
- version = "1.9.0"
8
+ version = "1.9.1"
9
9
  description = "Stouputils is a collection of utility modules designed to simplify and enhance the development process. It includes a range of tools for tasks such as execution of doctests, display utilities, decorators, as well as context managers, and many more."
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.10"
@@ -3,6 +3,7 @@ This module provides utility functions for parallel processing, such as:
3
3
 
4
4
  - multiprocessing(): Execute a function in parallel using multiprocessing
5
5
  - multithreading(): Execute a function in parallel using multithreading
6
+ - run_in_subprocess(): Execute a function in a subprocess with args and kwargs
6
7
 
7
8
  I highly encourage you to read the function docstrings to understand when to use each method.
8
9
 
@@ -35,7 +36,7 @@ R = TypeVar("R")
35
36
  # Functions
36
37
  @handle_error(error_log=LogLevels.ERROR_TRACEBACK)
37
38
  def multiprocessing(
38
- func: Callable[[T], R],
39
+ func: Callable[[T], R] | list[Callable[[T], R]],
39
40
  args: list[T],
40
41
  use_starmap: bool = False,
41
42
  chunksize: int = 1,
@@ -53,15 +54,15 @@ def multiprocessing(
53
54
  - For computationally intensive tasks like scientific simulations, data analysis, or machine learning workloads.
54
55
 
55
56
  Args:
56
- func (Callable): Function to execute
57
- args (list): List of arguments to pass to the function
57
+ func (Callable | list[Callable]): Function to execute, or list of functions (one per argument)
58
+ args (list): List of arguments to pass to the function(s)
58
59
  use_starmap (bool): Whether to use starmap or not (Defaults to False):
59
60
  True means the function will be called like func(\*args[i]) instead of func(args[i])
60
61
  chunksize (int): Number of arguments to process at a time
61
62
  (Defaults to 1 for proper progress bar display)
62
63
  desc (str): Description displayed in the progress bar
63
64
  (if not provided no progress bar will be displayed)
64
- max_workers (int): Number of workers to use (Defaults to CPU_COUNT)
65
+ max_workers (int): Number of workers to use (Defaults to CPU_COUNT), -1 means CPU_COUNT
65
66
  delay_first_calls (float): Apply i*delay_first_calls seconds delay to the first "max_workers" calls.
66
67
  For instance, the first process will be delayed by 0 seconds, the second by 1 second, etc.
67
68
  (Defaults to 0): This can be useful to avoid functions being called in the same second.
@@ -81,6 +82,10 @@ def multiprocessing(
81
82
  > multiprocessing(int.__mul__, [(1,2), (3,4), (5,6)], use_starmap=True)
82
83
  [2, 12, 30]
83
84
 
85
+ > # Using a list of functions (one per argument)
86
+ > multiprocessing([doctest_square, doctest_square, doctest_square], [1, 2, 3])
87
+ [1, 4, 9]
88
+
84
89
  > # Will process in parallel with progress bar
85
90
  > multiprocessing(doctest_slow, range(10), desc="Processing")
86
91
  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
@@ -103,6 +108,8 @@ def multiprocessing(
103
108
  from tqdm.contrib.concurrent import process_map # pyright: ignore[reportUnknownVariableType]
104
109
 
105
110
  # Handle parameters
111
+ if max_workers == -1:
112
+ max_workers = CPU_COUNT
106
113
  verbose: bool = desc != ""
107
114
  desc, func, args = _handle_parameters(func, args, use_starmap, delay_first_calls, max_workers, desc, color)
108
115
  if bar_format == BAR_FORMAT:
@@ -145,7 +152,7 @@ def multiprocessing(
145
152
 
146
153
  @handle_error(error_log=LogLevels.ERROR_TRACEBACK)
147
154
  def multithreading(
148
- func: Callable[[T], R],
155
+ func: Callable[[T], R] | list[Callable[[T], R]],
149
156
  args: list[T],
150
157
  use_starmap: bool = False,
151
158
  desc: str = "",
@@ -162,13 +169,13 @@ def multithreading(
162
169
  - For operations that involve a lot of waiting, such as GUI event handling or handling user input.
163
170
 
164
171
  Args:
165
- func (Callable): Function to execute
166
- args (list): List of arguments to pass to the function
172
+ func (Callable | list[Callable]): Function to execute, or list of functions (one per argument)
173
+ args (list): List of arguments to pass to the function(s)
167
174
  use_starmap (bool): Whether to use starmap or not (Defaults to False):
168
175
  True means the function will be called like func(\*args[i]) instead of func(args[i])
169
176
  desc (str): Description displayed in the progress bar
170
177
  (if not provided no progress bar will be displayed)
171
- max_workers (int): Number of workers to use (Defaults to CPU_COUNT)
178
+ max_workers (int): Number of workers to use (Defaults to CPU_COUNT), -1 means CPU_COUNT
172
179
  delay_first_calls (float): Apply i*delay_first_calls seconds delay to the first "max_workers" calls.
173
180
  For instance with value to 1, the first thread will be delayed by 0 seconds, the second by 1 second, etc.
174
181
  (Defaults to 0): This can be useful to avoid functions being called in the same second.
@@ -188,6 +195,10 @@ def multithreading(
188
195
  > multithreading(int.__mul__, [(1,2), (3,4), (5,6)], use_starmap=True)
189
196
  [2, 12, 30]
190
197
 
198
+ > # Using a list of functions (one per argument)
199
+ > multithreading([doctest_square, doctest_square, doctest_square], [1, 2, 3])
200
+ [1, 4, 9]
201
+
191
202
  > # Will process in parallel with progress bar
192
203
  > multithreading(doctest_slow, range(10), desc="Threading")
193
204
  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
@@ -208,6 +219,8 @@ def multithreading(
208
219
  from tqdm.auto import tqdm
209
220
 
210
221
  # Handle parameters
222
+ if max_workers == -1:
223
+ max_workers = CPU_COUNT
211
224
  verbose: bool = desc != ""
212
225
  desc, func, args = _handle_parameters(func, args, use_starmap, delay_first_calls, max_workers, desc, color)
213
226
  if bar_format == BAR_FORMAT:
@@ -230,6 +243,99 @@ def multithreading(
230
243
  return [func(arg) for arg in args]
231
244
 
232
245
 
246
+ @handle_error(error_log=LogLevels.ERROR_TRACEBACK)
247
+ def run_in_subprocess(
248
+ func: Callable[..., R],
249
+ *args: Any,
250
+ **kwargs: Any
251
+ ) -> R:
252
+ """ Execute a function in a subprocess with positional and keyword arguments.
253
+
254
+ This is useful when you need to run a function in isolation to avoid memory leaks,
255
+ resource conflicts, or to ensure a clean execution environment. The subprocess will
256
+ be created, run the function with the provided arguments, and return the result.
257
+
258
+ Args:
259
+ func (Callable): The function to execute in a subprocess.
260
+ (SHOULD BE A TOP-LEVEL FUNCTION TO BE PICKLABLE)
261
+ *args (Any): Positional arguments to pass to the function.
262
+ **kwargs (Any): Keyword arguments to pass to the function.
263
+
264
+ Returns:
265
+ R: The return value of the function.
266
+
267
+ Raises:
268
+ RuntimeError: If the subprocess exits with a non-zero exit code.
269
+
270
+ Examples:
271
+ .. code-block:: python
272
+
273
+ > # Simple function execution
274
+ > run_in_subprocess(doctest_square, 5)
275
+ 25
276
+
277
+ > # Function with multiple arguments
278
+ > def add(a: int, b: int) -> int:
279
+ . return a + b
280
+ > run_in_subprocess(add, 10, 20)
281
+ 30
282
+
283
+ > # Function with keyword arguments
284
+ > def greet(name: str, greeting: str = "Hello") -> str:
285
+ . return f"{greeting}, {name}!"
286
+ > run_in_subprocess(greet, "World", greeting="Hi")
287
+ 'Hi, World!'
288
+ """
289
+ import multiprocessing as mp
290
+ from multiprocessing import Queue
291
+
292
+ # Create a queue to get the result from the subprocess
293
+ result_queue: Queue[R | Exception] = Queue()
294
+
295
+ # Create and start the subprocess using the module-level wrapper
296
+ process: mp.Process = mp.Process(
297
+ target=_subprocess_wrapper,
298
+ args=(result_queue, func, args, kwargs)
299
+ )
300
+ process.start()
301
+ process.join()
302
+
303
+ # Check exit code
304
+ if process.exitcode != 0:
305
+ raise RuntimeError(f"Subprocess failed with exit code {process.exitcode}")
306
+
307
+ # Retrieve the result
308
+ if not result_queue.empty():
309
+ result_or_exception = result_queue.get()
310
+ if isinstance(result_or_exception, Exception):
311
+ raise result_or_exception
312
+ return result_or_exception
313
+ else:
314
+ raise RuntimeError("Subprocess did not return any result")
315
+
316
+
317
+ # "Private" function for subprocess wrapper (must be at module level for pickling on Windows)
318
+ def _subprocess_wrapper(
319
+ result_queue: Any,
320
+ func: Callable[..., R],
321
+ args: tuple[Any, ...],
322
+ kwargs: dict[str, Any]
323
+ ) -> None:
324
+ """ Wrapper function to execute the target function and store the result in the queue.
325
+
326
+ Must be at module level to be pickable on Windows (spawn context).
327
+
328
+ Args:
329
+ result_queue (multiprocessing.Queue): Queue to store the result or exception.
330
+ func (Callable): The target function to execute.
331
+ args (tuple): Positional arguments for the function.
332
+ kwargs (dict): Keyword arguments for the function.
333
+ """
334
+ try:
335
+ result: R = func(*args, **kwargs)
336
+ result_queue.put(result)
337
+ except Exception as e:
338
+ result_queue.put(e)
233
339
 
234
340
  # "Private" function to use starmap
235
341
  def _starmap(args: tuple[Callable[[T], R], list[T]]) -> R:
@@ -258,7 +364,7 @@ def _delayed_call(args: tuple[Callable[[T], R], float, T]) -> R:
258
364
 
259
365
  # "Private" function to handle parameters for multiprocessing or multithreading functions
260
366
  def _handle_parameters(
261
- func: Callable[[T], R],
367
+ func: Callable[[T], R] | list[Callable[[T], R]],
262
368
  args: list[T],
263
369
  use_starmap: bool,
264
370
  delay_first_calls: float,
@@ -269,8 +375,8 @@ def _handle_parameters(
269
375
  r""" Private function to handle the parameters for multiprocessing or multithreading functions
270
376
 
271
377
  Args:
272
- func (Callable): Function to execute
273
- args (list): List of arguments to pass to the function
378
+ func (Callable | list[Callable]): Function to execute, or list of functions (one per argument)
379
+ args (list): List of arguments to pass to the function(s)
274
380
  use_starmap (bool): Whether to use starmap or not (Defaults to False):
275
381
  True means the function will be called like func(\*args[i]) instead of func(args[i])
276
382
  delay_first_calls (int): Apply i*delay_first_calls seconds delay to the first "max_workers" calls.
@@ -285,8 +391,15 @@ def _handle_parameters(
285
391
  """
286
392
  desc = color + desc
287
393
 
288
- # If use_starmap is True, we use the __starmap function
289
- if use_starmap:
394
+ # Handle list of functions: validate and convert to starmap format
395
+ if isinstance(func, list):
396
+ func = cast(list[Callable[[T], R]], func)
397
+ assert len(func) == len(args), f"Length mismatch: {len(func)} functions but {len(args)} arguments"
398
+ args = [(f, arg) for f, arg in zip(func, args, strict=False)] # type: ignore
399
+ func = _starmap # type: ignore
400
+
401
+ # If use_starmap is True, we use the _starmap function
402
+ elif use_starmap:
290
403
  args = [(func, arg) for arg in args] # type: ignore
291
404
  func = _starmap # type: ignore
292
405
 
@@ -298,5 +411,5 @@ def _handle_parameters(
298
411
  ]
299
412
  func = _delayed_call # type: ignore
300
413
 
301
- return desc, func, args
414
+ return desc, func, args # type: ignore
302
415
 
@@ -1,7 +1,7 @@
1
1
  from .decorators import LogLevels as LogLevels, handle_error as handle_error
2
2
  from .print import BAR_FORMAT as BAR_FORMAT, MAGENTA as MAGENTA
3
- from collections.abc import Callable as Callable
4
- from typing import TypeVar
3
+ from collections.abc import Callable
4
+ from typing import Any, TypeVar
5
5
 
6
6
  def doctest_square(x: int) -> int: ...
7
7
  def doctest_slow(x: int) -> int: ...
@@ -10,7 +10,7 @@ CPU_COUNT: int
10
10
  T = TypeVar('T')
11
11
  R = TypeVar('R')
12
12
 
13
- def multiprocessing(func: Callable[[T], R], args: list[T], use_starmap: bool = False, chunksize: int = 1, desc: str = '', max_workers: int = ..., delay_first_calls: float = 0, color: str = ..., bar_format: str = ..., ascii: bool = False) -> list[R]:
13
+ def multiprocessing(func: Callable[[T], R] | list[Callable[[T], R]], args: list[T], use_starmap: bool = False, chunksize: int = 1, desc: str = '', max_workers: int = ..., delay_first_calls: float = 0, color: str = ..., bar_format: str = ..., ascii: bool = False) -> list[R]:
14
14
  ''' Method to execute a function in parallel using multiprocessing
15
15
 
16
16
  \t- For CPU-bound operations where the GIL (Global Interpreter Lock) is a bottleneck.
@@ -18,15 +18,15 @@ def multiprocessing(func: Callable[[T], R], args: list[T], use_starmap: bool = F
18
18
  \t- For computationally intensive tasks like scientific simulations, data analysis, or machine learning workloads.
19
19
 
20
20
  \tArgs:
21
- \t\tfunc\t\t\t\t(Callable):\t\t\tFunction to execute
22
- \t\targs\t\t\t\t(list):\t\t\t\tList of arguments to pass to the function
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(list):\t\t\t\tList of arguments to pass to the function(s)
23
23
  \t\tuse_starmap\t\t\t(bool):\t\t\t\tWhether to use starmap or not (Defaults to False):
24
24
  \t\t\tTrue means the function will be called like func(\\*args[i]) instead of func(args[i])
25
25
  \t\tchunksize\t\t\t(int):\t\t\t\tNumber of arguments to process at a time
26
26
  \t\t\t(Defaults to 1 for proper progress bar display)
27
27
  \t\tdesc\t\t\t\t(str):\t\t\t\tDescription displayed in the progress bar
28
28
  \t\t\t(if not provided no progress bar will be displayed)
29
- \t\tmax_workers\t\t\t(int):\t\t\t\tNumber of workers to use (Defaults to CPU_COUNT)
29
+ \t\tmax_workers\t\t\t(int):\t\t\t\tNumber of workers to use (Defaults to CPU_COUNT), -1 means CPU_COUNT
30
30
  \t\tdelay_first_calls\t(float):\t\t\tApply i*delay_first_calls seconds delay to the first "max_workers" calls.
31
31
  \t\t\tFor instance, the first process will be delayed by 0 seconds, the second by 1 second, etc.
32
32
  \t\t\t(Defaults to 0): This can be useful to avoid functions being called in the same second.
@@ -46,6 +46,10 @@ def multiprocessing(func: Callable[[T], R], args: list[T], use_starmap: bool = F
46
46
  \t\t\t> multiprocessing(int.__mul__, [(1,2), (3,4), (5,6)], use_starmap=True)
47
47
  \t\t\t[2, 12, 30]
48
48
 
49
+ \t\t\t> # Using a list of functions (one per argument)
50
+ \t\t\t> multiprocessing([doctest_square, doctest_square, doctest_square], [1, 2, 3])
51
+ \t\t\t[1, 4, 9]
52
+
49
53
  \t\t\t> # Will process in parallel with progress bar
50
54
  \t\t\t> multiprocessing(doctest_slow, range(10), desc="Processing")
51
55
  \t\t\t[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
@@ -60,7 +64,7 @@ def multiprocessing(func: Callable[[T], R], args: list[T], use_starmap: bool = F
60
64
  \t\t\t. )
61
65
  \t\t\t[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
62
66
  \t'''
63
- def multithreading(func: Callable[[T], R], args: list[T], use_starmap: bool = False, desc: str = '', max_workers: int = ..., delay_first_calls: float = 0, color: str = ..., bar_format: str = ..., ascii: bool = False) -> list[R]:
67
+ def multithreading(func: Callable[[T], R] | list[Callable[[T], R]], args: list[T], use_starmap: bool = False, desc: str = '', max_workers: int = ..., delay_first_calls: float = 0, color: str = ..., bar_format: str = ..., ascii: bool = False) -> list[R]:
64
68
  ''' Method to execute a function in parallel using multithreading, you should use it:
65
69
 
66
70
  \t- For I/O-bound operations where the GIL is not a bottleneck, such as network requests or disk operations.
@@ -68,13 +72,13 @@ def multithreading(func: Callable[[T], R], args: list[T], use_starmap: bool = Fa
68
72
  \t- For operations that involve a lot of waiting, such as GUI event handling or handling user input.
69
73
 
70
74
  \tArgs:
71
- \t\tfunc\t\t\t\t(Callable):\t\t\tFunction to execute
72
- \t\targs\t\t\t\t(list):\t\t\t\tList of arguments to pass to the function
75
+ \t\tfunc\t\t\t\t(Callable | list[Callable]):\tFunction to execute, or list of functions (one per argument)
76
+ \t\targs\t\t\t\t(list):\t\t\t\tList of arguments to pass to the function(s)
73
77
  \t\tuse_starmap\t\t\t(bool):\t\t\t\tWhether to use starmap or not (Defaults to False):
74
78
  \t\t\tTrue means the function will be called like func(\\*args[i]) instead of func(args[i])
75
79
  \t\tdesc\t\t\t\t(str):\t\t\t\tDescription displayed in the progress bar
76
80
  \t\t\t(if not provided no progress bar will be displayed)
77
- \t\tmax_workers\t\t\t(int):\t\t\t\tNumber of workers to use (Defaults to CPU_COUNT)
81
+ \t\tmax_workers\t\t\t(int):\t\t\t\tNumber of workers to use (Defaults to CPU_COUNT), -1 means CPU_COUNT
78
82
  \t\tdelay_first_calls\t(float):\t\t\tApply i*delay_first_calls seconds delay to the first "max_workers" calls.
79
83
  \t\t\tFor instance with value to 1, the first thread will be delayed by 0 seconds, the second by 1 second, etc.
80
84
  \t\t\t(Defaults to 0): This can be useful to avoid functions being called in the same second.
@@ -94,6 +98,10 @@ def multithreading(func: Callable[[T], R], args: list[T], use_starmap: bool = Fa
94
98
  \t\t\t> multithreading(int.__mul__, [(1,2), (3,4), (5,6)], use_starmap=True)
95
99
  \t\t\t[2, 12, 30]
96
100
 
101
+ \t\t\t> # Using a list of functions (one per argument)
102
+ \t\t\t> multithreading([doctest_square, doctest_square, doctest_square], [1, 2, 3])
103
+ \t\t\t[1, 4, 9]
104
+
97
105
  \t\t\t> # Will process in parallel with progress bar
98
106
  \t\t\t> multithreading(doctest_slow, range(10), desc="Threading")
99
107
  \t\t\t[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
@@ -108,6 +116,55 @@ def multithreading(func: Callable[[T], R], args: list[T], use_starmap: bool = Fa
108
116
  \t\t\t. )
109
117
  \t\t\t[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
110
118
  \t'''
119
+ def run_in_subprocess(func: Callable[..., R], *args: Any, **kwargs: Any) -> R:
120
+ ''' Execute a function in a subprocess with positional and keyword arguments.
121
+
122
+ \tThis is useful when you need to run a function in isolation to avoid memory leaks,
123
+ \tresource conflicts, or to ensure a clean execution environment. The subprocess will
124
+ \tbe created, run the function with the provided arguments, and return the result.
125
+
126
+ \tArgs:
127
+ \t\tfunc (Callable): The function to execute in a subprocess.
128
+ \t\t\t(SHOULD BE A TOP-LEVEL FUNCTION TO BE PICKLABLE)
129
+ \t\t*args (Any): Positional arguments to pass to the function.
130
+ \t\t**kwargs (Any): Keyword arguments to pass to the function.
131
+
132
+ \tReturns:
133
+ \t\tR: The return value of the function.
134
+
135
+ \tRaises:
136
+ \t\tRuntimeError: If the subprocess exits with a non-zero exit code.
137
+
138
+ \tExamples:
139
+ \t\t.. code-block:: python
140
+
141
+ \t\t\t> # Simple function execution
142
+ \t\t\t> run_in_subprocess(doctest_square, 5)
143
+ \t\t\t25
144
+
145
+ \t\t\t> # Function with multiple arguments
146
+ \t\t\t> def add(a: int, b: int) -> int:
147
+ \t\t\t. return a + b
148
+ \t\t\t> run_in_subprocess(add, 10, 20)
149
+ \t\t\t30
150
+
151
+ \t\t\t> # Function with keyword arguments
152
+ \t\t\t> def greet(name: str, greeting: str = "Hello") -> str:
153
+ \t\t\t. return f"{greeting}, {name}!"
154
+ \t\t\t> run_in_subprocess(greet, "World", greeting="Hi")
155
+ \t\t\t\'Hi, World!\'
156
+ \t'''
157
+ def _subprocess_wrapper(result_queue: Any, func: Callable[..., R], args: tuple[Any, ...], kwargs: dict[str, Any]) -> None:
158
+ """ Wrapper function to execute the target function and store the result in the queue.
159
+
160
+ \tMust be at module level to be pickable on Windows (spawn context).
161
+
162
+ \tArgs:
163
+ \t\tresult_queue (multiprocessing.Queue): Queue to store the result or exception.
164
+ \t\tfunc (Callable): The target function to execute.
165
+ \t\targs (tuple): Positional arguments for the function.
166
+ \t\tkwargs (dict): Keyword arguments for the function.
167
+ \t"""
111
168
  def _starmap(args: tuple[Callable[[T], R], list[T]]) -> R:
112
169
  """ Private function to use starmap using args[0](\\*args[1])
113
170
 
@@ -124,12 +181,12 @@ def _delayed_call(args: tuple[Callable[[T], R], float, T]) -> R:
124
181
  \tReturns:
125
182
  \t\tobject: Result of the function execution
126
183
  \t"""
127
- def _handle_parameters(func: 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]]:
184
+ def _handle_parameters(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]]:
128
185
  ''' Private function to handle the parameters for multiprocessing or multithreading functions
129
186
 
130
187
  \tArgs:
131
- \t\tfunc\t\t\t\t(Callable):\t\t\tFunction to execute
132
- \t\targs\t\t\t\t(list):\t\t\t\tList of arguments to pass to the function
188
+ \t\tfunc\t\t\t\t(Callable | list[Callable]):\tFunction to execute, or list of functions (one per argument)
189
+ \t\targs\t\t\t\t(list):\t\t\t\tList of arguments to pass to the function(s)
133
190
  \t\tuse_starmap\t\t\t(bool):\t\t\t\tWhether to use starmap or not (Defaults to False):
134
191
  \t\t\tTrue means the function will be called like func(\\*args[i]) instead of func(args[i])
135
192
  \t\tdelay_first_calls\t(int):\t\t\t\tApply i*delay_first_calls seconds delay to the first "max_workers" calls.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes