afterpython 0.1.0__py3-none-any.whl → 0.1.0.dev6__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.
- afterpython/{templates/pre-commit-config-template.yaml → .pre-commit-config.yaml} +1 -1
- afterpython/_io/toml.py +3 -5
- afterpython/_paths.py +1 -1
- afterpython/_typing.py +2 -1
- afterpython/builders/__init__.py +3 -12
- afterpython/builders/metadata.py +3 -7
- afterpython/builders/molab.py +99 -0
- afterpython/cli/__init__.py +1 -0
- afterpython/cli/commands/build.py +68 -97
- afterpython/cli/commands/bump.py +0 -30
- afterpython/cli/commands/check.py +1 -1
- afterpython/cli/commands/clean.py +3 -4
- afterpython/cli/commands/commit.py +3 -21
- afterpython/cli/commands/commitizen.py +1 -1
- afterpython/cli/commands/dev.py +9 -13
- afterpython/cli/commands/format.py +1 -1
- afterpython/cli/commands/init.py +39 -48
- afterpython/cli/commands/install.py +2 -8
- afterpython/cli/commands/pre_commit.py +1 -1
- afterpython/cli/commands/preview.py +1 -1
- afterpython/cli/commands/start.py +4 -7
- afterpython/cli/commands/sync.py +21 -53
- afterpython/cli/commands/update.py +8 -31
- afterpython/cli/main.py +14 -75
- afterpython/const.py +1 -0
- afterpython/cz.toml +27 -0
- afterpython/pcu.py +1 -3
- afterpython/templates/deploy-workflow-template.yml +5 -5
- afterpython/templates/release-workflow-template.yml +3 -3
- afterpython/templates/ruff-template.toml +1 -1
- afterpython/tools/_afterpython.py +10 -73
- afterpython/tools/_git.py +2 -28
- afterpython/tools/commitizen.py +45 -5
- afterpython/tools/github_actions.py +53 -23
- afterpython/tools/myst.py +5 -46
- afterpython/tools/pre_commit.py +31 -6
- afterpython/tools/pyproject.py +2 -40
- afterpython/utils.py +0 -82
- {afterpython-0.1.0.dist-info → afterpython-0.1.0.dev6.dist-info}/METADATA +10 -34
- afterpython-0.1.0.dev6.dist-info/RECORD +47 -0
- {afterpython-0.1.0.dist-info → afterpython-0.1.0.dev6.dist-info}/WHEEL +1 -1
- afterpython/builders/content_json.py +0 -131
- afterpython/builders/index_md.py +0 -94
- afterpython/builders/jupyter_notebook.py +0 -293
- afterpython/builders/markdown.py +0 -271
- afterpython/cli/commands/add.py +0 -67
- afterpython/cli/commands/init_branch_rules.py +0 -9
- afterpython/cli/commands/lock.py +0 -23
- afterpython/cli/commands/remove.py +0 -67
- afterpython/templates/ci-workflow-template.yml +0 -197
- afterpython/templates/cz-template.toml +0 -7
- afterpython/templates/dependabot-template.yml +0 -30
- afterpython/tools/branch_rules.py +0 -106
- afterpython-0.1.0.dist-info/RECORD +0 -57
- {afterpython-0.1.0.dist-info → afterpython-0.1.0.dev6.dist-info}/entry_points.txt +0 -0
afterpython/cli/commands/init.py
CHANGED
|
@@ -7,13 +7,38 @@ import afterpython as ap
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
def init_ruff_toml():
|
|
10
|
-
|
|
10
|
+
from afterpython.tools.pre_commit import update_pre_commit
|
|
11
|
+
|
|
12
|
+
afterpython_path = ap.paths.afterpython_path
|
|
13
|
+
ruff_toml_path = afterpython_path / "ruff.toml"
|
|
11
14
|
if ruff_toml_path.exists():
|
|
12
15
|
click.echo(f"Ruff configuration file {ruff_toml_path} already exists")
|
|
13
16
|
return
|
|
14
17
|
ruff_template_path = ap.paths.templates_path / "ruff-template.toml"
|
|
15
18
|
shutil.copy(ruff_template_path, ruff_toml_path)
|
|
16
19
|
click.echo(f"Created {ruff_toml_path}")
|
|
20
|
+
# add ruff-pre-commit hook to .pre-commit-config.yaml
|
|
21
|
+
data_update = {
|
|
22
|
+
"repos": [
|
|
23
|
+
{
|
|
24
|
+
"repo": "https://github.com/astral-sh/ruff-pre-commit",
|
|
25
|
+
"rev": "v0.14.5",
|
|
26
|
+
"hooks": [
|
|
27
|
+
{
|
|
28
|
+
"id": "ruff-check",
|
|
29
|
+
"stages": ["pre-commit"],
|
|
30
|
+
"args": ["--config", "./afterpython/ruff.toml"],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "ruff-format",
|
|
34
|
+
"stages": ["pre-commit"],
|
|
35
|
+
"args": ["--config", "./afterpython/ruff.toml"],
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
update_pre_commit(data_update)
|
|
17
42
|
|
|
18
43
|
|
|
19
44
|
def init_website():
|
|
@@ -21,43 +46,19 @@ def init_website():
|
|
|
21
46
|
subprocess.run(["ap", "update", "website"])
|
|
22
47
|
|
|
23
48
|
|
|
24
|
-
def init_py_typed():
|
|
25
|
-
from afterpython.tools.pyproject import find_package_directory
|
|
26
|
-
|
|
27
|
-
try:
|
|
28
|
-
package_dir = find_package_directory()
|
|
29
|
-
except FileNotFoundError:
|
|
30
|
-
click.echo(
|
|
31
|
-
"Could not find package directory (__init__.py not found), skipping py-typed initialization"
|
|
32
|
-
)
|
|
33
|
-
return
|
|
34
|
-
py_typed_path = package_dir / "py.typed"
|
|
35
|
-
if py_typed_path.exists():
|
|
36
|
-
click.echo(f"py.typed file already exists at {py_typed_path}")
|
|
37
|
-
return
|
|
38
|
-
py_typed_path.touch()
|
|
39
|
-
click.echo(f"Created {py_typed_path}")
|
|
40
|
-
|
|
41
|
-
|
|
42
49
|
@click.command()
|
|
43
|
-
@click.option(
|
|
44
|
-
"--yes",
|
|
45
|
-
"-y",
|
|
46
|
-
is_flag=True,
|
|
47
|
-
help="Automatically answer yes to all prompts",
|
|
48
|
-
)
|
|
49
50
|
@click.pass_context
|
|
50
|
-
def init(ctx
|
|
51
|
-
"""Initialize
|
|
51
|
+
def init(ctx):
|
|
52
|
+
"""Initialize afterpython with MyST Markdown (by default) and project website template"""
|
|
53
|
+
from afterpython.tools.pyproject import init_pyproject
|
|
52
54
|
from afterpython.tools._afterpython import init_afterpython
|
|
55
|
+
from afterpython.tools.myst import init_myst
|
|
56
|
+
from afterpython.tools.pre_commit import init_pre_commit
|
|
53
57
|
from afterpython.tools.commitizen import init_commitizen
|
|
54
58
|
from afterpython.tools.github_actions import (
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
init_release_workflow,
|
|
60
|
+
init_deploy_workflow,
|
|
57
61
|
)
|
|
58
|
-
from afterpython.tools.myst import init_myst
|
|
59
|
-
from afterpython.tools.pre_commit import init_pre_commit
|
|
60
|
-
from afterpython.tools.pyproject import init_pyproject
|
|
61
62
|
|
|
62
63
|
paths = ctx.obj["paths"]
|
|
63
64
|
click.echo("Initializing afterpython...")
|
|
@@ -66,6 +67,7 @@ def init(ctx, yes):
|
|
|
66
67
|
|
|
67
68
|
afterpython_path.mkdir(parents=True, exist_ok=True)
|
|
68
69
|
static_path.mkdir(parents=True, exist_ok=True)
|
|
70
|
+
afterpython_path.joinpath("afterpython.toml").touch()
|
|
69
71
|
|
|
70
72
|
init_pyproject()
|
|
71
73
|
|
|
@@ -77,31 +79,20 @@ def init(ctx, yes):
|
|
|
77
79
|
|
|
78
80
|
init_website()
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
init_py_typed()
|
|
82
|
-
|
|
83
|
-
create_workflow("deploy")
|
|
84
|
-
create_workflow("ci")
|
|
85
|
-
|
|
86
|
-
if yes or click.confirm(
|
|
82
|
+
if click.confirm(
|
|
87
83
|
f"\nCreate .pre-commit-config.yaml in {afterpython_path}?", default=True
|
|
88
84
|
):
|
|
89
85
|
init_pre_commit()
|
|
90
86
|
|
|
91
|
-
if
|
|
87
|
+
if click.confirm(f"\nCreate ruff.toml in {afterpython_path}?", default=True):
|
|
92
88
|
init_ruff_toml()
|
|
93
89
|
|
|
94
|
-
if
|
|
90
|
+
if click.confirm(
|
|
95
91
|
f"\nCreate commitizen configuration (cz.toml) in {afterpython_path} "
|
|
96
92
|
f"and release workflow in .github/workflows/release.yml?",
|
|
97
93
|
default=True,
|
|
98
94
|
):
|
|
99
95
|
init_commitizen()
|
|
100
|
-
|
|
96
|
+
init_release_workflow()
|
|
101
97
|
|
|
102
|
-
|
|
103
|
-
"\nCreate Dependabot configuration (.github/dependabot.yml) "
|
|
104
|
-
"to auto-update GitHub Actions versions?",
|
|
105
|
-
default=True,
|
|
106
|
-
):
|
|
107
|
-
create_dependabot()
|
|
98
|
+
init_deploy_workflow()
|
|
@@ -3,7 +3,7 @@ import subprocess
|
|
|
3
3
|
import click
|
|
4
4
|
from click.exceptions import Exit
|
|
5
5
|
|
|
6
|
-
from afterpython.utils import
|
|
6
|
+
from afterpython.utils import has_uv
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
@click.command(
|
|
@@ -13,16 +13,10 @@ from afterpython.utils import has_pixi, has_uv
|
|
|
13
13
|
)
|
|
14
14
|
)
|
|
15
15
|
def install():
|
|
16
|
-
"""
|
|
16
|
+
"""Run 'uv sync --all-extras --all-groups' to install all dependencies"""
|
|
17
17
|
if not has_uv():
|
|
18
18
|
click.echo("uv not found. Please install uv first.")
|
|
19
19
|
return
|
|
20
|
-
|
|
21
20
|
result = subprocess.run(["uv", "sync", "--all-extras", "--all-groups"], check=False)
|
|
22
21
|
if result.returncode != 0:
|
|
23
22
|
raise Exit(result.returncode)
|
|
24
|
-
|
|
25
|
-
if has_pixi():
|
|
26
|
-
result = subprocess.run(["pixi", "install"], check=False)
|
|
27
|
-
if result.returncode != 0:
|
|
28
|
-
raise Exit(result.returncode)
|
|
@@ -27,7 +27,7 @@ def _command_supports_config(command: str) -> bool:
|
|
|
27
27
|
)
|
|
28
28
|
@click.pass_context
|
|
29
29
|
def pre_commit(ctx):
|
|
30
|
-
"""Run pre-commit
|
|
30
|
+
"""Run pre-commit, always use the afterpython/.pre-commit-config.yaml if it exists"""
|
|
31
31
|
from afterpython.utils import handle_passthrough_help
|
|
32
32
|
|
|
33
33
|
# Show both our options and pre-commit's help and exit
|
|
@@ -7,7 +7,7 @@ from click.exceptions import Exit
|
|
|
7
7
|
@click.command()
|
|
8
8
|
@click.pass_context
|
|
9
9
|
def preview(ctx):
|
|
10
|
-
"""Preview the production build of the project website"""
|
|
10
|
+
"""Preview the production build of the project website (including myst's builds)"""
|
|
11
11
|
from afterpython.utils import find_node_env
|
|
12
12
|
|
|
13
13
|
paths = ctx.obj["paths"]
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
|
|
3
2
|
from typing import TYPE_CHECKING
|
|
4
3
|
|
|
5
4
|
if TYPE_CHECKING:
|
|
@@ -10,6 +9,7 @@ import subprocess
|
|
|
10
9
|
import click
|
|
11
10
|
from click.exceptions import Exit
|
|
12
11
|
|
|
12
|
+
|
|
13
13
|
command_kwargs = {
|
|
14
14
|
"add_help_option": False, # disable click's --help option so that myst start --help can work
|
|
15
15
|
"context_settings": dict(
|
|
@@ -42,13 +42,10 @@ command_kwargs = {
|
|
|
42
42
|
"--guide", is_flag=True, help="Start the development server for guide/ directory"
|
|
43
43
|
)
|
|
44
44
|
def start(ctx, doc: bool, blog: bool, tutorial: bool, example: bool, guide: bool):
|
|
45
|
-
"""
|
|
45
|
+
"""Simple wrapper for `myst start` for convenience"""
|
|
46
|
+
from afterpython.utils import find_node_env, has_content_for_myst
|
|
46
47
|
from afterpython.const import CONTENT_TYPES
|
|
47
|
-
from afterpython.utils import
|
|
48
|
-
find_node_env,
|
|
49
|
-
handle_passthrough_help,
|
|
50
|
-
has_content_for_myst,
|
|
51
|
-
)
|
|
48
|
+
from afterpython.utils import handle_passthrough_help
|
|
52
49
|
|
|
53
50
|
# Show both our options and myst's help and exit
|
|
54
51
|
handle_passthrough_help(
|
afterpython/cli/commands/sync.py
CHANGED
|
@@ -5,13 +5,13 @@ from pyproject_metadata import StandardMetadata
|
|
|
5
5
|
from tomlkit.toml_document import TOMLDocument
|
|
6
6
|
|
|
7
7
|
import afterpython as ap
|
|
8
|
-
from afterpython.utils import convert_author_name_to_id
|
|
8
|
+
from afterpython.utils import convert_author_name_to_id
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def _sync_authors_yml(authors: list[tuple[str, str | None]]):
|
|
12
12
|
"""Sync authors.yml with authors in pyproject.toml"""
|
|
13
|
-
from afterpython._io.yaml import read_yaml
|
|
14
13
|
from afterpython.tools.myst import update_authors_yml
|
|
14
|
+
from afterpython._io.yaml import read_yaml
|
|
15
15
|
|
|
16
16
|
# read myst.yml from docs path to get "version"
|
|
17
17
|
doc_myst_yml = read_yaml(ap.paths.afterpython_path / "doc" / "myst.yml")
|
|
@@ -36,56 +36,34 @@ def _sync_authors_yml(authors: list[tuple[str, str | None]]):
|
|
|
36
36
|
|
|
37
37
|
@click.command()
|
|
38
38
|
def sync():
|
|
39
|
-
"""Sync
|
|
40
|
-
from afterpython._io.toml import _from_tomlkit
|
|
39
|
+
"""Sync between pyproject.toml+afterpython.toml and authors.yml+myst.yml files"""
|
|
41
40
|
from afterpython.const import CONTENT_TYPES
|
|
42
41
|
from afterpython.tools._afterpython import read_afterpython
|
|
43
|
-
from afterpython.tools.myst import update_myst_yml
|
|
44
42
|
from afterpython.tools.pyproject import (
|
|
45
43
|
read_metadata,
|
|
46
44
|
read_pyproject,
|
|
47
45
|
write_pyproject,
|
|
48
46
|
)
|
|
47
|
+
from afterpython._io.toml import _from_tomlkit
|
|
48
|
+
from afterpython.tools.myst import update_myst_yml
|
|
49
49
|
|
|
50
50
|
pyproject: StandardMetadata = read_metadata()
|
|
51
51
|
project_name = str(pyproject.name)
|
|
52
52
|
afterpython = read_afterpython()
|
|
53
53
|
github_url = str(pyproject.urls.get("repository", ""))
|
|
54
|
-
company_name = str(_from_tomlkit(afterpython
|
|
55
|
-
company_url = str(_from_tomlkit(afterpython
|
|
56
|
-
website_url = str(_from_tomlkit(afterpython
|
|
57
|
-
try:
|
|
58
|
-
website_favicon = normalize_static_path(
|
|
59
|
-
str(_from_tomlkit(afterpython.get("website", {})).get("favicon", ""))
|
|
60
|
-
)
|
|
61
|
-
website_logo = normalize_static_path(
|
|
62
|
-
str(_from_tomlkit(afterpython.get("website", {})).get("logo", ""))
|
|
63
|
-
)
|
|
64
|
-
website_logo_dark = normalize_static_path(
|
|
65
|
-
str(_from_tomlkit(afterpython.get("website", {})).get("logo_dark", ""))
|
|
66
|
-
)
|
|
67
|
-
website_thumbnail = normalize_static_path(
|
|
68
|
-
str(_from_tomlkit(afterpython.get("website", {})).get("thumbnail", ""))
|
|
69
|
-
)
|
|
70
|
-
except ValueError as e:
|
|
71
|
-
click.echo(f"Error in reading afterpython.toml: {e}")
|
|
72
|
-
return
|
|
73
|
-
|
|
54
|
+
company_name = str(_from_tomlkit(afterpython["company"]).get("name", ""))
|
|
55
|
+
company_url = str(_from_tomlkit(afterpython["company"]).get("url", ""))
|
|
56
|
+
website_url = str(_from_tomlkit(afterpython["website"]).get("url", ""))
|
|
74
57
|
authors = pyproject.authors
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"url": f"{website_url}/{content_type}",
|
|
85
|
-
}
|
|
86
|
-
for content_type in CONTENT_TYPES
|
|
87
|
-
]
|
|
88
|
-
)
|
|
58
|
+
nav_bar = [
|
|
59
|
+
{
|
|
60
|
+
"title": content_type.capitalize() + "s",
|
|
61
|
+
"url": f"{website_url}/{content_type}",
|
|
62
|
+
}
|
|
63
|
+
if website_url
|
|
64
|
+
else ""
|
|
65
|
+
for content_type in CONTENT_TYPES
|
|
66
|
+
]
|
|
89
67
|
|
|
90
68
|
_sync_authors_yml(authors)
|
|
91
69
|
|
|
@@ -100,9 +78,9 @@ def sync():
|
|
|
100
78
|
# based on the current values in pyproject.toml and afterpython.toml
|
|
101
79
|
for content_type in CONTENT_TYPES:
|
|
102
80
|
path = ap.paths.afterpython_path / content_type
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
81
|
+
nav_bar_per_content_type = [
|
|
82
|
+
item for item in nav_bar if item["title"] != content_type.capitalize() + "s"
|
|
83
|
+
]
|
|
106
84
|
title = project_name + f"'s {content_type.capitalize()}"
|
|
107
85
|
data = {
|
|
108
86
|
"project": {
|
|
@@ -120,24 +98,14 @@ def sync():
|
|
|
120
98
|
"description": str(pyproject.description),
|
|
121
99
|
"keywords": list(map(str, pyproject.keywords)),
|
|
122
100
|
"github": github_url,
|
|
123
|
-
"thumbnail": "../static" + website_thumbnail
|
|
124
|
-
if website_thumbnail
|
|
125
|
-
else "",
|
|
126
101
|
},
|
|
127
102
|
"site": {
|
|
128
103
|
"title": title,
|
|
129
104
|
"options": {
|
|
130
|
-
"favicon": "../static" + website_favicon if website_favicon else "",
|
|
131
|
-
"logo": "../static" + website_logo if website_logo else "",
|
|
132
|
-
"logo_dark": "../static" + website_logo_dark
|
|
133
|
-
if website_logo_dark
|
|
134
|
-
else "",
|
|
135
105
|
"logo_text": project_name,
|
|
136
106
|
"logo_url": website_url,
|
|
137
107
|
},
|
|
138
|
-
|
|
139
|
-
# the current issue is they prepend the BASE_URL to the nav bar links even they are external
|
|
140
|
-
# "nav": nav_bar_per_content_type,
|
|
108
|
+
"nav": nav_bar_per_content_type,
|
|
141
109
|
"actions": [
|
|
142
110
|
{
|
|
143
111
|
"title": "⭐ Star",
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
|
|
3
2
|
from typing import TYPE_CHECKING
|
|
4
3
|
|
|
5
4
|
if TYPE_CHECKING:
|
|
6
5
|
from afterpython._typing import NodeEnv
|
|
7
6
|
from afterpython.pcu import Dependencies
|
|
8
7
|
|
|
9
|
-
import shutil
|
|
10
8
|
import subprocess
|
|
9
|
+
import shutil
|
|
11
10
|
|
|
12
11
|
import click
|
|
13
12
|
from click.exceptions import Exit
|
|
@@ -24,17 +23,17 @@ def update():
|
|
|
24
23
|
"-u",
|
|
25
24
|
"--upgrade",
|
|
26
25
|
is_flag=True,
|
|
27
|
-
help="
|
|
26
|
+
help="if enabled, the dependencies will be upgraded to the latest version",
|
|
28
27
|
)
|
|
29
28
|
@click.option(
|
|
30
29
|
"--all",
|
|
31
30
|
is_flag=True,
|
|
32
|
-
help="
|
|
31
|
+
help="update all versions in dependencies and tool configurations (e.g. pre-commit-config.yaml)",
|
|
33
32
|
)
|
|
34
33
|
def dependencies(upgrade: bool, all: bool):
|
|
35
|
-
"""
|
|
34
|
+
"""Update pyproject.toml dependencies to the latest version"""
|
|
36
35
|
from afterpython.pcu import get_dependencies, update_dependencies
|
|
37
|
-
from afterpython.utils import
|
|
36
|
+
from afterpython.utils import has_uv
|
|
38
37
|
|
|
39
38
|
dependencies: Dependencies = get_dependencies()
|
|
40
39
|
has_at_least_one_update = False
|
|
@@ -80,9 +79,7 @@ def dependencies(upgrade: bool, all: bool):
|
|
|
80
79
|
raise Exit(result.returncode)
|
|
81
80
|
click.echo(
|
|
82
81
|
click.style(
|
|
83
|
-
"✓ All dependencies
|
|
84
|
-
fg="green",
|
|
85
|
-
bold=True,
|
|
82
|
+
"✓ All dependencies upgraded successfully 🎉", fg="green", bold=True
|
|
86
83
|
)
|
|
87
84
|
)
|
|
88
85
|
else:
|
|
@@ -92,26 +89,6 @@ def dependencies(upgrade: bool, all: bool):
|
|
|
92
89
|
if all:
|
|
93
90
|
subprocess.run(["ap", "pre-commit", "autoupdate"])
|
|
94
91
|
click.echo("All pre-commit hooks updated successfully.")
|
|
95
|
-
if has_pixi():
|
|
96
|
-
click.echo("Upgrading dependencies with pixi...")
|
|
97
|
-
result = subprocess.run(
|
|
98
|
-
["pixi", "upgrade", "--exclude", "python"], check=False
|
|
99
|
-
)
|
|
100
|
-
if result.returncode != 0:
|
|
101
|
-
raise Exit(result.returncode)
|
|
102
|
-
result = subprocess.run(["pixi", "lock"], check=False)
|
|
103
|
-
if result.returncode != 0:
|
|
104
|
-
raise Exit(result.returncode)
|
|
105
|
-
result = subprocess.run(["pixi", "install"], check=False)
|
|
106
|
-
if result.returncode != 0:
|
|
107
|
-
raise Exit(result.returncode)
|
|
108
|
-
click.echo(
|
|
109
|
-
click.style(
|
|
110
|
-
"✓ All dependencies in pixi.toml upgraded successfully 🎉",
|
|
111
|
-
fg="green",
|
|
112
|
-
bold=True,
|
|
113
|
-
)
|
|
114
|
-
)
|
|
115
92
|
|
|
116
93
|
|
|
117
94
|
update.add_command(dependencies, name="deps") # alias for "dependencies"
|
|
@@ -122,10 +99,10 @@ update.add_command(dependencies, name="deps") # alias for "dependencies"
|
|
|
122
99
|
@click.option(
|
|
123
100
|
"--no-backup",
|
|
124
101
|
is_flag=True,
|
|
125
|
-
help="
|
|
102
|
+
help="if enabled, the existing project website template will not be backed up",
|
|
126
103
|
)
|
|
127
104
|
def website(ctx, no_backup: bool):
|
|
128
|
-
"""Update project website template to the latest version"""
|
|
105
|
+
"""Update the project website template to the latest version"""
|
|
129
106
|
from afterpython.utils import find_node_env
|
|
130
107
|
|
|
131
108
|
website_template_repo = "AfterPythonOrg/project-website-template"
|
afterpython/cli/main.py
CHANGED
|
@@ -1,89 +1,32 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import subprocess
|
|
3
|
-
from collections import defaultdict
|
|
4
3
|
|
|
5
4
|
import click
|
|
6
|
-
from dotenv import find_dotenv, load_dotenv
|
|
7
5
|
from trogon import tui
|
|
6
|
+
from dotenv import load_dotenv, find_dotenv
|
|
8
7
|
|
|
9
8
|
import afterpython as ap
|
|
10
9
|
from afterpython import __version__
|
|
11
|
-
from afterpython.cli.commands.
|
|
10
|
+
from afterpython.cli.commands.init import init
|
|
12
11
|
from afterpython.cli.commands.build import build
|
|
13
|
-
from afterpython.cli.commands.bump import bump
|
|
14
|
-
from afterpython.cli.commands.check import check
|
|
15
|
-
from afterpython.cli.commands.clean import clean
|
|
16
|
-
from afterpython.cli.commands.commit import commit
|
|
17
|
-
from afterpython.cli.commands.commitizen import commitizen
|
|
18
12
|
from afterpython.cli.commands.dev import dev
|
|
19
|
-
from afterpython.cli.commands.
|
|
20
|
-
from afterpython.cli.commands.
|
|
21
|
-
from afterpython.cli.commands.init_branch_rules import init_branch_rules
|
|
13
|
+
from afterpython.cli.commands.update import update
|
|
14
|
+
from afterpython.cli.commands.check import check
|
|
22
15
|
from afterpython.cli.commands.install import install
|
|
23
|
-
from afterpython.cli.commands.
|
|
24
|
-
from afterpython.cli.commands.
|
|
16
|
+
from afterpython.cli.commands.format import format
|
|
17
|
+
from afterpython.cli.commands.sync import sync
|
|
18
|
+
from afterpython.cli.commands.start import start, doc, blog, tutorial, example, guide
|
|
25
19
|
from afterpython.cli.commands.preview import preview
|
|
20
|
+
from afterpython.cli.commands.clean import clean
|
|
21
|
+
from afterpython.cli.commands.pre_commit import pre_commit
|
|
22
|
+
from afterpython.cli.commands.commitizen import commitizen
|
|
23
|
+
from afterpython.cli.commands.commit import commit
|
|
24
|
+
from afterpython.cli.commands.bump import bump
|
|
26
25
|
from afterpython.cli.commands.release import release
|
|
27
|
-
from afterpython.cli.commands.remove import remove
|
|
28
|
-
from afterpython.cli.commands.start import blog, doc, example, guide, start, tutorial
|
|
29
|
-
from afterpython.cli.commands.sync import sync
|
|
30
|
-
from afterpython.cli.commands.update import update
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class AliasGroup(click.Group):
|
|
34
|
-
"""Custom group that displays command aliases together."""
|
|
35
|
-
|
|
36
|
-
def __init__(self, *args, **kwargs):
|
|
37
|
-
super().__init__(*args, **kwargs)
|
|
38
|
-
self._aliases = defaultdict(list) # Maps primary command -> list of aliases
|
|
39
|
-
self._alias_to_primary = {} # Maps alias -> primary command name
|
|
40
|
-
|
|
41
|
-
def add_command(self, cmd, name=None):
|
|
42
|
-
"""Track aliases when the same command is added with different names."""
|
|
43
|
-
name = name or cmd.name
|
|
44
|
-
|
|
45
|
-
# Check if this command object was already added under a different name
|
|
46
|
-
for existing_name, existing_cmd in self.commands.items():
|
|
47
|
-
if existing_cmd is cmd and existing_name != name:
|
|
48
|
-
# This is an alias
|
|
49
|
-
self._aliases[existing_name].append(name)
|
|
50
|
-
self._alias_to_primary[name] = existing_name
|
|
51
|
-
break
|
|
52
|
-
|
|
53
|
-
super().add_command(cmd, name)
|
|
54
|
-
|
|
55
|
-
def format_commands(self, ctx, formatter):
|
|
56
|
-
"""Format commands with aliases shown together."""
|
|
57
|
-
commands = []
|
|
58
|
-
for subcommand in self.list_commands(ctx):
|
|
59
|
-
# Skip aliases - they'll be shown with their primary command
|
|
60
|
-
if subcommand in self._alias_to_primary:
|
|
61
|
-
continue
|
|
62
|
-
|
|
63
|
-
cmd = self.get_command(ctx, subcommand)
|
|
64
|
-
if cmd is None:
|
|
65
|
-
continue
|
|
66
|
-
|
|
67
|
-
# Skip hidden commands
|
|
68
|
-
if cmd.hidden:
|
|
69
|
-
continue
|
|
70
|
-
|
|
71
|
-
help_text = cmd.get_short_help_str(limit=formatter.width)
|
|
72
|
-
|
|
73
|
-
# Build command name with aliases
|
|
74
|
-
aliases = self._aliases.get(subcommand, [])
|
|
75
|
-
if aliases:
|
|
76
|
-
subcommand = f"{subcommand}, {', '.join(aliases)}"
|
|
77
|
-
|
|
78
|
-
commands.append((subcommand, help_text))
|
|
79
|
-
|
|
80
|
-
if commands:
|
|
81
|
-
with formatter.section("Commands"):
|
|
82
|
-
formatter.write_dl(commands)
|
|
83
26
|
|
|
84
27
|
|
|
85
28
|
@tui(command="tui", help="Open terminal UI")
|
|
86
|
-
@click.group(
|
|
29
|
+
@click.group(context_settings={"help_option_names": ["-h", "--help"]})
|
|
87
30
|
@click.pass_context
|
|
88
31
|
@click.version_option(version=__version__)
|
|
89
32
|
def afterpython_group(ctx):
|
|
@@ -107,7 +50,6 @@ afterpython_group.add_command(build)
|
|
|
107
50
|
afterpython_group.add_command(dev)
|
|
108
51
|
afterpython_group.add_command(update)
|
|
109
52
|
afterpython_group.add_command(check)
|
|
110
|
-
afterpython_group.add_command(check, name="lint")
|
|
111
53
|
afterpython_group.add_command(format)
|
|
112
54
|
afterpython_group.add_command(sync)
|
|
113
55
|
afterpython_group.add_command(start)
|
|
@@ -121,12 +63,9 @@ afterpython_group.add_command(preview)
|
|
|
121
63
|
afterpython_group.add_command(clean)
|
|
122
64
|
afterpython_group.add_command(pre_commit)
|
|
123
65
|
afterpython_group.add_command(pre_commit, name="pc")
|
|
66
|
+
afterpython_group.add_command(pre_commit, name="precommit")
|
|
124
67
|
afterpython_group.add_command(commitizen)
|
|
125
68
|
afterpython_group.add_command(commitizen, name="cz")
|
|
126
69
|
afterpython_group.add_command(commit)
|
|
127
70
|
afterpython_group.add_command(bump)
|
|
128
71
|
afterpython_group.add_command(release)
|
|
129
|
-
afterpython_group.add_command(init_branch_rules)
|
|
130
|
-
afterpython_group.add_command(add)
|
|
131
|
-
afterpython_group.add_command(remove)
|
|
132
|
-
afterpython_group.add_command(lock)
|
afterpython/const.py
CHANGED
afterpython/cz.toml
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[tool.commitizen]
|
|
2
|
+
name = "cz_conventional_commits"
|
|
3
|
+
# name = "cz_customize"
|
|
4
|
+
tag_format = "v$version"
|
|
5
|
+
version_scheme = "pep440"
|
|
6
|
+
version_provider = "uv"
|
|
7
|
+
update_changelog_on_bump = false
|
|
8
|
+
major_version_zero = true
|
|
9
|
+
|
|
10
|
+
# FIXME: commitizen can't even add a few custom types like "chore" and "wip", skip it for now
|
|
11
|
+
# [[tool.commitizen.customize.questions]]
|
|
12
|
+
# type = "list"
|
|
13
|
+
# name = "change_type"
|
|
14
|
+
# choices = [
|
|
15
|
+
# {value = "fix", name = "fix: A bug fix. Correlates with PATCH in SemVer"},
|
|
16
|
+
# {value = "feat", name = "feat: A new feature. Correlates with MINOR in SemVer"},
|
|
17
|
+
# {value = "docs", name = "docs: Documentation only changes"},
|
|
18
|
+
# {value = "style", name = "style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)"},
|
|
19
|
+
# {value = "refactor", name = "refactor: A code change that neither fixes a bug nor adds a feature"},
|
|
20
|
+
# {value = "perf", name = "perf: A code change that improves performance"},
|
|
21
|
+
# {value = "test", name = "test: Adding missing or correcting existing tests"},
|
|
22
|
+
# {value = "build", name = "build: Changes that affect the build system or external dependencies (example scopes: pip, docker, npm)"},
|
|
23
|
+
# {value = "ci", name = "ci: Changes to CI configuration files and scripts (example scopes: GitLabCI)"},
|
|
24
|
+
# {value = "chore", name = "chore: Other changes that don't modify src or test files"},
|
|
25
|
+
# {value = "wip", name = "wip: Work in progress"}
|
|
26
|
+
# ]
|
|
27
|
+
# message = "Select the type of change you are committing"
|
afterpython/pcu.py
CHANGED
|
@@ -3,8 +3,7 @@ pcu = "pip check updates", similar to ncu (npm check updates in Node.js)
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
|
-
|
|
7
|
-
from typing import TYPE_CHECKING, NamedTuple, TypeAlias, TypedDict
|
|
6
|
+
from typing import TYPE_CHECKING, TypedDict, NamedTuple, TypeAlias
|
|
8
7
|
|
|
9
8
|
if TYPE_CHECKING:
|
|
10
9
|
from tomlkit.toml_document import TOMLDocument
|
|
@@ -61,7 +60,6 @@ async def get_latest_versions(
|
|
|
61
60
|
) -> dict[str, Version | None]:
|
|
62
61
|
"""Get latest versions for a list of dependencies from PyPI."""
|
|
63
62
|
import httpx
|
|
64
|
-
|
|
65
63
|
from afterpython.utils import fetch_pypi_json
|
|
66
64
|
|
|
67
65
|
async def fetch_version(
|
|
@@ -35,7 +35,7 @@ jobs:
|
|
|
35
35
|
runs-on: ubuntu-latest
|
|
36
36
|
steps:
|
|
37
37
|
- name: Checkout code
|
|
38
|
-
uses: actions/checkout@
|
|
38
|
+
uses: actions/checkout@v4
|
|
39
39
|
|
|
40
40
|
- name: Install pnpm
|
|
41
41
|
uses: pnpm/action-setup@v4
|
|
@@ -43,19 +43,19 @@ jobs:
|
|
|
43
43
|
version: 10
|
|
44
44
|
|
|
45
45
|
- name: Set up Node.js
|
|
46
|
-
uses: actions/setup-node@
|
|
46
|
+
uses: actions/setup-node@v4
|
|
47
47
|
with:
|
|
48
48
|
node-version: '24'
|
|
49
49
|
cache: 'pnpm'
|
|
50
50
|
cache-dependency-path: './afterpython/_website/pnpm-lock.yaml'
|
|
51
51
|
|
|
52
52
|
- name: Set up Python
|
|
53
|
-
uses: actions/setup-python@
|
|
53
|
+
uses: actions/setup-python@v5
|
|
54
54
|
with:
|
|
55
55
|
python-version: '3.11'
|
|
56
56
|
|
|
57
57
|
- name: Install uv
|
|
58
|
-
uses: astral-sh/setup-uv@
|
|
58
|
+
uses: astral-sh/setup-uv@v5
|
|
59
59
|
with:
|
|
60
60
|
version: "latest"
|
|
61
61
|
|
|
@@ -71,7 +71,7 @@ jobs:
|
|
|
71
71
|
ap build
|
|
72
72
|
|
|
73
73
|
- name: Upload artifact
|
|
74
|
-
uses: actions/upload-pages-artifact@
|
|
74
|
+
uses: actions/upload-pages-artifact@v3
|
|
75
75
|
with:
|
|
76
76
|
path: './afterpython/_website/build'
|
|
77
77
|
|
|
@@ -14,15 +14,15 @@ jobs:
|
|
|
14
14
|
|
|
15
15
|
steps:
|
|
16
16
|
- name: Checkout code
|
|
17
|
-
uses: actions/checkout@
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
18
|
|
|
19
19
|
- name: Set up Python
|
|
20
|
-
uses: actions/setup-python@
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
21
|
with:
|
|
22
22
|
python-version: '3.11'
|
|
23
23
|
|
|
24
24
|
- name: Install uv
|
|
25
|
-
uses: astral-sh/setup-uv@
|
|
25
|
+
uses: astral-sh/setup-uv@v5
|
|
26
26
|
with:
|
|
27
27
|
version: "latest"
|
|
28
28
|
|