winipedia-utils 0.2.63__py3-none-any.whl → 0.6.6__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.
Potentially problematic release.
This version of winipedia-utils might be problematic. Click here for more details.
- winipedia_utils/artifacts/build.py +78 -0
- winipedia_utils/concurrent/concurrent.py +7 -2
- winipedia_utils/concurrent/multiprocessing.py +1 -2
- winipedia_utils/concurrent/multithreading.py +2 -2
- winipedia_utils/data/dataframe/cleaning.py +337 -100
- winipedia_utils/git/github/__init__.py +1 -0
- winipedia_utils/git/github/github.py +31 -0
- winipedia_utils/git/github/repo/__init__.py +1 -0
- winipedia_utils/git/github/repo/protect.py +103 -0
- winipedia_utils/git/github/repo/repo.py +205 -0
- winipedia_utils/git/github/workflows/base/__init__.py +1 -0
- winipedia_utils/git/github/workflows/base/base.py +889 -0
- winipedia_utils/git/github/workflows/health_check.py +69 -0
- winipedia_utils/git/github/workflows/publish.py +51 -0
- winipedia_utils/git/github/workflows/release.py +90 -0
- winipedia_utils/git/gitignore/config.py +77 -0
- winipedia_utils/git/gitignore/gitignore.py +5 -63
- winipedia_utils/git/pre_commit/config.py +49 -59
- winipedia_utils/git/pre_commit/hooks.py +46 -46
- winipedia_utils/git/pre_commit/run_hooks.py +19 -12
- winipedia_utils/iterating/iterate.py +63 -1
- winipedia_utils/modules/class_.py +69 -12
- winipedia_utils/modules/function.py +26 -3
- winipedia_utils/modules/inspection.py +56 -0
- winipedia_utils/modules/module.py +22 -28
- winipedia_utils/modules/package.py +116 -10
- winipedia_utils/projects/poetry/config.py +255 -112
- winipedia_utils/projects/poetry/poetry.py +230 -13
- winipedia_utils/projects/project.py +11 -42
- winipedia_utils/setup.py +11 -29
- winipedia_utils/testing/config.py +127 -0
- winipedia_utils/testing/create_tests.py +5 -19
- winipedia_utils/testing/skip.py +19 -0
- winipedia_utils/testing/tests/base/fixtures/fixture.py +36 -0
- winipedia_utils/testing/tests/base/fixtures/scopes/class_.py +3 -3
- winipedia_utils/testing/tests/base/fixtures/scopes/module.py +9 -6
- winipedia_utils/testing/tests/base/fixtures/scopes/session.py +27 -176
- winipedia_utils/testing/tests/base/utils/utils.py +27 -57
- winipedia_utils/text/config.py +250 -0
- winipedia_utils/text/string.py +30 -0
- winipedia_utils-0.6.6.dist-info/METADATA +390 -0
- {winipedia_utils-0.2.63.dist-info → winipedia_utils-0.6.6.dist-info}/RECORD +46 -34
- winipedia_utils/consts.py +0 -21
- winipedia_utils/git/workflows/base/base.py +0 -77
- winipedia_utils/git/workflows/publish.py +0 -79
- winipedia_utils/git/workflows/release.py +0 -91
- winipedia_utils-0.2.63.dist-info/METADATA +0 -738
- /winipedia_utils/{git/workflows/base → artifacts}/__init__.py +0 -0
- /winipedia_utils/git/{workflows → github/workflows}/__init__.py +0 -0
- {winipedia_utils-0.2.63.dist-info → winipedia_utils-0.6.6.dist-info}/WHEEL +0 -0
- {winipedia_utils-0.2.63.dist-info → winipedia_utils-0.6.6.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Contains the pull request workflow.
|
|
2
|
+
|
|
3
|
+
This workflow is used to run tests on pull requests.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from winipedia_utils.git.github.workflows.base.base import Workflow
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class HealthCheckWorkflow(Workflow):
|
|
12
|
+
"""Pull request workflow.
|
|
13
|
+
|
|
14
|
+
This workflow is triggered by a pull request.
|
|
15
|
+
It runs tests on the pull request.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def get_workflow_triggers(cls) -> dict[str, Any]:
|
|
20
|
+
"""Get the workflow triggers."""
|
|
21
|
+
triggers = super().get_workflow_triggers()
|
|
22
|
+
triggers.update(cls.on_pull_request())
|
|
23
|
+
triggers.update(cls.on_schedule(cron="0 6 * * *"))
|
|
24
|
+
return triggers
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def get_jobs(cls) -> dict[str, Any]:
|
|
28
|
+
"""Get the workflow jobs."""
|
|
29
|
+
jobs: dict[str, Any] = {}
|
|
30
|
+
jobs.update(cls.job_health_check_matrix())
|
|
31
|
+
jobs.update(cls.job_health_check())
|
|
32
|
+
return jobs
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def job_health_check_matrix(cls) -> dict[str, Any]:
|
|
36
|
+
"""Get the health check matrix job."""
|
|
37
|
+
return cls.get_job(
|
|
38
|
+
job_func=cls.job_health_check_matrix,
|
|
39
|
+
strategy=cls.strategy_matrix_os_and_python_version(),
|
|
40
|
+
runs_on=cls.insert_matrix_os(),
|
|
41
|
+
steps=cls.steps_health_check_matrix(),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def job_health_check(cls) -> dict[str, Any]:
|
|
46
|
+
"""Get the health check job."""
|
|
47
|
+
return cls.get_job(
|
|
48
|
+
job_func=cls.job_health_check,
|
|
49
|
+
needs=[cls.make_id_from_func(cls.job_health_check_matrix)],
|
|
50
|
+
steps=cls.steps_aggregate_matrix_results(),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
@classmethod
|
|
54
|
+
def steps_health_check_matrix(cls) -> list[dict[str, Any]]:
|
|
55
|
+
"""Get the health check matrix steps."""
|
|
56
|
+
return [
|
|
57
|
+
*cls.steps_core_matrix_setup(
|
|
58
|
+
python_version=cls.insert_matrix_python_version()
|
|
59
|
+
),
|
|
60
|
+
cls.step_protect_repository(),
|
|
61
|
+
cls.step_run_pre_commit_hooks(),
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def steps_aggregate_matrix_results(cls) -> list[dict[str, Any]]:
|
|
66
|
+
"""Get the aggregate matrix results step."""
|
|
67
|
+
return [
|
|
68
|
+
cls.step_aggregate_matrix_results(),
|
|
69
|
+
]
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Contains the publish workflow.
|
|
2
|
+
|
|
3
|
+
This workflow is used to publish the package to PyPI with poetry.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from winipedia_utils.git.github.workflows.base.base import Workflow
|
|
9
|
+
from winipedia_utils.git.github.workflows.release import ReleaseWorkflow
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PublishWorkflow(Workflow):
|
|
13
|
+
"""Publish workflow.
|
|
14
|
+
|
|
15
|
+
This workflow is triggered by the release workflow.
|
|
16
|
+
It publishes the package to PyPI with poetry.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def get_workflow_triggers(cls) -> dict[str, Any]:
|
|
21
|
+
"""Get the workflow triggers."""
|
|
22
|
+
triggers = super().get_workflow_triggers()
|
|
23
|
+
triggers.update(
|
|
24
|
+
cls.on_workflow_run(workflows=[ReleaseWorkflow.get_workflow_name()])
|
|
25
|
+
)
|
|
26
|
+
return triggers
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def get_jobs(cls) -> dict[str, Any]:
|
|
30
|
+
"""Get the workflow jobs."""
|
|
31
|
+
jobs: dict[str, Any] = {}
|
|
32
|
+
jobs.update(cls.job_publish())
|
|
33
|
+
return jobs
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def job_publish(cls) -> dict[str, Any]:
|
|
37
|
+
"""Get the publish job."""
|
|
38
|
+
return cls.get_job(
|
|
39
|
+
job_func=cls.job_publish,
|
|
40
|
+
steps=cls.steps_publish(),
|
|
41
|
+
if_condition=cls.if_workflow_run_is_success(),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def steps_publish(cls) -> list[dict[str, Any]]:
|
|
46
|
+
"""Get the publish steps."""
|
|
47
|
+
return [
|
|
48
|
+
*cls.steps_core_setup(),
|
|
49
|
+
cls.step_add_pypi_token_to_poetry(),
|
|
50
|
+
cls.step_publish_to_pypi(),
|
|
51
|
+
]
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Contains the release workflow.
|
|
2
|
+
|
|
3
|
+
This workflow is used to create a release on GitHub.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from winipedia_utils.git.github.workflows.health_check import HealthCheckWorkflow
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ReleaseWorkflow(HealthCheckWorkflow):
|
|
12
|
+
"""Release workflow.
|
|
13
|
+
|
|
14
|
+
This workflow is triggered by a push to the main branch.
|
|
15
|
+
It creates a tag for the release and builds a changelog.
|
|
16
|
+
With tag and changelog it creates a release on GitHub
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def get_workflow_triggers(cls) -> dict[str, Any]:
|
|
21
|
+
"""Get the workflow triggers."""
|
|
22
|
+
triggers = super().get_workflow_triggers()
|
|
23
|
+
triggers.update(cls.on_push())
|
|
24
|
+
triggers.update(cls.on_schedule(cron="0 6 * * 2"))
|
|
25
|
+
return triggers
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def get_permissions(cls) -> dict[str, Any]:
|
|
29
|
+
"""Get the workflow permissions."""
|
|
30
|
+
permissions = super().get_permissions()
|
|
31
|
+
permissions["contents"] = "write"
|
|
32
|
+
return permissions
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def get_jobs(cls) -> dict[str, Any]:
|
|
36
|
+
"""Get the workflow jobs."""
|
|
37
|
+
jobs = super().get_jobs()
|
|
38
|
+
last_job_name = list(jobs.keys())[-1]
|
|
39
|
+
jobs.update(cls.job_build(needs=[last_job_name]))
|
|
40
|
+
jobs.update(cls.job_release())
|
|
41
|
+
return jobs
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
def job_build(cls, needs: list[str] | None = None) -> dict[str, Any]:
|
|
45
|
+
"""Get the build job."""
|
|
46
|
+
return cls.get_job(
|
|
47
|
+
job_func=cls.job_build,
|
|
48
|
+
needs=needs,
|
|
49
|
+
strategy=cls.strategy_matrix_os(),
|
|
50
|
+
runs_on=cls.insert_matrix_os(),
|
|
51
|
+
steps=cls.steps_build(),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def job_release(cls) -> dict[str, Any]:
|
|
56
|
+
"""Get the release job."""
|
|
57
|
+
return cls.get_job(
|
|
58
|
+
job_func=cls.job_release,
|
|
59
|
+
needs=[cls.make_id_from_func(cls.job_build)],
|
|
60
|
+
steps=cls.steps_release(),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def steps_build(cls) -> list[dict[str, Any]]:
|
|
65
|
+
"""Get the build steps."""
|
|
66
|
+
if not cls.BUILD_SCRIPT_PATH.exists():
|
|
67
|
+
return [cls.step_no_build_script()]
|
|
68
|
+
return [
|
|
69
|
+
*cls.steps_core_matrix_setup(),
|
|
70
|
+
cls.step_build_artifacts(),
|
|
71
|
+
cls.step_upload_artifacts(),
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def steps_release(cls) -> list[dict[str, Any]]:
|
|
76
|
+
"""Get the release steps."""
|
|
77
|
+
return [
|
|
78
|
+
*cls.steps_core_setup(repo_token=True),
|
|
79
|
+
cls.step_install_python_dependencies(),
|
|
80
|
+
cls.step_setup_keyring(),
|
|
81
|
+
cls.step_setup_git(),
|
|
82
|
+
cls.step_run_pre_commit_hooks(),
|
|
83
|
+
cls.step_commit_added_changes(),
|
|
84
|
+
cls.step_push_commits(),
|
|
85
|
+
cls.step_create_and_push_tag(),
|
|
86
|
+
cls.step_extract_version(),
|
|
87
|
+
cls.step_download_artifacts(),
|
|
88
|
+
cls.step_build_changelog(),
|
|
89
|
+
cls.step_create_release(),
|
|
90
|
+
]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""Config utilities for .gitignore."""
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
from winipedia_utils.testing.config import ExperimentConfigFile
|
|
9
|
+
from winipedia_utils.text.config import ConfigFile, DotEnvConfigFile
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class GitIgnoreConfigFile(ConfigFile):
|
|
13
|
+
"""Config file for .gitignore."""
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def get_filename(cls) -> str:
|
|
17
|
+
"""Get the filename of the config file."""
|
|
18
|
+
return "" # so it builds the path .gitignore and not gitignore.gitignore
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def get_parent_path(cls) -> Path:
|
|
22
|
+
"""Get the path to the config file."""
|
|
23
|
+
return Path()
|
|
24
|
+
|
|
25
|
+
@classmethod
|
|
26
|
+
def get_file_extension(cls) -> str:
|
|
27
|
+
"""Get the file extension of the config file."""
|
|
28
|
+
return "gitignore"
|
|
29
|
+
|
|
30
|
+
@classmethod
|
|
31
|
+
def load(cls) -> list[str]:
|
|
32
|
+
"""Load the config file."""
|
|
33
|
+
return cls.get_path().read_text().splitlines()
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def dump(cls, config: list[str] | dict[str, Any]) -> None:
|
|
37
|
+
"""Dump the config file."""
|
|
38
|
+
if not isinstance(config, list):
|
|
39
|
+
msg = f"Cannot dump {config} to .gitignore file."
|
|
40
|
+
raise TypeError(msg)
|
|
41
|
+
cls.get_path().write_text("\n".join(config))
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
def get_configs(cls) -> list[str]:
|
|
45
|
+
"""Get the config."""
|
|
46
|
+
# fetch the standard github gitignore via https://github.com/github/gitignore/blob/main/Python.gitignore
|
|
47
|
+
needed = [
|
|
48
|
+
*cls.get_github_python_gitignore(),
|
|
49
|
+
"# vscode stuff",
|
|
50
|
+
".vscode/",
|
|
51
|
+
"",
|
|
52
|
+
"# winipedia_utils stuff",
|
|
53
|
+
"# for walk_os_skipping_gitignore_patterns func",
|
|
54
|
+
".git/",
|
|
55
|
+
"# for executing experimental code",
|
|
56
|
+
ExperimentConfigFile.get_path().as_posix(),
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
dotenv_path = DotEnvConfigFile.get_path().as_posix()
|
|
60
|
+
if dotenv_path not in needed:
|
|
61
|
+
needed.extend(["# for secrets used locally", dotenv_path])
|
|
62
|
+
|
|
63
|
+
existing = cls.load()
|
|
64
|
+
needed = [p for p in needed if p not in set(existing)]
|
|
65
|
+
return existing + needed
|
|
66
|
+
|
|
67
|
+
@classmethod
|
|
68
|
+
def get_github_python_gitignore(cls) -> list[str]:
|
|
69
|
+
"""Get the standard github python gitignore."""
|
|
70
|
+
url = "https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore"
|
|
71
|
+
res = requests.get(url, timeout=10)
|
|
72
|
+
if not res.ok:
|
|
73
|
+
if not Path(".gitignore").exists():
|
|
74
|
+
msg = f"Failed to fetch {url}. Cannot create .gitignore."
|
|
75
|
+
raise RuntimeError(msg)
|
|
76
|
+
return []
|
|
77
|
+
return res.text.splitlines()
|
|
@@ -12,6 +12,7 @@ from pathlib import Path
|
|
|
12
12
|
|
|
13
13
|
import pathspec
|
|
14
14
|
|
|
15
|
+
from winipedia_utils.git.gitignore.config import GitIgnoreConfigFile
|
|
15
16
|
from winipedia_utils.logging.logger import get_logger
|
|
16
17
|
|
|
17
18
|
logger = get_logger(__name__)
|
|
@@ -37,7 +38,10 @@ def path_is_in_gitignore(relative_path: str | Path) -> bool:
|
|
|
37
38
|
if is_dir and not as_posix.endswith("/"):
|
|
38
39
|
as_posix += "/"
|
|
39
40
|
|
|
40
|
-
spec = pathspec.PathSpec.from_lines(
|
|
41
|
+
spec = pathspec.PathSpec.from_lines(
|
|
42
|
+
"gitwildmatch",
|
|
43
|
+
GitIgnoreConfigFile.load(),
|
|
44
|
+
)
|
|
41
45
|
|
|
42
46
|
return spec.match_file(as_posix)
|
|
43
47
|
|
|
@@ -72,65 +76,3 @@ def walk_os_skipping_gitignore_patterns(
|
|
|
72
76
|
valid_dirs = [d for d in dirs if not path_is_in_gitignore(rel_root / d)]
|
|
73
77
|
|
|
74
78
|
yield rel_root, valid_dirs, valid_files
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def load_gitignore() -> list[str]:
|
|
78
|
-
"""Load the .gitignore file."""
|
|
79
|
-
gitignore_path = Path(".gitignore")
|
|
80
|
-
if not gitignore_path.exists():
|
|
81
|
-
gitignore_path.touch()
|
|
82
|
-
return gitignore_path.read_text().splitlines()
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def dump_gitignore(patterns: list[str]) -> None:
|
|
86
|
-
"""Dump the given patterns to a .gitignore file (overwrites it)."""
|
|
87
|
-
gitignore_path = Path(".gitignore")
|
|
88
|
-
gitignore_path.write_text("\n".join(patterns))
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def add_patterns_to_gitignore(patterns: list[str]) -> None:
|
|
92
|
-
"""Add the given patterns to the .gitignore file."""
|
|
93
|
-
existing_patterns = load_gitignore()
|
|
94
|
-
new_patterns = [p for p in patterns if p not in existing_patterns]
|
|
95
|
-
if new_patterns:
|
|
96
|
-
logger.info("Adding patterns to .gitignore: %s", new_patterns)
|
|
97
|
-
dump_gitignore(existing_patterns + new_patterns)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
def _get_gitignore_patterns() -> list[str]:
|
|
101
|
-
"""Get the patterns that should be in the .gitignore file.
|
|
102
|
-
|
|
103
|
-
Those are the patterns that should be in there when using winipedia_utils.
|
|
104
|
-
"""
|
|
105
|
-
return [
|
|
106
|
-
"__pycache__/",
|
|
107
|
-
".idea/",
|
|
108
|
-
".mypy_cache/",
|
|
109
|
-
".pytest_cache/",
|
|
110
|
-
".ruff_cache/",
|
|
111
|
-
".vscode/",
|
|
112
|
-
"dist/",
|
|
113
|
-
"test.py", # I use this for testing code
|
|
114
|
-
".git/", # ignore the .git folder for walk_os_skipping_gitignore_patterns func
|
|
115
|
-
]
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def _get_missing_patterns() -> list[str]:
|
|
119
|
-
"""Get the patterns that are in the .gitignore file but shouldn't be."""
|
|
120
|
-
needed_patterns = _get_gitignore_patterns()
|
|
121
|
-
existing_patterns = load_gitignore()
|
|
122
|
-
return [p for p in needed_patterns if p not in existing_patterns]
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
def _gitignore_is_correct() -> bool:
|
|
126
|
-
"""Check if the .gitignore file contains all the patterns it should."""
|
|
127
|
-
missing_patterns = _get_missing_patterns()
|
|
128
|
-
return not missing_patterns
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
def _add_package_patterns_to_gitignore() -> None:
|
|
132
|
-
"""Add any missing patterns to the .gitignore file."""
|
|
133
|
-
if _gitignore_is_correct():
|
|
134
|
-
return
|
|
135
|
-
missing_patterns = _get_missing_patterns()
|
|
136
|
-
add_patterns_to_gitignore(missing_patterns)
|
|
@@ -3,68 +3,58 @@
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
|
|
6
|
+
import winipedia_utils
|
|
8
7
|
from winipedia_utils.logging.logger import get_logger
|
|
9
8
|
from winipedia_utils.os.os import run_subprocess
|
|
10
|
-
from winipedia_utils.
|
|
9
|
+
from winipedia_utils.text.config import YamlConfigFile
|
|
10
|
+
from winipedia_utils.text.string import make_name_from_obj
|
|
11
11
|
|
|
12
12
|
logger = get_logger(__name__)
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if not _pre_commit_config_is_correct():
|
|
62
|
-
logger.info("Adding winipedia-utils hook to pre-commit config")
|
|
63
|
-
config["repos"] = [package_hook_config, *config.get("repos", [])]
|
|
64
|
-
dump_pre_commit_config(config)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def _pre_commit_install() -> None:
|
|
68
|
-
"""Install pre-commit."""
|
|
69
|
-
logger.info("Running pre-commit install")
|
|
70
|
-
run_subprocess([*POETRY_RUN_ARGS, "pre-commit", "install"], check=True)
|
|
15
|
+
class PreCommitConfigConfigFile(YamlConfigFile):
|
|
16
|
+
"""Config file for pre-commit."""
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def get_filename(cls) -> str:
|
|
20
|
+
"""Get the filename of the config file."""
|
|
21
|
+
filename = super().get_filename()
|
|
22
|
+
return f".{filename.replace('_', '-')}"
|
|
23
|
+
|
|
24
|
+
@classmethod
|
|
25
|
+
def get_parent_path(cls) -> Path:
|
|
26
|
+
"""Get the path to the config file."""
|
|
27
|
+
return Path()
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def get_configs(cls) -> dict[str, Any]:
|
|
31
|
+
"""Get the config."""
|
|
32
|
+
hook_name = make_name_from_obj(winipedia_utils, capitalize=False)
|
|
33
|
+
return {
|
|
34
|
+
"repos": [
|
|
35
|
+
{
|
|
36
|
+
"repo": "local",
|
|
37
|
+
"hooks": [
|
|
38
|
+
{
|
|
39
|
+
"id": hook_name,
|
|
40
|
+
"name": hook_name,
|
|
41
|
+
"entry": cls.get_poetry_run_setup_script(),
|
|
42
|
+
"language": "system",
|
|
43
|
+
"always_run": True,
|
|
44
|
+
"pass_filenames": False,
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
def __init__(self) -> None:
|
|
52
|
+
"""Init the file."""
|
|
53
|
+
super().__init__()
|
|
54
|
+
self.install()
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def install(cls) -> None:
|
|
58
|
+
"""Installs the pre commits in the config."""
|
|
59
|
+
logger.info("Running pre-commit install")
|
|
60
|
+
run_subprocess(["pre-commit", "install"], check=True)
|
|
@@ -7,121 +7,121 @@ strings are the arguments to the command. These funcs will be called by
|
|
|
7
7
|
run_hooks.py, which will pass the returned list to subprocess.run().
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
from pathlib import Path
|
|
11
|
-
|
|
12
10
|
from winipedia_utils.projects.poetry.poetry import (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
POETRY_RUN_PYTHON_ARGS,
|
|
16
|
-
POETRY_RUN_RUFF_ARGS,
|
|
11
|
+
POETRY_ARG,
|
|
12
|
+
get_poetry_run_module_args,
|
|
17
13
|
)
|
|
18
14
|
|
|
19
15
|
|
|
20
|
-
def
|
|
21
|
-
"""Patch the version in pyproject.toml.
|
|
22
|
-
|
|
23
|
-
This function returns the input for subprocess.run() to patch the version
|
|
24
|
-
in pyproject.toml.
|
|
25
|
-
"""
|
|
26
|
-
return [POETRY_PATH, "version", "patch"]
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def _add_version_patch_to_git() -> list[str | Path]:
|
|
30
|
-
"""Add the version patch to git.
|
|
31
|
-
|
|
32
|
-
This function returns the input for subprocess.run() to add the version
|
|
33
|
-
patch to git, so that the hook does not fail bc the file was changed.
|
|
34
|
-
"""
|
|
35
|
-
return [*POETRY_RUN_ARGS, "git", "add", "pyproject.toml"]
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _update_package_manager() -> list[str | Path]:
|
|
16
|
+
def update_package_manager() -> list[str]:
|
|
39
17
|
"""Update the package manager.
|
|
40
18
|
|
|
41
19
|
This function returns the input for subprocess.run() to update the package
|
|
42
20
|
manager.
|
|
43
21
|
"""
|
|
44
|
-
return [
|
|
22
|
+
return [POETRY_ARG, "self", "update"]
|
|
45
23
|
|
|
46
24
|
|
|
47
|
-
def
|
|
25
|
+
def install_dependencies_with_dev() -> list[str]:
|
|
48
26
|
"""Install all dependencies.
|
|
49
27
|
|
|
50
28
|
This function returns the input for subprocess.run() to install all dependencies.
|
|
51
29
|
"""
|
|
52
|
-
return [
|
|
30
|
+
return [POETRY_ARG, "install", "--with", "dev"]
|
|
53
31
|
|
|
54
32
|
|
|
55
|
-
def
|
|
33
|
+
def update_dependencies_with_dev() -> list[str]:
|
|
56
34
|
"""Update all dependencies.
|
|
57
35
|
|
|
58
36
|
This function returns the input for subprocess.run() to update all dependencies.
|
|
59
37
|
"""
|
|
60
|
-
return [
|
|
38
|
+
return [POETRY_ARG, "update", "--with", "dev"]
|
|
61
39
|
|
|
62
40
|
|
|
63
|
-
def
|
|
41
|
+
def add_updates_to_git() -> list[str]:
|
|
42
|
+
"""Add the updated dependencies to git.
|
|
43
|
+
|
|
44
|
+
This function returns the input for subprocess.run() to add the updated
|
|
45
|
+
dependencies to git, so that the hook does not fail bc the file was changed.
|
|
46
|
+
"""
|
|
47
|
+
return ["git", "add", "pyproject.toml"]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def lock_dependencies() -> list[str]:
|
|
64
51
|
"""Lock the dependencies.
|
|
65
52
|
|
|
66
53
|
This function returns the input for subprocess.run() to lock the dependencies.
|
|
67
54
|
"""
|
|
68
|
-
return [
|
|
55
|
+
return [POETRY_ARG, "lock"]
|
|
56
|
+
|
|
69
57
|
|
|
58
|
+
def add_lock_file_to_git() -> list[str]:
|
|
59
|
+
"""Add the lock file to git.
|
|
70
60
|
|
|
71
|
-
|
|
61
|
+
This function returns the input for subprocess.run() to add the lock file
|
|
62
|
+
to git, so that the hook does not fail bc the file was changed.
|
|
63
|
+
"""
|
|
64
|
+
return ["git", "add", "poetry.lock"]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def check_package_manager_configs() -> list[str]:
|
|
72
68
|
"""Check that poetry.lock and pyproject.toml is up to date.
|
|
73
69
|
|
|
74
70
|
This function returns the input for subprocess.run() to check that poetry.lock
|
|
75
71
|
is up to date.
|
|
76
72
|
"""
|
|
77
|
-
return [
|
|
73
|
+
return [POETRY_ARG, "check", "--strict"]
|
|
78
74
|
|
|
79
75
|
|
|
80
|
-
def
|
|
76
|
+
def create_missing_tests() -> list[str]:
|
|
81
77
|
"""Create all tests for the project.
|
|
82
78
|
|
|
83
79
|
This function returns the input for subprocess.run() to create all tests.
|
|
84
80
|
"""
|
|
85
|
-
|
|
81
|
+
from winipedia_utils.testing import ( # noqa: PLC0415 # avoid circular import
|
|
82
|
+
create_tests,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
return get_poetry_run_module_args(create_tests)
|
|
86
86
|
|
|
87
87
|
|
|
88
|
-
def
|
|
88
|
+
def lint_code() -> list[str]:
|
|
89
89
|
"""Check the code.
|
|
90
90
|
|
|
91
91
|
This function returns the input for subprocess.run() to lint the code.
|
|
92
92
|
It autofixes all errors that can be autofixed with --fix.
|
|
93
93
|
"""
|
|
94
|
-
return [
|
|
94
|
+
return ["ruff", "check", "--fix"]
|
|
95
95
|
|
|
96
96
|
|
|
97
|
-
def
|
|
97
|
+
def format_code() -> list[str]:
|
|
98
98
|
"""Format the code.
|
|
99
99
|
|
|
100
100
|
This function calls ruff format to format the code.
|
|
101
101
|
"""
|
|
102
|
-
return [
|
|
102
|
+
return ["ruff", "format"]
|
|
103
103
|
|
|
104
104
|
|
|
105
|
-
def
|
|
105
|
+
def check_static_types() -> list[str]:
|
|
106
106
|
"""Check the types.
|
|
107
107
|
|
|
108
108
|
This function returns the input for subprocess.run() to check the static types.
|
|
109
109
|
"""
|
|
110
|
-
return [
|
|
110
|
+
return ["mypy", "--exclude-gitignore"]
|
|
111
111
|
|
|
112
112
|
|
|
113
|
-
def
|
|
113
|
+
def check_security() -> list[str]:
|
|
114
114
|
"""Check the security of the code.
|
|
115
115
|
|
|
116
116
|
This function returns the input for subprocess.run() to check the security of
|
|
117
117
|
the code.
|
|
118
118
|
"""
|
|
119
|
-
return [
|
|
119
|
+
return ["bandit", "-c", "pyproject.toml", "-r", "."]
|
|
120
120
|
|
|
121
121
|
|
|
122
|
-
def
|
|
122
|
+
def run_tests() -> list[str]:
|
|
123
123
|
"""Run the tests.
|
|
124
124
|
|
|
125
125
|
This function returns the input for subprocess.run() to run all tests.
|
|
126
126
|
"""
|
|
127
|
-
return [
|
|
127
|
+
return ["pytest"]
|