stouputils 1.10.4__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 (141) hide show
  1. {stouputils-1.10.4 → stouputils-1.12.0}/PKG-INFO +9 -10
  2. stouputils-1.12.0/pyproject.toml +106 -0
  3. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/applications/automatic_docs.py +1 -1
  4. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/collections.py +6 -3
  5. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/collections.pyi +2 -2
  6. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/continuous_delivery/cd_utils.py +68 -61
  7. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/continuous_delivery/cd_utils.pyi +2 -1
  8. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/continuous_delivery/pyproject.py +43 -20
  9. stouputils-1.12.0/stouputils/continuous_delivery/pyproject.pyi +67 -0
  10. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/continuous_delivery/stubs.py +4 -1
  11. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/ctx.py +1 -1
  12. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/ctx.pyi +1 -1
  13. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/image.py +4 -4
  14. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/image.pyi +3 -3
  15. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/io.py +13 -21
  16. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/io.pyi +6 -1
  17. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/parallel.py +7 -7
  18. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/parallel.pyi +7 -7
  19. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/print.py +2 -2
  20. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/print.pyi +2 -2
  21. stouputils-1.10.4/pyproject.toml +0 -89
  22. stouputils-1.10.4/stouputils/continuous_delivery/pyproject.pyi +0 -47
  23. {stouputils-1.10.4 → stouputils-1.12.0}/.gitignore +0 -0
  24. {stouputils-1.10.4 → stouputils-1.12.0}/LICENSE +0 -0
  25. {stouputils-1.10.4 → stouputils-1.12.0}/README.md +0 -0
  26. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/__init__.py +0 -0
  27. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/__init__.pyi +0 -0
  28. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/__main__.py +0 -0
  29. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/_deprecated.py +0 -0
  30. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/_deprecated.pyi +0 -0
  31. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/all_doctests.py +0 -0
  32. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/all_doctests.pyi +0 -0
  33. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/applications/__init__.py +0 -0
  34. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/applications/__init__.pyi +0 -0
  35. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/applications/automatic_docs.pyi +0 -0
  36. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/applications/upscaler/__init__.py +0 -0
  37. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/applications/upscaler/__init__.pyi +0 -0
  38. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/applications/upscaler/config.py +0 -0
  39. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/applications/upscaler/config.pyi +0 -0
  40. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/applications/upscaler/image.py +0 -0
  41. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/applications/upscaler/image.pyi +0 -0
  42. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/applications/upscaler/video.py +0 -0
  43. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/applications/upscaler/video.pyi +0 -0
  44. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/archive.py +0 -0
  45. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/archive.pyi +0 -0
  46. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/backup.py +0 -0
  47. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/backup.pyi +0 -0
  48. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/continuous_delivery/__init__.py +0 -0
  49. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/continuous_delivery/__init__.pyi +0 -0
  50. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/continuous_delivery/github.py +0 -0
  51. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/continuous_delivery/github.pyi +0 -0
  52. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/continuous_delivery/pypi.py +0 -0
  53. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/continuous_delivery/pypi.pyi +0 -0
  54. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/continuous_delivery/stubs.pyi +0 -0
  55. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/config/get.py +0 -0
  56. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/config/set.py +0 -0
  57. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/__init__.py +0 -0
  58. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/auto_contrast.py +0 -0
  59. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/axis_flip.py +0 -0
  60. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/bias_field_correction.py +0 -0
  61. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/binary_threshold.py +0 -0
  62. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/blur.py +0 -0
  63. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/brightness.py +0 -0
  64. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/canny.py +0 -0
  65. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/clahe.py +0 -0
  66. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/common.py +0 -0
  67. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/contrast.py +0 -0
  68. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/curvature_flow_filter.py +0 -0
  69. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/denoise.py +0 -0
  70. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/histogram_equalization.py +0 -0
  71. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/invert.py +0 -0
  72. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/laplacian.py +0 -0
  73. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/median_blur.py +0 -0
  74. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/noise.py +0 -0
  75. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/normalize.py +0 -0
  76. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/random_erase.py +0 -0
  77. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/resize.py +0 -0
  78. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/rotation.py +0 -0
  79. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/salt_pepper.py +0 -0
  80. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/sharpening.py +0 -0
  81. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/shearing.py +0 -0
  82. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/threshold.py +0 -0
  83. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/translation.py +0 -0
  84. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image/zoom.py +0 -0
  85. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image_augmentation.py +0 -0
  86. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/image_preprocess.py +0 -0
  87. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/prosthesis_detection.py +0 -0
  88. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/data_processing/technique.py +0 -0
  89. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/dataset/__init__.py +0 -0
  90. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/dataset/dataset.py +0 -0
  91. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/dataset/dataset_loader.py +0 -0
  92. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/dataset/grouping_strategy.py +0 -0
  93. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/dataset/image_loader.py +0 -0
  94. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/dataset/xy_tuple.py +0 -0
  95. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/metric_dictionnary.py +0 -0
  96. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/metric_utils.py +0 -0
  97. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/mlflow_utils.py +0 -0
  98. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/abstract_model.py +0 -0
  99. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/all.py +0 -0
  100. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/base_keras.py +0 -0
  101. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras/all.py +0 -0
  102. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras/convnext.py +0 -0
  103. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras/densenet.py +0 -0
  104. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras/efficientnet.py +0 -0
  105. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras/mobilenet.py +0 -0
  106. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras/resnet.py +0 -0
  107. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras/squeezenet.py +0 -0
  108. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras/vgg.py +0 -0
  109. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras/xception.py +0 -0
  110. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/callbacks/__init__.py +0 -0
  111. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +0 -0
  112. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +0 -0
  113. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +0 -0
  114. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +0 -0
  115. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +0 -0
  116. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/losses/__init__.py +0 -0
  117. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +0 -0
  118. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/keras_utils/visualizations.py +0 -0
  119. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/model_interface.py +0 -0
  120. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/models/sandbox.py +0 -0
  121. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/range_tuple.py +0 -0
  122. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/scripts/augment_dataset.py +0 -0
  123. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/scripts/exhaustive_process.py +0 -0
  124. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/scripts/preprocess_dataset.py +0 -0
  125. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/scripts/routine.py +0 -0
  126. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/data_science/utils.py +0 -0
  127. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/decorators.py +0 -0
  128. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/decorators.pyi +0 -0
  129. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/installer/__init__.py +0 -0
  130. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/installer/__init__.pyi +0 -0
  131. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/installer/common.py +0 -0
  132. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/installer/common.pyi +0 -0
  133. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/installer/downloader.py +0 -0
  134. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/installer/downloader.pyi +0 -0
  135. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/installer/linux.py +0 -0
  136. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/installer/linux.pyi +0 -0
  137. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/installer/main.py +0 -0
  138. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/installer/main.pyi +0 -0
  139. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/installer/windows.py +0 -0
  140. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/installer/windows.pyi +0 -0
  141. {stouputils-1.10.4 → stouputils-1.12.0}/stouputils/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stouputils
3
- Version: 1.10.4
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
@@ -9,22 +9,20 @@ License-File: LICENSE
9
9
  Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
11
  Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
12
15
  Requires-Python: >=3.12
13
16
  Requires-Dist: argcomplete>=3.0.0
14
- Requires-Dist: mypy>=1.18.2
15
- Requires-Dist: numpy>=2.4.0
16
- Requires-Dist: opencv-python>=4.0.0
17
- Requires-Dist: orjson>=3.0.0
17
+ Requires-Dist: msgspec[toml,yaml]>=0.20.0
18
+ Requires-Dist: numpy>=2.3.0
18
19
  Requires-Dist: pillow>=10.0.0
19
- Requires-Dist: pyfastcopy>=1.0.0
20
- Requires-Dist: python-box[all]>=7.0.0
21
- Requires-Dist: pyyaml>=6.0.0
20
+ Requires-Dist: python-box>=7.0.0
22
21
  Requires-Dist: requests>=2.20.0
23
- Requires-Dist: toml>=0.10.0
24
22
  Requires-Dist: tqdm>=4.0.0
25
- Requires-Dist: zarr>=2.18.3
26
23
  Provides-Extra: data-science
27
24
  Requires-Dist: mlflow; extra == 'data-science'
25
+ Requires-Dist: opencv-python; extra == 'data-science'
28
26
  Requires-Dist: pywavelets; extra == 'data-science'
29
27
  Requires-Dist: scikit-image; extra == 'data-science'
30
28
  Requires-Dist: scikit-learn; extra == 'data-science'
@@ -32,6 +30,7 @@ Requires-Dist: simpleitk; extra == 'data-science'
32
30
  Requires-Dist: tensorflow; extra == 'data-science'
33
31
  Provides-Extra: docs
34
32
  Requires-Dist: m2r2; extra == 'docs'
33
+ Requires-Dist: mypy; extra == 'docs'
35
34
  Requires-Dist: myst-parser; extra == 'docs'
36
35
  Requires-Dist: pydata-sphinx-theme; extra == 'docs'
37
36
  Requires-Dist: sphinx-breeze-theme; extra == 'docs'
@@ -0,0 +1,106 @@
1
+
2
+ [build-system]
3
+ requires = [
4
+ "hatchling",
5
+ ]
6
+ build-backend = "hatchling.build"
7
+
8
+ [project]
9
+ name = "stouputils"
10
+ version = "1.12.0"
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
+ readme = "README.md"
13
+ requires-python = ">=3.12"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Programming Language :: Python :: 3.13",
18
+ "Programming Language :: Python :: 3.14",
19
+ "License :: OSI Approved :: MIT License",
20
+ "Operating System :: OS Independent",
21
+ ]
22
+ dependencies = [
23
+ "tqdm>=4.0.0",
24
+ "requests>=2.20.0",
25
+ "msgspec[toml,yaml]>=0.20.0",
26
+ "pillow>=10.0.0",
27
+ "numpy>=2.3.0",
28
+ "python-box>=7.0.0",
29
+ "argcomplete>=3.0.0",
30
+ ]
31
+ authors = [
32
+ { name = "Stoupy51", email = "stoupy51@gmail.com" },
33
+ ]
34
+
35
+ [project.optional-dependencies]
36
+ docs = [
37
+ "mypy",
38
+ "m2r2",
39
+ "myst_parser",
40
+ "sphinx_copybutton",
41
+ "sphinx_design",
42
+ "sphinx_treeview",
43
+ "sphinx_breeze_theme",
44
+ "pydata_sphinx_theme",
45
+ ]
46
+ data_science = [
47
+ "opencv-python",
48
+ "scikit-image",
49
+ "simpleitk",
50
+ "mlflow",
51
+ "tensorflow",
52
+ "scikit-learn",
53
+ "PyWavelets",
54
+ ]
55
+
56
+ [project.urls]
57
+ Homepage = "https://github.com/Stoupy51/stouputils"
58
+ Issues = "https://github.com/Stoupy51/stouputils/issues"
59
+
60
+ [project.scripts]
61
+ stouputils = "stouputils.__main__:main"
62
+
63
+ [tool.pyright]
64
+ typeCheckingMode = "strict"
65
+
66
+ [tool.ruff]
67
+ exclude = [
68
+ ".git",
69
+ ".ruff_cache",
70
+ ".venv",
71
+ ".vscode",
72
+ ".cursor",
73
+ "build",
74
+ "dist",
75
+ "*.pyi",
76
+ ]
77
+ line-length = 200
78
+
79
+ [tool.ruff.lint]
80
+ select = [
81
+ "E",
82
+ "W",
83
+ "F",
84
+ "I",
85
+ "N",
86
+ "UP",
87
+ "B",
88
+ "C4",
89
+ "T20",
90
+ "RUF",
91
+ ]
92
+ ignore = [
93
+ "T201",
94
+ "W191",
95
+ "N803",
96
+ "N806",
97
+ "F403",
98
+ "F405",
99
+ ]
100
+
101
+ [tool.hatch.build]
102
+ include = [
103
+ "stouputils",
104
+ ]
105
+ ignore-vcs = true
106
+
@@ -566,7 +566,7 @@ a:hover {
566
566
  background-clip: text;
567
567
  -webkit-background-clip: text;
568
568
  -webkit-text-fill-color: transparent;
569
- animation: shine-slide 2s linear infinite;
569
+ animation: shine-slide 3.5s linear infinite;
570
570
  }
571
571
  """)
572
572
 
@@ -29,7 +29,7 @@ if TYPE_CHECKING:
29
29
  T = TypeVar("T")
30
30
 
31
31
  # Functions
32
- def unique_list(list_to_clean: Iterable[T], method: Literal["id", "hash", "str"] = "str") -> list[T]:
32
+ def unique_list[T](list_to_clean: Iterable[T], method: Literal["id", "hash", "str"] = "str") -> list[T]:
33
33
  """ Remove duplicates from the list while keeping the order using ids (default) or hash or str
34
34
 
35
35
  Args:
@@ -77,7 +77,7 @@ def unique_list(list_to_clean: Iterable[T], method: Literal["id", "hash", "str"]
77
77
  # Return the cleaned list
78
78
  return result
79
79
 
80
- def sort_dict_keys(dictionary: dict[T, Any], order: list[T], reverse: bool = False) -> dict[T, Any]:
80
+ def sort_dict_keys[T](dictionary: dict[T, Any], order: list[T], reverse: bool = False) -> dict[T, Any]:
81
81
  """ Sort dictionary keys using a given order list (reverse optional)
82
82
 
83
83
  Args:
@@ -185,7 +185,10 @@ def array_to_disk(
185
185
  )
186
186
 
187
187
  # Imports
188
- import zarr # pyright: ignore[reportMissingTypeStubs]
188
+ try:
189
+ import zarr # pyright: ignore[reportMissingTypeStubs]
190
+ except ImportError as e:
191
+ raise ImportError("zarr is required for array_to_disk function. Please install it via 'pip install zarr'.") from e
189
192
 
190
193
  # If data is already a zarr.Array and more_data is present, just append and return
191
194
  if isinstance(data, zarr.Array) and more_data is not None:
@@ -6,7 +6,7 @@ from typing import Any, Literal, TypeVar
6
6
 
7
7
  T = TypeVar('T')
8
8
 
9
- def unique_list(list_to_clean: Iterable[T], method: Literal['id', 'hash', 'str'] = 'str') -> list[T]:
9
+ def unique_list[T](list_to_clean: Iterable[T], method: Literal['id', 'hash', 'str'] = 'str') -> list[T]:
10
10
  ''' Remove duplicates from the list while keeping the order using ids (default) or hash or str
11
11
 
12
12
  \tArgs:
@@ -31,7 +31,7 @@ def unique_list(list_to_clean: Iterable[T], method: Literal['id', 'hash', 'str']
31
31
  \t\t>>> unique_list([s1, s2, s1, s1, s3, s2, s3], method="str")
32
32
  \t\t[{1, 2, 3}, {2, 3, 4}]
33
33
  \t'''
34
- def sort_dict_keys(dictionary: dict[T, Any], order: list[T], reverse: bool = False) -> dict[T, Any]:
34
+ def sort_dict_keys[T](dictionary: dict[T, Any], order: list[T], reverse: bool = False) -> dict[T, Any]:
35
35
  ''' Sort dictionary keys using a given order list (reverse optional)
36
36
 
37
37
  \tArgs:
@@ -63,9 +63,9 @@ def load_credentials(credentials_path: str) -> dict[str, Any]:
63
63
 
64
64
  # Else, load the file if it's a YAML file
65
65
  elif credentials_path.endswith((".yml", ".yaml")):
66
- import yaml
66
+ from msgspec import yaml
67
67
  with open(credentials_path) as f:
68
- return yaml.safe_load(f)
68
+ return yaml.decode(f.read())
69
69
 
70
70
  # Else, raise an error
71
71
  else:
@@ -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
 
@@ -25,12 +25,17 @@ def read_pyproject(pyproject_path: str) -> dict[str, Any]:
25
25
 
26
26
  Args:
27
27
  pyproject_path: Path to the pyproject.toml file.
28
-
29
28
  Returns:
30
29
  dict[str, Any]: The content of the pyproject.toml file.
30
+ Example:
31
+ >>> content = read_pyproject("pyproject.toml")
32
+ >>> "." in content["project"]["version"]
33
+ True
31
34
  """
32
- import toml
33
- return toml.load(pyproject_path)
35
+ from msgspec import toml
36
+ with open(pyproject_path) as file:
37
+ content = file.read()
38
+ return toml.decode(content)
34
39
 
35
40
 
36
41
  def format_toml_lists(content: str) -> str:
@@ -38,9 +43,18 @@ def format_toml_lists(content: str) -> str:
38
43
 
39
44
  Args:
40
45
  content (str): The content of the pyproject.toml file.
41
-
42
46
  Returns:
43
47
  str: The formatted content with properly indented lists.
48
+ Example:
49
+ >>> toml_content = '''[project]
50
+ ... dependencies = [ "tqdm>=4.0.0", "requests>=2.20.0", "pyyaml>=6.0.0", ]'''
51
+ >>> format_toml_lists(toml_content).replace("\\t", " ") == '''[project]
52
+ ... dependencies = [
53
+ ... "tqdm>=4.0.0",
54
+ ... "requests>=2.20.0",
55
+ ... "pyyaml>=6.0.0",
56
+ ... ]'''
57
+ True
44
58
  """
45
59
  # Split the content into individual lines for processing
46
60
  lines: list[str] = content.split("\n")
@@ -78,14 +92,20 @@ def format_toml_lists(content: str) -> str:
78
92
  return "\n".join(formatted_lines)
79
93
 
80
94
 
81
- def write_pyproject(pyproject_path: str, pyproject_content: dict[str, Any]) -> None:
82
- """ Write to the pyproject.toml file with properly indented lists. """
83
- import toml
84
- content: str = "\n" + toml.dumps(pyproject_content) + "\n"
85
- content = format_toml_lists(content) # Apply formatting
95
+ def write_pyproject(path: str, content: dict[str, Any]) -> None:
96
+ """ Write to the pyproject.toml file with properly indented lists.
97
+
98
+ Args:
99
+ path: Path to the pyproject.toml file.
100
+ content: Content to write to the pyproject.toml file.
101
+ """
102
+ from msgspec.toml import _import_tomli_w # pyright: ignore[reportPrivateUsage]
103
+ toml = _import_tomli_w()
104
+ string: str = "\n" + toml.dumps(content) + "\n"
105
+ string = format_toml_lists(string) # Apply formatting
86
106
 
87
- with super_open(pyproject_path, "w") as file:
88
- file.write(content)
107
+ with super_open(path, "w") as file:
108
+ file.write(string)
89
109
 
90
110
 
91
111
  def increment_version_from_input(version: str) -> str:
@@ -93,32 +113,35 @@ def increment_version_from_input(version: str) -> str:
93
113
 
94
114
  Args:
95
115
  version: The version to increment. (ex: "0.1.0")
96
-
97
116
  Returns:
98
117
  str: The incremented version. (ex: "0.1.1")
118
+ Example:
119
+ >>> increment_version_from_input("0.1.0")
120
+ '0.1.1'
121
+ >>> increment_version_from_input("1.2.9")
122
+ '1.2.10'
99
123
  """
100
124
  version_parts: list[str] = version.split(".")
101
125
  version_parts[-1] = str(int(version_parts[-1]) + 1)
102
126
  return ".".join(version_parts)
103
127
 
104
- def increment_version_from_pyproject(pyproject_path: str) -> None:
128
+ def increment_version_from_pyproject(path: str) -> None:
105
129
  """ Increment the version in the pyproject.toml file.
106
130
 
107
131
  Args:
108
- pyproject_path: Path to the pyproject.toml file.
132
+ path: Path to the pyproject.toml file.
109
133
  """
110
- pyproject_content: dict[str, Any] = read_pyproject(pyproject_path)
134
+ pyproject_content: dict[str, Any] = read_pyproject(path)
111
135
  pyproject_content["project"]["version"] = increment_version_from_input(pyproject_content["project"]["version"])
112
- write_pyproject(pyproject_path, pyproject_content)
136
+ write_pyproject(path, pyproject_content)
113
137
 
114
- def get_version_from_pyproject(pyproject_path: str) -> str:
138
+ def get_version_from_pyproject(path: str) -> str:
115
139
  """ Get the version from the pyproject.toml file.
116
140
 
117
141
  Args:
118
- pyproject_path: Path to the pyproject.toml file.
119
-
142
+ path: Path to the pyproject.toml file.
120
143
  Returns:
121
144
  str: The version. (ex: "0.1.0")
122
145
  """
123
- return read_pyproject(pyproject_path)["project"]["version"]
146
+ return read_pyproject(path)["project"]["version"]
124
147
 
@@ -0,0 +1,67 @@
1
+ from ..io import super_open as super_open
2
+ from typing import Any
3
+
4
+ def read_pyproject(pyproject_path: str) -> dict[str, Any]:
5
+ ''' Read the pyproject.toml file.
6
+
7
+ \tArgs:
8
+ \t\tpyproject_path: Path to the pyproject.toml file.
9
+ \tReturns:
10
+ \t\tdict[str, Any]: The content of the pyproject.toml file.
11
+ \tExample:
12
+ \t\t>>> content = read_pyproject("pyproject.toml")
13
+ \t\t>>> "." in content["project"]["version"]
14
+ \t\tTrue
15
+ \t'''
16
+ def format_toml_lists(content: str) -> str:
17
+ ''' Format TOML lists with indentation.
18
+
19
+ \tArgs:
20
+ \t\tcontent (str): The content of the pyproject.toml file.
21
+ \tReturns:
22
+ \t\tstr: The formatted content with properly indented lists.
23
+ \tExample:
24
+ \t\t>>> toml_content = \'\'\'[project]
25
+ \t\t... dependencies = [ "tqdm>=4.0.0", "requests>=2.20.0", "pyyaml>=6.0.0", ]\'\'\'
26
+ \t\t>>> format_toml_lists(toml_content).replace("\\t", " ") == \'\'\'[project]
27
+ \t\t... dependencies = [
28
+ \t\t... "tqdm>=4.0.0",
29
+ \t\t... "requests>=2.20.0",
30
+ \t\t... "pyyaml>=6.0.0",
31
+ \t\t... ]\'\'\'
32
+ \t\tTrue
33
+ \t'''
34
+ def write_pyproject(path: str, content: dict[str, Any]) -> None:
35
+ """ Write to the pyproject.toml file with properly indented lists.
36
+
37
+ \tArgs:
38
+ \t\tpath: Path to the pyproject.toml file.
39
+ \t\tcontent: Content to write to the pyproject.toml file.
40
+ \t"""
41
+ def increment_version_from_input(version: str) -> str:
42
+ ''' Increment the version.
43
+
44
+ \tArgs:
45
+ \t\tversion: The version to increment. (ex: "0.1.0")
46
+ \tReturns:
47
+ \t\tstr: The incremented version. (ex: "0.1.1")
48
+ \tExample:
49
+ \t\t>>> increment_version_from_input("0.1.0")
50
+ \t\t\'0.1.1\'
51
+ \t\t>>> increment_version_from_input("1.2.9")
52
+ \t\t\'1.2.10\'
53
+ \t'''
54
+ def increment_version_from_pyproject(path: str) -> None:
55
+ """ Increment the version in the pyproject.toml file.
56
+
57
+ \tArgs:
58
+ \t\tpath: Path to the pyproject.toml file.
59
+ \t"""
60
+ def get_version_from_pyproject(path: str) -> str:
61
+ ''' Get the version from the pyproject.toml file.
62
+
63
+ \tArgs:
64
+ \t\tpath: Path to the pyproject.toml file.
65
+ \tReturns:
66
+ \t\tstr: The version. (ex: "0.1.0")
67
+ \t'''
@@ -26,7 +26,10 @@ def generate_stubs(
26
26
  Returns:
27
27
  int: Return code of the os.system call.
28
28
  """
29
- from mypy.stubgen import main as stubgen_main
29
+ try:
30
+ from mypy.stubgen import main as stubgen_main
31
+ except ImportError as e:
32
+ raise ImportError("mypy is required for array_to_disk function. Please install it via 'pip install mypy'.") from e
30
33
  try:
31
34
  stubgen_main(["-p", package_name, *extra_args.split()])
32
35
  return 0
@@ -29,7 +29,7 @@ from .print import TeeMultiOutput, debug
29
29
  T = TypeVar("T")
30
30
 
31
31
  # Abstract base class for context managers supporting both sync and async usage
32
- class AbstractBothContextManager(AbstractContextManager[T], AbstractAsyncContextManager[T]):
32
+ class AbstractBothContextManager[T](AbstractContextManager[T], AbstractAsyncContextManager[T]):
33
33
  """ Abstract base class for context managers that support both synchronous and asynchronous usage. """
34
34
  pass
35
35
 
@@ -7,7 +7,7 @@ from typing import Any, IO, TextIO, TypeVar
7
7
 
8
8
  T = TypeVar('T')
9
9
 
10
- class AbstractBothContextManager(AbstractContextManager[T], AbstractAsyncContextManager[T], metaclass=abc.ABCMeta):
10
+ class AbstractBothContextManager[T](AbstractContextManager[T], AbstractAsyncContextManager[T], metaclass=abc.ABCMeta):
11
11
  """ Abstract base class for context managers that support both synchronous and asynchronous usage. """
12
12
 
13
13
  class LogToFile(AbstractBothContextManager['LogToFile']):
@@ -25,7 +25,7 @@ if TYPE_CHECKING:
25
25
  PIL_Image_or_NDArray = TypeVar("PIL_Image_or_NDArray", bound="Image.Image | NDArray[np.number]")
26
26
 
27
27
  # Functions
28
- def image_resize(
28
+ def image_resize[PIL_Image_or_NDArray](
29
29
  image: PIL_Image_or_NDArray,
30
30
  max_result_size: int,
31
31
  resampling: "Image.Resampling | None" = None,
@@ -83,7 +83,7 @@ def image_resize(
83
83
  original_was_pil: bool = isinstance(image, Image.Image)
84
84
 
85
85
  # Convert numpy array to PIL Image if needed
86
- if isinstance(image, np.ndarray):
86
+ if not original_was_pil:
87
87
  image = Image.fromarray(image)
88
88
 
89
89
  if keep_aspect_ratio:
@@ -121,7 +121,7 @@ def image_resize(
121
121
  return new_image
122
122
 
123
123
 
124
- def auto_crop(
124
+ def auto_crop[PIL_Image_or_NDArray](
125
125
  image: PIL_Image_or_NDArray,
126
126
  mask: "NDArray[np.bool_] | None" = None,
127
127
  threshold: int | float | Callable[["NDArray[np.number]"], int | float] | None = None,
@@ -135,7 +135,7 @@ def auto_crop(
135
135
 
136
136
  Args:
137
137
  image (Image.Image | NDArray): The image to crop.
138
- mask (NDArray[np.bool_] | None): Optional binary mask indicating regions to keep.
138
+ mask (NDArray[bool] | None): Optional binary mask indicating regions to keep.
139
139
  threshold (int | float | Callable): Threshold value or function (default: np.min).
140
140
  return_type (type | str): Type of the return value (Image.Image, NDArray[np.number], or "same" to match input type).
141
141
  contiguous (bool): If True (default), crop to bounding box. If False, remove entire rows/columns with no content.
@@ -8,7 +8,7 @@ from typing import Any, TypeVar
8
8
 
9
9
  PIL_Image_or_NDArray = TypeVar('PIL_Image_or_NDArray', bound='Image.Image | NDArray[np.number]')
10
10
 
11
- def image_resize(image: PIL_Image_or_NDArray, max_result_size: int, resampling: Image.Resampling | None = None, min_or_max: Callable[[int, int], int] = ..., return_type: type[PIL_Image_or_NDArray] | str = 'same', keep_aspect_ratio: bool = True) -> Any:
11
+ def image_resize[PIL_Image_or_NDArray](image: PIL_Image_or_NDArray, max_result_size: int, resampling: Image.Resampling | None = None, min_or_max: Callable[[int, int], int] = ..., return_type: type[PIL_Image_or_NDArray] | str = 'same', keep_aspect_ratio: bool = True) -> Any:
12
12
  ''' Resize an image while preserving its aspect ratio by default.
13
13
  \tScales the image so that its largest dimension equals max_result_size.
14
14
 
@@ -47,7 +47,7 @@ def image_resize(image: PIL_Image_or_NDArray, max_result_size: int, resampling:
47
47
  \t\t>>> image_resize(pil_image, 50, resampling=Image.Resampling.NEAREST).size
48
48
  \t\t(50, 25)
49
49
  \t'''
50
- def auto_crop(image: PIL_Image_or_NDArray, mask: NDArray[np.bool_] | None = None, threshold: int | float | Callable[[NDArray[np.number]], int | float] | None = None, return_type: type[PIL_Image_or_NDArray] | str = 'same', contiguous: bool = True) -> Any:
50
+ def auto_crop[PIL_Image_or_NDArray](image: PIL_Image_or_NDArray, mask: NDArray[np.bool_] | None = None, threshold: int | float | Callable[[NDArray[np.number]], int | float] | None = None, return_type: type[PIL_Image_or_NDArray] | str = 'same', contiguous: bool = True) -> Any:
51
51
  ''' Automatically crop an image to remove zero or uniform regions.
52
52
 
53
53
  \tThis function crops the image to keep only the region where pixels are non-zero
@@ -55,7 +55,7 @@ def auto_crop(image: PIL_Image_or_NDArray, mask: NDArray[np.bool_] | None = None
55
55
 
56
56
  \tArgs:
57
57
  \t\timage (Image.Image | NDArray):\t The image to crop.
58
- \t\tmask (NDArray[np.bool_] | None): Optional binary mask indicating regions to keep.
58
+ \t\tmask (NDArray[bool] | None): Optional binary mask indicating regions to keep.
59
59
  \t\tthreshold (int | float | Callable): Threshold value or function (default: np.min).
60
60
  \t\treturn_type (type | str): Type of the return value (Image.Image, NDArray[np.number], or "same" to match input type).
61
61
  \t\tcontiguous (bool): If True (default), crop to bounding box. If False, remove entire rows/columns with no content.