stouputils 1.11.0__tar.gz → 1.12.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 (139) hide show
  1. {stouputils-1.11.0 → stouputils-1.12.0}/LICENSE +21 -21
  2. {stouputils-1.11.0 → stouputils-1.12.0}/PKG-INFO +1 -1
  3. {stouputils-1.11.0 → stouputils-1.12.0}/pyproject.toml +1 -1
  4. stouputils-1.12.0/stouputils/applications/automatic_docs.pyi +106 -0
  5. stouputils-1.12.0/stouputils/applications/upscaler/__init__.pyi +3 -0
  6. stouputils-1.12.0/stouputils/applications/upscaler/config.pyi +18 -0
  7. stouputils-1.12.0/stouputils/applications/upscaler/image.pyi +109 -0
  8. stouputils-1.12.0/stouputils/applications/upscaler/video.pyi +60 -0
  9. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/continuous_delivery/cd_utils.py +66 -59
  10. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/continuous_delivery/cd_utils.pyi +2 -1
  11. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/continuous_delivery/pypi.py +90 -90
  12. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/ctx.py +408 -408
  13. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/config/set.py +125 -125
  14. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +31 -31
  15. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/utils.py +285 -285
  16. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/image.py +2 -2
  17. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/image.pyi +1 -1
  18. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/installer/__init__.py +18 -18
  19. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/installer/linux.py +144 -144
  20. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/installer/main.py +223 -223
  21. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/installer/windows.py +136 -136
  22. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/io.py +8 -2
  23. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/io.pyi +6 -1
  24. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/py.typed +1 -1
  25. {stouputils-1.11.0 → stouputils-1.12.0}/.gitignore +0 -0
  26. {stouputils-1.11.0 → stouputils-1.12.0}/README.md +0 -0
  27. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/__init__.py +0 -0
  28. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/__init__.pyi +0 -0
  29. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/__main__.py +0 -0
  30. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/_deprecated.py +0 -0
  31. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/_deprecated.pyi +0 -0
  32. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/all_doctests.py +0 -0
  33. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/all_doctests.pyi +0 -0
  34. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/applications/__init__.py +0 -0
  35. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/applications/__init__.pyi +0 -0
  36. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/applications/automatic_docs.py +0 -0
  37. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/applications/upscaler/__init__.py +0 -0
  38. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/applications/upscaler/config.py +0 -0
  39. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/applications/upscaler/image.py +0 -0
  40. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/applications/upscaler/video.py +0 -0
  41. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/archive.py +0 -0
  42. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/archive.pyi +0 -0
  43. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/backup.py +0 -0
  44. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/backup.pyi +0 -0
  45. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/collections.py +0 -0
  46. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/collections.pyi +0 -0
  47. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/continuous_delivery/__init__.py +0 -0
  48. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/continuous_delivery/__init__.pyi +0 -0
  49. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/continuous_delivery/github.py +0 -0
  50. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/continuous_delivery/github.pyi +0 -0
  51. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/continuous_delivery/pypi.pyi +0 -0
  52. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/continuous_delivery/pyproject.py +0 -0
  53. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/continuous_delivery/pyproject.pyi +0 -0
  54. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/continuous_delivery/stubs.py +0 -0
  55. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/continuous_delivery/stubs.pyi +0 -0
  56. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/ctx.pyi +0 -0
  57. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/config/get.py +0 -0
  58. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/__init__.py +0 -0
  59. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/auto_contrast.py +0 -0
  60. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/axis_flip.py +0 -0
  61. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/bias_field_correction.py +0 -0
  62. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/binary_threshold.py +0 -0
  63. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/blur.py +0 -0
  64. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/brightness.py +0 -0
  65. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/canny.py +0 -0
  66. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/clahe.py +0 -0
  67. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/common.py +0 -0
  68. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/contrast.py +0 -0
  69. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/curvature_flow_filter.py +0 -0
  70. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/denoise.py +0 -0
  71. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/histogram_equalization.py +0 -0
  72. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/invert.py +0 -0
  73. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/laplacian.py +0 -0
  74. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/median_blur.py +0 -0
  75. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/noise.py +0 -0
  76. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/normalize.py +0 -0
  77. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/random_erase.py +0 -0
  78. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/resize.py +0 -0
  79. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/rotation.py +0 -0
  80. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/salt_pepper.py +0 -0
  81. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/sharpening.py +0 -0
  82. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/shearing.py +0 -0
  83. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/threshold.py +0 -0
  84. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/translation.py +0 -0
  85. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/zoom.py +0 -0
  86. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image_augmentation.py +0 -0
  87. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/image_preprocess.py +0 -0
  88. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/prosthesis_detection.py +0 -0
  89. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/data_processing/technique.py +0 -0
  90. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/dataset/__init__.py +0 -0
  91. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/dataset/dataset.py +0 -0
  92. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/dataset/dataset_loader.py +0 -0
  93. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/dataset/grouping_strategy.py +0 -0
  94. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/dataset/image_loader.py +0 -0
  95. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/dataset/xy_tuple.py +0 -0
  96. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/metric_dictionnary.py +0 -0
  97. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/metric_utils.py +0 -0
  98. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/mlflow_utils.py +0 -0
  99. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/abstract_model.py +0 -0
  100. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/all.py +0 -0
  101. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/base_keras.py +0 -0
  102. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras/all.py +0 -0
  103. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras/convnext.py +0 -0
  104. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras/densenet.py +0 -0
  105. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras/efficientnet.py +0 -0
  106. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras/mobilenet.py +0 -0
  107. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras/resnet.py +0 -0
  108. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras/squeezenet.py +0 -0
  109. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras/vgg.py +0 -0
  110. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras/xception.py +0 -0
  111. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/callbacks/__init__.py +0 -0
  112. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +0 -0
  113. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +0 -0
  114. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +0 -0
  115. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +0 -0
  116. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/losses/__init__.py +0 -0
  117. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +0 -0
  118. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/visualizations.py +0 -0
  119. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/model_interface.py +0 -0
  120. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/models/sandbox.py +0 -0
  121. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/range_tuple.py +0 -0
  122. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/scripts/augment_dataset.py +0 -0
  123. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/scripts/exhaustive_process.py +0 -0
  124. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/scripts/preprocess_dataset.py +0 -0
  125. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/data_science/scripts/routine.py +0 -0
  126. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/decorators.py +0 -0
  127. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/decorators.pyi +0 -0
  128. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/installer/__init__.pyi +0 -0
  129. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/installer/common.py +0 -0
  130. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/installer/common.pyi +0 -0
  131. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/installer/downloader.py +0 -0
  132. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/installer/downloader.pyi +0 -0
  133. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/installer/linux.pyi +0 -0
  134. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/installer/main.pyi +0 -0
  135. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/installer/windows.pyi +0 -0
  136. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/parallel.py +0 -0
  137. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/parallel.pyi +0 -0
  138. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/print.py +0 -0
  139. {stouputils-1.11.0 → stouputils-1.12.0}/stouputils/print.pyi +0 -0
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2024 Alexandre Collignon
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Alexandre Collignon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stouputils
3
- Version: 1.11.0
3
+ Version: 1.12.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
@@ -7,7 +7,7 @@ build-backend = "hatchling.build"
7
7
 
8
8
  [project]
9
9
  name = "stouputils"
10
- version = "1.11.0"
10
+ version = "1.12.0"
11
11
  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."
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.12"
@@ -0,0 +1,106 @@
1
+ from ..continuous_delivery import version_to_float as version_to_float
2
+ from ..decorators import LogLevels as LogLevels, handle_error as handle_error, simple_cache as simple_cache
3
+ from ..io import clean_path as clean_path, json_dump as json_dump, super_open as super_open
4
+ from ..print import info as info
5
+ from collections.abc import Callable as Callable
6
+
7
+ REQUIREMENTS: list[str]
8
+
9
+ def check_dependencies(html_theme: str) -> None:
10
+ ''' Check for each requirement if it is installed.
11
+
12
+ \tArgs:
13
+ \t\thtml_theme (str): HTML theme to use for the documentation, to check if it is installed (e.g. "breeze", "pydata_sphinx_theme", "furo", etc.)
14
+ \t'''
15
+ def get_sphinx_conf_content(project: str, project_dir: str, author: str, current_version: str, copyright: str, html_logo: str, html_favicon: str, html_theme: str = 'breeze', github_user: str = '', github_repo: str = '', version_list: list[str] | None = None, skip_undocumented: bool = True) -> str:
16
+ """ Get the content of the Sphinx configuration file.
17
+
18
+ \tArgs:
19
+ \t\tproject (str): Name of the project
20
+ \t\tproject_dir (str): Path to the project directory
21
+ \t\tauthor (str): Author of the project
22
+ \t\tcurrent_version (str): Current version
23
+ \t\tcopyright (str): Copyright information
24
+ \t\thtml_logo (str): URL to the logo
25
+ \t\thtml_favicon (str): URL to the favicon
26
+ \t\tgithub_user (str): GitHub username
27
+ \t\tgithub_repo (str): GitHub repository name
28
+ \t\tversion_list (list[str] | None): List of versions. Defaults to None
29
+ \t\tskip_undocumented (bool): Whether to skip undocumented members. Defaults to True
30
+
31
+ \tReturns:
32
+ \t\tstr: Content of the Sphinx configuration file
33
+ \t"""
34
+ def get_versions_from_github(github_user: str, github_repo: str, recent_minor_versions: int = 2) -> list[str]:
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.
38
+
39
+ \tArgs:
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).
43
+
44
+ \tReturns:
45
+ \t\tlist[str]: List of versions, with 'latest' as first element
46
+ \t"""
47
+ def markdown_to_rst(markdown_content: str) -> str:
48
+ """ Convert markdown content to RST format.
49
+
50
+ \tArgs:
51
+ \t\tmarkdown_content (str): Markdown content
52
+
53
+ \tReturns:
54
+ \t\tstr: RST content
55
+ \t"""
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:
57
+ """ Generate index.rst from README.md content.
58
+
59
+ \tArgs:
60
+ \t\treadme_path (str): Path to the README.md file
61
+ \t\tindex_path (str): Path where index.rst should be created
62
+ \t\tproject (str): Name of the project
63
+ \t\tgithub_user (str): GitHub username
64
+ \t\tgithub_repo (str): GitHub repository name
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
67
+ \t"""
68
+ def generate_documentation(source_dir: str, modules_dir: str, project_dir: str, build_dir: str) -> None:
69
+ """ Generate documentation using Sphinx.
70
+
71
+ \tArgs:
72
+ \t\tsource_dir (str): Source directory
73
+ \t\tmodules_dir (str): Modules directory
74
+ \t\tproject_dir (str): Project directory
75
+ \t\tbuild_dir (str): Build directory
76
+ \t"""
77
+ def generate_redirect_html(filepath: str) -> None:
78
+ """ Generate HTML content for redirect page.
79
+
80
+ \tArgs:
81
+ \t\tfilepath (str): Path to the file where the HTML content should be written
82
+ \t"""
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:
84
+ ''' Update the Sphinx documentation.
85
+
86
+ \tArgs:
87
+ \t\troot_path (str): Root path of the project
88
+ \t\tproject (str): Name of the project
89
+ \t\tproject_dir (str): Path to the project directory (to be used with generate_docs_function)
90
+ \t\tauthor (str): Author of the project
91
+ \t\tcopyright (str): Copyright information
92
+ \t\thtml_logo (str): URL to the logo
93
+ \t\thtml_favicon (str): URL to the favicon
94
+ \t\thtml_theme (str): Theme to use for the documentation. Defaults to "breeze"
95
+ \t\tgithub_user (str): GitHub username
96
+ \t\tgithub_repo (str): GitHub repository name
97
+ \t\tversion (str | None): Version to build documentation for (e.g. "1.0.0", defaults to "latest")
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
100
+
101
+ \t\tget_versions_function (Callable[[str, str, int], list[str]]): Function to get versions from GitHub
102
+ \t\tgenerate_index_function (Callable[..., None]): Function to generate index.rst
103
+ \t\tgenerate_docs_function (Callable[..., None]): Function to generate documentation
104
+ \t\tgenerate_redirect_function (Callable[[str], None]): Function to create redirect file
105
+ \t\tget_conf_content_function (Callable[..., str]): Function to get Sphinx conf.py content
106
+ \t'''
@@ -0,0 +1,3 @@
1
+ from .config import *
2
+ from .image import *
3
+ from .video import *
@@ -0,0 +1,18 @@
1
+ WAIFU2X_NCNN_VULKAN_RELEASES: dict[str, str]
2
+ FFMPEG_RELEASES: dict[str, str]
3
+ YOUTUBE_BITRATE_RECOMMENDATIONS: dict[str, dict[str, dict[int, int]]]
4
+
5
+ class Config:
6
+ """ Configuration class for the upscaler. """
7
+ JPG_QUALITY: int
8
+ VIDEO_FINAL_BITRATE: int
9
+ FFMPEG_EXECUTABLE: str
10
+ FFMPEG_ARGS: tuple[str, ...]
11
+ FFPROBE_EXECUTABLE: str
12
+ FFMPEG_CHECK_HELP_TEXT: str
13
+ UPSCALER_EXECUTABLE: str
14
+ UPSCALER_ARGS: tuple[str, ...]
15
+ UPSCALER_EXECUTABLE_HELP_TEXT: str
16
+ SLIGHTLY_FASTER_MODE: bool
17
+ upscaler_executable_checked: bool
18
+ ffmpeg_executable_checked: bool
@@ -0,0 +1,109 @@
1
+ from ...installer import check_executable as check_executable
2
+ from ...io import clean_path as clean_path
3
+ from ...parallel import multithreading as multithreading
4
+ from ...print import colored_for_loop as colored_for_loop, debug as debug, info as info
5
+ from .config import Config as Config, WAIFU2X_NCNN_VULKAN_RELEASES as WAIFU2X_NCNN_VULKAN_RELEASES
6
+ from tempfile import TemporaryDirectory
7
+
8
+ def convert_frame(frame_path: str, delete_png: bool = True) -> None:
9
+ ''' Convert a PNG frame to JPG format to take less space.
10
+
11
+ \tArgs:
12
+ \t\tframe_path (str): Path to the PNG frame to convert.
13
+ \t\tdelete_png (bool): Whether to delete the original PNG file after conversion.
14
+
15
+ \tReturns:
16
+ \t\tNone: This function doesn\'t return anything.
17
+
18
+ \tExample:
19
+ \t\t.. code-block:: python
20
+
21
+ \t\t\t> convert_frame("input.png", delete_png=True)
22
+ \t\t\t> # input.png will be converted to input.jpg and the original file will be deleted
23
+
24
+ \t\t\t> convert_frame("input.png", delete_png=False)
25
+ \t\t\t> # input.png will be converted to input.jpg and the original file will be kept
26
+ \t'''
27
+ def get_all_files(folder: str, suffix: str | tuple[str, ...] = '') -> list[str]:
28
+ ''' Get all files paths in a folder, with a specific suffix if provided.
29
+
30
+ \tArgs:
31
+ \t\tfolder (str): Path to the folder containing the files.
32
+ \t\tsuffix (str | tuple[str, ...]): Suffix of the files to get (e.g. ".png", ".jpg", etc.).
33
+
34
+ \tReturns:
35
+ \t\tlist[str]: List of all files paths in the folder.
36
+
37
+ \tExample:
38
+ \t\t>>> files: list[str] = get_all_files("some_folder", ".png")
39
+ \t\t>>> len(files)
40
+ \t\t0
41
+ \t'''
42
+ def create_temp_dir_for_not_upscaled(input_path: str, output_path: str) -> TemporaryDirectory[str] | None:
43
+ """ Creates a temporary directory containing only images that haven't been upscaled yet.
44
+
45
+ Args:
46
+ input_path (str): Path to the folder containing input images.
47
+ output_path (str): Path to the folder where upscaled images are saved.
48
+
49
+ Returns:
50
+ TemporaryDirectory[str] | None: A temporary directory object if there are images to process,
51
+ None if all images are already upscaled.
52
+ """
53
+ def check_upscaler_executable() -> None: ...
54
+ def upscale(input_path: str, output_path: str, upscale_ratio: int) -> None:
55
+ ''' Upscale an input image (or a directory of images) with the upscaler executable.
56
+
57
+ \tArgs:
58
+ \t\tinput_path (str): Path to the image to upscale (or a directory).
59
+ \t\toutput_path (str): Path to the output image (or a directory).
60
+ \t\tupscale_ratio (int): Upscaling ratio.
61
+
62
+ \tExample:
63
+ \t\t.. code-block:: python
64
+
65
+ \t\t\t> upscale("folder", "folder", 2)
66
+ \t\t\tTraceback (most recent call last):
67
+ \t\t\t\t...
68
+ \t\t\tAssertionError: Input and output paths cannot be the same, got \'folder\'
69
+
70
+ \t\t\t> upscale("stouputils", "stouputils/output.jpg", 2)
71
+ \t\t\tTraceback (most recent call last):
72
+ \t\t\t\t...
73
+ \t\t\tAssertionError: If input is a directory, output must be a directory too, got \'stouputils/output.jpg\'
74
+
75
+
76
+ \t\t\t> upscale("input.jpg", "output.jpg", 2)
77
+ \t\t\t> # The input.jpg will be upscaled to output.jpg with a ratio of 2
78
+
79
+ \t\t\t> upscale("input_folder", "output_folder", 2)
80
+ \t\t\t> # The input_folder will be upscaled to output_folder with a ratio of 2
81
+ \t'''
82
+ def upscale_images(images: list[str], output_folder: str, upscale_ratio: int, desc: str = 'Upscaling images') -> None:
83
+ """ Upscale multiple images from a list.
84
+
85
+ \tArgs:
86
+ \t\timages (list[str]): List of paths to the images to upscale.
87
+ \t\toutput_folder (str): Path to the output folder where the upscaled images will be saved.
88
+ \t\tupscale_ratio (int): Upscaling ratio.
89
+ \t\tdesc (str): Description of the function execution displayed in the progress bar.
90
+ \t\t\tNo progress bar will be displayed if desc is empty.
91
+
92
+ \tReturns:
93
+ \t\tNone: This function doesn't return anything.
94
+ \t"""
95
+ def upscale_folder(input_folder: str, output_folder: str, upscale_ratio: int, slightly_faster_mode: bool = True, desc: str = 'Upscaling folder') -> None:
96
+ """ Upscale all images in a folder.
97
+
98
+ \tArgs:
99
+ \t\tinput_folder (str): Path to the input folder containing the images to upscale.
100
+ \t\toutput_folder (str): Path to the output folder where the upscaled images will be saved.
101
+ \t\tupscale_ratio (int): Upscaling ratio.
102
+ \t\tslightly_faster_mode (bool): Whether to use the slightly faster mode (no progress bar),
103
+ \t\t\tone call to the upscaler executable.
104
+ \t\tdesc (str): Description of the function execution displayed in the progress bar.
105
+ \t\t\tNo progress bar will be displayed if desc is empty.
106
+
107
+ \tReturns:
108
+ \t\tNone: This function doesn't return anything.
109
+ \t"""
@@ -0,0 +1,60 @@
1
+ from ...installer import check_executable as check_executable
2
+ from ...io import clean_path as clean_path
3
+ from ...parallel import multithreading as multithreading
4
+ from ...print import colored_for_loop as colored_for_loop, debug as debug, error as error, info as info, warning as warning
5
+ from .config import Config as Config, FFMPEG_RELEASES as FFMPEG_RELEASES, YOUTUBE_BITRATE_RECOMMENDATIONS as YOUTUBE_BITRATE_RECOMMENDATIONS
6
+ from .image import convert_frame as convert_frame, get_all_files as get_all_files, upscale_folder as upscale_folder
7
+ from typing import Literal
8
+
9
+ def get_recommended_bitrate(resolution: tuple[int, int], frame_rate: int = 60, upload_type: Literal['SDR', 'HDR'] = 'SDR') -> int:
10
+ ''' Get the recommended bitrate (in kbps) for the output video based on the video resolution.
11
+
12
+ \tArgs:
13
+ \t\tresolution (tuple[int, int]): Video resolution (width, height).
14
+ \t\tframe_rate (int): Frame rate of the video, default is 60.
15
+ \t\tupload_type (Literal["SDR","HDR"]): Upload type from which the recommendation is made, default is "SDR".
16
+
17
+ \tReturns:
18
+ \t\tint: The recommended bitrate for the output video (in kbps)
19
+
20
+ \tSource: https://support.google.com/youtube/answer/1722171?hl=en#zippy=%2Cbitrate
21
+
22
+ \tExamples:
23
+ \t\t>>> # Valid examples
24
+ \t\t>>> get_recommended_bitrate((3840, 2160), 60, "SDR")
25
+ \t\t68000
26
+ \t\t>>> get_recommended_bitrate((1920, 1080), 60, "HDR")
27
+ \t\t15000
28
+ \t\t>>> get_recommended_bitrate((1920, 1080), 60, "SDR")
29
+ \t\t12000
30
+ \t\t>>> get_recommended_bitrate((1920, 1080), 30, "SDR")
31
+ \t\t8000
32
+
33
+ \t\t>>> # Invalid examples
34
+ \t\t>>> get_recommended_bitrate((1920, 1080), 60, "Ratio")
35
+ \t\tTraceback (most recent call last):
36
+ \t\t\t...
37
+ \t\tAssertionError: Invalid upload type: \'Ratio\'
38
+ \t\t>>> get_recommended_bitrate("1920x1080", 60, "SDR")
39
+ \t\tTraceback (most recent call last):
40
+ \t\t\t...
41
+ \t\tAssertionError: Invalid resolution: 1920x1080, must be a tuple of two integers
42
+ \t\t>>> get_recommended_bitrate((1920, 1080), -10, "SDR")
43
+ \t\tTraceback (most recent call last):
44
+ \t\t\t...
45
+ \t\tAssertionError: Invalid frame rate: -10, must be a positive integer
46
+ \t'''
47
+ def check_ffmpeg_executable() -> None: ...
48
+ def upscale_video(video_file: str, input_folder: str, progress_folder: str, output_folder: str) -> None:
49
+ """ Handles a video file. """
50
+ def video_upscaler_cli(input_folder: str, progress_folder: str, output_folder: str) -> None:
51
+ """ Upscales videos from an input folder and saves them to an output folder.
52
+
53
+ \tUses intermediate folders for extracted and upscaled frames within the progress folder.
54
+ \t**Handles resuming partially processed videos.**
55
+
56
+ \tArgs:
57
+ \t\tinput_folder (str): Path to the folder containing input videos.
58
+ \t\tprogress_folder (str): Path to the folder for storing intermediate files (frames).
59
+ \t\toutput_folder (str): Path to the folder where upscaled videos will be saved.
60
+ \t"""
@@ -106,7 +106,7 @@ def clean_version(version: str, keep: str = "") -> str:
106
106
  return "".join(c for c in version if c in "0123456789." + keep)
107
107
 
108
108
  # Convert a version string to a float
109
- def version_to_float(version: str) -> float:
109
+ def version_to_float(version: str, error: bool = True) -> Any:
110
110
  """ Converts a version string into a float for comparison purposes.
111
111
  The version string is expected to follow the format of major.minor.patch.something_else....,
112
112
  where each part is separated by a dot and can be extended indefinitely.
@@ -115,6 +115,7 @@ def version_to_float(version: str) -> float:
115
115
 
116
116
  Args:
117
117
  version (str): The version string to convert. (e.g. "v1.0.0.1.2.3", "v2.0.0b2", "v1.0.0rc1")
118
+ error (bool): Return None on error instead of raising an exception
118
119
  Returns:
119
120
  float: The float representation of the version. (e.g. 0)
120
121
 
@@ -175,62 +176,68 @@ def version_to_float(version: str) -> float:
175
176
  >>> sorted_versions == versions
176
177
  True
177
178
  """
178
- # Check for pre-release suffixes and calculate suffix modifier
179
- # Suffixes are ordered from longest to shortest to avoid partial matches
180
- suffix_modifiers: dict[str, int] = {
181
- "dev": 4, # dev is lowest
182
- "d": 4, # d (dev) is lowest
183
- "a": 3, # alpha
184
- "b": 2, # beta
185
- "rc": 1, # rc is highest pre-release
186
- "c": 1, # c (release candidate)
187
- }
188
- suffix_type: int = 0 # 0 = no suffix, 1-4 = rc/c, b, a, dev/d
189
- suffix_number: int = 0
190
-
191
- # Check for suffixes with optional numbers
192
- for suffix, modifier in suffix_modifiers.items():
193
- if suffix in version:
194
- # Find the suffix position
195
- suffix_pos: int = version.rfind(suffix)
196
- after_suffix: str = version[suffix_pos + len(suffix):]
197
-
198
- # Check if there's a number after the suffix
199
- if after_suffix.isdigit():
200
- suffix_number = int(after_suffix)
201
- version = version[:suffix_pos]
202
- elif after_suffix == "":
203
- # Suffix at the end without number
204
- version = version[:suffix_pos]
205
- else:
206
- # Not a valid suffix match, continue searching
207
- continue
208
-
209
- # Found a valid suffix, set the type and break
210
- suffix_type = modifier
211
- break
212
-
213
- # Clean the version string by keeping only the numbers and dots
214
- version = clean_version(version)
215
-
216
- # Split the version string into parts
217
- version_parts: list[str] = version.split(".")
218
- total: float = 0.0
219
- multiplier: float = 1.0
220
-
221
- # Iterate over the parts and add lesser and lesser weight to each part
222
- for part in version_parts:
223
- total += int(part) * multiplier
224
- multiplier /= 1_000
225
-
226
- # Apply pre-release modifier
227
- # Pre-releases are represented as negative offsets from the base version
228
- # Lower suffix_type = closer to release (rc=1 is closest, dev=4 is furthest)
229
- # Higher suffix_number = closer to release within the same suffix type
230
- # Formula: base_version - (suffix_type * 1000 - suffix_number) * 1e-9
231
- # This ensures: 1.0.0 > 1.0.0rc2 > 1.0.0rc1 > 1.0.0b2 > 1.0.0a2 > 1.0.0dev2
232
- if suffix_type > 0:
233
- total -= (suffix_type * 1000 - suffix_number) * 1e-9
234
-
235
- return total
179
+ try:
180
+ # Check for pre-release suffixes and calculate suffix modifier
181
+ # Suffixes are ordered from longest to shortest to avoid partial matches
182
+ suffix_modifiers: dict[str, int] = {
183
+ "dev": 4, # dev is lowest
184
+ "d": 4, # d (dev) is lowest
185
+ "a": 3, # alpha
186
+ "b": 2, # beta
187
+ "rc": 1, # rc is highest pre-release
188
+ "c": 1, # c (release candidate)
189
+ }
190
+ suffix_type: int = 0 # 0 = no suffix, 1-4 = rc/c, b, a, dev/d
191
+ suffix_number: int = 0
192
+
193
+ # Check for suffixes with optional numbers
194
+ for suffix, modifier in suffix_modifiers.items():
195
+ if suffix in version:
196
+ # Find the suffix position
197
+ suffix_pos: int = version.rfind(suffix)
198
+ after_suffix: str = version[suffix_pos + len(suffix):]
199
+
200
+ # Check if there's a number after the suffix
201
+ if after_suffix.isdigit():
202
+ suffix_number = int(after_suffix)
203
+ version = version[:suffix_pos]
204
+ elif after_suffix == "":
205
+ # Suffix at the end without number
206
+ version = version[:suffix_pos]
207
+ else:
208
+ # Not a valid suffix match, continue searching
209
+ continue
210
+
211
+ # Found a valid suffix, set the type and break
212
+ suffix_type = modifier
213
+ break
214
+
215
+ # Clean the version string by keeping only the numbers and dots
216
+ version = clean_version(version)
217
+
218
+ # Split the version string into parts
219
+ version_parts: list[str] = version.split(".")
220
+ total: float = 0.0
221
+ multiplier: float = 1.0
222
+
223
+ # Iterate over the parts and add lesser and lesser weight to each part
224
+ for part in version_parts:
225
+ total += int(part) * multiplier
226
+ multiplier /= 1_000
227
+
228
+ # Apply pre-release modifier
229
+ # Pre-releases are represented as negative offsets from the base version
230
+ # Lower suffix_type = closer to release (rc=1 is closest, dev=4 is furthest)
231
+ # Higher suffix_number = closer to release within the same suffix type
232
+ # Formula: base_version - (suffix_type * 1000 - suffix_number) * 1e-9
233
+ # This ensures: 1.0.0 > 1.0.0rc2 > 1.0.0rc1 > 1.0.0b2 > 1.0.0a2 > 1.0.0dev2
234
+ if suffix_type > 0:
235
+ total -= (suffix_type * 1000 - suffix_number) * 1e-9
236
+
237
+ return total
238
+ except Exception as e:
239
+ if error:
240
+ raise ValueError(f"Invalid version string: '{version}'") from e
241
+ else:
242
+ return None # type: ignore
236
243
 
@@ -57,7 +57,7 @@ def clean_version(version: str, keep: str = '') -> str:
57
57
  \t>>> clean_version("v1.2.3b", keep="ab")
58
58
  \t\'1.2.3b\'
59
59
  \t'''
60
- def version_to_float(version: str) -> float:
60
+ def version_to_float(version: str, error: bool = True) -> Any:
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.
@@ -66,6 +66,7 @@ def version_to_float(version: str) -> float:
66
66
 
67
67
  \tArgs:
68
68
  \t\tversion (str): The version string to convert. (e.g. "v1.0.0.1.2.3", "v2.0.0b2", "v1.0.0rc1")
69
+ \t\terror (bool): Return None on error instead of raising an exception
69
70
  \tReturns:
70
71
  \t\tfloat: The float representation of the version. (e.g. 0)
71
72