afterpython 0.1.0__py3-none-any.whl → 0.1.0.dev4__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 +63 -136
- 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 +13 -80
- 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 -8
- afterpython/cli/commands/sync.py +21 -65
- afterpython/cli/commands/update.py +8 -31
- afterpython/cli/main.py +14 -75
- afterpython/const.py +2 -1
- afterpython/cz.toml +27 -0
- afterpython/pcu.py +1 -3
- afterpython/templates/deploy-workflow-template.yml +5 -22
- 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 +38 -82
- afterpython/tools/pre_commit.py +31 -6
- afterpython/tools/pyproject.py +2 -40
- afterpython/utils.py +3 -87
- {afterpython-0.1.0.dist-info → afterpython-0.1.0.dev4.dist-info}/METADATA +13 -39
- afterpython-0.1.0.dev4.dist-info/RECORD +47 -0
- {afterpython-0.1.0.dist-info → afterpython-0.1.0.dev4.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.dev4.dist-info}/entry_points.txt +0 -0
afterpython/cli/commands/dev.py
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
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
|
|
|
8
|
-
import subprocess
|
|
9
7
|
import time
|
|
8
|
+
import subprocess
|
|
10
9
|
|
|
11
10
|
import click
|
|
12
11
|
from click.exceptions import Exit
|
|
13
12
|
|
|
14
|
-
from afterpython.
|
|
13
|
+
from afterpython.utils import find_node_env, find_available_port
|
|
15
14
|
from afterpython.const import CONTENT_TYPES
|
|
16
|
-
from afterpython.utils import find_available_port, find_node_env
|
|
17
15
|
|
|
18
16
|
|
|
19
17
|
@click.command(
|
|
@@ -29,61 +27,19 @@ from afterpython.utils import find_available_port, find_node_env
|
|
|
29
27
|
is_flag=True,
|
|
30
28
|
help="Start the development server for all content types and the project website",
|
|
31
29
|
)
|
|
32
|
-
@click.option(
|
|
33
|
-
"--doc",
|
|
34
|
-
is_flag=True,
|
|
35
|
-
help="Start the development server for documentation content",
|
|
36
|
-
)
|
|
37
|
-
@click.option(
|
|
38
|
-
"--blog",
|
|
39
|
-
is_flag=True,
|
|
40
|
-
help="Start the development server for blog content",
|
|
41
|
-
)
|
|
42
|
-
@click.option(
|
|
43
|
-
"--tutorial",
|
|
44
|
-
is_flag=True,
|
|
45
|
-
help="Start the development server for tutorial content",
|
|
46
|
-
)
|
|
47
|
-
@click.option(
|
|
48
|
-
"--example",
|
|
49
|
-
is_flag=True,
|
|
50
|
-
help="Start the development server for example content",
|
|
51
|
-
)
|
|
52
|
-
@click.option(
|
|
53
|
-
"--guide",
|
|
54
|
-
is_flag=True,
|
|
55
|
-
help="Start the development server for guide content",
|
|
56
|
-
)
|
|
57
30
|
@click.option(
|
|
58
31
|
"--execute", is_flag=True, help="Execute Jupyter notebooks for all content types"
|
|
59
32
|
)
|
|
60
33
|
@click.option(
|
|
61
34
|
"--no-website",
|
|
62
|
-
"-n",
|
|
63
35
|
is_flag=True,
|
|
64
36
|
help="Skip running the website dev server (pnpm dev). Useful when you want to run pnpm dev manually with custom options.",
|
|
65
37
|
)
|
|
66
|
-
def dev(
|
|
67
|
-
ctx,
|
|
68
|
-
all: bool,
|
|
69
|
-
doc: bool,
|
|
70
|
-
blog: bool,
|
|
71
|
-
tutorial: bool,
|
|
72
|
-
example: bool,
|
|
73
|
-
guide: bool,
|
|
74
|
-
execute: bool,
|
|
75
|
-
no_website: bool,
|
|
76
|
-
):
|
|
38
|
+
def dev(ctx, all: bool, execute: bool, no_website: bool):
|
|
77
39
|
"""Run the development server for the project website.
|
|
78
40
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
Examples:
|
|
83
|
-
ap dev # Website only
|
|
84
|
-
ap dev --all # Website + all content types
|
|
85
|
-
ap dev --doc # Website + doc content
|
|
86
|
-
ap dev --doc --blog # Website + doc and blog content
|
|
41
|
+
If --all is enabled, starts MyST dev servers for all content types (doc/blog/tutorial/example/guide)
|
|
42
|
+
and the project website.
|
|
87
43
|
|
|
88
44
|
Any extra arguments are passed to the MyST servers (via 'ap doc/blog/tutorial/example/guide' commands).
|
|
89
45
|
See "myst start --help" for more details.
|
|
@@ -108,6 +64,9 @@ def dev(
|
|
|
108
64
|
|
|
109
65
|
paths = ctx.obj["paths"]
|
|
110
66
|
|
|
67
|
+
# OPTIMIZE: should implement incremental build?
|
|
68
|
+
subprocess.run(["ap", "build", "--dev"])
|
|
69
|
+
|
|
111
70
|
def cleanup_processes():
|
|
112
71
|
"""Clean up all MyST server processes"""
|
|
113
72
|
click.echo("\nShutting down MyST servers...")
|
|
@@ -120,38 +79,14 @@ def dev(
|
|
|
120
79
|
except Exception:
|
|
121
80
|
pass
|
|
122
81
|
|
|
123
|
-
# Determine which content types to run
|
|
124
|
-
if all:
|
|
125
|
-
enabled_content_types = set(CONTENT_TYPES)
|
|
126
|
-
else:
|
|
127
|
-
# Check individual flags
|
|
128
|
-
content_flags = {
|
|
129
|
-
"doc": doc,
|
|
130
|
-
"blog": blog,
|
|
131
|
-
"tutorial": tutorial,
|
|
132
|
-
"example": example,
|
|
133
|
-
"guide": guide,
|
|
134
|
-
}
|
|
135
|
-
assert set(content_flags.keys()) == set(CONTENT_TYPES), (
|
|
136
|
-
"Incomplete content flags"
|
|
137
|
-
)
|
|
138
|
-
enabled_content_types = {ct for ct, flag in content_flags.items() if flag}
|
|
139
|
-
|
|
140
82
|
try:
|
|
141
|
-
|
|
83
|
+
if all:
|
|
84
|
+
# Clear .env.development before writing new ports
|
|
85
|
+
env_file = paths.website_path / ".env.development"
|
|
86
|
+
env_file.write_text("") # Clear existing content
|
|
142
87
|
|
|
143
|
-
# Clear .env.development before writing new ports
|
|
144
|
-
env_file = paths.website_path / ".env.development"
|
|
145
|
-
env_file.write_text("") # Clear existing content
|
|
146
|
-
|
|
147
|
-
# myst development servers
|
|
148
|
-
if enabled_content_types:
|
|
149
88
|
next_port = 3000
|
|
150
89
|
for content_type in CONTENT_TYPES:
|
|
151
|
-
# Skip content types that are not enabled
|
|
152
|
-
if content_type not in enabled_content_types:
|
|
153
|
-
continue
|
|
154
|
-
|
|
155
90
|
# Find available port for MyST server
|
|
156
91
|
myst_port = find_available_port(start_port=next_port)
|
|
157
92
|
next_port = myst_port + 1
|
|
@@ -187,8 +122,6 @@ def dev(
|
|
|
187
122
|
# causing "address already in use" errors.
|
|
188
123
|
time.sleep(3)
|
|
189
124
|
|
|
190
|
-
postbuild(dev_build=True)
|
|
191
|
-
|
|
192
125
|
if not no_website:
|
|
193
126
|
node_env: NodeEnv = find_node_env()
|
|
194
127
|
click.echo("Running the web dev server...")
|
|
@@ -201,7 +134,7 @@ def dev(
|
|
|
201
134
|
click.echo(
|
|
202
135
|
"Skipping website dev server (--no-website flag). Run 'pnpm dev' manually in afterpython/_website/ with your custom options."
|
|
203
136
|
)
|
|
204
|
-
if
|
|
137
|
+
if all:
|
|
205
138
|
# Keep the process running to maintain MyST servers
|
|
206
139
|
click.echo("Press Ctrl+C to stop MyST servers...")
|
|
207
140
|
while True:
|
|
@@ -13,7 +13,7 @@ from click.exceptions import Exit
|
|
|
13
13
|
)
|
|
14
14
|
@click.pass_context
|
|
15
15
|
def format(ctx):
|
|
16
|
-
"""
|
|
16
|
+
"""Simple wrapper for ruff format for convenience"""
|
|
17
17
|
from afterpython.utils import handle_passthrough_help
|
|
18
18
|
|
|
19
19
|
# Show both our options and ruff's help and exit
|
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,13 +9,13 @@ 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(
|
|
16
16
|
ignore_unknown_options=True,
|
|
17
17
|
allow_extra_args=True,
|
|
18
18
|
),
|
|
19
|
-
"hidden": True, # Hide these commands from help output
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
|
|
@@ -42,13 +41,10 @@ command_kwargs = {
|
|
|
42
41
|
"--guide", is_flag=True, help="Start the development server for guide/ directory"
|
|
43
42
|
)
|
|
44
43
|
def start(ctx, doc: bool, blog: bool, tutorial: bool, example: bool, guide: bool):
|
|
45
|
-
"""
|
|
44
|
+
"""Simple wrapper for `myst start` for convenience"""
|
|
45
|
+
from afterpython.utils import find_node_env, has_content_for_myst
|
|
46
46
|
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
|
-
)
|
|
47
|
+
from afterpython.utils import handle_passthrough_help
|
|
52
48
|
|
|
53
49
|
# Show both our options and myst's help and exit
|
|
54
50
|
handle_passthrough_help(
|
afterpython/cli/commands/sync.py
CHANGED
|
@@ -2,16 +2,15 @@ from datetime import datetime
|
|
|
2
2
|
|
|
3
3
|
import click
|
|
4
4
|
from pyproject_metadata import StandardMetadata
|
|
5
|
-
from tomlkit.toml_document import TOMLDocument
|
|
6
5
|
|
|
7
6
|
import afterpython as ap
|
|
8
|
-
from afterpython.utils import convert_author_name_to_id
|
|
7
|
+
from afterpython.utils import convert_author_name_to_id
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
def _sync_authors_yml(authors: list[tuple[str, str | None]]):
|
|
12
11
|
"""Sync authors.yml with authors in pyproject.toml"""
|
|
13
|
-
from afterpython._io.yaml import read_yaml
|
|
14
12
|
from afterpython.tools.myst import update_authors_yml
|
|
13
|
+
from afterpython._io.yaml import read_yaml
|
|
15
14
|
|
|
16
15
|
# read myst.yml from docs path to get "version"
|
|
17
16
|
doc_myst_yml = read_yaml(ap.paths.afterpython_path / "doc" / "myst.yml")
|
|
@@ -36,73 +35,40 @@ def _sync_authors_yml(authors: list[tuple[str, str | None]]):
|
|
|
36
35
|
|
|
37
36
|
@click.command()
|
|
38
37
|
def sync():
|
|
39
|
-
"""Sync
|
|
40
|
-
from afterpython._io.toml import _from_tomlkit
|
|
38
|
+
"""Sync between pyproject.toml+afterpython.toml and authors.yml+myst.yml files"""
|
|
41
39
|
from afterpython.const import CONTENT_TYPES
|
|
42
40
|
from afterpython.tools._afterpython import read_afterpython
|
|
41
|
+
from afterpython.tools.pyproject import read_metadata
|
|
42
|
+
from afterpython._io.toml import _from_tomlkit
|
|
43
43
|
from afterpython.tools.myst import update_myst_yml
|
|
44
|
-
from afterpython.tools.pyproject import (
|
|
45
|
-
read_metadata,
|
|
46
|
-
read_pyproject,
|
|
47
|
-
write_pyproject,
|
|
48
|
-
)
|
|
49
44
|
|
|
50
45
|
pyproject: StandardMetadata = read_metadata()
|
|
51
46
|
project_name = str(pyproject.name)
|
|
52
47
|
afterpython = read_afterpython()
|
|
53
48
|
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
|
-
|
|
49
|
+
company_name = str(_from_tomlkit(afterpython["company"]).get("name", ""))
|
|
50
|
+
company_url = str(_from_tomlkit(afterpython["company"]).get("url", ""))
|
|
51
|
+
website_url = str(_from_tomlkit(afterpython["website"]).get("url", ""))
|
|
74
52
|
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
|
-
)
|
|
53
|
+
nav_bar = [
|
|
54
|
+
{
|
|
55
|
+
"title": content_type.capitalize() + "s",
|
|
56
|
+
"url": f"{website_url}/{content_type}",
|
|
57
|
+
}
|
|
58
|
+
if website_url
|
|
59
|
+
else ""
|
|
60
|
+
for content_type in CONTENT_TYPES
|
|
61
|
+
]
|
|
89
62
|
|
|
90
63
|
_sync_authors_yml(authors)
|
|
91
64
|
|
|
92
|
-
# update "homepage", "repository", and "documentation" in pyproject.toml
|
|
93
|
-
if website_url:
|
|
94
|
-
doc: TOMLDocument = read_pyproject()
|
|
95
|
-
doc["project"]["urls"]["homepage"] = website_url
|
|
96
|
-
doc["project"]["urls"]["documentation"] = f"{website_url}/doc"
|
|
97
|
-
write_pyproject(doc)
|
|
98
|
-
|
|
99
65
|
# update myst.yml files for each content type (e.g. doc/, blog/, tutorial/, example/, guide/)
|
|
100
66
|
# based on the current values in pyproject.toml and afterpython.toml
|
|
101
67
|
for content_type in CONTENT_TYPES:
|
|
102
68
|
path = ap.paths.afterpython_path / content_type
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
69
|
+
nav_bar_per_content_type = [
|
|
70
|
+
item for item in nav_bar if item["title"] != content_type.capitalize()
|
|
71
|
+
]
|
|
106
72
|
title = project_name + f"'s {content_type.capitalize()}"
|
|
107
73
|
data = {
|
|
108
74
|
"project": {
|
|
@@ -120,24 +86,14 @@ def sync():
|
|
|
120
86
|
"description": str(pyproject.description),
|
|
121
87
|
"keywords": list(map(str, pyproject.keywords)),
|
|
122
88
|
"github": github_url,
|
|
123
|
-
"thumbnail": "../static" + website_thumbnail
|
|
124
|
-
if website_thumbnail
|
|
125
|
-
else "",
|
|
126
89
|
},
|
|
127
90
|
"site": {
|
|
128
91
|
"title": title,
|
|
129
92
|
"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
93
|
"logo_text": project_name,
|
|
136
94
|
"logo_url": website_url,
|
|
137
95
|
},
|
|
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,
|
|
96
|
+
"nav": nav_bar_per_content_type,
|
|
141
97
|
"actions": [
|
|
142
98
|
{
|
|
143
99
|
"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"
|