package-dev-tools 0.8.4__tar.gz → 0.8.6__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.
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/PKG-INFO +8 -7
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/README.md +1 -1
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/pyproject.toml +9 -6
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/instantiate_new_project/instantiate_new_project.py +3 -2
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/instantiate_new_project/substitute_template_name/substitute_template_name.py +2 -9
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/template_sync/merge.py +4 -10
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/template_sync/sync.py +2 -5
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/extract_info.py +2 -2
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/models/path.py +1 -4
- package_dev_tools-0.8.6/src/package_dev_tools/pre_commit/check_coverage.py +55 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/pre_commit/check_import.py +2 -3
- package_dev_tools-0.8.6/src/package_dev_tools/pre_commit/check_shields.py +25 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/utils/badge.py +1 -0
- {package_dev_tools-0.8.4/src/package_dev_tools/actions/instantiate_new_project → package_dev_tools-0.8.6/src/package_dev_tools/utils}/git.py +12 -3
- package_dev_tools-0.8.6/src/package_dev_tools/utils/package.py +50 -0
- package_dev_tools-0.8.6/src/package_dev_tools/utils/python_versions.py +77 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools.egg-info/PKG-INFO +8 -7
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools.egg-info/SOURCES.txt +3 -2
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools.egg-info/requires.txt +5 -4
- package_dev_tools-0.8.4/src/package_dev_tools/pre_commit/check_coverage.py +0 -54
- package_dev_tools-0.8.4/src/package_dev_tools/pre_commit/check_shields.py +0 -25
- package_dev_tools-0.8.4/src/package_dev_tools/utils/package.py +0 -89
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/LICENSE +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/bin/pre-commit/bump-version +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/bin/pre-commit/check-version +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/setup.cfg +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/__init__.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/__init__.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/instantiate_new_project/__init__.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/instantiate_new_project/cleanup_readme.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/instantiate_new_project/cleanup_workflows.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/instantiate_new_project/substitute_template_name/__init__.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/instantiate_new_project/substitute_template_name/project.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/template_sync/__init__.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/template_sync/git.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/template_sync/trigger.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/__init__.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/check_coverage.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/check_shields.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/cleanup_readme.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/export_pre_commit_config.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/instantiate_new_project.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/substitute_template_name.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/sync_template.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/trigger_template_sync.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/models/__init__.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/pre_commit/__init__.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/pre_commit/expand_docstrings.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/pre_commit/export_config.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/py.typed +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/utils/__init__.py +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools.egg-info/dependency_links.txt +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools.egg-info/entry_points.txt +0 -0
- {package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools.egg-info/top_level.txt +0 -0
|
@@ -1,40 +1,41 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: package-dev-tools
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.6
|
|
4
4
|
Summary: CI/CD tools for Python packages
|
|
5
5
|
Author-email: Quinten Roets <qdr2104@columbia.edu>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Source Code, https://github.com/quintenroets/package-dev-tools
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
Requires-Dist: package-utils<1,>=0.8.4
|
|
12
|
+
Requires-Dist: packaging<27,>=23.2
|
|
12
13
|
Requires-Dist: powercli<1,>=0.4.0
|
|
13
14
|
Requires-Dist: pygithub<3,>=2.1.1
|
|
14
15
|
Requires-Dist: python-slugify<9,>=8.0.1
|
|
16
|
+
Requires-Dist: PyYaml<7,>=6.0.1
|
|
17
|
+
Requires-Dist: requests<3,>=2.31.0
|
|
15
18
|
Requires-Dist: simple-classproperty<5,>=4.0.2
|
|
16
19
|
Requires-Dist: superpathlib<3,>=2.0.12
|
|
17
|
-
Requires-Dist: toml<1,>=0.10.2
|
|
18
20
|
Requires-Dist: autotyping<25,>=23.3.0
|
|
19
21
|
Requires-Dist: bump2version<2,>=1.0.1
|
|
20
22
|
Requires-Dist: coverage<8,>=7.4.0
|
|
21
23
|
Requires-Dist: libcst<2,>=1.7.0
|
|
22
24
|
Requires-Dist: pre-commit<5,>=3.5.0
|
|
23
25
|
Requires-Dist: pytest<10,>=9.0.2
|
|
24
|
-
Requires-Dist: mypy<2.
|
|
25
|
-
Requires-Dist: ruff<0.
|
|
26
|
+
Requires-Dist: mypy<2.4,>=2.3
|
|
27
|
+
Requires-Dist: ruff<0.17,>=0.16.3
|
|
26
28
|
Provides-Extra: dev
|
|
27
29
|
Requires-Dist: hypothesis<7,>=6.91.0; extra == "dev"
|
|
28
30
|
Requires-Dist: package-dev-utils<1,>=0.1.6; extra == "dev"
|
|
29
31
|
Requires-Dist: package-utils[context]<1,>=0.8.4; extra == "dev"
|
|
30
32
|
Requires-Dist: types-requests<3,>=2.31.0.10; extra == "dev"
|
|
31
|
-
Requires-Dist: types-toml<1,>=0.10.8.7; extra == "dev"
|
|
32
33
|
Dynamic: license-file
|
|
33
34
|
|
|
34
35
|
# Package Dev Tools
|
|
35
36
|
[](https://badge.fury.io/py/package-dev-tools)
|
|
36
37
|

|
|
37
|
-

|
|
38
39
|

|
|
39
40
|

|
|
40
41
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Package Dev Tools
|
|
2
2
|
[](https://badge.fury.io/py/package-dev-tools)
|
|
3
3
|

|
|
4
|
-

|
|
5
5
|

|
|
6
6
|

|
|
7
7
|
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "package-dev-tools"
|
|
3
|
-
version = "0.8.
|
|
3
|
+
version = "0.8.6"
|
|
4
4
|
description = "CI/CD tools for Python packages"
|
|
5
5
|
authors = [{name = "Quinten Roets", email = "qdr2104@columbia.edu"}]
|
|
6
6
|
license = "MIT"
|
|
7
7
|
readme = "README.md"
|
|
8
|
-
requires-python = ">=3.
|
|
8
|
+
requires-python = ">=3.11"
|
|
9
9
|
dependencies = [
|
|
10
10
|
"package-utils >=0.8.4, <1",
|
|
11
|
+
"packaging >=23.2, <27",
|
|
11
12
|
"powercli >=0.4.0, <1",
|
|
12
13
|
"pygithub >=2.1.1, <3",
|
|
13
14
|
"python-slugify >=8.0.1, <9",
|
|
15
|
+
"PyYaml >=6.0.1, <7",
|
|
16
|
+
"requests >=2.31.0, <3",
|
|
14
17
|
"simple-classproperty >=4.0.2, <5",
|
|
15
18
|
"superpathlib >=2.0.12, <3",
|
|
16
|
-
"toml >=0.10.2, <1",
|
|
17
19
|
|
|
18
20
|
# pre-commit binaries
|
|
19
21
|
"autotyping >=23.3.0, <25",
|
|
@@ -24,8 +26,8 @@ dependencies = [
|
|
|
24
26
|
"pytest >=9.0.2, <10",
|
|
25
27
|
|
|
26
28
|
# formatting binaries, stricter version range
|
|
27
|
-
"mypy >= 2.
|
|
28
|
-
"ruff >=0.
|
|
29
|
+
"mypy >= 2.3, < 2.4",
|
|
30
|
+
"ruff >=0.16.3, <0.17"
|
|
29
31
|
]
|
|
30
32
|
|
|
31
33
|
[project.optional-dependencies]
|
|
@@ -36,7 +38,6 @@ dev = [
|
|
|
36
38
|
|
|
37
39
|
# mypy
|
|
38
40
|
"types-requests >=2.31.0.10, <3",
|
|
39
|
-
"types-toml >=0.10.8.7, <1",
|
|
40
41
|
]
|
|
41
42
|
|
|
42
43
|
[project.urls]
|
|
@@ -63,6 +64,7 @@ build-backend = "setuptools.build_meta"
|
|
|
63
64
|
|
|
64
65
|
[tool.coverage.run]
|
|
65
66
|
command_line = "-m pytest tests"
|
|
67
|
+
relative_files = true
|
|
66
68
|
|
|
67
69
|
[tool.coverage.report]
|
|
68
70
|
precision = 4
|
|
@@ -84,6 +86,7 @@ fix = true
|
|
|
84
86
|
select = ["ALL"]
|
|
85
87
|
ignore = [
|
|
86
88
|
"ANN401", # annotated with Any
|
|
89
|
+
"CPY001", # missing copyright notice
|
|
87
90
|
"D1", # missing docstrings
|
|
88
91
|
"D200", # one-line docstring
|
|
89
92
|
"D203", # conflicts with D211
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
|
|
3
|
+
from package_dev_tools.utils.git import GitInterface
|
|
4
|
+
|
|
3
5
|
from .cleanup_readme import ReadmeCleaner
|
|
4
6
|
from .cleanup_workflows import WorkflowsCleaner
|
|
5
|
-
from .git import GitInterface
|
|
6
7
|
from .substitute_template_name import NameSubstitutor
|
|
7
8
|
|
|
8
9
|
|
|
@@ -25,4 +26,4 @@ class ProjectInstantiator(NameSubstitutor):
|
|
|
25
26
|
git = GitInterface(self.path)
|
|
26
27
|
git.clean()
|
|
27
28
|
if self.commit:
|
|
28
|
-
git.commit()
|
|
29
|
+
git.commit("Instantiate new project")
|
|
@@ -2,11 +2,10 @@ import urllib.parse
|
|
|
2
2
|
from collections.abc import Iterator
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
4
|
|
|
5
|
-
import cli
|
|
6
5
|
from slugify import slugify
|
|
7
6
|
|
|
8
|
-
from package_dev_tools.actions.instantiate_new_project.git import GitInterface
|
|
9
7
|
from package_dev_tools.models import Path
|
|
8
|
+
from package_dev_tools.utils.git import GitInterface
|
|
10
9
|
from package_dev_tools.utils.package import PackageInfo
|
|
11
10
|
|
|
12
11
|
from .project import Project
|
|
@@ -71,7 +70,7 @@ class NameSubstitutor:
|
|
|
71
70
|
|
|
72
71
|
def generate_paths_to_substitute(self) -> Iterator[Path]:
|
|
73
72
|
workflows_folder = self.path / ".github" / "workflows"
|
|
74
|
-
for path in self.
|
|
73
|
+
for path in GitInterface(self.path).generate_files():
|
|
75
74
|
# Modifying workflow files requires additional permissions.
|
|
76
75
|
# Therefore, we don't do substitute those
|
|
77
76
|
is_workflow = path.is_relative_to(workflows_folder)
|
|
@@ -87,9 +86,3 @@ class NameSubstitutor:
|
|
|
87
86
|
)
|
|
88
87
|
renamed_path = Path(renamed_path_str)
|
|
89
88
|
path.rename(renamed_path)
|
|
90
|
-
|
|
91
|
-
def generate_project_files(self) -> Iterator[Path]:
|
|
92
|
-
command = ("git", "ls-tree", "-r", "HEAD", "--name-only")
|
|
93
|
-
relative_paths = cli.capture_output_lines(command, cwd=self.path)
|
|
94
|
-
for path in relative_paths:
|
|
95
|
-
yield self.path / path
|
|
@@ -7,7 +7,7 @@ from superpathlib import Path
|
|
|
7
7
|
|
|
8
8
|
from package_dev_tools import models
|
|
9
9
|
from package_dev_tools.actions.instantiate_new_project import ProjectInstantiator
|
|
10
|
-
from package_dev_tools.
|
|
10
|
+
from package_dev_tools.utils.git import GitInterface
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
@dataclass
|
|
@@ -52,7 +52,7 @@ class Merger: # pragma: nocover
|
|
|
52
52
|
self.git.capture_output("checkout -B", name, "main")
|
|
53
53
|
self.overwrite_project_files(path, self.template_directory)
|
|
54
54
|
self.git.capture_output("add -A")
|
|
55
|
-
self.git.commit()
|
|
55
|
+
self.git.commit("Instantiate new project", allow_empty=True)
|
|
56
56
|
|
|
57
57
|
def overwrite_project_files(self, source: Path, destination: Path) -> None:
|
|
58
58
|
self.remove_project_files(destination)
|
|
@@ -63,15 +63,9 @@ class Merger: # pragma: nocover
|
|
|
63
63
|
|
|
64
64
|
def generate_project_files(self) -> Iterator[Path]:
|
|
65
65
|
path = models.Path(self.repository_directory)
|
|
66
|
-
|
|
67
|
-
yield file.relative_to(path)
|
|
66
|
+
return GitInterface(path).generate_relative_files()
|
|
68
67
|
|
|
69
68
|
@classmethod
|
|
70
69
|
def remove_project_files(cls, directory: Path) -> None:
|
|
71
|
-
for file in
|
|
70
|
+
for file in GitInterface(models.Path(directory)).generate_files():
|
|
72
71
|
file.unlink()
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def generate_project_files(path: models.Path) -> Iterator[models.Path]:
|
|
76
|
-
instantiator = ProjectInstantiator(path=path, current_project_name="dummy")
|
|
77
|
-
yield from instantiator.generate_project_files()
|
|
@@ -11,10 +11,7 @@ from slugify import slugify
|
|
|
11
11
|
from superpathlib import Path
|
|
12
12
|
|
|
13
13
|
from package_dev_tools import models
|
|
14
|
-
from package_dev_tools.
|
|
15
|
-
GitInterface,
|
|
16
|
-
resolve_git_binary,
|
|
17
|
-
)
|
|
14
|
+
from package_dev_tools.utils.git import GitInterface, resolve_git_binary
|
|
18
15
|
|
|
19
16
|
from . import git
|
|
20
17
|
from .merge import Merger
|
|
@@ -79,7 +76,7 @@ class TemplateSyncer(git.Client):
|
|
|
79
76
|
self.apply_ignore_patterns()
|
|
80
77
|
path = models.Path(self.downloaded_repository_directory)
|
|
81
78
|
try:
|
|
82
|
-
GitInterface(path=path
|
|
79
|
+
GitInterface(path=path).commit(self.commit_message)
|
|
83
80
|
is_updated = True
|
|
84
81
|
except cli.CalledProcessError:
|
|
85
82
|
is_updated = False
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/extract_info.py
RENAMED
|
@@ -11,11 +11,11 @@ def extract_package_name(info: PackageInfo) -> None:
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def extract_required_python_version(info: PackageInfo) -> None:
|
|
14
|
-
cli.console.print(info.
|
|
14
|
+
cli.console.print(info.python_versions.required)
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def extract_supported_python_versions(info: PackageInfo) -> None:
|
|
18
|
-
cli.console.print(json.dumps(
|
|
18
|
+
cli.console.print(json.dumps(info.python_versions.supported))
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
package_name = create_entry_point(extract_package_name)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from io import StringIO
|
|
3
|
+
|
|
4
|
+
import cli
|
|
5
|
+
from coverage import Coverage
|
|
6
|
+
from coverage.results import should_fail_under
|
|
7
|
+
|
|
8
|
+
from package_dev_tools.models import Path
|
|
9
|
+
from package_dev_tools.utils.badge import Badge, BadgeUpdater
|
|
10
|
+
from package_dev_tools.utils.git import GitInterface
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def check_coverage() -> None:
|
|
14
|
+
coverage = load_coverage()
|
|
15
|
+
files = [str(path) for path in GitInterface().generate_relative_files("*.py")]
|
|
16
|
+
percentage = coverage.report(files, ignore_errors=True, file=StringIO())
|
|
17
|
+
verify_fail_under(coverage, files, percentage)
|
|
18
|
+
has_changed = update_badge(coverage, files, percentage)
|
|
19
|
+
sys.exit(1 if has_changed else 0)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def load_coverage() -> Coverage:
|
|
23
|
+
coverage = Coverage()
|
|
24
|
+
if not Path(coverage.config.data_file).exists():
|
|
25
|
+
message = "No coverage results found."
|
|
26
|
+
raise FileNotFoundError(message)
|
|
27
|
+
coverage.load()
|
|
28
|
+
config = coverage.config
|
|
29
|
+
config.report_omit = [*config.run_omit, *(config.report_omit or [])]
|
|
30
|
+
return coverage
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def verify_fail_under(coverage: Coverage, files: list[str], percentage: float) -> None:
|
|
34
|
+
config = coverage.config
|
|
35
|
+
if should_fail_under(percentage, config.fail_under, config.precision):
|
|
36
|
+
coverage.html_report(files, ignore_errors=True)
|
|
37
|
+
coverage.report(files, show_missing=True, ignore_errors=True)
|
|
38
|
+
current = format_percentage(percentage, config.precision)
|
|
39
|
+
required = format_percentage(config.fail_under, config.precision)
|
|
40
|
+
message = f"Coverage {current} is below the required {required}"
|
|
41
|
+
raise RuntimeError(message)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def update_badge(coverage: Coverage, files: list[str], percentage: float) -> bool:
|
|
45
|
+
badge = Badge("Coverage", f"coverage-{round(percentage)}%25")
|
|
46
|
+
has_changed = BadgeUpdater(badge).run()
|
|
47
|
+
if has_changed:
|
|
48
|
+
formatted_percentage = format_percentage(percentage, coverage.config.precision)
|
|
49
|
+
cli.console.print(f"Updated test coverage: {formatted_percentage}")
|
|
50
|
+
coverage.html_report(files, ignore_errors=True)
|
|
51
|
+
return has_changed
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def format_percentage(value: float, precision: int) -> str:
|
|
55
|
+
return f"{value:.{precision}f}%"
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/pre_commit/check_import.py
RENAMED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import importlib
|
|
2
2
|
|
|
3
|
-
from package_utils.cli import create_entry_point
|
|
3
|
+
from package_utils.cli import create_entry_point
|
|
4
4
|
|
|
5
5
|
from package_dev_tools.utils.package import PackageInfo
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
def check_import() -> None:
|
|
9
|
-
package_info = instantiate_from_cli_args(PackageInfo)
|
|
8
|
+
def check_import(package_info: PackageInfo) -> None:
|
|
10
9
|
importlib.import_module(package_info.package_name)
|
|
11
10
|
|
|
12
11
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from package_dev_tools.utils.badge import Badge, BadgeUpdater
|
|
2
|
+
from package_dev_tools.utils.package import PackageInfo
|
|
3
|
+
from package_dev_tools.utils.python_versions import PythonVersions
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def check_shields() -> None:
|
|
7
|
+
info = PackageInfo()
|
|
8
|
+
python_versions = describe_python_versions(info.python_versions)
|
|
9
|
+
operating_systems = Badge.separator.join(info.supported_operating_systems)
|
|
10
|
+
badges = (
|
|
11
|
+
Badge("Python version", f"python-{python_versions}"),
|
|
12
|
+
Badge("Operating system", f"os-{operating_systems}"),
|
|
13
|
+
)
|
|
14
|
+
for badge in badges:
|
|
15
|
+
BadgeUpdater(badge).run()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def describe_python_versions(versions: PythonVersions) -> str:
|
|
19
|
+
return (
|
|
20
|
+
Badge.separator.join(versions.supported)
|
|
21
|
+
if versions.has_excluded_minors or versions.maximum == versions.required
|
|
22
|
+
else f"{versions.required}+"
|
|
23
|
+
if versions.maximum is None
|
|
24
|
+
else f"{versions.required}--{versions.maximum}"
|
|
25
|
+
)
|
|
@@ -2,6 +2,7 @@ import os
|
|
|
2
2
|
import shlex
|
|
3
3
|
import shutil
|
|
4
4
|
import subprocess
|
|
5
|
+
from collections.abc import Iterator
|
|
5
6
|
from dataclasses import dataclass, field
|
|
6
7
|
from functools import cache
|
|
7
8
|
from typing import Any
|
|
@@ -28,15 +29,23 @@ class GitInterface:
|
|
|
28
29
|
path: Path = field(default_factory=Path.cwd)
|
|
29
30
|
git_name: str = "Quinten"
|
|
30
31
|
git_email: str = "quinten.roets@gmail.com"
|
|
31
|
-
commit_message: str = "Instantiate new project"
|
|
32
32
|
|
|
33
33
|
def clean(self) -> None:
|
|
34
34
|
self.capture_output("add -A")
|
|
35
35
|
self.capture_output("clean -fd")
|
|
36
36
|
|
|
37
|
-
def commit(self) -> None:
|
|
37
|
+
def commit(self, message: str, *, allow_empty: bool = False) -> None:
|
|
38
38
|
self.configure()
|
|
39
|
-
|
|
39
|
+
options = "--no-verify --allow-empty" if allow_empty else "--no-verify"
|
|
40
|
+
self.capture_output(f"commit {options} -m", message)
|
|
41
|
+
|
|
42
|
+
def generate_files(self, *patterns: str) -> Iterator[Path]:
|
|
43
|
+
return (self.path / path for path in self.generate_relative_files(*patterns))
|
|
44
|
+
|
|
45
|
+
def generate_relative_files(self, *patterns: str) -> Iterator[Path]:
|
|
46
|
+
command = "ls-files --cached --others --exclude-standard"
|
|
47
|
+
output = self.capture_output(command, *patterns)
|
|
48
|
+
return (Path(relative_path) for relative_path in output.splitlines())
|
|
40
49
|
|
|
41
50
|
def capture_output(self, *args: CommandItem, **kwargs: Any) -> str:
|
|
42
51
|
return self.create_runner(*args, **kwargs).capture_output()
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import tomllib
|
|
2
|
+
import typing
|
|
3
|
+
from collections.abc import Iterator
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from functools import cached_property
|
|
6
|
+
from typing import Any, ClassVar
|
|
7
|
+
|
|
8
|
+
from superpathlib import Path
|
|
9
|
+
|
|
10
|
+
from .python_versions import PythonVersions
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class PackageInfo:
|
|
15
|
+
path: Path = field(default_factory=Path.cwd)
|
|
16
|
+
os_mapper: ClassVar[dict[str, str]] = {"ubuntu": "linux", "macos": "macOS"}
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def package_name(self) -> str:
|
|
20
|
+
package_data = self.pyproject_info["tool"]["setuptools"]["package-data"]
|
|
21
|
+
project_name = next(iter(package_data))
|
|
22
|
+
return typing.cast("str", project_name)
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def package_slug(self) -> str:
|
|
26
|
+
package_slug = self.pyproject_info["project"]["name"]
|
|
27
|
+
return typing.cast("str", package_slug)
|
|
28
|
+
|
|
29
|
+
@cached_property
|
|
30
|
+
def python_versions(self) -> PythonVersions:
|
|
31
|
+
requirement = self.pyproject_info["project"]["requires-python"]
|
|
32
|
+
return PythonVersions(typing.cast("str", requirement))
|
|
33
|
+
|
|
34
|
+
@cached_property
|
|
35
|
+
def pyproject_info(self) -> dict[str, Any]:
|
|
36
|
+
info_path = self.path / "pyproject.toml"
|
|
37
|
+
return tomllib.loads(info_path.text)
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def supported_operating_systems(self) -> Iterator[str]:
|
|
41
|
+
workflow_path = self.path / ".github" / "workflows" / "build.yml"
|
|
42
|
+
workflow = typing.cast("dict[str, Any]", workflow_path.yaml)
|
|
43
|
+
matrices = (
|
|
44
|
+
job.get("strategy", {}).get("matrix", {})
|
|
45
|
+
for job in workflow["jobs"].values()
|
|
46
|
+
)
|
|
47
|
+
entries = next(matrix["os"] for matrix in matrices if "os" in matrix)
|
|
48
|
+
for entry in typing.cast("list[str]", entries):
|
|
49
|
+
operating_system = entry.removesuffix("-latest")
|
|
50
|
+
yield self.os_mapper.get(operating_system, operating_system)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from collections.abc import Iterator
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from functools import cache, cached_property
|
|
4
|
+
from typing import Any, ClassVar
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
from packaging.specifiers import SpecifierSet
|
|
8
|
+
from packaging.version import Version
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class PythonVersions:
|
|
13
|
+
requirement: str
|
|
14
|
+
major: ClassVar[int] = 3
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def required(self) -> str:
|
|
18
|
+
return str(min(self.specified_versions))
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def supported(self) -> list[str]:
|
|
22
|
+
versions = (
|
|
23
|
+
self.specified_versions
|
|
24
|
+
if self.is_bounded
|
|
25
|
+
else self.included_versions(fetch_latest_python_version(self.major))
|
|
26
|
+
)
|
|
27
|
+
return [str(version) for version in versions]
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def maximum(self) -> str | None:
|
|
31
|
+
return str(max(self.specified_versions)) if self.is_bounded else None
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def has_excluded_minors(self) -> bool:
|
|
35
|
+
minors = [version.minor for version in self.specified_versions]
|
|
36
|
+
return minors != list(range(min(minors), max(minors) + 1))
|
|
37
|
+
|
|
38
|
+
@cached_property
|
|
39
|
+
def specified_versions(self) -> list[Version]:
|
|
40
|
+
return list(self.included_versions(self.search_ceiling))
|
|
41
|
+
|
|
42
|
+
@cached_property
|
|
43
|
+
def is_bounded(self) -> bool:
|
|
44
|
+
return self.search_ceiling not in self.specifiers
|
|
45
|
+
|
|
46
|
+
@cached_property
|
|
47
|
+
def search_ceiling(self) -> Version:
|
|
48
|
+
versions = (
|
|
49
|
+
Version(specifier.version.removesuffix(".*"))
|
|
50
|
+
for specifier in self.specifiers
|
|
51
|
+
)
|
|
52
|
+
minors = (version.minor for version in versions if version.major == self.major)
|
|
53
|
+
return self.version(max(minors, default=0) + 1)
|
|
54
|
+
|
|
55
|
+
def included_versions(self, ceiling: Version) -> Iterator[Version]:
|
|
56
|
+
candidates = (self.version(minor) for minor in range(ceiling.minor + 1))
|
|
57
|
+
return (version for version in candidates if version in self.specifiers)
|
|
58
|
+
|
|
59
|
+
@cached_property
|
|
60
|
+
def specifiers(self) -> SpecifierSet:
|
|
61
|
+
return SpecifierSet(self.requirement)
|
|
62
|
+
|
|
63
|
+
def version(self, minor: int) -> Version:
|
|
64
|
+
return Version(f"{self.major}.{minor}")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@cache
|
|
68
|
+
def fetch_latest_python_version(major: int) -> Version:
|
|
69
|
+
url = "https://www.python.org/api/v2/downloads/release/"
|
|
70
|
+
parameters = {"is_published": "true", "pre_release": "false"}
|
|
71
|
+
response = requests.get(url, params=parameters, timeout=10)
|
|
72
|
+
releases: list[dict[str, Any]] = response.json()
|
|
73
|
+
return max(
|
|
74
|
+
Version(release["name"].removeprefix("Python "))
|
|
75
|
+
for release in releases
|
|
76
|
+
if release["version"] == major
|
|
77
|
+
)
|
|
@@ -1,40 +1,41 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: package-dev-tools
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.6
|
|
4
4
|
Summary: CI/CD tools for Python packages
|
|
5
5
|
Author-email: Quinten Roets <qdr2104@columbia.edu>
|
|
6
6
|
License-Expression: MIT
|
|
7
7
|
Project-URL: Source Code, https://github.com/quintenroets/package-dev-tools
|
|
8
|
-
Requires-Python: >=3.
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
9
|
Description-Content-Type: text/markdown
|
|
10
10
|
License-File: LICENSE
|
|
11
11
|
Requires-Dist: package-utils<1,>=0.8.4
|
|
12
|
+
Requires-Dist: packaging<27,>=23.2
|
|
12
13
|
Requires-Dist: powercli<1,>=0.4.0
|
|
13
14
|
Requires-Dist: pygithub<3,>=2.1.1
|
|
14
15
|
Requires-Dist: python-slugify<9,>=8.0.1
|
|
16
|
+
Requires-Dist: PyYaml<7,>=6.0.1
|
|
17
|
+
Requires-Dist: requests<3,>=2.31.0
|
|
15
18
|
Requires-Dist: simple-classproperty<5,>=4.0.2
|
|
16
19
|
Requires-Dist: superpathlib<3,>=2.0.12
|
|
17
|
-
Requires-Dist: toml<1,>=0.10.2
|
|
18
20
|
Requires-Dist: autotyping<25,>=23.3.0
|
|
19
21
|
Requires-Dist: bump2version<2,>=1.0.1
|
|
20
22
|
Requires-Dist: coverage<8,>=7.4.0
|
|
21
23
|
Requires-Dist: libcst<2,>=1.7.0
|
|
22
24
|
Requires-Dist: pre-commit<5,>=3.5.0
|
|
23
25
|
Requires-Dist: pytest<10,>=9.0.2
|
|
24
|
-
Requires-Dist: mypy<2.
|
|
25
|
-
Requires-Dist: ruff<0.
|
|
26
|
+
Requires-Dist: mypy<2.4,>=2.3
|
|
27
|
+
Requires-Dist: ruff<0.17,>=0.16.3
|
|
26
28
|
Provides-Extra: dev
|
|
27
29
|
Requires-Dist: hypothesis<7,>=6.91.0; extra == "dev"
|
|
28
30
|
Requires-Dist: package-dev-utils<1,>=0.1.6; extra == "dev"
|
|
29
31
|
Requires-Dist: package-utils[context]<1,>=0.8.4; extra == "dev"
|
|
30
32
|
Requires-Dist: types-requests<3,>=2.31.0.10; extra == "dev"
|
|
31
|
-
Requires-Dist: types-toml<1,>=0.10.8.7; extra == "dev"
|
|
32
33
|
Dynamic: license-file
|
|
33
34
|
|
|
34
35
|
# Package Dev Tools
|
|
35
36
|
[](https://badge.fury.io/py/package-dev-tools)
|
|
36
37
|

|
|
37
|
-

|
|
38
39
|

|
|
39
40
|

|
|
40
41
|
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools.egg-info/SOURCES.txt
RENAMED
|
@@ -15,7 +15,6 @@ src/package_dev_tools/actions/__init__.py
|
|
|
15
15
|
src/package_dev_tools/actions/instantiate_new_project/__init__.py
|
|
16
16
|
src/package_dev_tools/actions/instantiate_new_project/cleanup_readme.py
|
|
17
17
|
src/package_dev_tools/actions/instantiate_new_project/cleanup_workflows.py
|
|
18
|
-
src/package_dev_tools/actions/instantiate_new_project/git.py
|
|
19
18
|
src/package_dev_tools/actions/instantiate_new_project/instantiate_new_project.py
|
|
20
19
|
src/package_dev_tools/actions/instantiate_new_project/substitute_template_name/__init__.py
|
|
21
20
|
src/package_dev_tools/actions/instantiate_new_project/substitute_template_name/project.py
|
|
@@ -45,4 +44,6 @@ src/package_dev_tools/pre_commit/expand_docstrings.py
|
|
|
45
44
|
src/package_dev_tools/pre_commit/export_config.py
|
|
46
45
|
src/package_dev_tools/utils/__init__.py
|
|
47
46
|
src/package_dev_tools/utils/badge.py
|
|
48
|
-
src/package_dev_tools/utils/
|
|
47
|
+
src/package_dev_tools/utils/git.py
|
|
48
|
+
src/package_dev_tools/utils/package.py
|
|
49
|
+
src/package_dev_tools/utils/python_versions.py
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools.egg-info/requires.txt
RENAMED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
package-utils<1,>=0.8.4
|
|
2
|
+
packaging<27,>=23.2
|
|
2
3
|
powercli<1,>=0.4.0
|
|
3
4
|
pygithub<3,>=2.1.1
|
|
4
5
|
python-slugify<9,>=8.0.1
|
|
6
|
+
PyYaml<7,>=6.0.1
|
|
7
|
+
requests<3,>=2.31.0
|
|
5
8
|
simple-classproperty<5,>=4.0.2
|
|
6
9
|
superpathlib<3,>=2.0.12
|
|
7
|
-
toml<1,>=0.10.2
|
|
8
10
|
autotyping<25,>=23.3.0
|
|
9
11
|
bump2version<2,>=1.0.1
|
|
10
12
|
coverage<8,>=7.4.0
|
|
11
13
|
libcst<2,>=1.7.0
|
|
12
14
|
pre-commit<5,>=3.5.0
|
|
13
15
|
pytest<10,>=9.0.2
|
|
14
|
-
mypy<2.
|
|
15
|
-
ruff<0.
|
|
16
|
+
mypy<2.4,>=2.3
|
|
17
|
+
ruff<0.17,>=0.16.3
|
|
16
18
|
|
|
17
19
|
[dev]
|
|
18
20
|
hypothesis<7,>=6.91.0
|
|
19
21
|
package-dev-utils<1,>=0.1.6
|
|
20
22
|
package-utils[context]<1,>=0.8.4
|
|
21
23
|
types-requests<3,>=2.31.0.10
|
|
22
|
-
types-toml<1,>=0.10.8.7
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
|
|
3
|
-
import cli
|
|
4
|
-
|
|
5
|
-
from package_dev_tools.models import Path
|
|
6
|
-
from package_dev_tools.utils.badge import Badge, BadgeUpdater
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def check_coverage(*, verify_all_files_tested: bool = True) -> None:
|
|
10
|
-
verify_coverage_results()
|
|
11
|
-
if verify_all_files_tested:
|
|
12
|
-
verify_all_python_files_tested()
|
|
13
|
-
|
|
14
|
-
try:
|
|
15
|
-
coverage_percentage = cli.capture_output("coverage report -i --format total")
|
|
16
|
-
except cli.CalledProcessError:
|
|
17
|
-
cli.capture_output("coverage html -i", check=False)
|
|
18
|
-
cli.run("coverage report -mi", check=False)
|
|
19
|
-
raise
|
|
20
|
-
coverage_percentage_has_changed = update_coverage_shield(coverage_percentage)
|
|
21
|
-
if coverage_percentage_has_changed:
|
|
22
|
-
cli.console.print(f"Updated test coverage: {coverage_percentage}%")
|
|
23
|
-
cli.capture_output("coverage html")
|
|
24
|
-
exit_code = 1 if coverage_percentage_has_changed else 0
|
|
25
|
-
sys.exit(exit_code)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def update_coverage_shield(coverage_percentage: float | str) -> bool:
|
|
29
|
-
if isinstance(coverage_percentage, str):
|
|
30
|
-
coverage_percentage = float(coverage_percentage)
|
|
31
|
-
coverage_percentage_int = round(coverage_percentage)
|
|
32
|
-
badge = Badge("Coverage", f"coverage-{coverage_percentage_int}%25")
|
|
33
|
-
return BadgeUpdater(badge).run()
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def verify_all_python_files_tested() -> None:
|
|
37
|
-
python_files = set(cli.capture_output_lines("git ls-files '*.py'"))
|
|
38
|
-
coverage_lines = cli.capture_output_lines("coverage report -i", check=False)
|
|
39
|
-
covered_files = {line.split()[0] for line in coverage_lines[2:-2]}
|
|
40
|
-
not_covered_files = python_files - covered_files
|
|
41
|
-
if not_covered_files:
|
|
42
|
-
cli.run("coverage html -i", check=False)
|
|
43
|
-
message_parts = (
|
|
44
|
-
"The following files are not covered by tests:",
|
|
45
|
-
*not_covered_files,
|
|
46
|
-
)
|
|
47
|
-
message = "\n\t".join(message_parts)
|
|
48
|
-
raise RuntimeError(message)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def verify_coverage_results() -> None:
|
|
52
|
-
if not Path(".coverage").exists():
|
|
53
|
-
message = "No coverage results found."
|
|
54
|
-
raise OSError(message)
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
from package_dev_tools.utils.badge import Badge, BadgeUpdater
|
|
2
|
-
from package_dev_tools.utils.package import PackageInfo
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def check_shields() -> None:
|
|
6
|
-
package_info = PackageInfo()
|
|
7
|
-
python_version = create_python_version_badge(package_info=package_info)
|
|
8
|
-
operating_systems = package_info.supported_operating_systems
|
|
9
|
-
operating_system = "os-" + "%20%7c%20".join(operating_systems)
|
|
10
|
-
badges = (
|
|
11
|
-
Badge("Python version", python_version),
|
|
12
|
-
Badge("Operating system", operating_system),
|
|
13
|
-
)
|
|
14
|
-
for badge in badges:
|
|
15
|
-
BadgeUpdater(badge).run()
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def create_python_version_badge(package_info: PackageInfo) -> str:
|
|
19
|
-
minimum_version = package_info.required_python_version
|
|
20
|
-
if "," in package_info.listed_version: # pragma: nocover
|
|
21
|
-
maximum_version = f"3.{package_info.latest_supported_python_minor}"
|
|
22
|
-
version = minimum_version + "--" + maximum_version
|
|
23
|
-
else:
|
|
24
|
-
version = minimum_version + "+"
|
|
25
|
-
return f"python-{version}"
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import typing
|
|
2
|
-
from collections.abc import Iterator
|
|
3
|
-
from dataclasses import dataclass, field
|
|
4
|
-
from functools import cached_property
|
|
5
|
-
from typing import Any, ClassVar
|
|
6
|
-
|
|
7
|
-
import requests
|
|
8
|
-
import toml
|
|
9
|
-
from superpathlib import Path
|
|
10
|
-
|
|
11
|
-
SUCCESS_CODE = 200
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@dataclass
|
|
15
|
-
class PackageInfo:
|
|
16
|
-
path: Path = field(default_factory=Path.cwd)
|
|
17
|
-
os_mapper: ClassVar[dict[str, str]] = {"ubuntu": "linux", "macos": "macOS"}
|
|
18
|
-
|
|
19
|
-
@property
|
|
20
|
-
def package_name(self) -> str:
|
|
21
|
-
package_data = self.pyproject_info["tool"]["setuptools"]["package-data"]
|
|
22
|
-
project_name = next(iter(package_data))
|
|
23
|
-
return typing.cast("str", project_name)
|
|
24
|
-
|
|
25
|
-
@property
|
|
26
|
-
def package_slug(self) -> str:
|
|
27
|
-
package_slug = self.pyproject_info["project"]["name"]
|
|
28
|
-
return typing.cast("str", package_slug)
|
|
29
|
-
|
|
30
|
-
@cached_property
|
|
31
|
-
def listed_version(self) -> str:
|
|
32
|
-
version = self.pyproject_info["project"]["requires-python"].split(">=")[1]
|
|
33
|
-
return typing.cast("str", version)
|
|
34
|
-
|
|
35
|
-
@property
|
|
36
|
-
def required_python_version(self) -> str:
|
|
37
|
-
version = self.listed_version
|
|
38
|
-
if "," in version:
|
|
39
|
-
version = version.split(",")[0]
|
|
40
|
-
return version
|
|
41
|
-
|
|
42
|
-
@property
|
|
43
|
-
def required_python_minor(self) -> int:
|
|
44
|
-
minor_version = self.required_python_version.split(".")[-1]
|
|
45
|
-
return int(minor_version)
|
|
46
|
-
|
|
47
|
-
@property
|
|
48
|
-
def supported_python_versions(self) -> Iterator[str]:
|
|
49
|
-
latest_python_minor = self.latest_supported_python_minor
|
|
50
|
-
minors = range(self.required_python_minor, latest_python_minor + 1)
|
|
51
|
-
return (f"3.{minor_version}" for minor_version in minors)
|
|
52
|
-
|
|
53
|
-
@property
|
|
54
|
-
def latest_supported_python_minor(self) -> int:
|
|
55
|
-
return (
|
|
56
|
-
int(self.listed_version.split("<")[1].split(".")[-1]) - 1
|
|
57
|
-
if "," in self.listed_version
|
|
58
|
-
else self.retrieve_latest_python_minor()
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
def retrieve_latest_python_minor(self) -> int:
|
|
62
|
-
minor_version = self.required_python_minor
|
|
63
|
-
while self.release_exists(minor_version + 1):
|
|
64
|
-
minor_version += 1
|
|
65
|
-
return minor_version
|
|
66
|
-
|
|
67
|
-
@classmethod
|
|
68
|
-
def release_exists(cls, minor_version: int) -> bool:
|
|
69
|
-
version = f"3.{minor_version}.0"
|
|
70
|
-
base_url = "https://www.python.org/ftp/python/"
|
|
71
|
-
filename = f"Python-{version}.tar.xz"
|
|
72
|
-
url = f"{base_url}/{version}/{filename}"
|
|
73
|
-
return requests.head(url, timeout=10).status_code == SUCCESS_CODE
|
|
74
|
-
|
|
75
|
-
@property
|
|
76
|
-
def pyproject_info(self) -> dict[str, Any]:
|
|
77
|
-
info_path = self.path / "pyproject.toml"
|
|
78
|
-
return toml.loads(info_path.text)
|
|
79
|
-
|
|
80
|
-
@property
|
|
81
|
-
def supported_operating_systems(self) -> Iterator[str]:
|
|
82
|
-
workflow_path = self.path / ".github" / "workflows" / "build.yml"
|
|
83
|
-
os_keyword = "os: ["
|
|
84
|
-
os_line = next(line for line in workflow_path.lines if os_keyword in line)
|
|
85
|
-
os_entries = os_line.split(os_keyword)[1].split("]")[0].split(",")
|
|
86
|
-
for entry in os_entries:
|
|
87
|
-
parsed_entry = entry.strip().replace("-latest", "")
|
|
88
|
-
mapped_entry = self.os_mapper.get(parsed_entry, parsed_entry)
|
|
89
|
-
yield mapped_entry
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/actions/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/check_coverage.py
RENAMED
|
File without changes
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/check_shields.py
RENAMED
|
File without changes
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/cleanup_readme.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/cli/sync_template.py
RENAMED
|
File without changes
|
|
File without changes
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/models/__init__.py
RENAMED
|
File without changes
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools/pre_commit/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{package_dev_tools-0.8.4 → package_dev_tools-0.8.6}/src/package_dev_tools.egg-info/top_level.txt
RENAMED
|
File without changes
|