stouputils 1.14.2__py3-none-any.whl → 1.14.3__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 (40) hide show
  1. stouputils/continuous_delivery/pypi.py +1 -1
  2. stouputils/continuous_delivery/pypi.pyi +3 -2
  3. stouputils/decorators.pyi +10 -0
  4. stouputils/parallel.pyi +12 -7
  5. stouputils/print.pyi +2 -2
  6. {stouputils-1.14.2.dist-info → stouputils-1.14.3.dist-info}/METADATA +1 -1
  7. {stouputils-1.14.2.dist-info → stouputils-1.14.3.dist-info}/RECORD +9 -40
  8. {stouputils-1.14.2.dist-info → stouputils-1.14.3.dist-info}/WHEEL +1 -1
  9. stouputils/stouputils/__init__.pyi +0 -15
  10. stouputils/stouputils/_deprecated.pyi +0 -12
  11. stouputils/stouputils/all_doctests.pyi +0 -46
  12. stouputils/stouputils/applications/__init__.pyi +0 -2
  13. stouputils/stouputils/applications/automatic_docs.pyi +0 -106
  14. stouputils/stouputils/applications/upscaler/__init__.pyi +0 -3
  15. stouputils/stouputils/applications/upscaler/config.pyi +0 -18
  16. stouputils/stouputils/applications/upscaler/image.pyi +0 -109
  17. stouputils/stouputils/applications/upscaler/video.pyi +0 -60
  18. stouputils/stouputils/archive.pyi +0 -67
  19. stouputils/stouputils/backup.pyi +0 -109
  20. stouputils/stouputils/collections.pyi +0 -86
  21. stouputils/stouputils/continuous_delivery/__init__.pyi +0 -5
  22. stouputils/stouputils/continuous_delivery/cd_utils.pyi +0 -129
  23. stouputils/stouputils/continuous_delivery/github.pyi +0 -162
  24. stouputils/stouputils/continuous_delivery/pypi.pyi +0 -53
  25. stouputils/stouputils/continuous_delivery/pyproject.pyi +0 -67
  26. stouputils/stouputils/continuous_delivery/stubs.pyi +0 -39
  27. stouputils/stouputils/ctx.pyi +0 -211
  28. stouputils/stouputils/decorators.pyi +0 -252
  29. stouputils/stouputils/image.pyi +0 -172
  30. stouputils/stouputils/installer/__init__.pyi +0 -5
  31. stouputils/stouputils/installer/common.pyi +0 -39
  32. stouputils/stouputils/installer/downloader.pyi +0 -24
  33. stouputils/stouputils/installer/linux.pyi +0 -39
  34. stouputils/stouputils/installer/main.pyi +0 -57
  35. stouputils/stouputils/installer/windows.pyi +0 -31
  36. stouputils/stouputils/io.pyi +0 -213
  37. stouputils/stouputils/parallel.pyi +0 -216
  38. stouputils/stouputils/print.pyi +0 -136
  39. stouputils/stouputils/version_pkg.pyi +0 -15
  40. {stouputils-1.14.2.dist-info → stouputils-1.14.3.dist-info}/entry_points.txt +0 -0
@@ -1,67 +0,0 @@
1
- from .decorators import LogLevels as LogLevels, handle_error as handle_error
2
- from .io import clean_path as clean_path, super_copy as super_copy
3
- from .print import CYAN as CYAN, GREEN as GREEN, RESET as RESET, debug as debug, error as error, info as info
4
-
5
- def repair_zip_file(file_path: str, destination: str) -> bool:
6
- ''' Try to repair a corrupted zip file by ignoring some of the errors
7
-
8
- \tThis function manually parses the ZIP file structure to extract files
9
- \teven when the ZIP file is corrupted. It reads the central directory
10
- \tentries and attempts to decompress each file individually.
11
-
12
- \tArgs:
13
- \t\tfile_path\t\t(str):\tPath of the zip file to repair
14
- \t\tdestination\t\t(str):\tDestination of the new file
15
- \tReturns:
16
- \t\tbool: Always returns True unless any strong error
17
-
18
- \tExamples:
19
-
20
- \t.. code-block:: python
21
-
22
- \t\t> repair_zip_file("/path/to/source.zip", "/path/to/destination.zip")
23
- \t'''
24
- def make_archive(source: str, destinations: list[str] | str | None = None, override_time: None | tuple[int, int, int, int, int, int] = None, create_dir: bool = False, ignore_patterns: str | None = None) -> bool:
25
- ''' Create a zip archive from a source directory with consistent file timestamps.
26
- \t(Meaning deterministic zip file each time)
27
-
28
- \tCreates a zip archive from the source directory and copies it to one or more destinations.
29
- \tThe archive will have consistent file timestamps across runs if override_time is specified.
30
- \tUses maximum compression level (9) with ZIP_DEFLATED algorithm.
31
-
32
- \tArgs:
33
- \t\tsource\t\t\t\t(str):\t\t\t\t\t\tThe source folder to archive
34
- \t\tdestinations\t\t(list[str]|str):\t\t\tThe destination folder(s) or file(s) to copy the archive to
35
- \t\toverride_time\t\t(None | tuple[int, ...]):\tThe constant time to use for the archive
36
- \t\t\t(e.g. (2024, 1, 1, 0, 0, 0) for 2024-01-01 00:00:00)
37
- \t\tcreate_dir\t\t\t(bool):\t\t\t\t\t\tWhether to create the destination directory if it doesn\'t exist
38
- \t\tignore_patterns\t\t(str | None):\t\t\t\tGlob pattern(s) to ignore files. Can be a single pattern or comma-separated patterns (e.g. "*.pyc" or "*.pyc,__pycache__,*.log")
39
- \tReturns:
40
- \t\tbool: Always returns True unless any strong error
41
- \tExamples:
42
-
43
- \t.. code-block:: python
44
-
45
- \t\t> make_archive("/path/to/source", "/path/to/destination.zip")
46
- \t\t> make_archive("/path/to/source", ["/path/to/destination.zip", "/path/to/destination2.zip"])
47
- \t\t> make_archive("src", "hello_from_year_2085.zip", override_time=(2085,1,1,0,0,0))
48
- \t\t> make_archive("src", "output.zip", ignore_patterns="*.pyc")
49
- \t\t> make_archive("src", "output.zip", ignore_patterns="__pycache__")
50
- \t\t> make_archive("src", "output.zip", ignore_patterns="*.pyc,__pycache__,*.log")
51
- \t'''
52
- def archive_cli() -> None:
53
- ''' Main entry point for command line usage.
54
-
55
- \tExamples:
56
-
57
- \t.. code-block:: bash
58
-
59
- \t\t# Repair a corrupted zip file
60
- \t\tpython -m stouputils.archive repair /path/to/corrupted.zip /path/to/repaired.zip
61
-
62
- \t\t# Create a zip archive
63
- \t\tpython -m stouputils.archive make /path/to/source /path/to/destination.zip
64
-
65
- \t\t# Create a zip archive with ignore patterns
66
- \t\tpython -m stouputils.archive make /path/to/source /path/to/destination.zip --ignore "*.pyc,__pycache__"
67
- \t'''
@@ -1,109 +0,0 @@
1
- import zipfile
2
- from .decorators import handle_error as handle_error, measure_time as measure_time
3
- from .io import clean_path as clean_path
4
- from .print import CYAN as CYAN, GREEN as GREEN, RESET as RESET, colored_for_loop as colored_for_loop, info as info, warning as warning
5
-
6
- CHUNK_SIZE: int
7
- LARGE_CHUNK_SIZE: int
8
-
9
- def backup_cli() -> None:
10
- ''' Main entry point for command line usage.
11
-
12
- \tExamples:
13
-
14
- \t.. code-block:: bash
15
-
16
- \t\t# Create a delta backup, excluding libraries and cache folders
17
- \t\tpython -m stouputils.backup delta /path/to/source /path/to/backups -x "libraries/*" "cache/*"
18
-
19
- \t\t# Consolidate backups into a single file
20
- \t\tpython -m stouputils.backup consolidate /path/to/backups/latest.zip /path/to/consolidated.zip
21
-
22
- \t\t# Limit the number of delta backups to 5
23
- \t\tpython -m stouputils.backup limit 5 /path/to/backups
24
- \t'''
25
- def create_delta_backup(source_path: str, destination_folder: str, exclude_patterns: list[str] | None = None) -> None:
26
- ''' Creates a ZIP delta backup, saving only modified or new files while tracking deleted files.
27
-
28
- \tArgs:
29
- \t\tsource_path (str): Path to the source file or directory to back up
30
- \t\tdestination_folder (str): Path to the folder where the backup will be saved
31
- \t\texclude_patterns (list[str] | None): List of glob patterns to exclude from backup
32
- \tExamples:
33
-
34
- \t.. code-block:: python
35
-
36
- \t\t> create_delta_backup("/path/to/source", "/path/to/backups", exclude_patterns=["libraries/*", "cache/*"])
37
- \t\t[INFO HH:MM:SS] Creating ZIP backup
38
- \t\t[INFO HH:MM:SS] Backup created: \'/path/to/backups/backup_2025_02_18-10_00_00.zip\'
39
- \t'''
40
- def consolidate_backups(zip_path: str, destination_zip: str) -> None:
41
- ''' Consolidates the files from the given backup and all previous ones into a new ZIP file,
42
- \tensuring that the most recent version of each file is kept and deleted files are not restored.
43
-
44
- \tArgs:
45
- \t\tzip_path (str): Path to the latest backup ZIP file (If endswith "/latest.zip" or "/", the latest backup will be used)
46
- \t\tdestination_zip (str): Path to the destination ZIP file where the consolidated backup will be saved
47
- \tExamples:
48
-
49
- \t.. code-block:: python
50
-
51
- \t\t> consolidate_backups("/path/to/backups/latest.zip", "/path/to/consolidated.zip")
52
- \t\t[INFO HH:MM:SS] Consolidating backups
53
- \t\t[INFO HH:MM:SS] Consolidated backup created: \'/path/to/consolidated.zip\'
54
- \t'''
55
- def limit_backups(max_backups: int, backup_folder: str, keep_oldest: bool = True) -> None:
56
- ''' Limits the number of delta backups by consolidating the oldest ones.
57
-
58
- \tIf the number of backups exceeds max_backups, the oldest backups are consolidated
59
- \tinto a single backup file, then deleted, until the count is within the limit.
60
-
61
- \tArgs:
62
- \t\tmax_backups (int): Maximum number of delta backups to keep
63
- \t\tbackup_folder (str): Path to the folder containing backups
64
- \t\tkeep_oldest (bool): If True, never delete the oldest backup (default: True)
65
- \tExamples:
66
-
67
- \t.. code-block:: python
68
-
69
- \t\t> limit_backups(5, "/path/to/backups")
70
- \t\t[INFO HH:MM:SS] Limiting backups
71
- \t\t[INFO HH:MM:SS] Consolidated 3 oldest backups into \'/path/to/backups/consolidated_YYYY_MM_DD-HH_MM_SS.zip\'
72
- \t\t[INFO HH:MM:SS] Deleted 3 old backups
73
- \t'''
74
- def get_file_hash(file_path: str) -> str | None:
75
- """ Computes the SHA-256 hash of a file.
76
-
77
- \tArgs:
78
- \t\tfile_path (str): Path to the file
79
- \tReturns:
80
- \t\tstr | None: SHA-256 hash as a hexadecimal string or None if an error occurs
81
- \t"""
82
- def extract_hash_from_zipinfo(zip_info: zipfile.ZipInfo) -> str | None:
83
- """ Extracts the stored hash from a ZipInfo object's comment.
84
-
85
- \tArgs:
86
- \t\tzip_info (zipfile.ZipInfo): The ZipInfo object representing a file in the ZIP
87
- \tReturns:
88
- \t\tstr | None: The stored hash if available, otherwise None
89
- \t"""
90
- def get_all_previous_backups(backup_folder: str, all_before: str | None = None) -> dict[str, dict[str, str]]:
91
- ''' Retrieves all previous backups in a folder and maps each backup to a dictionary of file paths and their hashes.
92
-
93
- \tArgs:
94
- \t\tbackup_folder (str): The folder containing previous backup zip files
95
- \t\tall_before (str | None): Path to the latest backup ZIP file
96
- \t\t\t(If endswith "/latest.zip" or "/", the latest backup will be used)
97
- \tReturns:
98
- \t\tdict[str, dict[str, str]]: Dictionary mapping backup file paths to dictionaries of {file_path: file_hash}
99
- \t'''
100
- def is_file_in_any_previous_backup(file_path: str, file_hash: str, previous_backups: dict[str, dict[str, str]]) -> bool:
101
- """ Checks if a file with the same hash exists in any previous backup.
102
-
103
- \tArgs:
104
- \t\tfile_path (str): The relative path of the file
105
- \t\tfile_hash (str): The SHA-256 hash of the file
106
- \t\tprevious_backups (dict[str, dict[str, str]]): Dictionary mapping backup zip paths to their stored file hashes
107
- \tReturns:
108
- \t\tbool: True if the file exists unchanged in any previous backup, False otherwise
109
- \t"""
@@ -1,86 +0,0 @@
1
- import polars as pl
2
- import zarr
3
- from collections.abc import Iterable
4
- from numpy.typing import NDArray as NDArray
5
- from typing import Any, Literal, TypeVar
6
-
7
- T = TypeVar('T')
8
-
9
- def unique_list[T](list_to_clean: Iterable[T], method: Literal['id', 'hash', 'str'] = 'str') -> list[T]:
10
- ''' Remove duplicates from the list while keeping the order using ids (default) or hash or str
11
-
12
- \tArgs:
13
- \t\tlist_to_clean\t(Iterable[T]):\t\t\t\t\tThe list to clean
14
- \t\tmethod\t\t\t(Literal["id", "hash", "str"]):\tThe method to use to identify duplicates
15
- \tReturns:
16
- \t\tlist[T]: The cleaned list
17
-
18
- \tExamples:
19
- \t\t>>> unique_list([1, 2, 3, 2, 1], method="id")
20
- \t\t[1, 2, 3]
21
-
22
- \t\t>>> s1 = {1, 2, 3}
23
- \t\t>>> s2 = {2, 3, 4}
24
- \t\t>>> s3 = {1, 2, 3}
25
- \t\t>>> unique_list([s1, s2, s1, s1, s3, s2, s3], method="id")
26
- \t\t[{1, 2, 3}, {2, 3, 4}, {1, 2, 3}]
27
-
28
- \t\t>>> s1 = {1, 2, 3}
29
- \t\t>>> s2 = {2, 3, 4}
30
- \t\t>>> s3 = {1, 2, 3}
31
- \t\t>>> unique_list([s1, s2, s1, s1, s3, s2, s3], method="str")
32
- \t\t[{1, 2, 3}, {2, 3, 4}]
33
- \t'''
34
- def sort_dict_keys[T](dictionary: dict[T, Any], order: list[T], reverse: bool = False) -> dict[T, Any]:
35
- ''' Sort dictionary keys using a given order list (reverse optional)
36
-
37
- \tArgs:
38
- \t\tdictionary\t(dict[T, Any]):\tThe dictionary to sort
39
- \t\torder\t\t(list[T]):\t\tThe order list
40
- \t\treverse\t\t(bool):\t\t\tWhether to sort in reverse order (given to sorted function which behaves differently than order.reverse())
41
- \tReturns:
42
- \t\tdict[T, Any]: The sorted dictionary
43
-
44
- \tExamples:
45
- \t\t>>> sort_dict_keys({\'b\': 2, \'a\': 1, \'c\': 3}, order=["a", "b", "c"])
46
- \t\t{\'a\': 1, \'b\': 2, \'c\': 3}
47
-
48
- \t\t>>> sort_dict_keys({\'b\': 2, \'a\': 1, \'c\': 3}, order=["a", "b", "c"], reverse=True)
49
- \t\t{\'c\': 3, \'b\': 2, \'a\': 1}
50
-
51
- \t\t>>> sort_dict_keys({\'b\': 2, \'a\': 1, \'c\': 3, \'d\': 4}, order=["c", "b"])
52
- \t\t{\'c\': 3, \'b\': 2, \'a\': 1, \'d\': 4}
53
- \t'''
54
- def upsert_in_dataframe(df: pl.DataFrame, new_entry: dict[str, Any], primary_keys: dict[str, Any] | None = None) -> pl.DataFrame:
55
- """ Insert or update a row in the Polars DataFrame based on primary keys.
56
-
57
- \tArgs:
58
- \t\tdf\t\t\t\t(pl.DataFrame):\t\tThe Polars DataFrame to update.
59
- \t\tnew_entry\t\t(dict[str, Any]):\tThe new entry to insert or update.
60
- \t\tprimary_keys\t(dict[str, Any]):\tThe primary keys to identify the row (default: empty).
61
- \tReturns:
62
- \t\tpl.DataFrame: The updated Polars DataFrame.
63
- \t"""
64
- def array_to_disk(data: NDArray[Any] | zarr.Array, delete_input: bool = True, more_data: NDArray[Any] | zarr.Array | None = None) -> tuple['zarr.Array', str, int]:
65
- """ Easily handle large numpy arrays on disk using zarr for efficient storage and access.
66
-
67
- \tZarr provides a simpler and more efficient alternative to np.memmap with better compression
68
- \tand chunking capabilities.
69
-
70
- \tArgs:
71
- \t\tdata\t\t\t(NDArray | zarr.Array):\tThe data to save/load as a zarr array
72
- \t\tdelete_input\t(bool):\tWhether to delete the input data after creating the zarr array
73
- \t\tmore_data\t\t(NDArray | zarr.Array | None): Additional data to append to the zarr array
74
- \tReturns:
75
- \t\ttuple[zarr.Array, str, int]: The zarr array, the directory path, and the total size in bytes
76
-
77
- \tExamples:
78
- \t\t>>> import numpy as np
79
- \t\t>>> data = np.random.rand(1000, 1000)
80
- \t\t>>> zarr_array = array_to_disk(data)[0]
81
- \t\t>>> zarr_array.shape
82
- \t\t(1000, 1000)
83
-
84
- \t\t>>> more_data = np.random.rand(500, 1000)
85
- \t\t>>> longer_array, dir_path, total_size = array_to_disk(zarr_array, more_data=more_data)
86
- \t"""
@@ -1,5 +0,0 @@
1
- from .cd_utils import *
2
- from .github import *
3
- from .pypi import *
4
- from .pyproject import *
5
- from .stubs import *
@@ -1,129 +0,0 @@
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'''
@@ -1,162 +0,0 @@
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'''
@@ -1,53 +0,0 @@
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"""