stouputils 1.6.6__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.6 → stouputils-1.7.0}/PKG-INFO +1 -1
  2. {stouputils-1.6.6 → stouputils-1.7.0}/pyproject.toml +1 -1
  3. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/all_doctests.py +12 -4
  4. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/applications/automatic_docs.py +46 -14
  5. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/applications/automatic_docs.pyi +13 -8
  6. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/continuous_delivery/cd_utils.py +94 -1
  7. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/continuous_delivery/cd_utils.pyi +49 -1
  8. {stouputils-1.6.6 → stouputils-1.7.0}/.gitignore +0 -0
  9. {stouputils-1.6.6 → stouputils-1.7.0}/LICENSE +0 -0
  10. {stouputils-1.6.6 → stouputils-1.7.0}/README.md +0 -0
  11. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/__init__.py +0 -0
  12. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/__init__.pyi +0 -0
  13. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/__main__.py +0 -0
  14. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/all_doctests.pyi +0 -0
  15. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/applications/__init__.py +0 -0
  16. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/applications/__init__.pyi +0 -0
  17. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/applications/upscaler/__init__.py +0 -0
  18. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/applications/upscaler/__init__.pyi +0 -0
  19. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/applications/upscaler/config.py +0 -0
  20. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/applications/upscaler/config.pyi +0 -0
  21. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/applications/upscaler/image.py +0 -0
  22. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/applications/upscaler/image.pyi +0 -0
  23. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/applications/upscaler/video.py +0 -0
  24. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/applications/upscaler/video.pyi +0 -0
  25. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/archive.py +0 -0
  26. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/archive.pyi +0 -0
  27. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/backup.py +0 -0
  28. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/backup.pyi +0 -0
  29. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/collections.py +0 -0
  30. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/collections.pyi +0 -0
  31. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/continuous_delivery/__init__.py +0 -0
  32. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/continuous_delivery/__init__.pyi +0 -0
  33. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/continuous_delivery/github.py +0 -0
  34. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/continuous_delivery/github.pyi +0 -0
  35. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/continuous_delivery/pypi.py +0 -0
  36. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/continuous_delivery/pypi.pyi +0 -0
  37. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/continuous_delivery/pyproject.py +0 -0
  38. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/continuous_delivery/pyproject.pyi +0 -0
  39. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/continuous_delivery/stubs.py +0 -0
  40. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/continuous_delivery/stubs.pyi +0 -0
  41. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/ctx.py +0 -0
  42. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/ctx.pyi +0 -0
  43. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/config/get.py +0 -0
  44. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/config/set.py +0 -0
  45. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/__init__.py +0 -0
  46. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/auto_contrast.py +0 -0
  47. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/axis_flip.py +0 -0
  48. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/bias_field_correction.py +0 -0
  49. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/binary_threshold.py +0 -0
  50. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/blur.py +0 -0
  51. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/brightness.py +0 -0
  52. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/canny.py +0 -0
  53. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/clahe.py +0 -0
  54. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/common.py +0 -0
  55. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/contrast.py +0 -0
  56. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/curvature_flow_filter.py +0 -0
  57. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/denoise.py +0 -0
  58. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/histogram_equalization.py +0 -0
  59. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/invert.py +0 -0
  60. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/laplacian.py +0 -0
  61. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/median_blur.py +0 -0
  62. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/noise.py +0 -0
  63. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/normalize.py +0 -0
  64. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/random_erase.py +0 -0
  65. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/resize.py +0 -0
  66. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/rotation.py +0 -0
  67. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/salt_pepper.py +0 -0
  68. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/sharpening.py +0 -0
  69. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/shearing.py +0 -0
  70. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/threshold.py +0 -0
  71. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/translation.py +0 -0
  72. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image/zoom.py +0 -0
  73. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image_augmentation.py +0 -0
  74. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/image_preprocess.py +0 -0
  75. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/prosthesis_detection.py +0 -0
  76. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/data_processing/technique.py +0 -0
  77. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/dataset/__init__.py +0 -0
  78. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/dataset/dataset.py +0 -0
  79. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/dataset/dataset_loader.py +0 -0
  80. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/dataset/grouping_strategy.py +0 -0
  81. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/dataset/image_loader.py +0 -0
  82. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/dataset/xy_tuple.py +0 -0
  83. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/metric_dictionnary.py +0 -0
  84. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/metric_utils.py +0 -0
  85. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/mlflow_utils.py +0 -0
  86. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/abstract_model.py +0 -0
  87. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/all.py +0 -0
  88. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/base_keras.py +0 -0
  89. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras/all.py +0 -0
  90. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras/convnext.py +0 -0
  91. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras/densenet.py +0 -0
  92. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras/efficientnet.py +0 -0
  93. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras/mobilenet.py +0 -0
  94. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras/resnet.py +0 -0
  95. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras/squeezenet.py +0 -0
  96. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras/vgg.py +0 -0
  97. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras/xception.py +0 -0
  98. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/callbacks/__init__.py +0 -0
  99. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +0 -0
  100. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +0 -0
  101. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +0 -0
  102. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +0 -0
  103. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +0 -0
  104. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/losses/__init__.py +0 -0
  105. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +0 -0
  106. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/keras_utils/visualizations.py +0 -0
  107. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/model_interface.py +0 -0
  108. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/models/sandbox.py +0 -0
  109. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/range_tuple.py +0 -0
  110. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/scripts/augment_dataset.py +0 -0
  111. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/scripts/exhaustive_process.py +0 -0
  112. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/scripts/preprocess_dataset.py +0 -0
  113. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/scripts/routine.py +0 -0
  114. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/data_science/utils.py +0 -0
  115. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/decorators.py +0 -0
  116. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/decorators.pyi +0 -0
  117. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/image.py +0 -0
  118. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/image.pyi +0 -0
  119. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/installer/__init__.py +0 -0
  120. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/installer/__init__.pyi +0 -0
  121. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/installer/common.py +0 -0
  122. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/installer/common.pyi +0 -0
  123. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/installer/downloader.py +0 -0
  124. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/installer/downloader.pyi +0 -0
  125. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/installer/linux.py +0 -0
  126. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/installer/linux.pyi +0 -0
  127. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/installer/main.py +0 -0
  128. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/installer/main.pyi +0 -0
  129. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/installer/windows.py +0 -0
  130. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/installer/windows.pyi +0 -0
  131. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/io.py +0 -0
  132. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/io.pyi +0 -0
  133. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/parallel.py +0 -0
  134. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/parallel.pyi +0 -0
  135. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/print.py +0 -0
  136. {stouputils-1.6.6 → stouputils-1.7.0}/stouputils/print.pyi +0 -0
  137. {stouputils-1.6.6 → 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.6
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.6"
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'''
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes