dycw-actions 0.2.2__py3-none-any.whl → 0.6.4__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.
- actions/__init__.py +1 -1
- actions/action_dicts/constants.py +8 -0
- actions/action_dicts/lib.py +186 -0
- actions/clean_dir/cli.py +33 -0
- actions/clean_dir/lib.py +59 -0
- actions/clean_dir/settings.py +18 -0
- actions/cli.py +44 -6
- actions/conformalize_repo/cli.py +76 -0
- actions/conformalize_repo/configs/gitignore +244 -0
- actions/conformalize_repo/constants.py +72 -0
- actions/conformalize_repo/lib.py +1522 -0
- actions/conformalize_repo/settings.py +119 -0
- actions/constants.py +10 -0
- actions/format_requirements/__init__.py +1 -0
- actions/format_requirements/cli.py +37 -0
- actions/format_requirements/lib.py +121 -0
- actions/publish_package/__init__.py +1 -0
- actions/publish_package/cli.py +39 -0
- actions/publish_package/doc.py +6 -0
- actions/{publish → publish_package}/lib.py +17 -16
- actions/publish_package/settings.py +31 -0
- actions/random_sleep/__init__.py +1 -0
- actions/random_sleep/cli.py +35 -0
- actions/random_sleep/doc.py +6 -0
- actions/{sleep → random_sleep}/lib.py +14 -13
- actions/{sleep → random_sleep}/settings.py +4 -4
- actions/replace_sequence_strs/__init__.py +1 -0
- actions/replace_sequence_strs/cli.py +37 -0
- actions/replace_sequence_strs/lib.py +79 -0
- actions/run_hooks/__init__.py +1 -0
- actions/run_hooks/cli.py +33 -0
- actions/run_hooks/doc.py +6 -0
- actions/run_hooks/lib.py +97 -0
- actions/run_hooks/settings.py +24 -0
- actions/setup_cronjob/__init__.py +1 -0
- actions/setup_cronjob/cli.py +43 -0
- actions/setup_cronjob/configs/cron.tmpl +3 -0
- actions/setup_cronjob/configs/logrotate.tmpl +10 -0
- actions/setup_cronjob/constants.py +8 -0
- actions/setup_cronjob/lib.py +120 -0
- actions/setup_cronjob/settings.py +27 -0
- actions/tag_commit/__init__.py +1 -0
- actions/tag_commit/cli.py +39 -0
- actions/tag_commit/doc.py +6 -0
- actions/tag_commit/lib.py +63 -0
- actions/{tag → tag_commit}/settings.py +4 -4
- actions/types.py +18 -0
- actions/utilities.py +97 -10
- dycw_actions-0.6.4.dist-info/METADATA +21 -0
- dycw_actions-0.6.4.dist-info/RECORD +56 -0
- {dycw_actions-0.2.2.dist-info → dycw_actions-0.6.4.dist-info}/WHEEL +1 -1
- actions/publish/cli.py +0 -45
- actions/publish/settings.py +0 -35
- actions/settings.py +0 -19
- actions/sleep/cli.py +0 -39
- actions/tag/cli.py +0 -43
- actions/tag/lib.py +0 -60
- dycw_actions-0.2.2.dist-info/METADATA +0 -14
- dycw_actions-0.2.2.dist-info/RECORD +0 -21
- /actions/{publish → action_dicts}/__init__.py +0 -0
- /actions/{sleep → clean_dir}/__init__.py +0 -0
- /actions/{tag → conformalize_repo}/__init__.py +0 -0
- {dycw_actions-0.2.2.dist-info → dycw_actions-0.6.4.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typed_settings import load_settings, option, settings
|
|
4
|
+
|
|
5
|
+
from actions.conformalize_repo.constants import RUN_VERSION_BUMP
|
|
6
|
+
from actions.utilities import LOADER
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@settings
|
|
10
|
+
class Settings:
|
|
11
|
+
coverage: bool = option(default=False, help="Set up '.coveragerc.toml'")
|
|
12
|
+
description: str | None = option(default=None, help="Repo description")
|
|
13
|
+
envrc: bool = option(default=False, help="Set up '.envrc'")
|
|
14
|
+
envrc__uv: bool = option(default=False, help="Set up '.envrc' with uv")
|
|
15
|
+
envrc__uv__native_tls: bool = option(
|
|
16
|
+
default=False, help="Set up '.envrc' with uv native TLS"
|
|
17
|
+
)
|
|
18
|
+
github__pull_request__pre_commit: bool = option(
|
|
19
|
+
default=False, help="Set up 'pull-request.yaml' pre-commit"
|
|
20
|
+
)
|
|
21
|
+
github__pull_request__pre_commit__gitea: bool = option(
|
|
22
|
+
default=False, help="Set up 'pull-request.yaml' for Gitea"
|
|
23
|
+
)
|
|
24
|
+
github__pull_request__pyright: bool = option(
|
|
25
|
+
default=False, help="Set up 'pull-request.yaml' pyright"
|
|
26
|
+
)
|
|
27
|
+
github__pull_request__pytest__macos: bool = option(
|
|
28
|
+
default=False, help="Set up 'pull-request.yaml' pytest with MacOS"
|
|
29
|
+
)
|
|
30
|
+
github__pull_request__pytest__ubuntu: bool = option(
|
|
31
|
+
default=False, help="Set up 'pull-request.yaml' pytest with Ubuntu"
|
|
32
|
+
)
|
|
33
|
+
github__pull_request__pytest__windows: bool = option(
|
|
34
|
+
default=False, help="Set up 'pull-request.yaml' pytest with Windows"
|
|
35
|
+
)
|
|
36
|
+
github__pull_request__ruff: bool = option(
|
|
37
|
+
default=False, help="Set up 'pull-request.yaml' ruff"
|
|
38
|
+
)
|
|
39
|
+
github__push__publish: bool = option(
|
|
40
|
+
default=False, help="Set up 'push.yaml' publishing"
|
|
41
|
+
)
|
|
42
|
+
github__push__tag: bool = option(default=False, help="Set up 'push.yaml' tagging")
|
|
43
|
+
github__push__tag__major: bool = option(
|
|
44
|
+
default=False, help="Set up 'push.yaml' with the 'major' tag"
|
|
45
|
+
)
|
|
46
|
+
github__push__tag__major_minor: bool = option(
|
|
47
|
+
default=False, help="Set up 'push.yaml' with the 'major.minor' tag"
|
|
48
|
+
)
|
|
49
|
+
github__push__tag__latest: bool = option(
|
|
50
|
+
default=False, help="Set up 'push.yaml' tagging"
|
|
51
|
+
)
|
|
52
|
+
gitignore: bool = option(default=False, help="Set up '.gitignore'")
|
|
53
|
+
package_name: str | None = option(default=None, help="Package name")
|
|
54
|
+
pre_commit__dockerfmt: bool = option(
|
|
55
|
+
default=False, help="Set up '.pre-commit-config.yaml' dockerfmt"
|
|
56
|
+
)
|
|
57
|
+
pre_commit__prettier: bool = option(
|
|
58
|
+
default=False, help="Set up '.pre-commit-config.yaml' prettier"
|
|
59
|
+
)
|
|
60
|
+
pre_commit__python: bool = option(
|
|
61
|
+
default=False, help="Set up '.pre-commit-config.yaml' python"
|
|
62
|
+
)
|
|
63
|
+
pre_commit__ruff: bool = option(
|
|
64
|
+
default=False, help="Set up '.pre-commit-config.yaml' ruff"
|
|
65
|
+
)
|
|
66
|
+
pre_commit__shell: bool = option(
|
|
67
|
+
default=False, help="Set up '.pre-commit-config.yaml' shell"
|
|
68
|
+
)
|
|
69
|
+
pre_commit__taplo: bool = option(
|
|
70
|
+
default=False, help="Set up '.pre-commit-config.yaml' taplo"
|
|
71
|
+
)
|
|
72
|
+
pre_commit__uv: bool = option(
|
|
73
|
+
default=False, help="Set up '.pre-commit-config.yaml' uv"
|
|
74
|
+
)
|
|
75
|
+
pre_commit__uv__script: str | None = option(
|
|
76
|
+
default=None, help="Set up '.pre-commit-config.yaml' uv lock script"
|
|
77
|
+
)
|
|
78
|
+
pyproject: bool = option(default=False, help="Set up 'pyproject.toml'")
|
|
79
|
+
pyproject__project__optional_dependencies__scripts: bool = option(
|
|
80
|
+
default=False,
|
|
81
|
+
help="Set up 'pyproject.toml' [project.optional-dependencies.scripts]",
|
|
82
|
+
)
|
|
83
|
+
pyproject__tool__uv__indexes: list[tuple[str, str]] = option(
|
|
84
|
+
factory=list, help="Set up 'pyproject.toml' [[uv.tool.index]]"
|
|
85
|
+
)
|
|
86
|
+
pyright: bool = option(default=False, help="Set up 'pyrightconfig.json'")
|
|
87
|
+
pytest: bool = option(default=False, help="Set up 'pytest.toml'")
|
|
88
|
+
pytest__asyncio: bool = option(default=False, help="Set up 'pytest.toml' asyncio_*")
|
|
89
|
+
pytest__ignore_warnings: bool = option(
|
|
90
|
+
default=False, help="Set up 'pytest.toml' filterwarnings"
|
|
91
|
+
)
|
|
92
|
+
pytest__timeout: int | None = option(
|
|
93
|
+
default=None, help="Set up 'pytest.toml' timeout"
|
|
94
|
+
)
|
|
95
|
+
python_package_name: str | None = option(
|
|
96
|
+
default=None, help="Python package name override"
|
|
97
|
+
)
|
|
98
|
+
python_version: str = option(default="3.14", help="Python version")
|
|
99
|
+
readme: bool = option(default=False, help="Set up 'README.md'")
|
|
100
|
+
repo_name: str | None = option(default=None, help="Repo name")
|
|
101
|
+
ruff: bool = option(default=False, help="Set up 'ruff.toml'")
|
|
102
|
+
run_version_bump: bool = option(default=RUN_VERSION_BUMP, help="Run version bump")
|
|
103
|
+
script: str | None = option(
|
|
104
|
+
default=None, help="Set up a script instead of a package"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def python_package_name_use(self) -> str | None:
|
|
109
|
+
if self.python_package_name is not None:
|
|
110
|
+
return self.python_package_name
|
|
111
|
+
if self.package_name is not None:
|
|
112
|
+
return self.package_name.replace("-", "_")
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
SETTINGS = load_settings(Settings, [LOADER])
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
__all__ = ["SETTINGS", "Settings"]
|
actions/constants.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from click import argument
|
|
7
|
+
from utilities.logging import basic_config
|
|
8
|
+
from utilities.os import is_pytest
|
|
9
|
+
from utilities.text import strip_and_dedent
|
|
10
|
+
|
|
11
|
+
from actions import __version__
|
|
12
|
+
from actions.format_requirements.lib import format_requirements
|
|
13
|
+
from actions.logging import LOGGER
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@argument(
|
|
17
|
+
"paths",
|
|
18
|
+
nargs=-1,
|
|
19
|
+
type=click.Path(exists=True, file_okay=True, dir_okay=False, path_type=Path),
|
|
20
|
+
)
|
|
21
|
+
def format_requirements_sub_cmd(*, paths: tuple[Path, ...]) -> None:
|
|
22
|
+
if is_pytest():
|
|
23
|
+
return
|
|
24
|
+
basic_config(obj=LOGGER)
|
|
25
|
+
LOGGER.info(
|
|
26
|
+
strip_and_dedent("""
|
|
27
|
+
Running '%s' (version %s) with settings:
|
|
28
|
+
- paths = %s
|
|
29
|
+
"""),
|
|
30
|
+
format_requirements.__name__,
|
|
31
|
+
__version__,
|
|
32
|
+
paths,
|
|
33
|
+
)
|
|
34
|
+
format_requirements(*paths)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
__all__ = ["format_requirements_sub_cmd"]
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import TYPE_CHECKING, Any, override
|
|
6
|
+
|
|
7
|
+
from packaging._tokenizer import ParserSyntaxError
|
|
8
|
+
from packaging.requirements import InvalidRequirement, Requirement, _parse_requirement
|
|
9
|
+
from packaging.specifiers import Specifier, SpecifierSet
|
|
10
|
+
from tomlkit import TOMLDocument, array, dumps, loads, string
|
|
11
|
+
from tomlkit.items import Array, Table
|
|
12
|
+
from utilities.text import repr_str, strip_and_dedent
|
|
13
|
+
|
|
14
|
+
from actions import __version__
|
|
15
|
+
from actions.logging import LOGGER
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from collections.abc import Iterator
|
|
19
|
+
|
|
20
|
+
from utilities.types import PathLike
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
_MODIFICATIONS: set[Path] = set()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def format_requirements(*paths: PathLike) -> None:
|
|
27
|
+
LOGGER.info(
|
|
28
|
+
strip_and_dedent("""
|
|
29
|
+
Running '%s' (version %s) with settings:
|
|
30
|
+
- paths = %s
|
|
31
|
+
"""),
|
|
32
|
+
format_requirements.__name__,
|
|
33
|
+
__version__,
|
|
34
|
+
paths,
|
|
35
|
+
)
|
|
36
|
+
for path in paths:
|
|
37
|
+
_format_path(path)
|
|
38
|
+
if len(_MODIFICATIONS) >= 1:
|
|
39
|
+
LOGGER.info(
|
|
40
|
+
"Exiting due to modifications: %s",
|
|
41
|
+
", ".join(map(repr_str, sorted(_MODIFICATIONS))),
|
|
42
|
+
)
|
|
43
|
+
sys.exit(1)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _format_path(path: PathLike, /) -> None:
|
|
47
|
+
path = Path(path)
|
|
48
|
+
current = loads(path.read_text())
|
|
49
|
+
expected = _get_formatted(path)
|
|
50
|
+
is_equal = current == expected # tomlkit cannot handle !=
|
|
51
|
+
if not is_equal:
|
|
52
|
+
_ = path.write_text(dumps(expected).rstrip("\n") + "\n")
|
|
53
|
+
_MODIFICATIONS.add(path)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _get_formatted(path: PathLike, /) -> TOMLDocument:
|
|
57
|
+
path = Path(path)
|
|
58
|
+
doc = loads(path.read_text())
|
|
59
|
+
if isinstance(dep_grps := doc.get("dependency-groups"), Table):
|
|
60
|
+
for key, value in dep_grps.items():
|
|
61
|
+
if isinstance(value, Array):
|
|
62
|
+
dep_grps[key] = _format_array(value)
|
|
63
|
+
if isinstance(project := doc["project"], Table):
|
|
64
|
+
if isinstance(deps := project["dependencies"], Array):
|
|
65
|
+
project["dependencies"] = _format_array(deps)
|
|
66
|
+
if isinstance(optional := project.get("optional-dependencies"), Table):
|
|
67
|
+
for key, value in optional.items():
|
|
68
|
+
if isinstance(value, Array):
|
|
69
|
+
optional[key] = _format_array(value)
|
|
70
|
+
return doc
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _format_array(dependencies: Array, /) -> Array:
|
|
74
|
+
new = array().multiline(multiline=True)
|
|
75
|
+
new.extend(map(_format_item, dependencies))
|
|
76
|
+
return new
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _format_item(item: Any, /) -> Any:
|
|
80
|
+
if not isinstance(item, str):
|
|
81
|
+
return item
|
|
82
|
+
return string(str(_CustomRequirement(item)))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class _CustomRequirement(Requirement):
|
|
86
|
+
@override
|
|
87
|
+
def __init__(self, requirement_string: str) -> None:
|
|
88
|
+
super().__init__(requirement_string)
|
|
89
|
+
try:
|
|
90
|
+
parsed = _parse_requirement(requirement_string)
|
|
91
|
+
except ParserSyntaxError as e:
|
|
92
|
+
raise InvalidRequirement(str(e)) from e
|
|
93
|
+
self.specifier = _CustomSpecifierSet(parsed.specifier)
|
|
94
|
+
|
|
95
|
+
@override
|
|
96
|
+
def _iter_parts(self, name: str) -> Iterator[str]:
|
|
97
|
+
yield name
|
|
98
|
+
if self.extras:
|
|
99
|
+
formatted_extras = ",".join(sorted(self.extras))
|
|
100
|
+
yield f"[{formatted_extras}]"
|
|
101
|
+
if self.specifier:
|
|
102
|
+
yield f" {self.specifier}"
|
|
103
|
+
if self.url:
|
|
104
|
+
yield f"@ {self.url}"
|
|
105
|
+
if self.marker:
|
|
106
|
+
yield " "
|
|
107
|
+
if self.marker:
|
|
108
|
+
yield f"; {self.marker}"
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class _CustomSpecifierSet(SpecifierSet):
|
|
112
|
+
@override
|
|
113
|
+
def __str__(self) -> str:
|
|
114
|
+
specs = sorted(self._specs, key=self._key)
|
|
115
|
+
return ", ".join(map(str, specs))
|
|
116
|
+
|
|
117
|
+
def _key(self, spec: Specifier, /) -> int:
|
|
118
|
+
return [">=", "<"].index(spec.operator)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
__all__ = ["format_requirements"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from rich.pretty import pretty_repr
|
|
4
|
+
from typed_settings import click_options
|
|
5
|
+
from utilities.logging import basic_config
|
|
6
|
+
from utilities.os import is_pytest
|
|
7
|
+
from utilities.text import strip_and_dedent
|
|
8
|
+
|
|
9
|
+
from actions import __version__
|
|
10
|
+
from actions.logging import LOGGER
|
|
11
|
+
from actions.publish_package.lib import publish_package
|
|
12
|
+
from actions.publish_package.settings import Settings
|
|
13
|
+
from actions.utilities import LOADER
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click_options(Settings, [LOADER], show_envvars_in_help=True, argname="publish")
|
|
17
|
+
def publish_package_sub_cmd(*, publish: Settings) -> None:
|
|
18
|
+
if is_pytest():
|
|
19
|
+
return
|
|
20
|
+
basic_config(obj=LOGGER)
|
|
21
|
+
LOGGER.info(
|
|
22
|
+
strip_and_dedent("""
|
|
23
|
+
Running '%s' (version %s) with settings:
|
|
24
|
+
%s
|
|
25
|
+
"""),
|
|
26
|
+
publish_package.__name__,
|
|
27
|
+
__version__,
|
|
28
|
+
pretty_repr(publish),
|
|
29
|
+
)
|
|
30
|
+
publish_package(
|
|
31
|
+
username=publish.username,
|
|
32
|
+
password=publish.password,
|
|
33
|
+
publish_url=publish.publish_url,
|
|
34
|
+
trusted_publishing=publish.trusted_publishing,
|
|
35
|
+
native_tls=publish.native_tls,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
__all__ = ["publish_package_sub_cmd"]
|
|
@@ -3,10 +3,11 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from utilities.tempfile import TemporaryDirectory
|
|
6
|
+
from utilities.text import strip_and_dedent
|
|
6
7
|
|
|
7
8
|
from actions import __version__
|
|
8
9
|
from actions.logging import LOGGER
|
|
9
|
-
from actions.
|
|
10
|
+
from actions.publish_package.settings import SETTINGS
|
|
10
11
|
from actions.utilities import log_run
|
|
11
12
|
|
|
12
13
|
if TYPE_CHECKING:
|
|
@@ -15,21 +16,21 @@ if TYPE_CHECKING:
|
|
|
15
16
|
|
|
16
17
|
def publish_package(
|
|
17
18
|
*,
|
|
18
|
-
username: str | None =
|
|
19
|
-
password: Secret[str] | None =
|
|
20
|
-
publish_url: str | None =
|
|
21
|
-
trusted_publishing: bool =
|
|
22
|
-
native_tls: bool =
|
|
19
|
+
username: str | None = SETTINGS.username,
|
|
20
|
+
password: Secret[str] | None = SETTINGS.password,
|
|
21
|
+
publish_url: str | None = SETTINGS.publish_url,
|
|
22
|
+
trusted_publishing: bool = SETTINGS.trusted_publishing,
|
|
23
|
+
native_tls: bool = SETTINGS.native_tls,
|
|
23
24
|
) -> None:
|
|
24
25
|
LOGGER.info(
|
|
25
|
-
"""
|
|
26
|
-
Running %
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
strip_and_dedent("""
|
|
27
|
+
Running '%s' (version %s) with settings:
|
|
28
|
+
- username = %s
|
|
29
|
+
- password = %s
|
|
30
|
+
- publish_url = %s
|
|
31
|
+
- trusted_publishing = %s
|
|
32
|
+
- native_tls = %s
|
|
33
|
+
"""),
|
|
33
34
|
publish_package.__name__,
|
|
34
35
|
__version__,
|
|
35
36
|
username,
|
|
@@ -39,8 +40,8 @@ Running %r (version %s) with settings:
|
|
|
39
40
|
native_tls,
|
|
40
41
|
)
|
|
41
42
|
with TemporaryDirectory() as temp:
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
log_run("uv", "build", "--out-dir", str(temp), "--wheel", "--clear")
|
|
44
|
+
log_run(
|
|
44
45
|
"uv",
|
|
45
46
|
"publish",
|
|
46
47
|
*([] if username is None else ["--username", username]),
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typed_settings import Secret, load_settings, option, secret, settings
|
|
4
|
+
|
|
5
|
+
from actions.utilities import LOADER, convert_secret_str, convert_str
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@settings
|
|
9
|
+
class Settings:
|
|
10
|
+
username: str | None = option(
|
|
11
|
+
default=None, converter=convert_str, help="The username of the upload"
|
|
12
|
+
)
|
|
13
|
+
password: Secret[str] | None = secret(
|
|
14
|
+
default=None, converter=convert_secret_str, help="The password for the upload"
|
|
15
|
+
)
|
|
16
|
+
publish_url: str | None = option(
|
|
17
|
+
default=None, converter=convert_str, help="The URL of the upload endpoint"
|
|
18
|
+
)
|
|
19
|
+
trusted_publishing: bool = option(
|
|
20
|
+
default=False, help="Configure trusted publishing"
|
|
21
|
+
)
|
|
22
|
+
native_tls: bool = option(
|
|
23
|
+
default=False,
|
|
24
|
+
help="Whether to load TLS certificates from the platform's native certificate store",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
SETTINGS = load_settings(Settings, [LOADER])
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
__all__ = ["SETTINGS", "Settings"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from rich.pretty import pretty_repr
|
|
4
|
+
from typed_settings import click_options
|
|
5
|
+
from utilities.logging import basic_config
|
|
6
|
+
from utilities.os import is_pytest
|
|
7
|
+
from utilities.text import strip_and_dedent
|
|
8
|
+
|
|
9
|
+
from actions import __version__
|
|
10
|
+
from actions.logging import LOGGER
|
|
11
|
+
from actions.random_sleep.lib import random_sleep
|
|
12
|
+
from actions.random_sleep.settings import Settings
|
|
13
|
+
from actions.utilities import LOADER
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click_options(Settings, [LOADER], show_envvars_in_help=True, argname="sleep")
|
|
17
|
+
def random_sleep_sub_cmd(*, sleep: Settings) -> None:
|
|
18
|
+
if is_pytest():
|
|
19
|
+
return
|
|
20
|
+
basic_config(obj=LOGGER)
|
|
21
|
+
LOGGER.info(
|
|
22
|
+
strip_and_dedent("""
|
|
23
|
+
Running '%s' (version %s) with settings:
|
|
24
|
+
%s
|
|
25
|
+
"""),
|
|
26
|
+
random_sleep.__name__,
|
|
27
|
+
__version__,
|
|
28
|
+
pretty_repr(sleep),
|
|
29
|
+
)
|
|
30
|
+
random_sleep(
|
|
31
|
+
min_=sleep.min, max_=sleep.max, step=sleep.step, log_freq=sleep.log_freq
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
__all__ = ["random_sleep_sub_cmd"]
|
|
@@ -4,29 +4,30 @@ from math import ceil, floor
|
|
|
4
4
|
from random import choice
|
|
5
5
|
from time import sleep
|
|
6
6
|
|
|
7
|
+
from utilities.text import strip_and_dedent
|
|
7
8
|
from utilities.whenever import get_now
|
|
8
9
|
from whenever import TimeDelta, ZonedDateTime
|
|
9
10
|
|
|
10
11
|
from actions import __version__
|
|
11
12
|
from actions.logging import LOGGER
|
|
12
|
-
from actions.
|
|
13
|
+
from actions.random_sleep.settings import SETTINGS
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def random_sleep(
|
|
16
17
|
*,
|
|
17
|
-
min_: int =
|
|
18
|
-
max_: int =
|
|
19
|
-
step: int =
|
|
20
|
-
log_freq: int =
|
|
18
|
+
min_: int = SETTINGS.min,
|
|
19
|
+
max_: int = SETTINGS.max,
|
|
20
|
+
step: int = SETTINGS.step,
|
|
21
|
+
log_freq: int = SETTINGS.log_freq,
|
|
21
22
|
) -> None:
|
|
22
23
|
LOGGER.info(
|
|
23
|
-
"""
|
|
24
|
-
Running %
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
""",
|
|
24
|
+
strip_and_dedent("""
|
|
25
|
+
Running '%s' (version %s) with settings:
|
|
26
|
+
- min_ = %s
|
|
27
|
+
- max_ = %s
|
|
28
|
+
- step = %s
|
|
29
|
+
- log_freq = %s
|
|
30
|
+
"""),
|
|
30
31
|
random_sleep.__name__,
|
|
31
32
|
__version__,
|
|
32
33
|
min_,
|
|
@@ -49,7 +50,7 @@ def _intermediate(
|
|
|
49
50
|
end: ZonedDateTime,
|
|
50
51
|
/,
|
|
51
52
|
*,
|
|
52
|
-
log_freq: int =
|
|
53
|
+
log_freq: int = SETTINGS.log_freq,
|
|
53
54
|
) -> None:
|
|
54
55
|
elapsed = TimeDelta(seconds=floor((now - start).in_seconds()))
|
|
55
56
|
remaining = TimeDelta(seconds=ceil((end - now).in_seconds()))
|
|
@@ -2,18 +2,18 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from typed_settings import load_settings, option, settings
|
|
4
4
|
|
|
5
|
-
from actions.utilities import
|
|
5
|
+
from actions.utilities import LOADER
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
@settings
|
|
9
|
-
class
|
|
9
|
+
class Settings:
|
|
10
10
|
min: int = option(default=0, help="Minimum duration, in seconds")
|
|
11
11
|
max: int = option(default=3600, help="Maximum duration, in seconds")
|
|
12
12
|
step: int = option(default=1, help="Step duration, in seconds")
|
|
13
13
|
log_freq: int = option(default=60, help="Log frequency, in seconds")
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
SETTINGS = load_settings(Settings, [LOADER])
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
__all__ = ["
|
|
19
|
+
__all__ = ["SETTINGS", "Settings"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from click import argument
|
|
7
|
+
from utilities.logging import basic_config
|
|
8
|
+
from utilities.os import is_pytest
|
|
9
|
+
from utilities.text import strip_and_dedent
|
|
10
|
+
|
|
11
|
+
from actions import __version__
|
|
12
|
+
from actions.logging import LOGGER
|
|
13
|
+
from actions.replace_sequence_strs.lib import replace_sequence_strs
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@argument(
|
|
17
|
+
"paths",
|
|
18
|
+
nargs=-1,
|
|
19
|
+
type=click.Path(exists=True, file_okay=True, dir_okay=False, path_type=Path),
|
|
20
|
+
)
|
|
21
|
+
def sequence_strs_sub_cmd(*, paths: tuple[Path, ...]) -> None:
|
|
22
|
+
if is_pytest():
|
|
23
|
+
return
|
|
24
|
+
basic_config(obj=LOGGER)
|
|
25
|
+
LOGGER.info(
|
|
26
|
+
strip_and_dedent("""
|
|
27
|
+
Running '%s' (version %s) with settings:
|
|
28
|
+
- paths = %s
|
|
29
|
+
"""),
|
|
30
|
+
replace_sequence_strs.__name__,
|
|
31
|
+
__version__,
|
|
32
|
+
paths,
|
|
33
|
+
)
|
|
34
|
+
replace_sequence_strs(*paths)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
__all__ = ["sequence_strs_sub_cmd"]
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import TYPE_CHECKING, override
|
|
6
|
+
|
|
7
|
+
from libcst import CSTTransformer, Module, Name, Subscript, parse_module
|
|
8
|
+
from libcst.matchers import Index as MIndex
|
|
9
|
+
from libcst.matchers import Name as MName
|
|
10
|
+
from libcst.matchers import Subscript as MSubscript
|
|
11
|
+
from libcst.matchers import SubscriptElement as MSubscriptElement
|
|
12
|
+
from libcst.matchers import matches
|
|
13
|
+
from libcst.metadata import MetadataWrapper
|
|
14
|
+
from utilities.text import repr_str, strip_and_dedent
|
|
15
|
+
|
|
16
|
+
from actions import __version__
|
|
17
|
+
from actions.logging import LOGGER
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from utilities.types import PathLike
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
_MODIFICATIONS: set[Path] = set()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def replace_sequence_strs(*paths: PathLike) -> None:
|
|
27
|
+
LOGGER.info(
|
|
28
|
+
strip_and_dedent("""
|
|
29
|
+
Running '%s' (version %s) with settings:
|
|
30
|
+
- paths = %s
|
|
31
|
+
"""),
|
|
32
|
+
replace_sequence_strs.__name__,
|
|
33
|
+
__version__,
|
|
34
|
+
paths,
|
|
35
|
+
)
|
|
36
|
+
for path in paths:
|
|
37
|
+
_format_path(path)
|
|
38
|
+
if len(_MODIFICATIONS) >= 1:
|
|
39
|
+
LOGGER.info(
|
|
40
|
+
"Exiting due to modifications: %s",
|
|
41
|
+
", ".join(map(repr_str, sorted(_MODIFICATIONS))),
|
|
42
|
+
)
|
|
43
|
+
sys.exit(1)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _format_path(path: PathLike, /) -> None:
|
|
47
|
+
path = Path(path)
|
|
48
|
+
current = parse_module(path.read_text())
|
|
49
|
+
expected = _get_formatted(path)
|
|
50
|
+
if current.code != expected.code:
|
|
51
|
+
_ = path.write_text(expected.code.rstrip("\n") + "\n")
|
|
52
|
+
_MODIFICATIONS.add(path)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _get_formatted(path: PathLike, /) -> Module:
|
|
56
|
+
path = Path(path)
|
|
57
|
+
existing = path.read_text()
|
|
58
|
+
wrapper = MetadataWrapper(parse_module(existing))
|
|
59
|
+
return wrapper.module.visit(SequenceToListTransformer())
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class SequenceToListTransformer(CSTTransformer):
|
|
63
|
+
@override
|
|
64
|
+
def leave_Subscript(
|
|
65
|
+
self, original_node: Subscript, updated_node: Subscript
|
|
66
|
+
) -> Subscript:
|
|
67
|
+
_ = original_node
|
|
68
|
+
if matches(
|
|
69
|
+
updated_node,
|
|
70
|
+
MSubscript(
|
|
71
|
+
value=MName("Sequence"),
|
|
72
|
+
slice=[MSubscriptElement(slice=MIndex(value=MName("str")))],
|
|
73
|
+
),
|
|
74
|
+
):
|
|
75
|
+
return updated_node.with_changes(value=Name("list"))
|
|
76
|
+
return updated_node
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
__all__ = ["replace_sequence_strs"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from __future__ import annotations
|