stouputils 1.14.0__py3-none-any.whl → 1.14.1__py3-none-any.whl

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 (108) hide show
  1. stouputils/__init__.pyi +15 -0
  2. stouputils/_deprecated.pyi +12 -0
  3. stouputils/all_doctests.pyi +46 -0
  4. stouputils/applications/__init__.pyi +2 -0
  5. stouputils/applications/automatic_docs.py +3 -0
  6. stouputils/applications/automatic_docs.pyi +106 -0
  7. stouputils/applications/upscaler/__init__.pyi +3 -0
  8. stouputils/applications/upscaler/config.pyi +18 -0
  9. stouputils/applications/upscaler/image.pyi +109 -0
  10. stouputils/applications/upscaler/video.pyi +60 -0
  11. stouputils/archive.pyi +67 -0
  12. stouputils/backup.pyi +109 -0
  13. stouputils/collections.pyi +86 -0
  14. stouputils/continuous_delivery/__init__.pyi +5 -0
  15. stouputils/continuous_delivery/cd_utils.pyi +129 -0
  16. stouputils/continuous_delivery/github.pyi +162 -0
  17. stouputils/continuous_delivery/pypi.pyi +52 -0
  18. stouputils/continuous_delivery/pyproject.pyi +67 -0
  19. stouputils/continuous_delivery/stubs.pyi +39 -0
  20. stouputils/ctx.pyi +211 -0
  21. stouputils/data_science/config/get.py +51 -51
  22. stouputils/data_science/data_processing/image/__init__.py +66 -66
  23. stouputils/data_science/data_processing/image/auto_contrast.py +79 -79
  24. stouputils/data_science/data_processing/image/axis_flip.py +58 -58
  25. stouputils/data_science/data_processing/image/bias_field_correction.py +74 -74
  26. stouputils/data_science/data_processing/image/binary_threshold.py +73 -73
  27. stouputils/data_science/data_processing/image/blur.py +59 -59
  28. stouputils/data_science/data_processing/image/brightness.py +54 -54
  29. stouputils/data_science/data_processing/image/canny.py +110 -110
  30. stouputils/data_science/data_processing/image/clahe.py +92 -92
  31. stouputils/data_science/data_processing/image/common.py +30 -30
  32. stouputils/data_science/data_processing/image/contrast.py +53 -53
  33. stouputils/data_science/data_processing/image/curvature_flow_filter.py +74 -74
  34. stouputils/data_science/data_processing/image/denoise.py +378 -378
  35. stouputils/data_science/data_processing/image/histogram_equalization.py +123 -123
  36. stouputils/data_science/data_processing/image/invert.py +64 -64
  37. stouputils/data_science/data_processing/image/laplacian.py +60 -60
  38. stouputils/data_science/data_processing/image/median_blur.py +52 -52
  39. stouputils/data_science/data_processing/image/noise.py +59 -59
  40. stouputils/data_science/data_processing/image/normalize.py +65 -65
  41. stouputils/data_science/data_processing/image/random_erase.py +66 -66
  42. stouputils/data_science/data_processing/image/resize.py +69 -69
  43. stouputils/data_science/data_processing/image/rotation.py +80 -80
  44. stouputils/data_science/data_processing/image/salt_pepper.py +68 -68
  45. stouputils/data_science/data_processing/image/sharpening.py +55 -55
  46. stouputils/data_science/data_processing/image/shearing.py +64 -64
  47. stouputils/data_science/data_processing/image/threshold.py +64 -64
  48. stouputils/data_science/data_processing/image/translation.py +71 -71
  49. stouputils/data_science/data_processing/image/zoom.py +83 -83
  50. stouputils/data_science/data_processing/image_augmentation.py +118 -118
  51. stouputils/data_science/data_processing/image_preprocess.py +183 -183
  52. stouputils/data_science/data_processing/prosthesis_detection.py +359 -359
  53. stouputils/data_science/data_processing/technique.py +481 -481
  54. stouputils/data_science/dataset/__init__.py +45 -45
  55. stouputils/data_science/dataset/dataset.py +292 -292
  56. stouputils/data_science/dataset/dataset_loader.py +135 -135
  57. stouputils/data_science/dataset/grouping_strategy.py +296 -296
  58. stouputils/data_science/dataset/image_loader.py +100 -100
  59. stouputils/data_science/dataset/xy_tuple.py +696 -696
  60. stouputils/data_science/metric_dictionnary.py +106 -106
  61. stouputils/data_science/mlflow_utils.py +206 -206
  62. stouputils/data_science/models/abstract_model.py +149 -149
  63. stouputils/data_science/models/all.py +85 -85
  64. stouputils/data_science/models/keras/all.py +38 -38
  65. stouputils/data_science/models/keras/convnext.py +62 -62
  66. stouputils/data_science/models/keras/densenet.py +50 -50
  67. stouputils/data_science/models/keras/efficientnet.py +60 -60
  68. stouputils/data_science/models/keras/mobilenet.py +56 -56
  69. stouputils/data_science/models/keras/resnet.py +52 -52
  70. stouputils/data_science/models/keras/squeezenet.py +233 -233
  71. stouputils/data_science/models/keras/vgg.py +42 -42
  72. stouputils/data_science/models/keras/xception.py +38 -38
  73. stouputils/data_science/models/keras_utils/callbacks/__init__.py +20 -20
  74. stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +219 -219
  75. stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +148 -148
  76. stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +31 -31
  77. stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +249 -249
  78. stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +66 -66
  79. stouputils/data_science/models/keras_utils/losses/__init__.py +12 -12
  80. stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +56 -56
  81. stouputils/data_science/models/keras_utils/visualizations.py +416 -416
  82. stouputils/data_science/models/sandbox.py +116 -116
  83. stouputils/data_science/range_tuple.py +234 -234
  84. stouputils/data_science/utils.py +285 -285
  85. stouputils/decorators.pyi +242 -0
  86. stouputils/image.pyi +172 -0
  87. stouputils/installer/__init__.py +18 -18
  88. stouputils/installer/__init__.pyi +5 -0
  89. stouputils/installer/common.pyi +39 -0
  90. stouputils/installer/downloader.pyi +24 -0
  91. stouputils/installer/linux.py +144 -144
  92. stouputils/installer/linux.pyi +39 -0
  93. stouputils/installer/main.py +223 -223
  94. stouputils/installer/main.pyi +57 -0
  95. stouputils/installer/windows.py +136 -136
  96. stouputils/installer/windows.pyi +31 -0
  97. stouputils/io.pyi +213 -0
  98. stouputils/parallel.py +13 -10
  99. stouputils/parallel.pyi +211 -0
  100. stouputils/print.pyi +136 -0
  101. stouputils/py.typed +1 -1
  102. stouputils/stouputils/parallel.pyi +4 -4
  103. stouputils/version_pkg.pyi +15 -0
  104. {stouputils-1.14.0.dist-info → stouputils-1.14.1.dist-info}/METADATA +1 -1
  105. stouputils-1.14.1.dist-info/RECORD +171 -0
  106. stouputils-1.14.0.dist-info/RECORD +0 -140
  107. {stouputils-1.14.0.dist-info → stouputils-1.14.1.dist-info}/WHEEL +0 -0
  108. {stouputils-1.14.0.dist-info → stouputils-1.14.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,5 @@
1
+ from .cd_utils import *
2
+ from .github import *
3
+ from .pypi import *
4
+ from .pyproject import *
5
+ from .stubs import *
@@ -0,0 +1,129 @@
1
+ import requests
2
+ from ..decorators import handle_error as handle_error
3
+ from ..io import clean_path as clean_path, json_load as json_load
4
+ from ..print import warning as warning
5
+ from typing import Any
6
+
7
+ def load_credentials(credentials_path: str) -> dict[str, Any]:
8
+ ''' Load credentials from a JSON or YAML file into a dictionary.
9
+
10
+ \tLoads credentials from either a JSON or YAML file and returns them as a dictionary.
11
+ \tThe file must contain the required credentials in the appropriate format.
12
+
13
+ \tArgs:
14
+ \t\tcredentials_path (str): Path to the credentials file (.json or .yml)
15
+ \tReturns:
16
+ \t\tdict[str, Any]: Dictionary containing the credentials
17
+
18
+ \tExample JSON format:
19
+
20
+ \t.. code-block:: json
21
+
22
+ \t\t{
23
+ \t\t\t"github": {
24
+ \t\t\t\t"username": "Stoupy51",
25
+ \t\t\t\t"api_key": "ghp_XXXXXXXXXXXXXXXXXXXXXXXXXX"
26
+ \t\t\t}
27
+ \t\t}
28
+
29
+ \tExample YAML format:
30
+
31
+ \t.. code-block:: yaml
32
+
33
+ \t\tgithub:
34
+ \t\t\tusername: "Stoupy51"
35
+ \t\t\tapi_key: "ghp_XXXXXXXXXXXXXXXXXXXXXXXXXX"
36
+ \t'''
37
+ def handle_response(response: requests.Response, error_message: str) -> None:
38
+ """ Handle a response from the API by raising an error if the response is not successful (status code not in 200-299).
39
+
40
+ \tArgs:
41
+ \t\tresponse\t\t(requests.Response): The response from the API
42
+ \t\terror_message\t(str): The error message to raise if the response is not successful
43
+ \t"""
44
+ def clean_version(version: str, keep: str = '') -> str:
45
+ ''' Clean a version string
46
+
47
+ \tArgs:
48
+ \t\tversion\t(str): The version string to clean
49
+ \t\tkeep\t(str): The characters to keep in the version string
50
+ \tReturns:
51
+ \t\tstr: The cleaned version string
52
+
53
+ \t>>> clean_version("v1.e0.zfezf0.1.2.3zefz")
54
+ \t\'1.0.0.1.2.3\'
55
+ \t>>> clean_version("v1.e0.zfezf0.1.2.3zefz", keep="v")
56
+ \t\'v1.0.0.1.2.3\'
57
+ \t>>> clean_version("v1.2.3b", keep="ab")
58
+ \t\'1.2.3b\'
59
+ \t'''
60
+ def version_to_float(version: str, error: bool = True) -> Any:
61
+ ''' Converts a version string into a float for comparison purposes.
62
+ \tThe version string is expected to follow the format of major.minor.patch.something_else....,
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
66
+
67
+ \tArgs:
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
70
+ \tReturns:
71
+ \t\tfloat: The float representation of the version. (e.g. 0)
72
+
73
+ \t>>> version_to_float("v1.0.0")
74
+ \t1.0
75
+ \t>>> version_to_float("v1.0.0.1")
76
+ \t1.000000001
77
+ \t>>> version_to_float("v2.3.7")
78
+ \t2.003007
79
+ \t>>> version_to_float("v1.0.0.1.2.3")
80
+ \t1.0000000010020031
81
+ \t>>> version_to_float("v2.0") > version_to_float("v1.0.0.1")
82
+ \tTrue
83
+ \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")
84
+ \tTrue
85
+ \t>>> version_to_float("v1.0.0b") > version_to_float("v1.0.0a")
86
+ \tTrue
87
+ \t>>> version_to_float("v1.0.0") > version_to_float("v1.0.0b")
88
+ \tTrue
89
+ \t>>> version_to_float("v3.0.0a") > version_to_float("v2.9.9")
90
+ \tTrue
91
+ \t>>> version_to_float("v1.2.3b") < version_to_float("v1.2.3")
92
+ \tTrue
93
+ \t>>> version_to_float("1.0.0") == version_to_float("v1.0.0")
94
+ \tTrue
95
+ \t>>> version_to_float("2.0.0.0.0.0.1b") > version_to_float("2.0.0.0.0.0.1a")
96
+ \tTrue
97
+ \t>>> version_to_float("2.0.0.0.0.0.1") > version_to_float("2.0.0.0.0.0.1b")
98
+ \tTrue
99
+ \t>>> version_to_float("v1.0.0rc") == version_to_float("v1.0.0c")
100
+ \tTrue
101
+ \t>>> version_to_float("v1.0.0c") > version_to_float("v1.0.0b")
102
+ \tTrue
103
+ \t>>> version_to_float("v1.0.0d") < version_to_float("v1.0.0a")
104
+ \tTrue
105
+ \t>>> version_to_float("v1.0.0dev") < version_to_float("v1.0.0a")
106
+ \tTrue
107
+ \t>>> version_to_float("v1.0.0dev") == version_to_float("v1.0.0d")
108
+ \tTrue
109
+ \t>>> version_to_float("v1.0.0rc2") > version_to_float("v1.0.0rc1")
110
+ \tTrue
111
+ \t>>> version_to_float("v1.0.0b2") > version_to_float("v1.0.0b1")
112
+ \tTrue
113
+ \t>>> version_to_float("v1.0.0a2") > version_to_float("v1.0.0a1")
114
+ \tTrue
115
+ \t>>> version_to_float("v1.0.0dev2") > version_to_float("v1.0.0dev1")
116
+ \tTrue
117
+ \t>>> version_to_float("v1.0.0") > version_to_float("v1.0.0rc2") > version_to_float("v1.0.0rc1")
118
+ \tTrue
119
+ \t>>> version_to_float("v1.0.0rc1") > version_to_float("v1.0.0b2")
120
+ \tTrue
121
+ \t>>> version_to_float("v1.0.0b1") > version_to_float("v1.0.0a2")
122
+ \tTrue
123
+ \t>>> version_to_float("v1.0.0a1") > version_to_float("v1.0.0dev2")
124
+ \tTrue
125
+ \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"]
126
+ \t>>> sorted_versions = sorted(versions, key=version_to_float, reverse=True)
127
+ \t>>> sorted_versions == versions
128
+ \tTrue
129
+ \t'''
@@ -0,0 +1,162 @@
1
+ from ..decorators import handle_error as handle_error, measure_time as measure_time
2
+ from ..io import clean_path as clean_path
3
+ from ..print import info as info, progress as progress, warning as warning
4
+ from .cd_utils import clean_version as clean_version, handle_response as handle_response, version_to_float as version_to_float
5
+ from typing import Any
6
+
7
+ GITHUB_API_URL: str
8
+ PROJECT_ENDPOINT: str
9
+ COMMIT_TYPES: dict[str, str]
10
+
11
+ def validate_credentials(credentials: dict[str, dict[str, str]]) -> tuple[str, dict[str, str]]:
12
+ """ Get and validate GitHub credentials
13
+
14
+ \tArgs:
15
+ \t\tcredentials (dict[str, dict[str, str]]):\tCredentials for the GitHub API
16
+ \tReturns:
17
+ \t\ttuple[str, dict[str, str]]:
18
+ \t\t\tstr:\t\t\tOwner (the username of the account to use)
19
+
20
+ \t\t\tdict[str, str]:\tHeaders (for the requests to the GitHub API)
21
+ \t"""
22
+ def validate_config(github_config: dict[str, Any]) -> tuple[str, str, str, list[str]]:
23
+ """ Validate GitHub configuration
24
+
25
+ \tArgs:
26
+ \t\tgithub_config (dict[str, str]):\tConfiguration for the GitHub project
27
+ \tReturns:
28
+ \t\ttuple[str, str, str, list[str]]:
29
+ \t\t\tstr: Project name on GitHub
30
+
31
+ \t\t\tstr: Version of the project
32
+
33
+ \t\t\tstr: Build folder path containing zip files to upload to the release
34
+
35
+ \t\t\tlist[str]: List of zip files to upload to the release
36
+ \t"""
37
+ def handle_existing_tag(owner: str, project_name: str, version: str, headers: dict[str, str]) -> bool:
38
+ """ Check if tag exists and handle deletion if needed
39
+
40
+ \tArgs:
41
+ \t\towner\t\t\t(str):\t\t\t\tGitHub username
42
+ \t\tproject_name\t(str):\t\t\t\tName of the GitHub repository
43
+ \t\tversion\t\t\t(str):\t\t\t\tVersion to check for existing tag
44
+ \t\theaders\t\t\t(dict[str, str]):\tHeaders for GitHub API requests
45
+ \tReturns:
46
+ \t\tbool: True if the tag was deleted or if it was not found, False otherwise
47
+ \t"""
48
+ def delete_existing_release(owner: str, project_name: str, version: str, headers: dict[str, str]) -> None:
49
+ """ Delete existing release for a version
50
+
51
+ \tArgs:
52
+ \t\towner\t\t\t(str):\t\t\t\tGitHub username
53
+ \t\tproject_name\t(str):\t\t\t\tName of the GitHub repository
54
+ \t\tversion\t\t\t(str):\t\t\t\tVersion of the release to delete
55
+ \t\theaders\t\t\t(dict[str, str]):\tHeaders for GitHub API requests
56
+ \t"""
57
+ def delete_existing_tag(tag_url: str, headers: dict[str, str]) -> None:
58
+ """ Delete existing tag
59
+
60
+ \tArgs:
61
+ \t\ttag_url\t(str):\t\t\t\tURL of the tag to delete
62
+ \t\theaders\t(dict[str, str]):\tHeaders for GitHub API requests
63
+ \t"""
64
+ def get_latest_tag(owner: str, project_name: str, version: str, headers: dict[str, str]) -> tuple[str, str] | tuple[None, None]:
65
+ """ Get latest tag information
66
+
67
+ \tArgs:
68
+ \t\towner\t\t\t(str):\t\t\t\tGitHub username
69
+ \t\tproject_name\t(str):\t\t\t\tName of the GitHub repository
70
+ \t\tversion\t\t\t(str):\t\t\t\tVersion to remove from the list of tags
71
+ \t\theaders\t\t\t(dict[str, str]):\tHeaders for GitHub API requests
72
+ \tReturns:
73
+ \t\tstr|None: SHA of the latest tag commit, None if no tags exist
74
+ \t\tstr|None: Version number of the latest tag, None if no tags exist
75
+ \t"""
76
+ def get_commits_since_tag(owner: str, project_name: str, latest_tag_sha: str | None, headers: dict[str, str]) -> list[dict[str, Any]]:
77
+ """ Get commits since last tag
78
+
79
+ \tArgs:
80
+ \t\towner\t\t\t(str):\t\t\t\tGitHub username
81
+ \t\tproject_name\t(str):\t\t\t\tName of the GitHub repository
82
+ \t\tlatest_tag_sha\t(str|None):\t\t\tSHA of the latest tag commit
83
+ \t\theaders\t\t\t(dict[str, str]):\tHeaders for GitHub API requests
84
+ \tReturns:
85
+ \t\tlist[dict]: List of commits since the last tag
86
+ \t"""
87
+ def generate_changelog(commits: list[dict[str, Any]], owner: str, project_name: str, latest_tag_version: str | None, version: str) -> str:
88
+ """ Generate changelog from commits. They must follow the conventional commits convention.
89
+
90
+ \tConvention format: <type>: <description> or <type>(<sub-category>): <description>
91
+
92
+ \tArgs:
93
+ \t\tcommits\t\t\t\t(list[dict]):\tList of commits to generate changelog from
94
+ \t\towner\t\t\t\t(str):\t\t\tGitHub username
95
+ \t\tproject_name\t\t(str):\t\t\tName of the GitHub repository
96
+ \t\tlatest_tag_version\t(str|None):\t\tVersion number of the latest tag
97
+ \t\tversion\t\t\t\t(str):\t\t\tCurrent version being released
98
+ \tReturns:
99
+ \t\tstr: Generated changelog text
100
+ \tSource:
101
+ \t\thttps://www.conventionalcommits.org/en/v1.0.0/
102
+ \t"""
103
+ def create_tag(owner: str, project_name: str, version: str, headers: dict[str, str]) -> None:
104
+ """ Create a new tag
105
+
106
+ \tArgs:
107
+ \t\towner\t\t\t(str):\t\t\t\tGitHub username
108
+ \t\tproject_name\t(str):\t\t\t\tName of the GitHub repository
109
+ \t\tversion\t\t\t(str):\t\t\t\tVersion for the new tag
110
+ \t\theaders\t\t\t(dict[str, str]):\tHeaders for GitHub API requests
111
+ \t"""
112
+ def create_release(owner: str, project_name: str, version: str, changelog: str, headers: dict[str, str]) -> int:
113
+ """ Create a new release
114
+
115
+ \tArgs:
116
+ \t\towner\t\t\t(str):\t\t\t\tGitHub username
117
+ \t\tproject_name\t(str):\t\t\t\tName of the GitHub repository
118
+ \t\tversion\t\t\t(str):\t\t\t\tVersion for the new release
119
+ \t\tchangelog\t\t(str):\t\t\t\tChangelog text for the release
120
+ \t\theaders\t\t\t(dict[str, str]):\tHeaders for GitHub API requests
121
+ \tReturns:
122
+ \t\tint: ID of the created release
123
+ \t"""
124
+ def upload_assets(owner: str, project_name: str, release_id: int, build_folder: str, headers: dict[str, str], endswith: list[str]) -> None:
125
+ """ Upload release assets
126
+
127
+ \tArgs:
128
+ \t\towner\t\t\t(str):\t\t\t\tGitHub username
129
+ \t\tproject_name\t(str):\t\t\t\tName of the GitHub repository
130
+ \t\trelease_id\t\t(int):\t\t\t\tID of the release to upload assets to
131
+ \t\tbuild_folder\t(str):\t\t\t\tFolder containing assets to upload
132
+ \t\theaders\t\t\t(dict[str, str]):\tHeaders for GitHub API requests
133
+ \t\tendswith\t\t(list[str]):\t\tList of files to upload to the release
134
+ \t\t\t(every file ending with one of these strings will be uploaded)
135
+ \t"""
136
+ def upload_to_github(credentials: dict[str, Any], github_config: dict[str, Any]) -> str:
137
+ ''' Upload the project to GitHub using the credentials and the configuration
138
+
139
+ \tArgs:
140
+ \t\tcredentials\t\t(dict[str, Any]):\tCredentials for the GitHub API
141
+ \t\tgithub_config\t(dict[str, Any]):\tConfiguration for the GitHub project
142
+ \tReturns:
143
+ \t\tstr: Generated changelog text
144
+ \tExamples:
145
+
146
+ \t.. code-block:: python
147
+
148
+ \t\t> upload_to_github(
149
+ \t\t\tcredentials={
150
+ \t\t\t\t"github": {
151
+ \t\t\t\t\t"api_key": "ghp_...",
152
+ \t\t\t\t\t"username": "Stoupy"
153
+ \t\t\t\t}
154
+ \t\t\t},
155
+ \t\t\tgithub_config={
156
+ \t\t\t\t"project_name": "stouputils",
157
+ \t\t\t\t"version": "1.0.0",
158
+ \t\t\t\t"build_folder": "build",
159
+ \t\t\t\t"endswith": [".zip"]
160
+ \t\t\t}
161
+ \t\t)
162
+ \t'''
@@ -0,0 +1,52 @@
1
+ from ..decorators import LogLevels as LogLevels, handle_error as handle_error
2
+ from .pyproject import read_pyproject as read_pyproject
3
+ from collections.abc import Callable as Callable
4
+
5
+ def update_pip_and_required_packages() -> int:
6
+ """ Update pip and required packages.
7
+
8
+ \tReturns:
9
+ \t\tint: Return code of the os.system call.
10
+ \t"""
11
+ def build_package() -> int:
12
+ """ Build the package.
13
+
14
+ \tReturns:
15
+ \t\tint: Return code of the os.system call.
16
+ \t"""
17
+ def upload_package(repository: str, filepath: str) -> int:
18
+ """ Upload the package to PyPI.
19
+
20
+ \tArgs:
21
+ \t\trepository (str): Repository to upload to.
22
+ \t\tfilepath (str): Path to the file to upload.
23
+
24
+ \tReturns:
25
+ \t\tint: Return code of the os.system call.
26
+ \t"""
27
+ def pypi_full_routine(repository: str, dist_directory: str, last_files: int = 1, endswith: str = '.tar.gz', update_all_function: Callable[[], int] = ..., build_package_function: Callable[[], int] = ..., upload_package_function: Callable[[str, str], int] = ...) -> None:
28
+ ''' Upload the most recent file(s) to PyPI after updating pip and required packages and building the package.
29
+
30
+ \tArgs:
31
+ \t\trepository (str): Repository to upload to.
32
+ \t\tdist_directory (str): Directory to upload from.
33
+ \t\tlast_files (int): Number of most recent files to upload. Defaults to 1.
34
+ \t\tendswith (str): End of the file name to upload. Defaults to ".tar.gz".
35
+ \t\tupdate_all_function (Callable[[], int]): Function to update pip and required packages.
36
+ \t\t\tDefaults to :func:`update_pip_and_required_packages`.
37
+ \t\tbuild_package_function (Callable[[], int]): Function to build the package.
38
+ \t\t\tDefaults to :func:`build_package`.
39
+ \t\tupload_package_function (Callable[[str, str], int]): Function to upload the package.
40
+ \t\t\tDefaults to :func:`upload_package`.
41
+
42
+ \tReturns:
43
+ \t\tint: Return code of the command.
44
+ \t'''
45
+ def pypi_full_routine_using_uv() -> None:
46
+ """ Full build and publish routine using 'uv' command line tool.
47
+
48
+ \tSteps:
49
+ \t\t1. Generate stubs unless '--no-stubs' is passed
50
+ \t\t2. Build the package using 'uv build'
51
+ \t\t3. Upload the most recent file to PyPI using 'uv publish'
52
+ \t"""
@@ -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'''
@@ -0,0 +1,39 @@
1
+ from ..decorators import LogLevels as LogLevels, handle_error as handle_error
2
+ from collections.abc import Callable as Callable
3
+
4
+ def generate_stubs(package_name: str, extra_args: str = '--include-docstrings --include-private') -> int:
5
+ ''' Generate stub files for a Python package using stubgen.
6
+
7
+ \tNote: stubgen generates stubs in the \'out\' directory by default in the current working directory.
8
+
9
+ \tArgs:
10
+ \t\tpackage_name (str): Name of the package to generate stubs for.
11
+ \t\textra_args (str): Extra arguments to pass to stubgen. Defaults to "--include-docstrings --include-private".
12
+ \tReturns:
13
+ \t\tint: Return code of the os.system call.
14
+ \t'''
15
+ def clean_stubs_directory(output_directory: str, package_name: str) -> None:
16
+ """ Clean the stubs directory by deleting all .pyi files.
17
+
18
+ \tArgs:
19
+ \t\toutput_directory (str): Directory to clean.
20
+ \t\tpackage_name (str): Package name subdirectory. Only cleans output_directory/package_name.
21
+ \t"""
22
+ def stubs_full_routine(package_name: str, output_directory: str = 'typings', extra_args: str = '--include-docstrings --include-private', clean_before: bool = False, generate_stubs_function: Callable[[str, str], int] = ..., clean_stubs_function: Callable[[str, str], None] = ...) -> None:
23
+ ''' Generate stub files for a Python package using stubgen.
24
+
25
+ \tNote: stubgen generates stubs in the \'out\' directory by default in the current working directory.
26
+
27
+ \tArgs:
28
+ \t\tpackage_name (str): Name of the package to generate stubs for.
29
+ \t\toutput_directory (str): Directory to clean before generating stubs. Defaults to "typings".
30
+ \t\t\tThis parameter is used for cleaning the directory before stub generation.
31
+ \t\textra_args (str): Extra arguments to pass to stubgen. Defaults to "--include-docstrings --include-private".
32
+ \t\tclean_before (bool): Whether to clean the output directory before generating stubs. Defaults to False.
33
+ \t\tgenerate_stubs_function (Callable[[str, str], int]): Function to generate stubs.
34
+ \t\t\tDefaults to :func:`generate_stubs`.
35
+ \t\tclean_stubs_function (Callable[[str], None]): Function to clean the stubs directory.
36
+ \t\t\tDefaults to :func:`clean_stubs_directory`.
37
+ \tRaises:
38
+ \t\tException: If stub generation fails.
39
+ \t'''
stouputils/ctx.pyi ADDED
@@ -0,0 +1,211 @@
1
+ import abc
2
+ from .io import super_open as super_open
3
+ from .print import TeeMultiOutput as TeeMultiOutput, debug as debug
4
+ from collections.abc import Callable as Callable
5
+ from contextlib import AbstractAsyncContextManager, AbstractContextManager
6
+ from typing import Any, IO, TextIO, TypeVar
7
+
8
+ T = TypeVar('T')
9
+
10
+ class AbstractBothContextManager[T](AbstractContextManager[T], AbstractAsyncContextManager[T], metaclass=abc.ABCMeta):
11
+ """ Abstract base class for context managers that support both synchronous and asynchronous usage. """
12
+
13
+ class LogToFile(AbstractBothContextManager['LogToFile']):
14
+ ''' Context manager to log to a file.
15
+
16
+ \tThis context manager allows you to temporarily log output to a file while still printing normally.
17
+ \tThe file will receive log messages without ANSI color codes.
18
+
19
+ \tArgs:
20
+ \t\tpath (str): Path to the log file
21
+ \t\tmode (str): Mode to open the file in (default: "w")
22
+ \t\tencoding (str): Encoding to use for the file (default: "utf-8")
23
+ \t\ttee_stdout (bool): Whether to redirect stdout to the file (default: True)
24
+ \t\ttee_stderr (bool): Whether to redirect stderr to the file (default: True)
25
+ \t\tignore_lineup (bool): Whether to ignore lines containing LINE_UP escape sequence in files (default: False)
26
+ \t\trestore_on_exit (bool): Whether to restore original stdout/stderr on exit (default: False)
27
+ \t\t\tThis ctx uses TeeMultiOutput which handles closed files gracefully, so restoring is not mandatory.
28
+
29
+ \tExamples:
30
+ \t\t.. code-block:: python
31
+
32
+ \t\t\t> import stouputils as stp
33
+ \t\t\t> with stp.LogToFile("output.log"):
34
+ \t\t\t> stp.info("This will be logged to output.log and printed normally")
35
+ \t\t\t> print("This will also be logged")
36
+
37
+ \t\t\t> with stp.LogToFile("output.log") as log_ctx:
38
+ \t\t\t> stp.warning("This will be logged to output.log and printed normally")
39
+ \t\t\t> log_ctx.change_file("new_file.log")
40
+ \t\t\t> print("This will be logged to new_file.log")
41
+ \t'''
42
+ path: str
43
+ mode: str
44
+ encoding: str
45
+ tee_stdout: bool
46
+ tee_stderr: bool
47
+ ignore_lineup: bool
48
+ restore_on_exit: bool
49
+ file: IO[Any]
50
+ original_stdout: TextIO
51
+ original_stderr: TextIO
52
+ def __init__(self, path: str, mode: str = 'w', encoding: str = 'utf-8', tee_stdout: bool = True, tee_stderr: bool = True, ignore_lineup: bool = True, restore_on_exit: bool = False) -> None: ...
53
+ def __enter__(self) -> LogToFile:
54
+ """ Enter context manager which opens the log file and redirects stdout/stderr """
55
+ def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: Any | None) -> None:
56
+ """ Exit context manager which closes the log file and restores stdout/stderr """
57
+ async def __aenter__(self) -> LogToFile:
58
+ """ Enter async context manager which opens the log file and redirects stdout/stderr """
59
+ async def __aexit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: Any | None) -> None:
60
+ """ Exit async context manager which closes the log file and restores stdout/stderr """
61
+ def change_file(self, new_path: str) -> None:
62
+ """ Change the log file to a new path.
63
+
64
+ \t\tArgs:
65
+ \t\t\tnew_path (str): New path to the log file
66
+ \t\t"""
67
+ @staticmethod
68
+ def common(logs_folder: str, filepath: str, func: Callable[..., Any], *args: Any, **kwargs: Any) -> Any:
69
+ ''' Common code used at the beginning of a program to launch main function
70
+
71
+ \t\tArgs:
72
+ \t\t\tlogs_folder (str): Folder to store logs in
73
+ \t\t\tfilepath (str): Path to the main function
74
+ \t\t\tfunc (Callable[..., Any]): Main function to launch
75
+ \t\t\t*args (tuple[Any, ...]): Arguments to pass to the main function
76
+ \t\t\t**kwargs (dict[str, Any]): Keyword arguments to pass to the main function
77
+ \t\tReturns:
78
+ \t\t\tAny: Return value of the main function
79
+
80
+ \t\tExamples:
81
+ \t\t\t>>> if __name__ == "__main__":
82
+ \t\t\t... LogToFile.common(f"{ROOT}/logs", __file__, main)
83
+ \t\t'''
84
+
85
+ class MeasureTime(AbstractBothContextManager['MeasureTime']):
86
+ ''' Context manager to measure execution time.
87
+
88
+ \tThis context manager measures the execution time of the code block it wraps
89
+ \tand prints the result using a specified print function.
90
+
91
+ \tArgs:
92
+ \t\tprint_func (Callable): Function to use to print the execution time (e.g. debug, info, warning, error, etc.).
93
+ \t\tmessage (str): Message to display with the execution time. Defaults to "Execution time".
94
+ \t\tperf_counter (bool): Whether to use time.perf_counter_ns or time.time_ns. Defaults to True.
95
+
96
+ \tExamples:
97
+ \t\t.. code-block:: python
98
+
99
+ \t\t\t> import time
100
+ \t\t\t> import stouputils as stp
101
+ \t\t\t> with stp.MeasureTime(stp.info, message="My operation"):
102
+ \t\t\t... time.sleep(0.5)
103
+ \t\t\t> # [INFO HH:MM:SS] My operation: 500.123ms (500123456ns)
104
+
105
+ \t\t\t> with stp.MeasureTime(): # Uses debug by default
106
+ \t\t\t... time.sleep(0.1)
107
+ \t\t\t> # [DEBUG HH:MM:SS] Execution time: 100.456ms (100456789ns)
108
+ \t'''
109
+ print_func: Callable[..., None]
110
+ message: str
111
+ perf_counter: bool
112
+ ns: Callable[[], int]
113
+ start_ns: int
114
+ def __init__(self, print_func: Callable[..., None] = ..., message: str = 'Execution time', perf_counter: bool = True) -> None: ...
115
+ def __enter__(self) -> MeasureTime:
116
+ """ Enter context manager, record start time """
117
+ def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: Any | None) -> None:
118
+ """ Exit context manager, calculate duration and print """
119
+ async def __aenter__(self) -> MeasureTime:
120
+ """ Enter async context manager, record start time """
121
+ async def __aexit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: Any | None) -> None:
122
+ """ Exit async context manager, calculate duration and print """
123
+
124
+ class Muffle(AbstractBothContextManager['Muffle']):
125
+ ''' Context manager that temporarily silences output.
126
+ \t(No thread-safety guaranteed)
127
+
128
+ \tAlternative to stouputils.decorators.silent()
129
+
130
+ \tExamples:
131
+ \t\t>>> with Muffle():
132
+ \t\t... print("This will not be printed")
133
+ \t'''
134
+ mute_stderr: bool
135
+ original_stdout: IO[Any]
136
+ original_stderr: IO[Any]
137
+ def __init__(self, mute_stderr: bool = False) -> None: ...
138
+ def __enter__(self) -> Muffle:
139
+ """ Enter context manager which redirects stdout and stderr to devnull """
140
+ def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: Any | None) -> None:
141
+ """ Exit context manager which restores original stdout and stderr """
142
+ async def __aenter__(self) -> Muffle:
143
+ """ Enter async context manager which redirects stdout and stderr to devnull """
144
+ async def __aexit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: Any | None) -> None:
145
+ """ Exit async context manager which restores original stdout and stderr """
146
+
147
+ class DoNothing(AbstractBothContextManager['DoNothing']):
148
+ ''' Context manager that does nothing.
149
+
150
+ \tThis is a no-op context manager that can be used as a placeholder
151
+ \tor for conditional context management.
152
+
153
+ \tDifferent from contextlib.nullcontext because it handles args and kwargs,
154
+ \talong with **async** context management.
155
+
156
+ \tExamples:
157
+ \t\t>>> with DoNothing():
158
+ \t\t... print("This will be printed normally")
159
+ \t\tThis will be printed normally
160
+
161
+ \t\t>>> # Conditional context management
162
+ \t\t>>> some_condition = True
163
+ \t\t>>> ctx = DoNothing() if some_condition else Muffle()
164
+ \t\t>>> with ctx:
165
+ \t\t... print("May or may not be printed depending on condition")
166
+ \t\tMay or may not be printed depending on condition
167
+ \t'''
168
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
169
+ """ No initialization needed, this is a no-op context manager """
170
+ def __enter__(self) -> DoNothing:
171
+ """ Enter context manager (does nothing) """
172
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
173
+ """ Exit context manager (does nothing) """
174
+ async def __aenter__(self) -> DoNothing:
175
+ """ Enter async context manager (does nothing) """
176
+ async def __aexit__(self, *excinfo: Any) -> None:
177
+ """ Exit async context manager (does nothing) """
178
+ NullContextManager = DoNothing
179
+
180
+ class SetMPStartMethod(AbstractBothContextManager['SetMPStartMethod']):
181
+ ''' Context manager to temporarily set multiprocessing start method.
182
+
183
+ \tThis context manager allows you to temporarily change the multiprocessing start method
184
+ \tand automatically restores the original method when exiting the context.
185
+
186
+ \tArgs:
187
+ \t\tstart_method (str): The start method to use: "spawn", "fork", or "forkserver"
188
+
189
+ \tExamples:
190
+ \t\t.. code-block:: python
191
+
192
+ \t\t\t> import multiprocessing as mp
193
+ \t\t\t> import stouputils as stp
194
+ \t\t\t> # Temporarily use spawn method
195
+ \t\t\t> with stp.SetMPStartMethod("spawn"):
196
+ \t\t\t> ... # Your multiprocessing code here
197
+ \t\t\t> ... pass
198
+
199
+ \t\t\t> # Original method is automatically restored
200
+ \t'''
201
+ start_method: str | None
202
+ old_method: str | None
203
+ def __init__(self, start_method: str | None) -> None: ...
204
+ def __enter__(self) -> SetMPStartMethod:
205
+ """ Enter context manager which sets the start method """
206
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
207
+ """ Exit context manager which restores the original start method """
208
+ async def __aenter__(self) -> SetMPStartMethod:
209
+ """ Enter async context manager which sets the start method """
210
+ async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
211
+ """ Exit async context manager which restores the original start method """