stouputils 1.3.19__tar.gz → 1.3.20__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.19 → stouputils-1.3.20}/PKG-INFO +1 -3
  2. {stouputils-1.3.19 → stouputils-1.3.20}/README.md +0 -2
  3. {stouputils-1.3.19 → stouputils-1.3.20}/pyproject.toml +1 -1
  4. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/archive.py +156 -11
  5. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/io.py +3 -3
  6. stouputils-1.3.19/stouputils/dont_look/zip_file_override.py +0 -122
  7. {stouputils-1.3.19 → stouputils-1.3.20}/.gitignore +0 -0
  8. {stouputils-1.3.19 → stouputils-1.3.20}/LICENSE +0 -0
  9. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/__init__.py +0 -0
  10. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/all_doctests.py +0 -0
  11. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/applications/__init__.py +0 -0
  12. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/applications/automatic_docs.py +0 -0
  13. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/applications/upscaler/__init__.py +0 -0
  14. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/applications/upscaler/config.py +0 -0
  15. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/applications/upscaler/image.py +0 -0
  16. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/applications/upscaler/video.py +0 -0
  17. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/backup.py +0 -0
  18. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/collections.py +0 -0
  19. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/continuous_delivery/__init__.py +0 -0
  20. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/continuous_delivery/cd_utils.py +0 -0
  21. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/continuous_delivery/github.py +0 -0
  22. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/continuous_delivery/pypi.py +0 -0
  23. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/continuous_delivery/pyproject.py +0 -0
  24. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/ctx.py +0 -0
  25. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/config/get.py +0 -0
  26. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/config/set.py +0 -0
  27. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/__init__.py +0 -0
  28. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/auto_contrast.py +0 -0
  29. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/axis_flip.py +0 -0
  30. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/bias_field_correction.py +0 -0
  31. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/binary_threshold.py +0 -0
  32. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/blur.py +0 -0
  33. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/brightness.py +0 -0
  34. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/canny.py +0 -0
  35. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/clahe.py +0 -0
  36. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/common.py +0 -0
  37. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/contrast.py +0 -0
  38. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/curvature_flow_filter.py +0 -0
  39. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/denoise.py +0 -0
  40. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/histogram_equalization.py +0 -0
  41. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/invert.py +0 -0
  42. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/laplacian.py +0 -0
  43. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/median_blur.py +0 -0
  44. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/noise.py +0 -0
  45. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/normalize.py +0 -0
  46. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/random_erase.py +0 -0
  47. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/resize.py +0 -0
  48. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/rotation.py +0 -0
  49. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/salt_pepper.py +0 -0
  50. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/sharpening.py +0 -0
  51. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/shearing.py +0 -0
  52. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/threshold.py +0 -0
  53. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/translation.py +0 -0
  54. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image/zoom.py +0 -0
  55. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image_augmentation.py +0 -0
  56. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/image_preprocess.py +0 -0
  57. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/prosthesis_detection.py +0 -0
  58. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/data_processing/technique.py +0 -0
  59. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/dataset/__init__.py +0 -0
  60. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/dataset/dataset.py +0 -0
  61. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/dataset/dataset_loader.py +0 -0
  62. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/dataset/grouping_strategy.py +0 -0
  63. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/dataset/image_loader.py +0 -0
  64. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/dataset/xy_tuple.py +0 -0
  65. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/metric_dictionnary.py +0 -0
  66. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/metric_utils.py +0 -0
  67. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/mlflow_utils.py +0 -0
  68. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/abstract_model.py +0 -0
  69. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/all.py +0 -0
  70. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/base_keras.py +0 -0
  71. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras/all.py +0 -0
  72. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras/convnext.py +0 -0
  73. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras/densenet.py +0 -0
  74. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras/efficientnet.py +0 -0
  75. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras/mobilenet.py +0 -0
  76. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras/resnet.py +0 -0
  77. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras/squeezenet.py +0 -0
  78. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras/vgg.py +0 -0
  79. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras/xception.py +0 -0
  80. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras_utils/callbacks/__init__.py +0 -0
  81. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +0 -0
  82. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +0 -0
  83. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +0 -0
  84. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +0 -0
  85. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +0 -0
  86. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras_utils/losses/__init__.py +0 -0
  87. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +0 -0
  88. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/keras_utils/visualizations.py +0 -0
  89. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/model_interface.py +0 -0
  90. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/models/sandbox.py +0 -0
  91. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/range_tuple.py +0 -0
  92. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/scripts/augment_dataset.py +0 -0
  93. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/scripts/exhaustive_process.py +0 -0
  94. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/scripts/preprocess_dataset.py +0 -0
  95. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/scripts/routine.py +0 -0
  96. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/data_science/utils.py +0 -0
  97. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/decorators.py +0 -0
  98. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/image.py +0 -0
  99. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/installer/__init__.py +0 -0
  100. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/installer/common.py +0 -0
  101. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/installer/downloader.py +0 -0
  102. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/installer/linux.py +0 -0
  103. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/installer/main.py +0 -0
  104. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/installer/windows.py +0 -0
  105. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/parallel.py +0 -0
  106. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/print.py +0 -0
  107. {stouputils-1.3.19 → stouputils-1.3.20}/stouputils/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stouputils
3
- Version: 1.3.19
3
+ Version: 1.3.20
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
@@ -90,8 +90,6 @@ It includes a range of tools for tasks such as execution of doctests, display ut
90
90
  │ ├── <a href="https://stoupy51.github.io/stouputils/latest/modules/stouputils.data_science.mlflow_utils.html">mlflow_utils.py</a> <span class="comment"># 📊 MLflow integration utilities</span>
91
91
  │ └── ...
92
92
 
93
- ├── <a href="https://stoupy51.github.io/stouputils/latest/modules/stouputils.dont_look.html">dont_look/</a> <span class="comment"># 🙈 Internal utilities (zip_file_override)</span>
94
-
95
93
  ├── <a href="https://stoupy51.github.io/stouputils/latest/modules/stouputils.installer.html">installer/</a>
96
94
  │ ├── <a href="https://stoupy51.github.io/stouputils/latest/modules/stouputils.installer.common.html">common.py</a> <span class="comment"># 🔧 Common installer utilities</span>
97
95
  │ ├── <a href="https://stoupy51.github.io/stouputils/latest/modules/stouputils.installer.downloader.html">downloader.py</a> <span class="comment"># ⬇️ File download utilities</span>
@@ -66,8 +66,6 @@ It includes a range of tools for tasks such as execution of doctests, display ut
66
66
  │ ├── <a href="https://stoupy51.github.io/stouputils/latest/modules/stouputils.data_science.mlflow_utils.html">mlflow_utils.py</a> <span class="comment"># 📊 MLflow integration utilities</span>
67
67
  │ └── ...
68
68
 
69
- ├── <a href="https://stoupy51.github.io/stouputils/latest/modules/stouputils.dont_look.html">dont_look/</a> <span class="comment"># 🙈 Internal utilities (zip_file_override)</span>
70
-
71
69
  ├── <a href="https://stoupy51.github.io/stouputils/latest/modules/stouputils.installer.html">installer/</a>
72
70
  │ ├── <a href="https://stoupy51.github.io/stouputils/latest/modules/stouputils.installer.common.html">common.py</a> <span class="comment"># 🔧 Common installer utilities</span>
73
71
  │ ├── <a href="https://stoupy51.github.io/stouputils/latest/modules/stouputils.installer.downloader.html">downloader.py</a> <span class="comment"># ⬇️ File download utilities</span>
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
5
5
 
6
6
  [project]
7
7
  name = "stouputils"
8
- version = "1.3.19"
8
+ version = "1.3.20"
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"
@@ -8,13 +8,13 @@ This module provides functions for creating and managing archives.
8
8
  :alt: stouputils archive examples
9
9
  """
10
10
 
11
+ # pyright: reportUnusedVariable=false
11
12
  # Imports
12
13
  import fnmatch
13
14
  import os
14
15
  from zipfile import ZIP_DEFLATED, ZipFile, ZipInfo
15
16
 
16
17
  from .decorators import LogLevels, handle_error
17
- from .dont_look.zip_file_override import ZipFileOverride
18
18
  from .io import clean_path, super_copy
19
19
 
20
20
 
@@ -124,6 +124,10 @@ def make_archive(
124
124
  def repair_zip_file(file_path: str, destination: str) -> bool:
125
125
  """ Try to repair a corrupted zip file by ignoring some of the errors
126
126
 
127
+ This function manually parses the ZIP file structure to extract files
128
+ even when the ZIP file is corrupted. It reads the central directory
129
+ entries and attempts to decompress each file individually.
130
+
127
131
  Args:
128
132
  file_path (str): Path of the zip file to repair
129
133
  destination (str): Destination of the new file
@@ -136,6 +140,9 @@ def repair_zip_file(file_path: str, destination: str) -> bool:
136
140
 
137
141
  > repair_zip_file("/path/to/source.zip", "/path/to/destination.zip")
138
142
  """
143
+ import struct
144
+ import zlib
145
+
139
146
  # Check
140
147
  if not os.path.exists(file_path):
141
148
  raise FileNotFoundError(f"File '{file_path}' not found")
@@ -143,20 +150,158 @@ def repair_zip_file(file_path: str, destination: str) -> bool:
143
150
  if dirname and not os.path.exists(dirname):
144
151
  raise FileNotFoundError(f"Directory '{dirname}' not found")
145
152
 
146
- # Read it
147
- with ZipFileOverride(file_path, "r") as zip_file:
148
-
149
- # Get a list of all the files in the ZIP file
150
- file_list: list[str] = zip_file.namelist()
153
+ # Read the entire ZIP file into memory
154
+ with open(file_path, 'rb') as f:
155
+ data = f.read()
156
+
157
+ # Find central directory entries
158
+ CENTRAL_SIG = b'PK\x01\x02'
159
+ entries: list[dict[str, int | str]] = []
160
+ idx = 0
161
+
162
+ while True:
163
+ idx = data.find(CENTRAL_SIG, idx)
164
+ if idx == -1:
165
+ break
166
+ # Ensure enough length for central directory header
167
+ if idx + 46 > len(data):
168
+ break
169
+
170
+ header = data[idx:idx+46]
171
+ try:
172
+ (
173
+ sig,
174
+ ver_made, ver_needed, flags, comp_method, mtime, mdate,
175
+ crc, csize, usize,
176
+ name_len, extra_len, comm_len,
177
+ disk_start, int_attr,
178
+ ext_attr, local_off
179
+ ) = struct.unpack('<4s6H3L3H2H2L', header)
180
+
181
+ name_start = idx + 46
182
+ if name_start + name_len > len(data):
183
+ idx += 4
184
+ continue
185
+
186
+ name = data[name_start:name_start+name_len].decode('utf-8', errors='replace')
187
+ entries.append({
188
+ 'name': name,
189
+ 'comp_method': comp_method,
190
+ 'csize': csize,
191
+ 'usize': usize,
192
+ 'local_offset': local_off,
193
+ 'crc': crc
194
+ })
195
+ except (struct.error, UnicodeDecodeError):
196
+ # Skip corrupted entries
197
+ pass
198
+
199
+ idx += 4
200
+
201
+ # Create a new ZIP file with recovered entries
202
+ with ZipFile(destination, "w", compression=ZIP_DEFLATED) as new_zip_file:
203
+ for entry in entries:
204
+ try:
205
+ # Get the local header to find data start
206
+ lo: int = int(entry['local_offset'])
207
+ if lo + 30 > len(data):
208
+ continue
151
209
 
152
- # Create a new ZIP file at the destination
153
- with ZipFileOverride(destination, "w", compression=ZIP_DEFLATED) as new_zip_file:
154
- for file_name in file_list:
210
+ lh = data[lo:lo+30]
155
211
  try:
156
- new_zip_file.writestr(file_name, zip_file.read(file_name))
157
- except KeyboardInterrupt:
212
+ _, _, _, _, _, _, _, _, _, name_len, extra_len = struct.unpack('<4sHHHHHLLLHH', lh)
213
+ except struct.error:
214
+ continue
215
+
216
+ data_start: int = lo + 30 + name_len + extra_len
217
+ if data_start + int(entry['csize']) > len(data):
158
218
  continue
159
219
 
220
+ comp_data = data[data_start:data_start+int(entry['csize'])]
221
+
222
+ # Decompress the data
223
+ try:
224
+ if int(entry['comp_method']) == 0: # No compression
225
+ content = comp_data[:int(entry['usize'])]
226
+ elif int(entry['comp_method']) == 8: # Deflate compression
227
+ content = zlib.decompress(comp_data, -zlib.MAX_WBITS)
228
+ else:
229
+ # Unsupported compression method, skip
230
+ continue
231
+
232
+ # Write to new ZIP file
233
+ new_zip_file.writestr(str(entry['name']), content)
234
+
235
+ except (zlib.error, Exception):
236
+ # If decompression fails, try to write raw data as a fallback
237
+ try:
238
+ new_zip_file.writestr(f"{entry['name']!s}.corrupted", comp_data)
239
+ except Exception:
240
+ # Skip completely corrupted entries
241
+ continue
242
+
243
+ except Exception:
244
+ # Skip any entries that cause errors
245
+ continue
246
+
160
247
  return True
161
248
 
162
249
 
250
+ # CLI functionality
251
+ if __name__ == "__main__":
252
+ import argparse
253
+ import sys
254
+
255
+ parser = argparse.ArgumentParser(description="Archive utilities")
256
+ subparsers = parser.add_subparsers(dest="command", help="Available commands")
257
+
258
+ # Repair command
259
+ repair_parser = subparsers.add_parser("repair", help="Repair a corrupted zip file")
260
+ repair_parser.add_argument("input_file", help="Path to the corrupted zip file")
261
+ repair_parser.add_argument("output_file", nargs="?", help="Path to the repaired zip file (optional, defaults to input_file with '_repaired' suffix)")
262
+
263
+ # Make archive command
264
+ archive_parser = subparsers.add_parser("make", help="Create a zip archive")
265
+ archive_parser.add_argument("source", help="Source directory to archive")
266
+ archive_parser.add_argument("destination", help="Destination zip file")
267
+ archive_parser.add_argument("--ignore", help="Glob patterns to ignore (comma-separated)")
268
+ archive_parser.add_argument("--create-dir", action="store_true", help="Create destination directory if it doesn't exist")
269
+
270
+ args = parser.parse_args()
271
+
272
+ if args.command == "repair":
273
+ input_file = args.input_file
274
+ if args.output_file:
275
+ output_file = args.output_file
276
+ else:
277
+ # Generate default output filename
278
+ base, ext = os.path.splitext(input_file)
279
+ output_file = f"{base}_repaired{ext}"
280
+
281
+ print(f"Repairing '{input_file}' to '{output_file}'...")
282
+ try:
283
+ repair_zip_file(input_file, output_file)
284
+ print(f"Successfully repaired zip file: {output_file}")
285
+ except Exception as e:
286
+ print(f"Error repairing zip file: {e}", file=sys.stderr)
287
+ sys.exit(1)
288
+
289
+ elif args.command == "make":
290
+ print(f"Creating archive from '{args.source}' to '{args.destination}'...")
291
+ try:
292
+ make_archive(
293
+ source=args.source,
294
+ destinations=args.destination,
295
+ create_dir=args.create_dir,
296
+ ignore_patterns=args.ignore
297
+ )
298
+ print(f"Successfully created archive: {args.destination}")
299
+ except Exception as e:
300
+ print(f"Error creating archive: {e}", file=sys.stderr)
301
+ sys.exit(1)
302
+
303
+ else:
304
+ parser.print_help()
305
+ sys.exit(1)
306
+
307
+
@@ -117,7 +117,7 @@ def get_root_path(relative_path: str, go_up: int = 0) -> str:
117
117
  return clean_path(
118
118
  os.path.dirname(os.path.abspath(relative_path))
119
119
  + "/.." * go_up
120
- )
120
+ ) or "."
121
121
 
122
122
 
123
123
  # Function that returns the relative path of a file
@@ -139,9 +139,9 @@ def relative_path(file_path: str, relative_to: str = os.getcwd()) -> str:
139
139
  file_path = clean_path(file_path)
140
140
  relative_to = clean_path(relative_to)
141
141
  if file_path.startswith(relative_to):
142
- return clean_path(os.path.relpath(file_path, relative_to))
142
+ return clean_path(os.path.relpath(file_path, relative_to)) or "."
143
143
  else:
144
- return file_path
144
+ return file_path or "."
145
145
 
146
146
 
147
147
  # For easy file management
@@ -1,122 +0,0 @@
1
- """
2
- This module provides a zip file override to handle some corrupted zip files.
3
-
4
- For instance, some Minecraft servers resource packs are slightly corrupted
5
- and cannot be opened with the standard zipfile module.
6
- See the archive.py module for more information.
7
- """
8
-
9
- # Imports
10
- from zipfile import (
11
- _FH_EXTRA_FIELD_LENGTH, # type: ignore
12
- ZipExtFile,
13
- ZipFile,
14
- ZipInfo,
15
- _SharedFile, # type: ignore
16
- crc32, # type: ignore
17
- sizeFileHeader, # type: ignore
18
- struct, # type: ignore
19
- structFileHeader, # type: ignore
20
- )
21
-
22
-
23
- # Class overrides
24
- class ZipExtFileOverride(ZipExtFile):
25
- """ Override of the ZipExtFile class """
26
-
27
- def _update_crc(self, newdata) -> None: # type: ignore
28
- """ Override of the _update_crc method """
29
- # Update the CRC using the given data.
30
- if self._expected_crc is None: # type: ignore
31
- # No need to compute the CRC if we don't have a reference value
32
- return
33
- self._running_crc = crc32(newdata, self._running_crc) # type: ignore
34
-
35
- class ZipFileOverride(ZipFile):
36
- """ Override of the ZipFile class """
37
-
38
- def open(self, name, mode="r", pwd=None, *, force_zip64=False): # type: ignore
39
- """Return file-like object for 'name'.
40
-
41
- name is a string for the file name within the ZIP file, or a ZipInfo
42
- object.
43
-
44
- mode should be 'r' to read a file already in the ZIP file, or 'w' to
45
- write to a file newly added to the archive.
46
-
47
- pwd is the password to decrypt files (only used for reading).
48
-
49
- When writing, if the file size is not known in advance but may exceed
50
- 2 GiB, pass force_zip64 to use the ZIP64 format, which can handle large
51
- files. If the size is known in advance, it is best to pass a ZipInfo
52
- instance for name, with zinfo.file_size set.
53
- """
54
- if mode not in {"r", "w"}:
55
- raise ValueError('open() requires mode "r" or "w"')
56
- if pwd and (mode == "w"):
57
- raise ValueError("pwd is only supported for reading files")
58
- if not self.fp:
59
- raise ValueError(
60
- "Attempt to use ZIP archive that was already closed")
61
-
62
- # Make sure we have an info object
63
- if isinstance(name, ZipInfo):
64
- # 'name' is already an info object
65
- zinfo = name
66
- elif mode == 'w':
67
- zinfo = ZipInfo(name)
68
- zinfo.compress_type = self.compression
69
- zinfo._compresslevel = self.compresslevel # type: ignore
70
- else:
71
- # Get info object for name
72
- zinfo = self.getinfo(name)
73
-
74
- if mode == 'w':
75
- return self._open_to_write(zinfo, force_zip64=force_zip64) # type: ignore
76
-
77
- if self._writing: # type: ignore
78
- raise ValueError("Can't read from the ZIP file while there "
79
- "is an open writing handle on it. "
80
- "Close the writing handle before trying to read.")
81
-
82
- # Open for reading:
83
- self._fileRefCnt += 1 # type: ignore
84
- zef_file = _SharedFile(self.fp, zinfo.header_offset, # type: ignore
85
- self._fpclose, self._lock, lambda: self._writing) # type: ignore
86
- try:
87
- # Skip the file header:
88
- fheader = zef_file.read(sizeFileHeader) # type: ignore
89
- fheader = struct.unpack(structFileHeader, fheader) # type: ignore
90
-
91
- if fheader[_FH_EXTRA_FIELD_LENGTH]:
92
- zef_file.seek(fheader[_FH_EXTRA_FIELD_LENGTH], whence=1) # type: ignore
93
-
94
- if zinfo.flag_bits & 0x20:
95
- # Zip 2.7: compressed patched data
96
- raise NotImplementedError("compressed patched data (flag bit 5)")
97
-
98
- if zinfo.flag_bits & 0x40:
99
- # strong encryption
100
- raise NotImplementedError("strong encryption (flag bit 6)")
101
-
102
- # if (zinfo._end_offset is not None and
103
- # zef_file.tell() + zinfo.compress_size > zinfo._end_offset):
104
- # raise BadZipFile(f"Overlapped entries: {zinfo.orig_filename!r} (possible zip bomb)")
105
-
106
- # check for encrypted flag & handle password
107
- is_encrypted = zinfo.flag_bits & 0x1
108
- if is_encrypted:
109
- if not pwd:
110
- pwd = self.pwd
111
- if pwd and not isinstance(pwd, bytes): # type: ignore
112
- raise TypeError(f"pwd: expected bytes, got {type(pwd).__name__}")
113
- if not pwd:
114
- raise RuntimeError(f"File {name!r} is encrypted, password required for extraction")
115
- else:
116
- pwd = None
117
-
118
- return ZipExtFileOverride(zef_file, mode, zinfo, pwd, True) # type: ignore
119
- except:
120
- zef_file.close() # type: ignore
121
- raise
122
-
File without changes
File without changes