stouputils 1.6.5__tar.gz → 1.7.0__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 (137) hide show
  1. {stouputils-1.6.5 → stouputils-1.7.0}/PKG-INFO +1 -1
  2. {stouputils-1.6.5 → stouputils-1.7.0}/pyproject.toml +1 -1
  3. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/all_doctests.py +12 -4
  4. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/applications/automatic_docs.py +46 -14
  5. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/applications/automatic_docs.pyi +13 -8
  6. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/continuous_delivery/cd_utils.py +94 -1
  7. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/continuous_delivery/cd_utils.pyi +49 -1
  8. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/io.py +46 -21
  9. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/io.pyi +16 -15
  10. {stouputils-1.6.5 → stouputils-1.7.0}/.gitignore +0 -0
  11. {stouputils-1.6.5 → stouputils-1.7.0}/LICENSE +0 -0
  12. {stouputils-1.6.5 → stouputils-1.7.0}/README.md +0 -0
  13. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/__init__.py +0 -0
  14. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/__init__.pyi +0 -0
  15. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/__main__.py +0 -0
  16. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/all_doctests.pyi +0 -0
  17. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/applications/__init__.py +0 -0
  18. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/applications/__init__.pyi +0 -0
  19. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/applications/upscaler/__init__.py +0 -0
  20. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/applications/upscaler/__init__.pyi +0 -0
  21. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/applications/upscaler/config.py +0 -0
  22. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/applications/upscaler/config.pyi +0 -0
  23. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/applications/upscaler/image.py +0 -0
  24. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/applications/upscaler/image.pyi +0 -0
  25. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/applications/upscaler/video.py +0 -0
  26. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/applications/upscaler/video.pyi +0 -0
  27. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/archive.py +0 -0
  28. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/archive.pyi +0 -0
  29. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/backup.py +0 -0
  30. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/backup.pyi +0 -0
  31. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/collections.py +0 -0
  32. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/collections.pyi +0 -0
  33. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/continuous_delivery/__init__.py +0 -0
  34. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/continuous_delivery/__init__.pyi +0 -0
  35. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/continuous_delivery/github.py +0 -0
  36. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/continuous_delivery/github.pyi +0 -0
  37. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/continuous_delivery/pypi.py +0 -0
  38. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/continuous_delivery/pypi.pyi +0 -0
  39. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/continuous_delivery/pyproject.py +0 -0
  40. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/continuous_delivery/pyproject.pyi +0 -0
  41. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/continuous_delivery/stubs.py +0 -0
  42. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/continuous_delivery/stubs.pyi +0 -0
  43. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/ctx.py +0 -0
  44. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/ctx.pyi +0 -0
  45. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/config/get.py +0 -0
  46. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/config/set.py +0 -0
  47. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/__init__.py +0 -0
  48. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/auto_contrast.py +0 -0
  49. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/axis_flip.py +0 -0
  50. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/bias_field_correction.py +0 -0
  51. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/binary_threshold.py +0 -0
  52. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/blur.py +0 -0
  53. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/brightness.py +0 -0
  54. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/canny.py +0 -0
  55. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/clahe.py +0 -0
  56. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/common.py +0 -0
  57. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/contrast.py +0 -0
  58. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/curvature_flow_filter.py +0 -0
  59. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/denoise.py +0 -0
  60. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/histogram_equalization.py +0 -0
  61. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/invert.py +0 -0
  62. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/laplacian.py +0 -0
  63. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/median_blur.py +0 -0
  64. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/noise.py +0 -0
  65. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/normalize.py +0 -0
  66. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/random_erase.py +0 -0
  67. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/resize.py +0 -0
  68. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/rotation.py +0 -0
  69. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/salt_pepper.py +0 -0
  70. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/sharpening.py +0 -0
  71. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/shearing.py +0 -0
  72. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/threshold.py +0 -0
  73. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/translation.py +0 -0
  74. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/zoom.py +0 -0
  75. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image_augmentation.py +0 -0
  76. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/image_preprocess.py +0 -0
  77. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/prosthesis_detection.py +0 -0
  78. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/data_processing/technique.py +0 -0
  79. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/dataset/__init__.py +0 -0
  80. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/dataset/dataset.py +0 -0
  81. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/dataset/dataset_loader.py +0 -0
  82. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/dataset/grouping_strategy.py +0 -0
  83. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/dataset/image_loader.py +0 -0
  84. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/dataset/xy_tuple.py +0 -0
  85. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/metric_dictionnary.py +0 -0
  86. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/metric_utils.py +0 -0
  87. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/mlflow_utils.py +0 -0
  88. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/abstract_model.py +0 -0
  89. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/all.py +0 -0
  90. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/base_keras.py +0 -0
  91. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras/all.py +0 -0
  92. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras/convnext.py +0 -0
  93. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras/densenet.py +0 -0
  94. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras/efficientnet.py +0 -0
  95. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras/mobilenet.py +0 -0
  96. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras/resnet.py +0 -0
  97. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras/squeezenet.py +0 -0
  98. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras/vgg.py +0 -0
  99. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras/xception.py +0 -0
  100. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/callbacks/__init__.py +0 -0
  101. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +0 -0
  102. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +0 -0
  103. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +0 -0
  104. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +0 -0
  105. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +0 -0
  106. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/losses/__init__.py +0 -0
  107. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +0 -0
  108. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/visualizations.py +0 -0
  109. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/model_interface.py +0 -0
  110. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/models/sandbox.py +0 -0
  111. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/range_tuple.py +0 -0
  112. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/scripts/augment_dataset.py +0 -0
  113. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/scripts/exhaustive_process.py +0 -0
  114. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/scripts/preprocess_dataset.py +0 -0
  115. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/scripts/routine.py +0 -0
  116. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/data_science/utils.py +0 -0
  117. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/decorators.py +0 -0
  118. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/decorators.pyi +0 -0
  119. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/image.py +0 -0
  120. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/image.pyi +0 -0
  121. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/installer/__init__.py +0 -0
  122. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/installer/__init__.pyi +0 -0
  123. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/installer/common.py +0 -0
  124. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/installer/common.pyi +0 -0
  125. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/installer/downloader.py +0 -0
  126. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/installer/downloader.pyi +0 -0
  127. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/installer/linux.py +0 -0
  128. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/installer/linux.pyi +0 -0
  129. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/installer/main.py +0 -0
  130. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/installer/main.pyi +0 -0
  131. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/installer/windows.py +0 -0
  132. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/installer/windows.pyi +0 -0
  133. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/parallel.py +0 -0
  134. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/parallel.pyi +0 -0
  135. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/print.py +0 -0
  136. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/print.pyi +0 -0
  137. {stouputils-1.6.5 → stouputils-1.7.0}/stouputils/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stouputils
3
- Version: 1.6.5
3
+ Version: 1.7.0
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.6.5"
8
+ version = "1.7.0"
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"
@@ -119,17 +119,25 @@ def launch_tests(root_dir: str, strict: bool = True) -> int:
119
119
  ]
120
120
 
121
121
  # Display any error lines for each module at the end of the script
122
- nb_failed_tests: int = 0
122
+ total_failed: int = 0
123
123
  for module, result in zip(modules, results, strict=False):
124
124
  if result.failed > 0:
125
- error(f"Errors in module {module.__name__}", exit=False)
126
- nb_failed_tests += result.failed
125
+ successful_tests: int = result.attempted - result.failed
126
+ error(f"Errors in module {module.__name__} ({successful_tests}/{result.attempted} tests passed)", exit=False)
127
+ total_failed += result.failed
127
128
 
128
129
  # Reset force_raise_exception back
129
130
  decorators.force_raise_exception = strict
130
131
 
132
+ # Final info
133
+ total_tests: int = sum(result.attempted for result in results)
134
+ successful_tests: int = total_tests - total_failed
135
+ if total_failed == 0:
136
+ info(f"All tests passed for all {len(modules)} modules! ({total_tests}/{total_tests} tests passed)")
137
+ else:
138
+ error(f"Some tests failed: {successful_tests}/{total_tests} tests passed in total across {len(modules)} modules", exit=False)
131
139
  # Return the number of failed tests
132
- return nb_failed_tests
140
+ return total_failed
133
141
 
134
142
 
135
143
  def test_module_with_progress(module: ModuleType, separator: str) -> TestResults:
@@ -251,12 +251,15 @@ def setup(app: Any) -> None:
251
251
  return conf_content
252
252
 
253
253
  @simple_cache()
254
- def get_versions_from_github(github_user: str, github_repo: str) -> list[str]:
254
+ def get_versions_from_github(github_user: str, github_repo: str, recent_minor_versions: int = 2) -> list[str]:
255
255
  """ Get list of versions from GitHub gh-pages branch.
256
+ Only shows detailed versions for the last N minor versions, and keeps only
257
+ the latest patch version for older minor versions.
256
258
 
257
259
  Args:
258
- github_user (str): GitHub username
259
- github_repo (str): GitHub repository name
260
+ github_user (str): GitHub username
261
+ github_repo (str): GitHub repository name
262
+ recent_minor_versions (int): Number of recent minor versions to show all patches for (-1 for all).
260
263
 
261
264
  Returns:
262
265
  list[str]: List of versions, with 'latest' as first element
@@ -266,13 +269,37 @@ def get_versions_from_github(github_user: str, github_repo: str) -> list[str]:
266
269
  try:
267
270
  response = requests.get(f"https://api.github.com/repos/{github_user}/{github_repo}/contents?ref=gh-pages")
268
271
  if response.status_code == 200:
269
- contents = response.json()
270
- version_list = ["latest", *sorted([
272
+ contents: list[dict[str, str]] = response.json()
273
+ all_versions: list[str] = sorted([
271
274
  d["name"].replace("v", "")
272
275
  for d in contents
273
276
  if d["type"] == "dir" and d["name"].startswith("v")
274
277
  ], key=version_to_float, reverse=True
275
- )]
278
+ )
279
+
280
+ # Group versions by major.minor
281
+ from collections import defaultdict
282
+ minor_versions: dict[str, list[str]] = defaultdict(list)
283
+ for version in all_versions:
284
+ parts = version.split(".")
285
+ if len(parts) >= 2:
286
+ minor_key = f"{parts[0]}.{parts[1]}"
287
+ minor_versions[minor_key].append(version)
288
+
289
+ # Get the sorted minor version keys
290
+ sorted_minors = sorted(minor_versions.keys(), key=version_to_float, reverse=True)
291
+
292
+ # Build final version list
293
+ final_versions: list[str] = []
294
+ for i, minor_key in enumerate(sorted_minors):
295
+ if recent_minor_versions == -1 or i < recent_minor_versions:
296
+ # Keep all patch versions for the recent minor versions
297
+ final_versions.extend(minor_versions[minor_key])
298
+ else:
299
+ # Keep only the latest patch version for older minor versions
300
+ final_versions.append(minor_versions[minor_key][0])
301
+
302
+ version_list = ["latest", *final_versions]
276
303
  except Exception as e:
277
304
  info(f"Failed to get versions from GitHub: {e}")
278
305
  version_list = ["latest"]
@@ -300,17 +327,19 @@ def generate_index_rst(
300
327
  project: str,
301
328
  github_user: str,
302
329
  github_repo: str,
303
- get_versions_function: Callable[[str, str], list[str]] = get_versions_from_github,
330
+ get_versions_function: Callable[[str, str, int], list[str]] = get_versions_from_github,
331
+ recent_minor_versions: int = 2,
304
332
  ) -> None:
305
333
  """ Generate index.rst from README.md content.
306
334
 
307
335
  Args:
308
- readme_path (str): Path to the README.md file
336
+ readme_path (str): Path to the README.md file
309
337
  index_path (str): Path where index.rst should be created
310
338
  project (str): Name of the project
311
339
  github_user (str): GitHub username
312
340
  github_repo (str): GitHub repository name
313
- get_versions_function (Callable[[str, str], list[str]]): Function to get versions from GitHub
341
+ get_versions_function (Callable[[str, str, int], list[str]]): Function to get versions from GitHub
342
+ recent_minor_versions (int): Number of recent minor versions to show all patches for. Defaults to 2
314
343
  """
315
344
  # Read README content
316
345
  with open(readme_path, encoding="utf-8") as f:
@@ -320,7 +349,7 @@ def generate_index_rst(
320
349
  version_selector: str = "\n\n**Versions**: "
321
350
 
322
351
  # Get versions from GitHub
323
- version_list: list[str] = get_versions_function(github_user, github_repo)
352
+ version_list: list[str] = get_versions_function(github_user, github_repo, recent_minor_versions)
324
353
 
325
354
  # Create version links
326
355
  version_links: list[str] = []
@@ -429,8 +458,9 @@ def update_documentation(
429
458
  github_repo: str = "",
430
459
  version: str | None = None,
431
460
  skip_undocumented: bool = True,
461
+ recent_minor_versions: int = 2,
432
462
 
433
- get_versions_function: Callable[[str, str], list[str]] = get_versions_from_github,
463
+ get_versions_function: Callable[[str, str, int], list[str]] = get_versions_from_github,
434
464
  generate_index_function: Callable[..., None] = generate_index_rst,
435
465
  generate_docs_function: Callable[..., None] = generate_documentation,
436
466
  generate_redirect_function: Callable[[str], None] = generate_redirect_html,
@@ -451,8 +481,9 @@ def update_documentation(
451
481
  github_repo (str): GitHub repository name
452
482
  version (str | None): Version to build documentation for (e.g. "1.0.0", defaults to "latest")
453
483
  skip_undocumented (bool): Whether to skip undocumented members. Defaults to True
484
+ recent_minor_versions (int): Number of recent minor versions to show all patches for. Defaults to 2
454
485
 
455
- get_versions_function (Callable[[str, str], list[str]]): Function to get versions from GitHub
486
+ get_versions_function (Callable[[str, str, int], list[str]]): Function to get versions from GitHub
456
487
  generate_index_function (Callable[..., None]): Function to generate index.rst
457
488
  generate_docs_function (Callable[..., None]): Function to generate documentation
458
489
  generate_redirect_function (Callable[[str], None]): Function to create redirect file
@@ -490,15 +521,16 @@ def update_documentation(
490
521
  github_user=github_user,
491
522
  github_repo=github_repo,
492
523
  get_versions_function=get_versions_function,
524
+ recent_minor_versions=recent_minor_versions,
493
525
  )
494
526
 
495
527
  # Clean up old module documentation
496
528
  if os.path.exists(modules_dir):
497
529
  shutil.rmtree(modules_dir)
498
- os.makedirs(modules_dir)
530
+ os.makedirs(modules_dir, exist_ok=True)
499
531
 
500
532
  # Get versions and current version for conf.py
501
- version_list: list[str] = get_versions_function(github_user, github_repo)
533
+ version_list: list[str] = get_versions_function(github_user, github_repo, recent_minor_versions)
502
534
  current_version: str = version if version else "latest"
503
535
 
504
536
  # Generate conf.py
@@ -31,12 +31,15 @@ def get_sphinx_conf_content(project: str, project_dir: str, author: str, current
31
31
  \tReturns:
32
32
  \t\tstr: Content of the Sphinx configuration file
33
33
  \t"""
34
- def get_versions_from_github(github_user: str, github_repo: str) -> list[str]:
34
+ def get_versions_from_github(github_user: str, github_repo: str, recent_minor_versions: int = 2) -> list[str]:
35
35
  """ Get list of versions from GitHub gh-pages branch.
36
+ \tOnly shows detailed versions for the last N minor versions, and keeps only
37
+ \tthe latest patch version for older minor versions.
36
38
 
37
39
  \tArgs:
38
- \t\tgithub_user (str): GitHub username
39
- \t\tgithub_repo (str): GitHub repository name
40
+ \t\tgithub_user (str): GitHub username
41
+ \t\tgithub_repo (str): GitHub repository name
42
+ \t\trecent_minor_versions (int): Number of recent minor versions to show all patches for (-1 for all).
40
43
 
41
44
  \tReturns:
42
45
  \t\tlist[str]: List of versions, with 'latest' as first element
@@ -50,16 +53,17 @@ def markdown_to_rst(markdown_content: str) -> str:
50
53
  \tReturns:
51
54
  \t\tstr: RST content
52
55
  \t"""
53
- def generate_index_rst(readme_path: str, index_path: str, project: str, github_user: str, github_repo: str, get_versions_function: Callable[[str, str], list[str]] = ...) -> None:
56
+ def generate_index_rst(readme_path: str, index_path: str, project: str, github_user: str, github_repo: str, get_versions_function: Callable[[str, str, int], list[str]] = ..., recent_minor_versions: int = 2) -> None:
54
57
  """ Generate index.rst from README.md content.
55
58
 
56
59
  \tArgs:
57
- \t\treadme_path (str): Path to the README.md file
60
+ \t\treadme_path (str): Path to the README.md file
58
61
  \t\tindex_path (str): Path where index.rst should be created
59
62
  \t\tproject (str): Name of the project
60
63
  \t\tgithub_user (str): GitHub username
61
64
  \t\tgithub_repo (str): GitHub repository name
62
- \t\tget_versions_function (Callable[[str, str], list[str]]): Function to get versions from GitHub
65
+ \t\tget_versions_function (Callable[[str, str, int], list[str]]): Function to get versions from GitHub
66
+ \t\trecent_minor_versions (int): Number of recent minor versions to show all patches for. Defaults to 2
63
67
  \t"""
64
68
  def generate_documentation(source_dir: str, modules_dir: str, project_dir: str, build_dir: str) -> None:
65
69
  """ Generate documentation using Sphinx.
@@ -76,7 +80,7 @@ def generate_redirect_html(filepath: str) -> None:
76
80
  \tArgs:
77
81
  \t\tfilepath (str): Path to the file where the HTML content should be written
78
82
  \t"""
79
- def update_documentation(root_path: str, project: str, project_dir: str = '', author: str = 'Author', copyright: str = '2025, Author', html_logo: str = '', html_favicon: str = '', html_theme: str = 'breeze', github_user: str = '', github_repo: str = '', version: str | None = None, skip_undocumented: bool = True, get_versions_function: Callable[[str, str], list[str]] = ..., generate_index_function: Callable[..., None] = ..., generate_docs_function: Callable[..., None] = ..., generate_redirect_function: Callable[[str], None] = ..., get_conf_content_function: Callable[..., str] = ...) -> None:
83
+ def update_documentation(root_path: str, project: str, project_dir: str = '', author: str = 'Author', copyright: str = '2025, Author', html_logo: str = '', html_favicon: str = '', html_theme: str = 'breeze', github_user: str = '', github_repo: str = '', version: str | None = None, skip_undocumented: bool = True, recent_minor_versions: int = 2, get_versions_function: Callable[[str, str, int], list[str]] = ..., generate_index_function: Callable[..., None] = ..., generate_docs_function: Callable[..., None] = ..., generate_redirect_function: Callable[[str], None] = ..., get_conf_content_function: Callable[..., str] = ...) -> None:
80
84
  ''' Update the Sphinx documentation.
81
85
 
82
86
  \tArgs:
@@ -92,8 +96,9 @@ def update_documentation(root_path: str, project: str, project_dir: str = '', au
92
96
  \t\tgithub_repo (str): GitHub repository name
93
97
  \t\tversion (str | None): Version to build documentation for (e.g. "1.0.0", defaults to "latest")
94
98
  \t\tskip_undocumented (bool): Whether to skip undocumented members. Defaults to True
99
+ \t\trecent_minor_versions (int): Number of recent minor versions to show all patches for. Defaults to 2
95
100
 
96
- \t\tget_versions_function (Callable[[str, str], list[str]]): Function to get versions from GitHub
101
+ \t\tget_versions_function (Callable[[str, str, int], list[str]]): Function to get versions from GitHub
97
102
  \t\tgenerate_index_function (Callable[..., None]): Function to generate index.rst
98
103
  \t\tgenerate_docs_function (Callable[..., None]): Function to generate documentation
99
104
  \t\tgenerate_redirect_function (Callable[[str], None]): Function to create redirect file
@@ -108,9 +108,11 @@ def version_to_float(version: str) -> float:
108
108
  """ Converts a version string into a float for comparison purposes.
109
109
  The version string is expected to follow the format of major.minor.patch.something_else....,
110
110
  where each part is separated by a dot and can be extended indefinitely.
111
+ Supports pre-release suffixes with numbers: devN/dN (dev), aN (alpha), bN (beta), rcN/cN (release candidate).
112
+ Ordering: 1.0.0 > 1.0.0rc2 > 1.0.0rc1 > 1.0.0b2 > 1.0.0b1 > 1.0.0a2 > 1.0.0a1 > 1.0.0dev1
111
113
 
112
114
  Args:
113
- version (str): The version string to convert. (e.g. "v1.0.0.1.2.3")
115
+ version (str): The version string to convert. (e.g. "v1.0.0.1.2.3", "v2.0.0b2", "v1.0.0rc1")
114
116
  Returns:
115
117
  float: The float representation of the version. (e.g. 0)
116
118
 
@@ -124,7 +126,88 @@ def version_to_float(version: str) -> float:
124
126
  1.0000000010020031
125
127
  >>> version_to_float("v2.0") > version_to_float("v1.0.0.1")
126
128
  True
129
+ >>> version_to_float("v2.0.0") > version_to_float("v2.0.0rc") > version_to_float("v2.0.0b") > version_to_float("v2.0.0a") > version_to_float("v2.0.0dev")
130
+ True
131
+ >>> version_to_float("v1.0.0b") > version_to_float("v1.0.0a")
132
+ True
133
+ >>> version_to_float("v1.0.0") > version_to_float("v1.0.0b")
134
+ True
135
+ >>> version_to_float("v3.0.0a") > version_to_float("v2.9.9")
136
+ True
137
+ >>> version_to_float("v1.2.3b") < version_to_float("v1.2.3")
138
+ True
139
+ >>> version_to_float("1.0.0") == version_to_float("v1.0.0")
140
+ True
141
+ >>> version_to_float("2.0.0.0.0.0.1b") > version_to_float("2.0.0.0.0.0.1a")
142
+ True
143
+ >>> version_to_float("2.0.0.0.0.0.1") > version_to_float("2.0.0.0.0.0.1b")
144
+ True
145
+ >>> version_to_float("v1.0.0rc") == version_to_float("v1.0.0c")
146
+ True
147
+ >>> version_to_float("v1.0.0c") > version_to_float("v1.0.0b")
148
+ True
149
+ >>> version_to_float("v1.0.0d") < version_to_float("v1.0.0a")
150
+ True
151
+ >>> version_to_float("v1.0.0dev") < version_to_float("v1.0.0a")
152
+ True
153
+ >>> version_to_float("v1.0.0dev") == version_to_float("v1.0.0d")
154
+ True
155
+ >>> version_to_float("v1.0.0rc2") > version_to_float("v1.0.0rc1")
156
+ True
157
+ >>> version_to_float("v1.0.0b2") > version_to_float("v1.0.0b1")
158
+ True
159
+ >>> version_to_float("v1.0.0a2") > version_to_float("v1.0.0a1")
160
+ True
161
+ >>> version_to_float("v1.0.0dev2") > version_to_float("v1.0.0dev1")
162
+ True
163
+ >>> version_to_float("v1.0.0") > version_to_float("v1.0.0rc2") > version_to_float("v1.0.0rc1")
164
+ True
165
+ >>> version_to_float("v1.0.0rc1") > version_to_float("v1.0.0b2")
166
+ True
167
+ >>> version_to_float("v1.0.0b1") > version_to_float("v1.0.0a2")
168
+ True
169
+ >>> version_to_float("v1.0.0a1") > version_to_float("v1.0.0dev2")
170
+ True
171
+ >>> versions = ["v1.0.0", "v1.0.0rc2", "v1.0.0rc1", "v1.0.0b2", "v1.0.0b1", "v1.0.0a2", "v1.0.0a1", "v1.0.0dev2", "v1.0.0dev1"]
172
+ >>> sorted_versions = sorted(versions, key=version_to_float, reverse=True)
173
+ >>> sorted_versions == versions
174
+ True
127
175
  """
176
+ # Check for pre-release suffixes and calculate suffix modifier
177
+ # Suffixes are ordered from longest to shortest to avoid partial matches
178
+ suffix_modifiers: dict[str, int] = {
179
+ "dev": 4, # dev is lowest
180
+ "d": 4, # d (dev) is lowest
181
+ "a": 3, # alpha
182
+ "b": 2, # beta
183
+ "rc": 1, # rc is highest pre-release
184
+ "c": 1, # c (release candidate)
185
+ }
186
+ suffix_type: int = 0 # 0 = no suffix, 1-4 = rc/c, b, a, dev/d
187
+ suffix_number: int = 0
188
+
189
+ # Check for suffixes with optional numbers
190
+ for suffix, modifier in suffix_modifiers.items():
191
+ if suffix in version:
192
+ # Find the suffix position
193
+ suffix_pos: int = version.rfind(suffix)
194
+ after_suffix: str = version[suffix_pos + len(suffix):]
195
+
196
+ # Check if there's a number after the suffix
197
+ if after_suffix.isdigit():
198
+ suffix_number = int(after_suffix)
199
+ version = version[:suffix_pos]
200
+ elif after_suffix == "":
201
+ # Suffix at the end without number
202
+ version = version[:suffix_pos]
203
+ else:
204
+ # Not a valid suffix match, continue searching
205
+ continue
206
+
207
+ # Found a valid suffix, set the type and break
208
+ suffix_type = modifier
209
+ break
210
+
128
211
  # Clean the version string by keeping only the numbers and dots
129
212
  version = clean_version(version)
130
213
 
@@ -137,5 +220,15 @@ def version_to_float(version: str) -> float:
137
220
  for part in version_parts:
138
221
  total += int(part) * multiplier
139
222
  multiplier /= 1_000
223
+
224
+ # Apply pre-release modifier
225
+ # Pre-releases are represented as negative offsets from the base version
226
+ # Lower suffix_type = closer to release (rc=1 is closest, dev=4 is furthest)
227
+ # Higher suffix_number = closer to release within the same suffix type
228
+ # Formula: base_version - (suffix_type * 1000 - suffix_number) * 1e-9
229
+ # This ensures: 1.0.0 > 1.0.0rc2 > 1.0.0rc1 > 1.0.0b2 > 1.0.0a2 > 1.0.0dev2
230
+ if suffix_type > 0:
231
+ total -= (suffix_type * 1000 - suffix_number) * 1e-9
232
+
140
233
  return total
141
234
 
@@ -61,9 +61,11 @@ def version_to_float(version: str) -> float:
61
61
  ''' Converts a version string into a float for comparison purposes.
62
62
  \tThe version string is expected to follow the format of major.minor.patch.something_else....,
63
63
  \twhere each part is separated by a dot and can be extended indefinitely.
64
+ \tSupports pre-release suffixes with numbers: devN/dN (dev), aN (alpha), bN (beta), rcN/cN (release candidate).
65
+ \tOrdering: 1.0.0 > 1.0.0rc2 > 1.0.0rc1 > 1.0.0b2 > 1.0.0b1 > 1.0.0a2 > 1.0.0a1 > 1.0.0dev1
64
66
 
65
67
  \tArgs:
66
- \t\tversion (str): The version string to convert. (e.g. "v1.0.0.1.2.3")
68
+ \t\tversion (str): The version string to convert. (e.g. "v1.0.0.1.2.3", "v2.0.0b2", "v1.0.0rc1")
67
69
  \tReturns:
68
70
  \t\tfloat: The float representation of the version. (e.g. 0)
69
71
 
@@ -77,4 +79,50 @@ def version_to_float(version: str) -> float:
77
79
  \t1.0000000010020031
78
80
  \t>>> version_to_float("v2.0") > version_to_float("v1.0.0.1")
79
81
  \tTrue
82
+ \t>>> version_to_float("v2.0.0") > version_to_float("v2.0.0rc") > version_to_float("v2.0.0b") > version_to_float("v2.0.0a") > version_to_float("v2.0.0dev")
83
+ \tTrue
84
+ \t>>> version_to_float("v1.0.0b") > version_to_float("v1.0.0a")
85
+ \tTrue
86
+ \t>>> version_to_float("v1.0.0") > version_to_float("v1.0.0b")
87
+ \tTrue
88
+ \t>>> version_to_float("v3.0.0a") > version_to_float("v2.9.9")
89
+ \tTrue
90
+ \t>>> version_to_float("v1.2.3b") < version_to_float("v1.2.3")
91
+ \tTrue
92
+ \t>>> version_to_float("1.0.0") == version_to_float("v1.0.0")
93
+ \tTrue
94
+ \t>>> version_to_float("2.0.0.0.0.0.1b") > version_to_float("2.0.0.0.0.0.1a")
95
+ \tTrue
96
+ \t>>> version_to_float("2.0.0.0.0.0.1") > version_to_float("2.0.0.0.0.0.1b")
97
+ \tTrue
98
+ \t>>> version_to_float("v1.0.0rc") == version_to_float("v1.0.0c")
99
+ \tTrue
100
+ \t>>> version_to_float("v1.0.0c") > version_to_float("v1.0.0b")
101
+ \tTrue
102
+ \t>>> version_to_float("v1.0.0d") < version_to_float("v1.0.0a")
103
+ \tTrue
104
+ \t>>> version_to_float("v1.0.0dev") < version_to_float("v1.0.0a")
105
+ \tTrue
106
+ \t>>> version_to_float("v1.0.0dev") == version_to_float("v1.0.0d")
107
+ \tTrue
108
+ \t>>> version_to_float("v1.0.0rc2") > version_to_float("v1.0.0rc1")
109
+ \tTrue
110
+ \t>>> version_to_float("v1.0.0b2") > version_to_float("v1.0.0b1")
111
+ \tTrue
112
+ \t>>> version_to_float("v1.0.0a2") > version_to_float("v1.0.0a1")
113
+ \tTrue
114
+ \t>>> version_to_float("v1.0.0dev2") > version_to_float("v1.0.0dev1")
115
+ \tTrue
116
+ \t>>> version_to_float("v1.0.0") > version_to_float("v1.0.0rc2") > version_to_float("v1.0.0rc1")
117
+ \tTrue
118
+ \t>>> version_to_float("v1.0.0rc1") > version_to_float("v1.0.0b2")
119
+ \tTrue
120
+ \t>>> version_to_float("v1.0.0b1") > version_to_float("v1.0.0a2")
121
+ \tTrue
122
+ \t>>> version_to_float("v1.0.0a1") > version_to_float("v1.0.0dev2")
123
+ \tTrue
124
+ \t>>> versions = ["v1.0.0", "v1.0.0rc2", "v1.0.0rc1", "v1.0.0b2", "v1.0.0b1", "v1.0.0a2", "v1.0.0a1", "v1.0.0dev2", "v1.0.0dev1"]
125
+ \t>>> sorted_versions = sorted(versions, key=version_to_float, reverse=True)
126
+ \t>>> sorted_versions == versions
127
+ \tTrue
80
128
  \t'''
@@ -80,16 +80,22 @@ def relative_path(file_path: str, relative_to: str = "") -> str:
80
80
  return file_path or "."
81
81
 
82
82
  # JSON dump with indentation for levels
83
- def super_json_dump(data: Any, file: IO[Any]|None = None, max_level: int = 2, indent: str | int = '\t', suffix: str = "\n") -> str:
83
+ def super_json_dump(
84
+ data: Any,
85
+ file: IO[Any] | str | None = None,
86
+ max_level: int | None = 2,
87
+ indent: str | int = '\t',
88
+ suffix: str = "\n"
89
+ ) -> str:
84
90
  r""" Writes the provided data to a JSON file with a specified indentation depth.
85
91
  For instance, setting max_level to 2 will limit the indentation to 2 levels.
86
92
 
87
93
  Args:
88
- data (Any): The data to dump (usually a dict or a list)
89
- file (IO[Any]): The file to dump the data to, if None, the data is returned as a string
90
- max_level (int): The depth of indentation to stop at (-1 for infinite)
91
- indent (str | int): The indentation character (default: '\t')
92
- suffix (str): The suffix to add at the end of the string (default: '\n')
94
+ data (Any): The data to dump (usually a dict or a list)
95
+ file (IO[Any] | str): The file object or path to dump the data to
96
+ max_level (int | None): The depth of indentation to stop at (-1 for infinite), None will default to 2
97
+ indent (str | int): The indentation character (default: '\t')
98
+ suffix (str): The suffix to add at the end of the string (default: '\n')
93
99
  Returns:
94
100
  str: The content of the file in every case
95
101
 
@@ -102,9 +108,11 @@ def super_json_dump(data: Any, file: IO[Any]|None = None, max_level: int = 2, in
102
108
  >>> super_json_dump({"a": [[1,2,3]], "b": 2}, max_level = 3)
103
109
  '{\n\t"a": [\n\t\t[\n\t\t\t1,\n\t\t\t2,\n\t\t\t3\n\t\t]\n\t],\n\t"b": 2\n}\n'
104
110
  """
105
- # Normalize indentation to string
111
+ # Normalize indentation to string, and handle None values for max_level
106
112
  if isinstance(indent, int):
107
113
  indent = ' ' * indent
114
+ if max_level is None:
115
+ max_level = 2
108
116
 
109
117
  # Dump content with 2-space indent and replace it with the desired indent
110
118
  content: str = orjson.dumps(data, option=orjson.OPT_INDENT_2).decode("utf-8")
@@ -128,7 +136,11 @@ def super_json_dump(data: Any, file: IO[Any]|None = None, max_level: int = 2, in
128
136
  # Final newline and write
129
137
  content += suffix
130
138
  if file:
131
- file.write(content)
139
+ if isinstance(file, str):
140
+ with super_open(file, "w") as f:
141
+ f.write(content)
142
+ else:
143
+ file.write(content)
132
144
  return content
133
145
 
134
146
  # JSON load from file path
@@ -144,17 +156,26 @@ def super_json_load(file_path: str) -> Any:
144
156
  return orjson.loads(f.read())
145
157
 
146
158
  # CSV dump to file
147
- def super_csv_dump(data: Any, file: IO[Any] | None = None, delimiter: str = ',', has_header: bool = True, index: bool = False, *args: Any, **kwargs: Any) -> str:
148
- """ Writes data to a CSV file with customizable options
159
+ def super_csv_dump(
160
+ data: Any,
161
+ file: IO[Any] | str | None = None,
162
+ delimiter: str = ',',
163
+ has_header: bool = True,
164
+ index: bool = False,
165
+ *args: Any,
166
+ **kwargs: Any
167
+ ) -> str:
168
+ """ Writes data to a CSV file with customizable options and returns the CSV content as a string.
149
169
 
150
170
  Args:
151
- data (list[list[Any]] | list[dict[str, Any]] | pd.DataFrame | pl.DataFrame): The data to write, either a list of lists, list of dicts, pandas DataFrame, or Polars DataFrame
152
- file (IO[Any]): The file to dump the data to, if None, the data is returned as a string
153
- delimiter (str): The delimiter to use (default: ',')
154
- has_header (bool): Whether to include headers (default: True, applies to dict and DataFrame data)
155
- index (bool): Whether to include the index (default: False, only applies to pandas DataFrame)
156
- *args: Additional positional arguments to pass to the underlying CSV writer or DataFrame method
157
- **kwargs: Additional keyword arguments to pass to the underlying CSV writer or DataFrame method
171
+ data (list[list[Any]] | list[dict[str, Any]] | pd.DataFrame | pl.DataFrame):
172
+ The data to write, either a list of lists, list of dicts, pandas DataFrame, or Polars DataFrame
173
+ file (IO[Any] | str): The file object or path to dump the data to
174
+ delimiter (str): The delimiter to use (default: ',')
175
+ has_header (bool): Whether to include headers (default: True, applies to dict and DataFrame data)
176
+ index (bool): Whether to include the index (default: False, only applies to pandas DataFrame)
177
+ *args (Any): Additional positional arguments to pass to the underlying CSV writer or DataFrame method
178
+ **kwargs (Any): Additional keyword arguments to pass to the underlying CSV writer or DataFrame method
158
179
  Returns:
159
180
  str: The CSV content as a string
160
181
 
@@ -213,7 +234,11 @@ def super_csv_dump(data: Any, file: IO[Any] | None = None, delimiter: str = ',',
213
234
 
214
235
  content: str = output.getvalue()
215
236
  if file:
216
- file.write(content)
237
+ if isinstance(file, str):
238
+ with super_open(file, "w") as f:
239
+ f.write(content)
240
+ else:
241
+ file.write(content)
217
242
  output.close()
218
243
  return content
219
244
 
@@ -265,14 +290,14 @@ def super_csv_load(file_path: str, delimiter: str = ',', has_header: bool = True
265
290
  if use_polars:
266
291
  import polars as pl # type: ignore
267
292
  if not os.path.exists(file_path):
268
- return pl.DataFrame()
293
+ return pl.DataFrame() # type: ignore
269
294
  kwargs.setdefault("separator", delimiter)
270
295
  kwargs.setdefault("has_header", has_header)
271
- return pl.read_csv(file_path, *args, **kwargs)
296
+ return pl.read_csv(file_path, *args, **kwargs) # type: ignore
272
297
  else:
273
298
  import pandas as pd # type: ignore
274
299
  if not os.path.exists(file_path):
275
- return pd.DataFrame()
300
+ return pd.DataFrame() # type: ignore
276
301
  kwargs.setdefault("sep", delimiter)
277
302
  kwargs.setdefault("header", 0 if has_header else None)
278
303
  return pd.read_csv(file_path, *args, **kwargs) # type: ignore
@@ -35,16 +35,16 @@ def relative_path(file_path: str, relative_to: str = '') -> str:
35
35
  \t\t>>> relative_path("D:/some/random/path/stouputils/io.py", "D:\\\\some\\\\")
36
36
  \t\t\'random/path/stouputils/io.py\'
37
37
  \t'''
38
- def super_json_dump(data: Any, file: IO[Any] | None = None, max_level: int = 2, indent: str | int = '\t', suffix: str = '\n') -> str:
38
+ def super_json_dump(data: Any, file: IO[Any] | str | None = None, max_level: int | None = 2, indent: str | int = '\t', suffix: str = '\n') -> str:
39
39
  ''' Writes the provided data to a JSON file with a specified indentation depth.
40
40
  \tFor instance, setting max_level to 2 will limit the indentation to 2 levels.
41
41
 
42
42
  \tArgs:
43
- \t\tdata (Any): \t\t\t\tThe data to dump (usually a dict or a list)
44
- \t\tfile (IO[Any]): \t\t\tThe file to dump the data to, if None, the data is returned as a string
45
- \t\tmax_level (int):\t\t\tThe depth of indentation to stop at (-1 for infinite)
46
- \t\tindent (str | int):\t\t\tThe indentation character (default: \'\\t\')
47
- \t\tsuffix (str):\t\t\t\tThe suffix to add at the end of the string (default: \'\\n\')
43
+ \t\tdata\t\t(Any): \t\t\t\tThe data to dump (usually a dict or a list)
44
+ \t\tfile\t\t(IO[Any] | str): \tThe file object or path to dump the data to
45
+ \t\tmax_level\t(int | None):\t\tThe depth of indentation to stop at (-1 for infinite), None will default to 2
46
+ \t\tindent\t\t(str | int):\t\tThe indentation character (default: \'\\t\')
47
+ \t\tsuffix\t\t(str):\t\t\t\tThe suffix to add at the end of the string (default: \'\\n\')
48
48
  \tReturns:
49
49
  \t\tstr: The content of the file in every case
50
50
 
@@ -65,17 +65,18 @@ def super_json_load(file_path: str) -> Any:
65
65
  \tReturns:
66
66
  \t\tAny: The content of the JSON file
67
67
  \t"""
68
- def super_csv_dump(data: Any, file: IO[Any] | None = None, delimiter: str = ',', has_header: bool = True, index: bool = False, *args: Any, **kwargs: Any) -> str:
69
- ''' Writes data to a CSV file with customizable options
68
+ def super_csv_dump(data: Any, file: IO[Any] | str | None = None, delimiter: str = ',', has_header: bool = True, index: bool = False, *args: Any, **kwargs: Any) -> str:
69
+ ''' Writes data to a CSV file with customizable options and returns the CSV content as a string.
70
70
 
71
71
  \tArgs:
72
- \t\tdata (list[list[Any]] | list[dict[str, Any]] | pd.DataFrame | pl.DataFrame): The data to write, either a list of lists, list of dicts, pandas DataFrame, or Polars DataFrame
73
- \t\tfile (IO[Any]): The file to dump the data to, if None, the data is returned as a string
74
- \t\tdelimiter (str): The delimiter to use (default: \',\')
75
- \t\thas_header (bool): Whether to include headers (default: True, applies to dict and DataFrame data)
76
- \t\tindex (bool): Whether to include the index (default: False, only applies to pandas DataFrame)
77
- \t\t*args: Additional positional arguments to pass to the underlying CSV writer or DataFrame method
78
- \t\t**kwargs: Additional keyword arguments to pass to the underlying CSV writer or DataFrame method
72
+ \t\tdata\t\t(list[list[Any]] | list[dict[str, Any]] | pd.DataFrame | pl.DataFrame):
73
+ \t\t\t\t\t\tThe data to write, either a list of lists, list of dicts, pandas DataFrame, or Polars DataFrame
74
+ \t\tfile\t\t(IO[Any] | str): The file object or path to dump the data to
75
+ \t\tdelimiter\t(str): The delimiter to use (default: \',\')
76
+ \t\thas_header\t(bool): Whether to include headers (default: True, applies to dict and DataFrame data)
77
+ \t\tindex\t\t(bool): Whether to include the index (default: False, only applies to pandas DataFrame)
78
+ \t\t*args\t\t(Any): Additional positional arguments to pass to the underlying CSV writer or DataFrame method
79
+ \t\t**kwargs\t(Any): Additional keyword arguments to pass to the underlying CSV writer or DataFrame method
79
80
  \tReturns:
80
81
  \t\tstr: The CSV content as a string
81
82
 
File without changes
File without changes
File without changes
File without changes