stouputils 1.3.16__tar.gz → 1.3.18__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 (107) hide show
  1. {stouputils-1.3.16 → stouputils-1.3.18}/PKG-INFO +1 -1
  2. {stouputils-1.3.16 → stouputils-1.3.18}/pyproject.toml +1 -1
  3. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/backup.py +71 -22
  4. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/parallel.py +5 -5
  5. {stouputils-1.3.16 → stouputils-1.3.18}/.gitignore +0 -0
  6. {stouputils-1.3.16 → stouputils-1.3.18}/LICENSE +0 -0
  7. {stouputils-1.3.16 → stouputils-1.3.18}/README.md +0 -0
  8. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/__init__.py +0 -0
  9. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/all_doctests.py +0 -0
  10. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/applications/__init__.py +0 -0
  11. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/applications/automatic_docs.py +0 -0
  12. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/applications/upscaler/__init__.py +0 -0
  13. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/applications/upscaler/config.py +0 -0
  14. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/applications/upscaler/image.py +0 -0
  15. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/applications/upscaler/video.py +0 -0
  16. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/archive.py +0 -0
  17. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/collections.py +0 -0
  18. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/continuous_delivery/__init__.py +0 -0
  19. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/continuous_delivery/cd_utils.py +0 -0
  20. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/continuous_delivery/github.py +0 -0
  21. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/continuous_delivery/pypi.py +0 -0
  22. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/continuous_delivery/pyproject.py +0 -0
  23. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/ctx.py +0 -0
  24. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/config/get.py +0 -0
  25. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/config/set.py +0 -0
  26. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/__init__.py +0 -0
  27. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/auto_contrast.py +0 -0
  28. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/axis_flip.py +0 -0
  29. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/bias_field_correction.py +0 -0
  30. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/binary_threshold.py +0 -0
  31. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/blur.py +0 -0
  32. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/brightness.py +0 -0
  33. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/canny.py +0 -0
  34. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/clahe.py +0 -0
  35. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/common.py +0 -0
  36. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/contrast.py +0 -0
  37. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/curvature_flow_filter.py +0 -0
  38. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/denoise.py +0 -0
  39. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/histogram_equalization.py +0 -0
  40. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/invert.py +0 -0
  41. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/laplacian.py +0 -0
  42. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/median_blur.py +0 -0
  43. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/noise.py +0 -0
  44. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/normalize.py +0 -0
  45. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/random_erase.py +0 -0
  46. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/resize.py +0 -0
  47. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/rotation.py +0 -0
  48. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/salt_pepper.py +0 -0
  49. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/sharpening.py +0 -0
  50. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/shearing.py +0 -0
  51. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/threshold.py +0 -0
  52. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/translation.py +0 -0
  53. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image/zoom.py +0 -0
  54. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image_augmentation.py +0 -0
  55. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/image_preprocess.py +0 -0
  56. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/prosthesis_detection.py +0 -0
  57. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/data_processing/technique.py +0 -0
  58. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/dataset/__init__.py +0 -0
  59. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/dataset/dataset.py +0 -0
  60. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/dataset/dataset_loader.py +0 -0
  61. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/dataset/grouping_strategy.py +0 -0
  62. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/dataset/image_loader.py +0 -0
  63. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/dataset/xy_tuple.py +0 -0
  64. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/metric_dictionnary.py +0 -0
  65. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/metric_utils.py +0 -0
  66. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/mlflow_utils.py +0 -0
  67. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/abstract_model.py +0 -0
  68. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/all.py +0 -0
  69. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/base_keras.py +0 -0
  70. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras/all.py +0 -0
  71. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras/convnext.py +0 -0
  72. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras/densenet.py +0 -0
  73. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras/efficientnet.py +0 -0
  74. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras/mobilenet.py +0 -0
  75. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras/resnet.py +0 -0
  76. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras/squeezenet.py +0 -0
  77. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras/vgg.py +0 -0
  78. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras/xception.py +0 -0
  79. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras_utils/callbacks/__init__.py +0 -0
  80. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +0 -0
  81. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +0 -0
  82. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +0 -0
  83. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +0 -0
  84. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +0 -0
  85. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras_utils/losses/__init__.py +0 -0
  86. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +0 -0
  87. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/keras_utils/visualizations.py +0 -0
  88. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/model_interface.py +0 -0
  89. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/models/sandbox.py +0 -0
  90. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/range_tuple.py +0 -0
  91. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/scripts/augment_dataset.py +0 -0
  92. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/scripts/exhaustive_process.py +0 -0
  93. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/scripts/preprocess_dataset.py +0 -0
  94. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/scripts/routine.py +0 -0
  95. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/data_science/utils.py +0 -0
  96. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/decorators.py +0 -0
  97. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/dont_look/zip_file_override.py +0 -0
  98. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/image.py +0 -0
  99. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/installer/__init__.py +0 -0
  100. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/installer/common.py +0 -0
  101. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/installer/downloader.py +0 -0
  102. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/installer/linux.py +0 -0
  103. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/installer/main.py +0 -0
  104. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/installer/windows.py +0 -0
  105. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/io.py +0 -0
  106. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/print.py +0 -0
  107. {stouputils-1.3.16 → stouputils-1.3.18}/stouputils/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stouputils
3
- Version: 1.3.16
3
+ Version: 1.3.18
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.3.16"
8
+ version = "1.3.18"
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"
@@ -20,8 +20,12 @@ import zipfile
20
20
  # Local imports
21
21
  from .decorators import handle_error, measure_time
22
22
  from .io import clean_path
23
+ from .parallel import colored_for_loop
23
24
  from .print import info, progress, warning
24
25
 
26
+ # Constants
27
+ CHUNK_SIZE = 1048576 # 1MB chunks for I/O operations
28
+
25
29
 
26
30
  # Function to compute the SHA-256 hash of a file
27
31
  def get_file_hash(file_path: str) -> str | None:
@@ -35,7 +39,11 @@ def get_file_hash(file_path: str) -> str | None:
35
39
  try:
36
40
  sha256_hash = hashlib.sha256()
37
41
  with open(file_path, "rb") as f:
38
- for chunk in iter(lambda: f.read(4096), b""):
42
+ # Use larger chunks for better I/O performance
43
+ while True:
44
+ chunk = f.read(CHUNK_SIZE)
45
+ if not chunk:
46
+ break
39
47
  sha256_hash.update(chunk)
40
48
  return sha256_hash.hexdigest()
41
49
  except Exception as e:
@@ -175,10 +183,13 @@ def create_delta_backup(source_path: str, destination_folder: str, exclude_patte
175
183
  zip_info.compress_type = zipfile.ZIP_DEFLATED
176
184
  zip_info.comment = file_hash.encode() # Store hash in comment
177
185
 
178
- # Read and write file in chunks
186
+ # Read and write file in chunks with larger buffer
179
187
  with open(full_path, "rb") as f:
180
188
  with zipf.open(zip_info, "w", force_zip64=True) as zf:
181
- for chunk in iter(lambda: f.read(4096), b""):
189
+ while True:
190
+ chunk = f.read(CHUNK_SIZE)
191
+ if not chunk:
192
+ break
182
193
  zf.write(chunk)
183
194
  has_changes = True
184
195
  except Exception as e:
@@ -199,7 +210,10 @@ def create_delta_backup(source_path: str, destination_folder: str, exclude_patte
199
210
 
200
211
  with open(source_path, "rb") as f:
201
212
  with zipf.open(zip_info, "w", force_zip64=True) as zf:
202
- for chunk in iter(lambda: f.read(4096), b""):
213
+ while True:
214
+ chunk = f.read(CHUNK_SIZE)
215
+ if not chunk:
216
+ break
203
217
  zf.write(chunk)
204
218
  has_changes = True
205
219
  except Exception as e:
@@ -242,34 +256,69 @@ def consolidate_backups(zip_path: str, destination_zip: str) -> None:
242
256
 
243
257
  # Get all previous backups up to the specified one
244
258
  previous_backups: dict[str, dict[str, str]] = get_all_previous_backups(zip_folder, all_before=zip_path)
259
+ backup_paths: list[str] = list(previous_backups.keys())
245
260
 
261
+ # First pass: collect all deleted files and build file registry
246
262
  deleted_files: set[str] = set()
247
- final_files: set[str] = set()
263
+ file_registry: dict[str, tuple[str, zipfile.ZipInfo]] = {} # filename -> (backup_path, zipinfo)
248
264
 
249
- # Create destination ZIP file
250
- with zipfile.ZipFile(destination_zip, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zipf_out:
251
- # Process each backup, tracking deleted files and consolidating files
252
- for backup_path in previous_backups:
265
+ # Process backups in reverse order (newest first) to prioritize latest versions
266
+ for backup_path in reversed(backup_paths):
267
+ try:
253
268
  with zipfile.ZipFile(backup_path, "r") as zipf_in:
269
+
270
+ # Get namelist once for efficiency
271
+ namelist: list[str] = zipf_in.namelist()
272
+
254
273
  # Process deleted files
255
- if "__deleted_files__.txt" in zipf_in.namelist():
274
+ if "__deleted_files__.txt" in namelist:
256
275
  backup_deleted_files: list[str] = zipf_in.read("__deleted_files__.txt").decode().splitlines()
257
276
  deleted_files.update(backup_deleted_files)
258
277
 
259
- # Process files
278
+ # Process files - only add if not already in registry (newer versions take precedence)
260
279
  for inf in zipf_in.infolist():
261
280
  filename: str = inf.filename
262
- if filename \
263
- and filename != "__deleted_files__.txt" \
264
- and filename not in final_files \
265
- and filename not in deleted_files:
266
- final_files.add(filename)
267
-
268
- # Copy file in chunks
269
- with zipf_in.open(inf, "r") as source:
270
- with zipf_out.open(inf, "w", force_zip64=True) as target:
271
- for chunk in iter(lambda: source.read(4096), b""):
272
- target.write(chunk)
281
+ if (filename
282
+ and filename != "__deleted_files__.txt"
283
+ and filename not in deleted_files
284
+ and filename not in file_registry):
285
+ file_registry[filename] = (backup_path, inf)
286
+ except Exception as e:
287
+ warning(f"Error processing backup {backup_path}: {e}")
288
+ continue
289
+
290
+ # Second pass: copy files efficiently, keeping ZIP files open longer
291
+ open_zips: dict[str, zipfile.ZipFile] = {}
292
+
293
+ try:
294
+ with zipfile.ZipFile(destination_zip, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zipf_out:
295
+ for filename, (backup_path, inf) in colored_for_loop(file_registry.items(), desc="Making consolidated backup"):
296
+ try:
297
+ # Open ZIP file if not already open
298
+ if backup_path not in open_zips:
299
+ open_zips[backup_path] = zipfile.ZipFile(backup_path, "r")
300
+
301
+ zipf_in = open_zips[backup_path]
302
+
303
+ # Copy file with larger chunks for better performance
304
+ with zipf_in.open(inf, "r") as source:
305
+ with zipf_out.open(inf, "w", force_zip64=True) as target:
306
+ # Use larger chunk size for better I/O performance
307
+ while True:
308
+ chunk = source.read(CHUNK_SIZE)
309
+ if not chunk:
310
+ break
311
+ target.write(chunk)
312
+ except Exception as e:
313
+ warning(f"Error copying file {filename} from {backup_path}: {e}")
314
+ continue
315
+ finally:
316
+ # Clean up open ZIP files
317
+ for zipf in open_zips.values():
318
+ try:
319
+ zipf.close()
320
+ except Exception:
321
+ pass
273
322
 
274
323
  info(f"Consolidated backup created: {destination_zip}")
275
324
 
@@ -11,9 +11,9 @@ I highly encourage you to read the function docstrings to understand when to use
11
11
  """
12
12
 
13
13
  # Imports
14
- import time
15
14
  import multiprocessing as mp
16
- from collections.abc import Callable, Iterator
15
+ import time
16
+ from collections.abc import Callable, Iterable, Iterator
17
17
  from concurrent.futures import ThreadPoolExecutor
18
18
  from multiprocessing import Pool, cpu_count
19
19
  from typing import Any, TypeVar
@@ -179,7 +179,7 @@ def multiprocessing(
179
179
  old_method: str | None = mp.get_start_method(allow_none=True)
180
180
  new_method: str = "spawn" if old_method in (None, "fork") else "fork"
181
181
  mp.set_start_method(new_method, force=True)
182
-
182
+
183
183
  try:
184
184
  return process()
185
185
  finally:
@@ -278,7 +278,7 @@ def multithreading(
278
278
 
279
279
 
280
280
  def colored_for_loop(
281
- iterable: list[T],
281
+ iterable: Iterable[T],
282
282
  desc: str = "Processing",
283
283
  color: str = MAGENTA,
284
284
  bar_format: str = BAR_FORMAT,
@@ -288,7 +288,7 @@ def colored_for_loop(
288
288
  """ Function to iterate over a list with a colored TQDM progress bar like the other functions in this module.
289
289
 
290
290
  Args:
291
- iterable (list): List to iterate over
291
+ iterable (Iterable): List to iterate over
292
292
  desc (str): Description of the function execution displayed in the progress bar
293
293
  color (str): Color of the progress bar (Defaults to MAGENTA)
294
294
  bar_format (str): Format of the progress bar (Defaults to BAR_FORMAT)
File without changes
File without changes
File without changes