stouputils 1.14.0__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.
- stouputils/__init__.py +40 -0
- stouputils/__main__.py +86 -0
- stouputils/_deprecated.py +37 -0
- stouputils/all_doctests.py +160 -0
- stouputils/applications/__init__.py +22 -0
- stouputils/applications/automatic_docs.py +634 -0
- stouputils/applications/upscaler/__init__.py +39 -0
- stouputils/applications/upscaler/config.py +128 -0
- stouputils/applications/upscaler/image.py +247 -0
- stouputils/applications/upscaler/video.py +287 -0
- stouputils/archive.py +344 -0
- stouputils/backup.py +488 -0
- stouputils/collections.py +244 -0
- stouputils/continuous_delivery/__init__.py +27 -0
- stouputils/continuous_delivery/cd_utils.py +243 -0
- stouputils/continuous_delivery/github.py +522 -0
- stouputils/continuous_delivery/pypi.py +130 -0
- stouputils/continuous_delivery/pyproject.py +147 -0
- stouputils/continuous_delivery/stubs.py +86 -0
- stouputils/ctx.py +408 -0
- stouputils/data_science/config/get.py +51 -0
- stouputils/data_science/config/set.py +125 -0
- stouputils/data_science/data_processing/image/__init__.py +66 -0
- stouputils/data_science/data_processing/image/auto_contrast.py +79 -0
- stouputils/data_science/data_processing/image/axis_flip.py +58 -0
- stouputils/data_science/data_processing/image/bias_field_correction.py +74 -0
- stouputils/data_science/data_processing/image/binary_threshold.py +73 -0
- stouputils/data_science/data_processing/image/blur.py +59 -0
- stouputils/data_science/data_processing/image/brightness.py +54 -0
- stouputils/data_science/data_processing/image/canny.py +110 -0
- stouputils/data_science/data_processing/image/clahe.py +92 -0
- stouputils/data_science/data_processing/image/common.py +30 -0
- stouputils/data_science/data_processing/image/contrast.py +53 -0
- stouputils/data_science/data_processing/image/curvature_flow_filter.py +74 -0
- stouputils/data_science/data_processing/image/denoise.py +378 -0
- stouputils/data_science/data_processing/image/histogram_equalization.py +123 -0
- stouputils/data_science/data_processing/image/invert.py +64 -0
- stouputils/data_science/data_processing/image/laplacian.py +60 -0
- stouputils/data_science/data_processing/image/median_blur.py +52 -0
- stouputils/data_science/data_processing/image/noise.py +59 -0
- stouputils/data_science/data_processing/image/normalize.py +65 -0
- stouputils/data_science/data_processing/image/random_erase.py +66 -0
- stouputils/data_science/data_processing/image/resize.py +69 -0
- stouputils/data_science/data_processing/image/rotation.py +80 -0
- stouputils/data_science/data_processing/image/salt_pepper.py +68 -0
- stouputils/data_science/data_processing/image/sharpening.py +55 -0
- stouputils/data_science/data_processing/image/shearing.py +64 -0
- stouputils/data_science/data_processing/image/threshold.py +64 -0
- stouputils/data_science/data_processing/image/translation.py +71 -0
- stouputils/data_science/data_processing/image/zoom.py +83 -0
- stouputils/data_science/data_processing/image_augmentation.py +118 -0
- stouputils/data_science/data_processing/image_preprocess.py +183 -0
- stouputils/data_science/data_processing/prosthesis_detection.py +359 -0
- stouputils/data_science/data_processing/technique.py +481 -0
- stouputils/data_science/dataset/__init__.py +45 -0
- stouputils/data_science/dataset/dataset.py +292 -0
- stouputils/data_science/dataset/dataset_loader.py +135 -0
- stouputils/data_science/dataset/grouping_strategy.py +296 -0
- stouputils/data_science/dataset/image_loader.py +100 -0
- stouputils/data_science/dataset/xy_tuple.py +696 -0
- stouputils/data_science/metric_dictionnary.py +106 -0
- stouputils/data_science/metric_utils.py +847 -0
- stouputils/data_science/mlflow_utils.py +206 -0
- stouputils/data_science/models/abstract_model.py +149 -0
- stouputils/data_science/models/all.py +85 -0
- stouputils/data_science/models/base_keras.py +765 -0
- stouputils/data_science/models/keras/all.py +38 -0
- stouputils/data_science/models/keras/convnext.py +62 -0
- stouputils/data_science/models/keras/densenet.py +50 -0
- stouputils/data_science/models/keras/efficientnet.py +60 -0
- stouputils/data_science/models/keras/mobilenet.py +56 -0
- stouputils/data_science/models/keras/resnet.py +52 -0
- stouputils/data_science/models/keras/squeezenet.py +233 -0
- stouputils/data_science/models/keras/vgg.py +42 -0
- stouputils/data_science/models/keras/xception.py +38 -0
- stouputils/data_science/models/keras_utils/callbacks/__init__.py +20 -0
- stouputils/data_science/models/keras_utils/callbacks/colored_progress_bar.py +219 -0
- stouputils/data_science/models/keras_utils/callbacks/learning_rate_finder.py +148 -0
- stouputils/data_science/models/keras_utils/callbacks/model_checkpoint_v2.py +31 -0
- stouputils/data_science/models/keras_utils/callbacks/progressive_unfreezing.py +249 -0
- stouputils/data_science/models/keras_utils/callbacks/warmup_scheduler.py +66 -0
- stouputils/data_science/models/keras_utils/losses/__init__.py +12 -0
- stouputils/data_science/models/keras_utils/losses/next_generation_loss.py +56 -0
- stouputils/data_science/models/keras_utils/visualizations.py +416 -0
- stouputils/data_science/models/model_interface.py +939 -0
- stouputils/data_science/models/sandbox.py +116 -0
- stouputils/data_science/range_tuple.py +234 -0
- stouputils/data_science/scripts/augment_dataset.py +77 -0
- stouputils/data_science/scripts/exhaustive_process.py +133 -0
- stouputils/data_science/scripts/preprocess_dataset.py +70 -0
- stouputils/data_science/scripts/routine.py +168 -0
- stouputils/data_science/utils.py +285 -0
- stouputils/decorators.py +605 -0
- stouputils/image.py +441 -0
- stouputils/installer/__init__.py +18 -0
- stouputils/installer/common.py +67 -0
- stouputils/installer/downloader.py +101 -0
- stouputils/installer/linux.py +144 -0
- stouputils/installer/main.py +223 -0
- stouputils/installer/windows.py +136 -0
- stouputils/io.py +486 -0
- stouputils/parallel.py +483 -0
- stouputils/print.py +482 -0
- stouputils/py.typed +1 -0
- stouputils/stouputils/__init__.pyi +15 -0
- stouputils/stouputils/_deprecated.pyi +12 -0
- stouputils/stouputils/all_doctests.pyi +46 -0
- stouputils/stouputils/applications/__init__.pyi +2 -0
- stouputils/stouputils/applications/automatic_docs.pyi +106 -0
- stouputils/stouputils/applications/upscaler/__init__.pyi +3 -0
- stouputils/stouputils/applications/upscaler/config.pyi +18 -0
- stouputils/stouputils/applications/upscaler/image.pyi +109 -0
- stouputils/stouputils/applications/upscaler/video.pyi +60 -0
- stouputils/stouputils/archive.pyi +67 -0
- stouputils/stouputils/backup.pyi +109 -0
- stouputils/stouputils/collections.pyi +86 -0
- stouputils/stouputils/continuous_delivery/__init__.pyi +5 -0
- stouputils/stouputils/continuous_delivery/cd_utils.pyi +129 -0
- stouputils/stouputils/continuous_delivery/github.pyi +162 -0
- stouputils/stouputils/continuous_delivery/pypi.pyi +53 -0
- stouputils/stouputils/continuous_delivery/pyproject.pyi +67 -0
- stouputils/stouputils/continuous_delivery/stubs.pyi +39 -0
- stouputils/stouputils/ctx.pyi +211 -0
- stouputils/stouputils/decorators.pyi +252 -0
- stouputils/stouputils/image.pyi +172 -0
- stouputils/stouputils/installer/__init__.pyi +5 -0
- stouputils/stouputils/installer/common.pyi +39 -0
- stouputils/stouputils/installer/downloader.pyi +24 -0
- stouputils/stouputils/installer/linux.pyi +39 -0
- stouputils/stouputils/installer/main.pyi +57 -0
- stouputils/stouputils/installer/windows.pyi +31 -0
- stouputils/stouputils/io.pyi +213 -0
- stouputils/stouputils/parallel.pyi +216 -0
- stouputils/stouputils/print.pyi +136 -0
- stouputils/stouputils/version_pkg.pyi +15 -0
- stouputils/version_pkg.py +189 -0
- stouputils-1.14.0.dist-info/METADATA +178 -0
- stouputils-1.14.0.dist-info/RECORD +140 -0
- stouputils-1.14.0.dist-info/WHEEL +4 -0
- stouputils-1.14.0.dist-info/entry_points.txt +3 -0
|
@@ -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,53 @@
|
|
|
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. Increment version in pyproject.toml (patch by default, minor if 'minor' is passed as last argument, 'major' if 'major' is passed)
|
|
51
|
+
\t\t3. Build the package using 'uv build'
|
|
52
|
+
\t\t4. Upload the most recent file to PyPI using 'uv publish'
|
|
53
|
+
\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'''
|
|
@@ -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 """
|