stouputils 1.0.21__tar.gz → 1.0.23__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {stouputils-1.0.21 → stouputils-1.0.23}/.github/workflows/documentation.yml +2 -1
- {stouputils-1.0.21 → stouputils-1.0.23}/PKG-INFO +3 -2
- stouputils-1.0.23/assets/all_doctests_module.gif +0 -0
- stouputils-1.0.23/assets/archive_module.gif +0 -0
- stouputils-1.0.23/assets/backup_module.gif +0 -0
- stouputils-1.0.23/assets/collections_module.gif +0 -0
- stouputils-1.0.23/assets/continuous_delivery/github_module.gif +0 -0
- stouputils-1.0.23/assets/ctx_module.gif +0 -0
- stouputils-1.0.23/assets/decorators_module_1.gif +0 -0
- stouputils-1.0.23/assets/decorators_module_2.gif +0 -0
- stouputils-1.0.23/assets/io_module.gif +0 -0
- stouputils-1.0.23/assets/parallel_module.gif +0 -0
- stouputils-1.0.23/assets/print_module.gif +0 -0
- stouputils-1.0.23/build_all_in_one.py +20 -0
- stouputils-1.0.23/examples/all_doctests.py +13 -0
- stouputils-1.0.23/examples/archive/corrupted.zip +0 -0
- stouputils-1.0.23/examples/archive.py +24 -0
- stouputils-1.0.23/examples/collections.py +28 -0
- stouputils-1.0.23/examples/ctx.py +25 -0
- stouputils-1.0.23/examples/decorators_1.py +29 -0
- stouputils-1.0.23/examples/decorators_2.py +21 -0
- stouputils-1.0.23/examples/delta_backup.py +7 -0
- stouputils-1.0.23/examples/io.py +33 -0
- stouputils-1.0.23/examples/parallel.py +28 -0
- stouputils-1.0.23/examples/print.py +27 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/pyproject.toml +7 -17
- {stouputils-1.0.21 → stouputils-1.0.23}/scripts/create_docs.py +57 -16
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/all_doctests.py +8 -5
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/archive.py +16 -6
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/backup.py +3 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/collections.py +3 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/continuous_delivery/__init__.py +2 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/continuous_delivery/cd_utils.py +1 -1
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/continuous_delivery/github.py +11 -4
- stouputils-1.0.23/src/stouputils/continuous_delivery/pypi.py +85 -0
- stouputils-1.0.23/src/stouputils/continuous_delivery/pyproject.py +69 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/ctx.py +10 -5
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/decorators.py +25 -52
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/dont_look/zip_file_override.py +1 -8
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/io.py +30 -3
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/parallel.py +10 -7
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/print.py +9 -18
- stouputils-1.0.23/upgrade.py +16 -0
- stouputils-1.0.21/1_upgrades.py +0 -4
- stouputils-1.0.21/2_build.py +0 -4
- stouputils-1.0.21/3_upload.py +0 -10
- stouputils-1.0.21/build_all_in_one.py +0 -14
- stouputils-1.0.21/doctests.py +0 -17
- stouputils-1.0.21/examples/delta_backup.py +0 -7
- stouputils-1.0.21/upgrade.py +0 -58
- {stouputils-1.0.21 → stouputils-1.0.23}/.gitignore +0 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/.python-version +0 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/LICENSE +0 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/README.md +0 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/all_in_one.py +0 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/copy_in_local.py +0 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/github_release.py +0 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/__init__.py +0 -0
- {stouputils-1.0.21 → stouputils-1.0.23}/src/stouputils/py.typed +0 -0
|
@@ -20,7 +20,7 @@ jobs:
|
|
|
20
20
|
- uses: actions/setup-python@v5
|
|
21
21
|
- name: Install dependencies
|
|
22
22
|
run: |
|
|
23
|
-
pip install hatch stouputils sphinx sphinx_rtd_theme myst_parser
|
|
23
|
+
pip install hatch stouputils sphinx sphinx_rtd_theme myst_parser furo
|
|
24
24
|
hatch build
|
|
25
25
|
- name: Build latest docs
|
|
26
26
|
if: github.ref == 'refs/heads/main'
|
|
@@ -37,5 +37,6 @@ jobs:
|
|
|
37
37
|
publish_branch: gh-pages
|
|
38
38
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
39
39
|
publish_dir: docs/build/html
|
|
40
|
+
keep_files: true
|
|
40
41
|
force_orphan: false
|
|
41
42
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stouputils
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.23
|
|
4
4
|
Summary: Stouputils is a collection of utility modules designed to simplify and enhance the development process. It includes a range of tools for tasks such as execution of doctests, display utilities, decorators, as well as context managers, and many more.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Stoupy51/stouputils
|
|
6
6
|
Project-URL: Issues, https://github.com/Stoupy51/stouputils/issues
|
|
@@ -10,8 +10,9 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Classifier: Programming Language :: Python :: 3
|
|
12
12
|
Requires-Python: >=3.10
|
|
13
|
-
Requires-Dist: pyyaml
|
|
13
|
+
Requires-Dist: pyyaml
|
|
14
14
|
Requires-Dist: requests>=2.31.0
|
|
15
|
+
Requires-Dist: toml
|
|
15
16
|
Requires-Dist: tqdm>=4.66.4
|
|
16
17
|
Description-Content-Type: text/markdown
|
|
17
18
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
# Imports
|
|
3
|
+
import stouputils as stp
|
|
4
|
+
|
|
5
|
+
# Constants
|
|
6
|
+
ROOT: str = stp.get_root_path(__file__)
|
|
7
|
+
REPOSITORY: str = "stouputils"
|
|
8
|
+
DIST_DIRECTORY: str = f"{ROOT}/dist"
|
|
9
|
+
LAST_FILES: int = 1
|
|
10
|
+
ENDWITH: str = ".tar.gz"
|
|
11
|
+
|
|
12
|
+
if __name__ == "__main__":
|
|
13
|
+
|
|
14
|
+
stp.pypi_full_routine(
|
|
15
|
+
repository=REPOSITORY,
|
|
16
|
+
dist_directory=DIST_DIRECTORY,
|
|
17
|
+
last_files=LAST_FILES,
|
|
18
|
+
endswith=ENDWITH,
|
|
19
|
+
)
|
|
20
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
# Imports
|
|
3
|
+
import stouputils as stp
|
|
4
|
+
|
|
5
|
+
# Main
|
|
6
|
+
@stp.measure_time(stp.info, message="All doctests finished")
|
|
7
|
+
def main() -> None:
|
|
8
|
+
FOLDER_TO_TEST: str = stp.get_root_path(__file__, 1) + "/src"
|
|
9
|
+
stp.launch_tests(FOLDER_TO_TEST)
|
|
10
|
+
|
|
11
|
+
if __name__ == "__main__":
|
|
12
|
+
main()
|
|
13
|
+
|
|
Binary file
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
# Imports
|
|
3
|
+
import stouputils as stp
|
|
4
|
+
from zipfile import ZipFile, BadZipFile
|
|
5
|
+
|
|
6
|
+
# Main
|
|
7
|
+
if __name__ == "__main__":
|
|
8
|
+
PREFIX: str = "examples/archive"
|
|
9
|
+
|
|
10
|
+
## Repair a corrupted zip file
|
|
11
|
+
# Try to read the first file
|
|
12
|
+
@stp.handle_error(BadZipFile)
|
|
13
|
+
def read_file() -> None:
|
|
14
|
+
with ZipFile(f"{PREFIX}/corrupted.zip", "r") as zip_file:
|
|
15
|
+
stp.info(zip_file.read("pack.mcmeta"))
|
|
16
|
+
read_file()
|
|
17
|
+
|
|
18
|
+
# Repair it
|
|
19
|
+
stp.repair_zip_file(f"{PREFIX}/corrupted.zip", f"{PREFIX}/repaired.zip")
|
|
20
|
+
|
|
21
|
+
# Read the first file
|
|
22
|
+
with ZipFile(f"{PREFIX}/repaired.zip", "r") as zip_file:
|
|
23
|
+
stp.info(zip_file.read("pack.mcmeta"))
|
|
24
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
# Imports
|
|
3
|
+
import stouputils as stp
|
|
4
|
+
|
|
5
|
+
# Main
|
|
6
|
+
if __name__ == "__main__":
|
|
7
|
+
|
|
8
|
+
# Example with numbers
|
|
9
|
+
numbers: list[int] = [1, 2, 3, 2, 1, 4, 3]
|
|
10
|
+
unique_numbers: list[int] = stp.unique_list(numbers)
|
|
11
|
+
stp.info(f"Original numbers: {numbers}")
|
|
12
|
+
stp.info(f"Unique numbers: {unique_numbers}")
|
|
13
|
+
|
|
14
|
+
# Example with sets using different methods
|
|
15
|
+
s1: set[int] = {1, 2, 3}
|
|
16
|
+
s2: set[int] = {2, 3, 4}
|
|
17
|
+
s3: set[int] = {1, 2, 3}
|
|
18
|
+
sets: list[set[int]] = [s1, s2, s1, s1, s3, s2, s3]
|
|
19
|
+
|
|
20
|
+
# Using id method (keeps s1 and s3 as separate objects)
|
|
21
|
+
unique_sets_id: list[set[int]] = stp.unique_list(sets, method="id")
|
|
22
|
+
stp.info(f"Unique sets (id method): {unique_sets_id}")
|
|
23
|
+
|
|
24
|
+
# Using str method (combines s1 and s3 as they have same string representation)
|
|
25
|
+
unique_sets_str: list[set[int]] = stp.unique_list(sets, method="str")
|
|
26
|
+
stp.info(f"Unique sets (str method): {unique_sets_str}")
|
|
27
|
+
|
|
28
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
|
|
2
|
+
# Imports
|
|
3
|
+
import stouputils as stp
|
|
4
|
+
import sys
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
# Main
|
|
8
|
+
if __name__ == "__main__":
|
|
9
|
+
|
|
10
|
+
with stp.Muffle(mute_stderr=True):
|
|
11
|
+
print("Nothing")
|
|
12
|
+
print("here", file=sys.stderr)
|
|
13
|
+
stp.info("will be")
|
|
14
|
+
stp.info("printed", file=sys.stderr)
|
|
15
|
+
|
|
16
|
+
OUTPUT_PATH: str = "_super_idol_de_xiao_rong.log"
|
|
17
|
+
with stp.LogToFile(OUTPUT_PATH):
|
|
18
|
+
stp.info("""
|
|
19
|
+
Why did the programmer always bring a ladder to work?
|
|
20
|
+
Because they spent so much time debugging and climbing through their log files!
|
|
21
|
+
""")
|
|
22
|
+
|
|
23
|
+
stp.breakpoint("Press Enter to continue...")
|
|
24
|
+
os.remove(OUTPUT_PATH)
|
|
25
|
+
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
# Imports
|
|
3
|
+
import stouputils as stp
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
# Main
|
|
7
|
+
if __name__ == "__main__":
|
|
8
|
+
|
|
9
|
+
# Cache the result of the function and measure the time it takes to execute
|
|
10
|
+
@stp.measure_time(stp.progress, "Time taken to execute long_function")
|
|
11
|
+
@stp.simple_cache()
|
|
12
|
+
def long_function() -> dict[str, int]:
|
|
13
|
+
stp.info("Starting long function...")
|
|
14
|
+
time.sleep(1)
|
|
15
|
+
stp.info("Long function finished!")
|
|
16
|
+
return {"a": 1, "b": 2}
|
|
17
|
+
|
|
18
|
+
a = long_function() # Takes 1 second
|
|
19
|
+
b = long_function() # Takes 0 second
|
|
20
|
+
stp.info(f"a: {a}, b: {b}, a is b: {a is b}")
|
|
21
|
+
b["c"] = 3
|
|
22
|
+
stp.info(f"a has been modified because a is b: {a}")
|
|
23
|
+
|
|
24
|
+
# Silent decorator
|
|
25
|
+
@stp.silent
|
|
26
|
+
def silent_function():
|
|
27
|
+
print("ON THE CONSOLE")
|
|
28
|
+
silent_function()
|
|
29
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
# Imports
|
|
3
|
+
import stouputils as stp
|
|
4
|
+
|
|
5
|
+
# Main
|
|
6
|
+
if __name__ == "__main__":
|
|
7
|
+
|
|
8
|
+
# Handle exceptions
|
|
9
|
+
@stp.handle_error(ZeroDivisionError,
|
|
10
|
+
"Debugging: The process of removing software bugs, and putting in new ones",
|
|
11
|
+
error_log=stp.LogLevels.WARNING_TRACEBACK
|
|
12
|
+
)
|
|
13
|
+
def raise_value_error():
|
|
14
|
+
return 1 / 0
|
|
15
|
+
|
|
16
|
+
@stp.handle_error()
|
|
17
|
+
def raise_value_error_2():
|
|
18
|
+
return 1 / 0
|
|
19
|
+
|
|
20
|
+
raise_value_error() # This will show the error using stp.warning
|
|
21
|
+
raise_value_error_2() # This will show the error using stp.error
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
# Imports
|
|
3
|
+
import stouputils as stp
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
# Main
|
|
7
|
+
if __name__ == "__main__":
|
|
8
|
+
|
|
9
|
+
path: str = "C:\\\\Users\\\\Stoupy\\\\Documents\\\\test.txt"
|
|
10
|
+
path = stp.clean_path(path)
|
|
11
|
+
stp.info(path)
|
|
12
|
+
|
|
13
|
+
tilde_path: str = "~/Desktop/OnlyFansIncome.txt"
|
|
14
|
+
tilde_path = stp.replace_tilde(tilde_path)
|
|
15
|
+
stp.info(tilde_path)
|
|
16
|
+
|
|
17
|
+
this_folder_dont_exist: str = "./this_folder_dont_exist/a/c/feff/efefe/a"
|
|
18
|
+
with stp.super_open(this_folder_dont_exist, "w") as file: # Automatically create the folder
|
|
19
|
+
file.write("Hello, world!")
|
|
20
|
+
|
|
21
|
+
# Copy a file to a folder, or rename the copied file
|
|
22
|
+
stp.super_copy("LICENSE", "this_folder_dont_exist/a/") # .../a/LICENSE
|
|
23
|
+
stp.super_copy("LICENSE", "this_folder_dont_exist/a/LICENSE_2") # .../a/LICENSE_2
|
|
24
|
+
stp.breakpoint("Waiting for input to continue code execution...")
|
|
25
|
+
|
|
26
|
+
# Dump a JSON file with a specified indentation depth
|
|
27
|
+
data: dict[str, Any] = {"name": "John", "array": [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]}
|
|
28
|
+
stp.info("\n", stp.super_json_dump(data, max_level=2))
|
|
29
|
+
|
|
30
|
+
# Remove the folder
|
|
31
|
+
import shutil
|
|
32
|
+
shutil.rmtree("this_folder_dont_exist")
|
|
33
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
# Imports
|
|
3
|
+
import stouputils as stp
|
|
4
|
+
import time
|
|
5
|
+
|
|
6
|
+
# Functions
|
|
7
|
+
def is_even(n: int) -> bool:
|
|
8
|
+
return n % 2 == 0
|
|
9
|
+
|
|
10
|
+
def multiple_args(a: int, b: int) -> int:
|
|
11
|
+
return a * b
|
|
12
|
+
|
|
13
|
+
# Main
|
|
14
|
+
if __name__ == "__main__":
|
|
15
|
+
|
|
16
|
+
# Multi-threading (blazingly fast for IO-bound tasks)
|
|
17
|
+
args_1: list[int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
18
|
+
results_1: list[bool] = stp.multithreading(is_even, args_1)
|
|
19
|
+
stp.info(f"Results: {results_1}")
|
|
20
|
+
|
|
21
|
+
# Multi-processing (better for CPU-bound tasks)
|
|
22
|
+
time.sleep(1)
|
|
23
|
+
args_2: list[tuple[int, int]] = [(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
|
|
24
|
+
results_2: list[int] = stp.multiprocessing(
|
|
25
|
+
multiple_args, args_2, use_starmap=True, desc="Multiple args", max_workers=2, verbose=1
|
|
26
|
+
)
|
|
27
|
+
stp.info(f"Results: {results_2}")
|
|
28
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
# Imports
|
|
3
|
+
import time
|
|
4
|
+
import stouputils as stp
|
|
5
|
+
|
|
6
|
+
# Main
|
|
7
|
+
if __name__ == "__main__":
|
|
8
|
+
stp.info("Hello", "World")
|
|
9
|
+
time.sleep(0.5)
|
|
10
|
+
stp.info("Hello", "World")
|
|
11
|
+
time.sleep(0.5)
|
|
12
|
+
stp.info("Hello", "World")
|
|
13
|
+
time.sleep(0.5)
|
|
14
|
+
stp.info("Not Hello World !")
|
|
15
|
+
time.sleep(0.5)
|
|
16
|
+
stp.info("Hello", "World")
|
|
17
|
+
time.sleep(0.5)
|
|
18
|
+
stp.info("Hello", "World")
|
|
19
|
+
|
|
20
|
+
# All remaining print functions
|
|
21
|
+
stp.debug("Hello", "World")
|
|
22
|
+
stp.suggestion("Hello", "World")
|
|
23
|
+
stp.progress("Hello", "World")
|
|
24
|
+
stp.warning("Hello", "World")
|
|
25
|
+
stp.error("Hello", "World", exit=False)
|
|
26
|
+
stp.whatisit("Hello", "World")
|
|
27
|
+
|
|
@@ -1,27 +1,18 @@
|
|
|
1
|
-
|
|
2
1
|
[build-system]
|
|
3
|
-
requires = ["hatchling"]
|
|
2
|
+
requires = [ "hatchling",]
|
|
4
3
|
build-backend = "hatchling.build"
|
|
5
4
|
|
|
6
5
|
[project]
|
|
7
6
|
name = "stouputils"
|
|
8
|
-
version = "1.0.
|
|
9
|
-
authors = [
|
|
10
|
-
{ name="Stoupy51", email="stoupy51@gmail.com" },
|
|
11
|
-
]
|
|
7
|
+
version = "1.0.23"
|
|
12
8
|
description = "Stouputils is a collection of utility modules designed to simplify and enhance the development process. It includes a range of tools for tasks such as execution of doctests, display utilities, decorators, as well as context managers, and many more."
|
|
13
9
|
readme = "README.md"
|
|
14
10
|
requires-python = ">=3.10"
|
|
15
|
-
classifiers = [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
dependencies = [
|
|
21
|
-
"tqdm>=4.66.4",
|
|
22
|
-
"requests>=2.31.0",
|
|
23
|
-
"pyyaml>=6.0.2",
|
|
24
|
-
]
|
|
11
|
+
classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent",]
|
|
12
|
+
dependencies = [ "tqdm>=4.66.4", "requests>=2.31.0", "pyyaml", "toml",]
|
|
13
|
+
[[project.authors]]
|
|
14
|
+
name = "Stoupy51"
|
|
15
|
+
email = "stoupy51@gmail.com"
|
|
25
16
|
|
|
26
17
|
[project.urls]
|
|
27
18
|
Homepage = "https://github.com/Stoupy51/stouputils"
|
|
@@ -29,4 +20,3 @@ Issues = "https://github.com/Stoupy51/stouputils/issues"
|
|
|
29
20
|
|
|
30
21
|
[tool.pyright]
|
|
31
22
|
typeCheckingMode = "strict"
|
|
32
|
-
|
|
@@ -4,7 +4,8 @@ import os
|
|
|
4
4
|
import shutil
|
|
5
5
|
import subprocess
|
|
6
6
|
import sys
|
|
7
|
-
from stouputils import clean_path, handle_error
|
|
7
|
+
from stouputils import clean_path, handle_error, warning, simple_cache
|
|
8
|
+
from stouputils.continuous_delivery.github import version_to_float
|
|
8
9
|
clean_exec: str = clean_path(sys.executable)
|
|
9
10
|
|
|
10
11
|
conf_content: str = """
|
|
@@ -26,21 +27,45 @@ release: str = current_version
|
|
|
26
27
|
extensions: list[str] = [
|
|
27
28
|
'sphinx.ext.autodoc',
|
|
28
29
|
'sphinx.ext.napoleon',
|
|
29
|
-
'sphinx.ext.viewcode',
|
|
30
|
+
'sphinx.ext.viewcode',
|
|
30
31
|
'sphinx.ext.githubpages',
|
|
31
32
|
'sphinx.ext.intersphinx',
|
|
33
|
+
'furo.sphinxext',
|
|
32
34
|
]
|
|
33
35
|
|
|
34
36
|
templates_path: list[str] = ['_templates']
|
|
35
37
|
exclude_patterns: list[str] = []
|
|
36
38
|
|
|
37
39
|
# HTML output options
|
|
38
|
-
html_theme: str = '
|
|
40
|
+
html_theme: str = 'furo'
|
|
39
41
|
html_static_path: list[str] = ['_static']
|
|
42
|
+
html_logo: str = 'https://avatars.githubusercontent.com/u/35665974'
|
|
43
|
+
html_title: str = 'stouputils'
|
|
44
|
+
html_favicon: str = 'https://avatars.githubusercontent.com/u/35665974'
|
|
40
45
|
|
|
41
46
|
# Theme options
|
|
42
47
|
html_theme_options: dict[str, Any] = {
|
|
43
|
-
'
|
|
48
|
+
'light_css_variables': {
|
|
49
|
+
'color-brand-primary': '#2980B9',
|
|
50
|
+
'color-brand-content': '#2980B9',
|
|
51
|
+
'color-admonition-background': '#E8F0F8',
|
|
52
|
+
},
|
|
53
|
+
'dark_css_variables': {
|
|
54
|
+
'color-brand-primary': '#56B4E9',
|
|
55
|
+
'color-brand-content': '#56B4E9',
|
|
56
|
+
'color-admonition-background': '#1F262B',
|
|
57
|
+
},
|
|
58
|
+
'sidebar_hide_name': False,
|
|
59
|
+
'navigation_with_keys': True,
|
|
60
|
+
'announcement': 'This is the latest documentation of stouputils',
|
|
61
|
+
'footer_icons': [
|
|
62
|
+
{
|
|
63
|
+
'name': 'GitHub',
|
|
64
|
+
'url': 'https://github.com/Stoupy51/stouputils',
|
|
65
|
+
'html': '<i class="fab fa-github-square"></i>',
|
|
66
|
+
'class': '',
|
|
67
|
+
},
|
|
68
|
+
],
|
|
44
69
|
}
|
|
45
70
|
|
|
46
71
|
# Add any paths that contain custom static files
|
|
@@ -71,6 +96,7 @@ html_context = {
|
|
|
71
96
|
'github_version': 'main',
|
|
72
97
|
'conf_py_path': '/docs/source/',
|
|
73
98
|
'source_suffix': '.rst',
|
|
99
|
+
'default_mode': 'dark',
|
|
74
100
|
}
|
|
75
101
|
|
|
76
102
|
# Only document items with docstrings
|
|
@@ -83,6 +109,30 @@ def setup(app: Any) -> None:
|
|
|
83
109
|
app.connect('autodoc-skip-member', skip_undocumented)
|
|
84
110
|
"""
|
|
85
111
|
|
|
112
|
+
@simple_cache()
|
|
113
|
+
def get_versions_from_github() -> list[str]:
|
|
114
|
+
""" Get list of versions from GitHub gh-pages branch.
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
list[str]: List of versions, with 'latest' as first element
|
|
118
|
+
"""
|
|
119
|
+
import requests
|
|
120
|
+
version_list: list[str] = []
|
|
121
|
+
try:
|
|
122
|
+
response = requests.get("https://api.github.com/repos/Stoupy51/stouputils/contents?ref=gh-pages")
|
|
123
|
+
if response.status_code == 200:
|
|
124
|
+
contents = response.json()
|
|
125
|
+
version_list = ["latest"] + sorted(
|
|
126
|
+
[d["name"].replace("v", "") for d in contents
|
|
127
|
+
if d["type"] == "dir" and d["name"].startswith("v")],
|
|
128
|
+
key=version_to_float,
|
|
129
|
+
reverse=True
|
|
130
|
+
)
|
|
131
|
+
except Exception as e:
|
|
132
|
+
warning(f"Failed to get versions from GitHub: {e}")
|
|
133
|
+
version_list = ["latest"]
|
|
134
|
+
return version_list
|
|
135
|
+
|
|
86
136
|
def generate_index_rst(readme_path: str, index_path: str) -> None:
|
|
87
137
|
""" Generate index.rst from README.md content.
|
|
88
138
|
|
|
@@ -107,14 +157,8 @@ def generate_index_rst(readme_path: str, index_path: str) -> None:
|
|
|
107
157
|
|
|
108
158
|
**Versions**: """
|
|
109
159
|
|
|
110
|
-
#
|
|
111
|
-
version_list: list[str] =
|
|
112
|
-
html_dir = "docs/build/html"
|
|
113
|
-
if os.path.exists(html_dir):
|
|
114
|
-
version_list = [d[1:] for d in os.listdir(html_dir) if d.startswith('v')]
|
|
115
|
-
from stouputils.continuous_delivery.github import version_to_float
|
|
116
|
-
version_list.sort(key=version_to_float, reverse=True)
|
|
117
|
-
version_list.insert(0, 'latest')
|
|
160
|
+
# Get versions from GitHub
|
|
161
|
+
version_list: list[str] = get_versions_from_github()
|
|
118
162
|
|
|
119
163
|
# Create version links
|
|
120
164
|
version_links: list[str] = []
|
|
@@ -218,10 +262,7 @@ def update_documentation(version: str | None = None) -> None:
|
|
|
218
262
|
os.makedirs(modules_dir)
|
|
219
263
|
|
|
220
264
|
# Update conf.py to include version selector
|
|
221
|
-
version_list: list[str] =
|
|
222
|
-
if os.path.exists(clean_path(f"{docs_dir}/build/html")):
|
|
223
|
-
version_list = [d.replace("v", "") for d in os.listdir(clean_path(f"{docs_dir}/build/html"))
|
|
224
|
-
if d.startswith("v")] + ["latest"]
|
|
265
|
+
version_list: list[str] = get_versions_from_github()
|
|
225
266
|
|
|
226
267
|
# Update html_context in conf.py
|
|
227
268
|
global conf_content
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module is used to run all the doctests for all the modules in a given directory.
|
|
3
|
+
|
|
4
|
+
.. image:: https://raw.githubusercontent.com/Stoupy51/stouputils/refs/heads/main/assets/all_doctests_module.gif
|
|
5
|
+
:alt: stouputils all_doctests examples
|
|
3
6
|
"""
|
|
4
7
|
|
|
5
8
|
# Imports
|
|
6
9
|
import os
|
|
7
10
|
import sys
|
|
8
|
-
from .print import
|
|
9
|
-
from .decorators import measure_time, handle_error, LogLevels
|
|
11
|
+
from .print import info, error, progress
|
|
12
|
+
from .decorators import measure_time, handle_error, LogLevels
|
|
13
|
+
from . import decorators
|
|
10
14
|
from doctest import TestResults, testmod
|
|
11
15
|
from types import ModuleType
|
|
12
16
|
import importlib
|
|
@@ -46,10 +50,9 @@ def launch_tests(root_dir: str, importing_errors: LogLevels = LogLevels.WARNING_
|
|
|
46
50
|
[PROGRESS HH:MM:SS] Testing module 'module3' took 0.007s
|
|
47
51
|
[PROGRESS HH:MM:SS] Testing module 'module4' took 0.008s
|
|
48
52
|
"""
|
|
49
|
-
global force_raise_exception
|
|
50
53
|
if strict:
|
|
51
54
|
old_value: bool = strict
|
|
52
|
-
force_raise_exception = True
|
|
55
|
+
decorators.force_raise_exception = True
|
|
53
56
|
strict = old_value
|
|
54
57
|
|
|
55
58
|
|
|
@@ -91,5 +94,5 @@ def launch_tests(root_dir: str, importing_errors: LogLevels = LogLevels.WARNING_
|
|
|
91
94
|
error(f"Errors in module {module.__name__}", exit=False)
|
|
92
95
|
|
|
93
96
|
# Reset force_raise_exception back
|
|
94
|
-
force_raise_exception = strict
|
|
97
|
+
decorators.force_raise_exception = strict
|
|
95
98
|
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
"""
|
|
2
2
|
This module provides functions for creating and managing archives.
|
|
3
3
|
|
|
4
|
-
- make_archive:
|
|
5
|
-
- repair_zip_file: Try to repair a corrupted zip file
|
|
4
|
+
- make_archive: Create a zip archive from a source directory with consistent file timestamps.
|
|
5
|
+
- repair_zip_file: Try to repair a corrupted zip file by ignoring some of the errors
|
|
6
|
+
|
|
7
|
+
.. image:: https://raw.githubusercontent.com/Stoupy51/stouputils/refs/heads/main/assets/archive_module.gif
|
|
8
|
+
:alt: stouputils archive examples
|
|
6
9
|
"""
|
|
7
10
|
|
|
8
11
|
# Imports
|
|
9
|
-
|
|
10
|
-
from .print import *
|
|
12
|
+
import os
|
|
11
13
|
from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED
|
|
14
|
+
from .io import clean_path, super_copy
|
|
15
|
+
from .decorators import handle_error, LogLevels
|
|
16
|
+
from .dont_look.zip_file_override import ZipFileOverride
|
|
12
17
|
|
|
13
18
|
# Function that makes an archive with consistency (same zip file each time)
|
|
14
19
|
@handle_error()
|
|
@@ -18,7 +23,12 @@ def make_archive(
|
|
|
18
23
|
override_time: None | tuple[int, int, int, int, int, int] = None,
|
|
19
24
|
create_dir: bool = False
|
|
20
25
|
) -> bool:
|
|
21
|
-
"""
|
|
26
|
+
""" Create a zip archive from a source directory with consistent file timestamps.
|
|
27
|
+
(Meaning deterministic zip file each time)
|
|
28
|
+
|
|
29
|
+
Creates a zip archive from the source directory and copies it to one or more destinations.
|
|
30
|
+
The archive will have consistent file timestamps across runs if override_time is specified.
|
|
31
|
+
Uses maximum compression level (9) with ZIP_DEFLATED algorithm.
|
|
22
32
|
|
|
23
33
|
Args:
|
|
24
34
|
source (str): The source folder to archive
|
|
@@ -33,6 +43,7 @@ def make_archive(
|
|
|
33
43
|
|
|
34
44
|
> make_archive("/path/to/source", "/path/to/destination.zip")
|
|
35
45
|
> make_archive("/path/to/source", ["/path/to/destination.zip", "/path/to/destination2.zip"])
|
|
46
|
+
> make_archive("src", "hello_from_year_2085.zip", override_time=(2085,1,1,0,0,0))
|
|
36
47
|
"""
|
|
37
48
|
# Fix copy_destinations type if needed
|
|
38
49
|
if destinations and isinstance(destinations, str):
|
|
@@ -66,7 +77,6 @@ def make_archive(
|
|
|
66
77
|
|
|
67
78
|
|
|
68
79
|
# Function that repair a corrupted zip file (ignoring some of the errors)
|
|
69
|
-
from .dont_look.zip_file_override import ZipFileOverride
|
|
70
80
|
@handle_error()
|
|
71
81
|
def repair_zip_file(file_path: str, destination: str) -> bool:
|
|
72
82
|
""" Try to repair a corrupted zip file by ignoring some of the errors
|
|
@@ -5,6 +5,9 @@ This module provides utilities for backup management.
|
|
|
5
5
|
- create_delta_backup: Creates a ZIP delta backup, saving only modified or new files while tracking deleted files
|
|
6
6
|
- consolidate_backups: Consolidates the files from the given backup and all previous ones into a new ZIP file
|
|
7
7
|
- backup_cli: Main entry point for command line usage
|
|
8
|
+
|
|
9
|
+
.. image:: https://raw.githubusercontent.com/Stoupy51/stouputils/refs/heads/main/assets/backup_module.gif
|
|
10
|
+
:alt: stouputils backup examples
|
|
8
11
|
"""
|
|
9
12
|
|
|
10
13
|
# Standard library imports
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
This module provides utilities for collection manipulation:
|
|
3
3
|
|
|
4
4
|
- unique_list: Remove duplicates from a list while preserving order using object id, hash or str
|
|
5
|
+
|
|
6
|
+
.. image:: https://raw.githubusercontent.com/Stoupy51/stouputils/refs/heads/main/assets/collections_module.gif
|
|
7
|
+
:alt: stouputils collections examples
|
|
5
8
|
"""
|
|
6
9
|
|
|
7
10
|
# Imports
|
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
""" This module contains utilities for continuous delivery on GitHub.
|
|
2
2
|
|
|
3
3
|
- upload_to_github: Upload the project to GitHub using the credentials and the configuration (make a release and upload the assets, handle existing tag, generate changelog, etc.)
|
|
4
|
+
|
|
5
|
+
.. image:: https://raw.githubusercontent.com/Stoupy51/stouputils/refs/heads/main/assets/continuous_delivery/github_module.gif
|
|
6
|
+
:alt: stouputils upload_to_github examples
|
|
4
7
|
"""
|
|
5
8
|
|
|
6
9
|
# Imports
|
|
7
|
-
from ..print import
|
|
8
|
-
from ..decorators import measure_time
|
|
9
|
-
from
|
|
10
|
+
from ..print import info, warning, progress
|
|
11
|
+
from ..decorators import measure_time, handle_error
|
|
12
|
+
from ..io import clean_path
|
|
13
|
+
from .cd_utils import handle_response
|
|
14
|
+
from typing import Any
|
|
15
|
+
import requests
|
|
16
|
+
import os
|
|
10
17
|
|
|
11
18
|
# Constants
|
|
12
19
|
GITHUB_API_URL: str = "https://api.github.com"
|
|
@@ -131,7 +138,7 @@ def delete_existing_tag(tag_url: str, headers: dict[str, str]) -> None:
|
|
|
131
138
|
"""
|
|
132
139
|
delete_response: requests.Response = requests.delete(tag_url, headers=headers)
|
|
133
140
|
handle_response(delete_response, "Failed to delete existing tag")
|
|
134
|
-
info(
|
|
141
|
+
info("Deleted existing tag")
|
|
135
142
|
|
|
136
143
|
def clean_version(version: str, keep: str = "") -> str:
|
|
137
144
|
""" Clean a version string
|