stouputils 1.3.15__tar.gz → 1.3.17__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.15 → stouputils-1.3.17}/PKG-INFO +1 -1
  2. {stouputils-1.3.15 → stouputils-1.3.17}/pyproject.toml +1 -1
  3. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/backup.py +67 -22
  4. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/decorators.py +13 -8
  5. {stouputils-1.3.15 → stouputils-1.3.17}/.gitignore +0 -0
  6. {stouputils-1.3.15 → stouputils-1.3.17}/LICENSE +0 -0
  7. {stouputils-1.3.15 → stouputils-1.3.17}/README.md +0 -0
  8. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/__init__.py +0 -0
  9. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/all_doctests.py +0 -0
  10. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/applications/__init__.py +0 -0
  11. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/applications/automatic_docs.py +0 -0
  12. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/applications/upscaler/__init__.py +0 -0
  13. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/applications/upscaler/config.py +0 -0
  14. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/applications/upscaler/image.py +0 -0
  15. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/applications/upscaler/video.py +0 -0
  16. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/archive.py +0 -0
  17. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/collections.py +0 -0
  18. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/continuous_delivery/__init__.py +0 -0
  19. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/continuous_delivery/cd_utils.py +0 -0
  20. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/continuous_delivery/github.py +0 -0
  21. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/continuous_delivery/pypi.py +0 -0
  22. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/continuous_delivery/pyproject.py +0 -0
  23. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/ctx.py +0 -0
  24. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/config/get.py +0 -0
  25. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/config/set.py +0 -0
  26. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/__init__.py +0 -0
  27. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/auto_contrast.py +0 -0
  28. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/axis_flip.py +0 -0
  29. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/bias_field_correction.py +0 -0
  30. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/binary_threshold.py +0 -0
  31. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/blur.py +0 -0
  32. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/brightness.py +0 -0
  33. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/canny.py +0 -0
  34. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/clahe.py +0 -0
  35. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/common.py +0 -0
  36. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/contrast.py +0 -0
  37. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/curvature_flow_filter.py +0 -0
  38. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/denoise.py +0 -0
  39. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/histogram_equalization.py +0 -0
  40. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/invert.py +0 -0
  41. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/laplacian.py +0 -0
  42. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/median_blur.py +0 -0
  43. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/noise.py +0 -0
  44. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/normalize.py +0 -0
  45. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/random_erase.py +0 -0
  46. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/resize.py +0 -0
  47. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/rotation.py +0 -0
  48. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/salt_pepper.py +0 -0
  49. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/sharpening.py +0 -0
  50. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/shearing.py +0 -0
  51. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/threshold.py +0 -0
  52. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/translation.py +0 -0
  53. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image/zoom.py +0 -0
  54. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image_augmentation.py +0 -0
  55. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/image_preprocess.py +0 -0
  56. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/prosthesis_detection.py +0 -0
  57. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/data_processing/technique.py +0 -0
  58. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/dataset/__init__.py +0 -0
  59. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/dataset/dataset.py +0 -0
  60. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/dataset/dataset_loader.py +0 -0
  61. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/dataset/grouping_strategy.py +0 -0
  62. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/dataset/image_loader.py +0 -0
  63. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/dataset/xy_tuple.py +0 -0
  64. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/metric_dictionnary.py +0 -0
  65. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/metric_utils.py +0 -0
  66. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/mlflow_utils.py +0 -0
  67. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/abstract_model.py +0 -0
  68. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/all.py +0 -0
  69. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/base_keras.py +0 -0
  70. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras/all.py +0 -0
  71. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras/convnext.py +0 -0
  72. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras/densenet.py +0 -0
  73. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras/efficientnet.py +0 -0
  74. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras/mobilenet.py +0 -0
  75. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras/resnet.py +0 -0
  76. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras/squeezenet.py +0 -0
  77. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras/vgg.py +0 -0
  78. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras/xception.py +0 -0
  79. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras_utils/callbacks/__init__.py +0 -0
  80. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +0 -0
  81. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +0 -0
  82. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +0 -0
  83. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +0 -0
  84. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +0 -0
  85. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras_utils/losses/__init__.py +0 -0
  86. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +0 -0
  87. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/keras_utils/visualizations.py +0 -0
  88. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/model_interface.py +0 -0
  89. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/models/sandbox.py +0 -0
  90. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/range_tuple.py +0 -0
  91. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/scripts/augment_dataset.py +0 -0
  92. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/scripts/exhaustive_process.py +0 -0
  93. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/scripts/preprocess_dataset.py +0 -0
  94. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/scripts/routine.py +0 -0
  95. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/data_science/utils.py +0 -0
  96. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/dont_look/zip_file_override.py +0 -0
  97. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/image.py +0 -0
  98. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/installer/__init__.py +0 -0
  99. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/installer/common.py +0 -0
  100. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/installer/downloader.py +0 -0
  101. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/installer/linux.py +0 -0
  102. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/installer/main.py +0 -0
  103. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/installer/windows.py +0 -0
  104. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/io.py +0 -0
  105. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/parallel.py +0 -0
  106. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/print.py +0 -0
  107. {stouputils-1.3.15 → stouputils-1.3.17}/stouputils/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stouputils
3
- Version: 1.3.15
3
+ Version: 1.3.17
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.15"
8
+ version = "1.3.17"
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"
@@ -35,7 +35,11 @@ def get_file_hash(file_path: str) -> str | None:
35
35
  try:
36
36
  sha256_hash = hashlib.sha256()
37
37
  with open(file_path, "rb") as f:
38
- for chunk in iter(lambda: f.read(4096), b""):
38
+ # Use larger chunks for better I/O performance
39
+ while True:
40
+ chunk = f.read(65536) # 64KB chunks
41
+ if not chunk:
42
+ break
39
43
  sha256_hash.update(chunk)
40
44
  return sha256_hash.hexdigest()
41
45
  except Exception as e:
@@ -175,10 +179,13 @@ def create_delta_backup(source_path: str, destination_folder: str, exclude_patte
175
179
  zip_info.compress_type = zipfile.ZIP_DEFLATED
176
180
  zip_info.comment = file_hash.encode() # Store hash in comment
177
181
 
178
- # Read and write file in chunks
182
+ # Read and write file in chunks with larger buffer
179
183
  with open(full_path, "rb") as f:
180
184
  with zipf.open(zip_info, "w", force_zip64=True) as zf:
181
- for chunk in iter(lambda: f.read(4096), b""):
185
+ while True:
186
+ chunk = f.read(65536) # 64KB chunks for better performance
187
+ if not chunk:
188
+ break
182
189
  zf.write(chunk)
183
190
  has_changes = True
184
191
  except Exception as e:
@@ -199,7 +206,10 @@ def create_delta_backup(source_path: str, destination_folder: str, exclude_patte
199
206
 
200
207
  with open(source_path, "rb") as f:
201
208
  with zipf.open(zip_info, "w", force_zip64=True) as zf:
202
- for chunk in iter(lambda: f.read(4096), b""):
209
+ while True:
210
+ chunk = f.read(65536) # 64KB chunks for better performance
211
+ if not chunk:
212
+ break
203
213
  zf.write(chunk)
204
214
  has_changes = True
205
215
  except Exception as e:
@@ -242,34 +252,69 @@ def consolidate_backups(zip_path: str, destination_zip: str) -> None:
242
252
 
243
253
  # Get all previous backups up to the specified one
244
254
  previous_backups: dict[str, dict[str, str]] = get_all_previous_backups(zip_folder, all_before=zip_path)
255
+ backup_paths: list[str] = list(previous_backups.keys())
245
256
 
257
+ # First pass: collect all deleted files and build file registry
246
258
  deleted_files: set[str] = set()
247
- final_files: set[str] = set()
259
+ file_registry: dict[str, tuple[str, zipfile.ZipInfo]] = {} # filename -> (backup_path, zipinfo)
248
260
 
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:
261
+ # Process backups in reverse order (newest first) to prioritize latest versions
262
+ for backup_path in reversed(backup_paths):
263
+ try:
253
264
  with zipfile.ZipFile(backup_path, "r") as zipf_in:
265
+
266
+ # Get namelist once for efficiency
267
+ namelist: list[str] = zipf_in.namelist()
268
+
254
269
  # Process deleted files
255
- if "__deleted_files__.txt" in zipf_in.namelist():
270
+ if "__deleted_files__.txt" in namelist:
256
271
  backup_deleted_files: list[str] = zipf_in.read("__deleted_files__.txt").decode().splitlines()
257
272
  deleted_files.update(backup_deleted_files)
258
273
 
259
- # Process files
274
+ # Process files - only add if not already in registry (newer versions take precedence)
260
275
  for inf in zipf_in.infolist():
261
276
  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)
277
+ if (filename
278
+ and filename != "__deleted_files__.txt"
279
+ and filename not in deleted_files
280
+ and filename not in file_registry):
281
+ file_registry[filename] = (backup_path, inf)
282
+ except Exception as e:
283
+ warning(f"Error processing backup {backup_path}: {e}")
284
+ continue
285
+
286
+ # Second pass: copy files efficiently, keeping ZIP files open longer
287
+ open_zips: dict[str, zipfile.ZipFile] = {}
288
+
289
+ try:
290
+ with zipfile.ZipFile(destination_zip, "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as zipf_out:
291
+ for filename, (backup_path, inf) in file_registry.items():
292
+ try:
293
+ # Open ZIP file if not already open
294
+ if backup_path not in open_zips:
295
+ open_zips[backup_path] = zipfile.ZipFile(backup_path, "r")
296
+
297
+ zipf_in = open_zips[backup_path]
298
+
299
+ # Copy file with larger chunks for better performance
300
+ with zipf_in.open(inf, "r") as source:
301
+ with zipf_out.open(inf, "w", force_zip64=True) as target:
302
+ # Use larger chunk size (64KB) for better I/O performance
303
+ while True:
304
+ chunk = source.read(65536)
305
+ if not chunk:
306
+ break
307
+ target.write(chunk)
308
+ except Exception as e:
309
+ warning(f"Error copying file {filename} from {backup_path}: {e}")
310
+ continue
311
+ finally:
312
+ # Clean up open ZIP files
313
+ for zipf in open_zips.values():
314
+ try:
315
+ zipf.close()
316
+ except Exception:
317
+ pass
273
318
 
274
319
  info(f"Consolidated backup created: {destination_zip}")
275
320
 
@@ -15,7 +15,6 @@ This module provides decorators for various purposes:
15
15
  """
16
16
 
17
17
  # Imports
18
- import inspect
19
18
  import time
20
19
  from collections.abc import Callable
21
20
  from enum import Enum
@@ -92,7 +91,8 @@ def silent(
92
91
  def measure_time(
93
92
  print_func: Callable[..., None] = debug,
94
93
  message: str = "",
95
- perf_counter: bool = True
94
+ perf_counter: bool = True,
95
+ is_generator: bool = False
96
96
  ) -> Callable[..., Any]:
97
97
  """ Decorator that will measure the execution time of a function and print it with the given print function
98
98
 
@@ -101,6 +101,9 @@ def measure_time(
101
101
  message (str): Message to display with the execution time (e.g. "Execution time of Something"),
102
102
  defaults to "Execution time of {func.__name__}"
103
103
  perf_counter (bool): Whether to use time.perf_counter_ns or time.time_ns
104
+ defaults to True (use time.perf_counter_ns)
105
+ is_generator (bool): Whether the function is a generator or not (default: False)
106
+ When True, the decorator will yield from the function instead of returning it.
104
107
  Returns:
105
108
  Callable: Decorator to measure the time of the function.
106
109
 
@@ -117,13 +120,15 @@ def measure_time(
117
120
  # Set the message if not specified, else use the provided one
118
121
  new_msg: str = message if message else f"Execution time of {get_func_name(func)}"
119
122
 
120
- @wraps(func)
121
- def wrapper(*args: tuple[Any, ...], **kwargs: dict[str, Any]) -> Any:
122
- # Check if function is a generator
123
- with MeasureTime(print_func=print_func, message=new_msg, perf_counter=perf_counter):
124
- if inspect.isgeneratorfunction(func):
123
+ if is_generator:
124
+ @wraps(func)
125
+ def wrapper(*args: tuple[Any, ...], **kwargs: dict[str, Any]) -> Any:
126
+ with MeasureTime(print_func=print_func, message=new_msg, perf_counter=perf_counter):
125
127
  yield from func(*args, **kwargs)
126
- else:
128
+ else:
129
+ @wraps(func)
130
+ def wrapper(*args: tuple[Any, ...], **kwargs: dict[str, Any]) -> Any:
131
+ with MeasureTime(print_func=print_func, message=new_msg, perf_counter=perf_counter):
127
132
  return func(*args, **kwargs)
128
133
  wrapper.__name__ = get_wrapper_name("stouputils.decorators.measure_time", func)
129
134
  return wrapper
File without changes
File without changes
File without changes