afterpython 0.1.4__py3-none-any.whl → 0.2.1__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/cli/commands/build.py +8 -0
- afterpython/cli/commands/dev.py +8 -1
- afterpython/cli/commands/init.py +9 -4
- afterpython/cli/commands/preview.py +8 -1
- afterpython/cli/commands/update.py +4 -1
- afterpython/py.typed +0 -0
- afterpython/templates/ci-workflow-template.yml +13 -4
- afterpython/utils.py +66 -0
- {afterpython-0.1.4.dist-info → afterpython-0.2.1.dist-info}/METADATA +1 -1
- {afterpython-0.1.4.dist-info → afterpython-0.2.1.dist-info}/RECORD +12 -11
- {afterpython-0.1.4.dist-info → afterpython-0.2.1.dist-info}/WHEEL +1 -1
- {afterpython-0.1.4.dist-info → afterpython-0.2.1.dist-info}/entry_points.txt +0 -0
|
@@ -190,6 +190,7 @@ def build(ctx: click.Context, execute: bool):
|
|
|
190
190
|
find_node_env,
|
|
191
191
|
handle_passthrough_help,
|
|
192
192
|
has_content_for_myst,
|
|
193
|
+
is_website_initialized,
|
|
193
194
|
)
|
|
194
195
|
|
|
195
196
|
# Show both our options and myst's help and exit
|
|
@@ -199,6 +200,13 @@ def build(ctx: click.Context, execute: bool):
|
|
|
199
200
|
show_underlying=True,
|
|
200
201
|
)
|
|
201
202
|
|
|
203
|
+
if not is_website_initialized():
|
|
204
|
+
click.echo(
|
|
205
|
+
"Website has not been initialized. Skipping website build.\n"
|
|
206
|
+
"Run 'ap update website' to initialize the website."
|
|
207
|
+
)
|
|
208
|
+
return
|
|
209
|
+
|
|
202
210
|
paths = ctx.obj["paths"]
|
|
203
211
|
prebuild()
|
|
204
212
|
|
afterpython/cli/commands/dev.py
CHANGED
|
@@ -94,7 +94,7 @@ def dev(
|
|
|
94
94
|
with custom Vite options in the afterpython/_website directory.
|
|
95
95
|
"""
|
|
96
96
|
|
|
97
|
-
from afterpython.utils import handle_passthrough_help
|
|
97
|
+
from afterpython.utils import handle_passthrough_help, is_website_initialized
|
|
98
98
|
|
|
99
99
|
# Show both our options and myst's help and exit
|
|
100
100
|
handle_passthrough_help(
|
|
@@ -103,6 +103,13 @@ def dev(
|
|
|
103
103
|
show_underlying=True,
|
|
104
104
|
)
|
|
105
105
|
|
|
106
|
+
if not is_website_initialized():
|
|
107
|
+
click.echo(
|
|
108
|
+
"Website has not been initialized. Skipping dev server.\n"
|
|
109
|
+
"Run 'ap update website' to initialize the website."
|
|
110
|
+
)
|
|
111
|
+
return
|
|
112
|
+
|
|
106
113
|
# Track all MyST processes for cleanup
|
|
107
114
|
myst_processes = []
|
|
108
115
|
|
afterpython/cli/commands/init.py
CHANGED
|
@@ -46,8 +46,13 @@ def init_py_typed():
|
|
|
46
46
|
is_flag=True,
|
|
47
47
|
help="Automatically answer yes to all prompts",
|
|
48
48
|
)
|
|
49
|
+
@click.option(
|
|
50
|
+
"--skip-website",
|
|
51
|
+
is_flag=True,
|
|
52
|
+
help="Skip website template initialization",
|
|
53
|
+
)
|
|
49
54
|
@click.pass_context
|
|
50
|
-
def init(ctx, yes):
|
|
55
|
+
def init(ctx, yes, skip_website: bool):
|
|
51
56
|
"""Initialize AfterPython project structure and website template"""
|
|
52
57
|
from afterpython.tools._afterpython import init_afterpython
|
|
53
58
|
from afterpython.tools.commitizen import init_commitizen
|
|
@@ -73,9 +78,9 @@ def init(ctx, yes):
|
|
|
73
78
|
|
|
74
79
|
init_myst()
|
|
75
80
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
if not skip_website:
|
|
82
|
+
# TODO: init faq.yml
|
|
83
|
+
init_website()
|
|
79
84
|
|
|
80
85
|
# TODO: add type checking related stuff here
|
|
81
86
|
init_py_typed()
|
|
@@ -8,7 +8,14 @@ from click.exceptions import Exit
|
|
|
8
8
|
@click.pass_context
|
|
9
9
|
def preview(ctx):
|
|
10
10
|
"""Preview the production build of the project website"""
|
|
11
|
-
from afterpython.utils import find_node_env
|
|
11
|
+
from afterpython.utils import find_node_env, is_website_initialized
|
|
12
|
+
|
|
13
|
+
if not is_website_initialized():
|
|
14
|
+
click.echo(
|
|
15
|
+
"Website has not been initialized. Skipping preview.\n"
|
|
16
|
+
"Run 'ap update website' to initialize the website."
|
|
17
|
+
)
|
|
18
|
+
return
|
|
12
19
|
|
|
13
20
|
paths = ctx.obj["paths"]
|
|
14
21
|
node_env = find_node_env()
|
|
@@ -126,7 +126,7 @@ update.add_command(dependencies, name="deps") # alias for "dependencies"
|
|
|
126
126
|
)
|
|
127
127
|
def website(ctx, no_backup: bool):
|
|
128
128
|
"""Update project website template to the latest version"""
|
|
129
|
-
from afterpython.utils import find_node_env
|
|
129
|
+
from afterpython.utils import ensure_website_gitignore_rules, find_node_env
|
|
130
130
|
|
|
131
131
|
website_template_repo = "AfterPythonOrg/project-website-template"
|
|
132
132
|
|
|
@@ -166,6 +166,9 @@ def website(ctx, no_backup: bool):
|
|
|
166
166
|
)
|
|
167
167
|
if result.returncode != 0:
|
|
168
168
|
raise Exit(result.returncode)
|
|
169
|
+
|
|
170
|
+
# Ensure gitignore rules are present
|
|
171
|
+
ensure_website_gitignore_rules()
|
|
169
172
|
except Exception as e:
|
|
170
173
|
click.echo(f"✗ Error updating project website template: {e}", err=True)
|
|
171
174
|
if not no_backup:
|
afterpython/py.typed
ADDED
|
File without changes
|
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
- name: Install dependencies
|
|
34
34
|
# Install the package with uv in system mode
|
|
35
35
|
# This installs ruff and other tools defined in dependencies
|
|
36
|
-
run: uv pip install --system .
|
|
36
|
+
run: uv pip install --system . --group dev
|
|
37
37
|
|
|
38
38
|
- name: Run ruff check
|
|
39
39
|
run: ruff check --config ./afterpython/ruff.toml .
|
|
@@ -189,9 +189,18 @@ jobs:
|
|
|
189
189
|
run: uv pip install --system dist/*.whl
|
|
190
190
|
|
|
191
191
|
- name: Verify installation
|
|
192
|
-
#
|
|
193
|
-
#
|
|
194
|
-
run:
|
|
192
|
+
# Generic verification: assume project.name maps to import name
|
|
193
|
+
# by replacing '-' with '_'. If a project breaks this rule, CI fails.
|
|
194
|
+
run: |
|
|
195
|
+
PROJECT_NAME="$(python - <<'PY'
|
|
196
|
+
import tomllib
|
|
197
|
+
with open("pyproject.toml", "rb") as f:
|
|
198
|
+
data = tomllib.load(f)
|
|
199
|
+
print(data["project"]["name"])
|
|
200
|
+
PY
|
|
201
|
+
)"
|
|
202
|
+
IMPORT_NAME="${PROJECT_NAME//-/_}"
|
|
203
|
+
python -c "import ${IMPORT_NAME}"
|
|
195
204
|
|
|
196
205
|
# Job 5: Type Check
|
|
197
206
|
# typecheck:
|
afterpython/utils.py
CHANGED
|
@@ -297,3 +297,69 @@ def get_relative_static_prefix(file_path: Path, content_type_path: Path) -> str:
|
|
|
297
297
|
return "./" # File is directly in content_type_path
|
|
298
298
|
else:
|
|
299
299
|
return "../" * depth
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def is_website_initialized() -> bool:
|
|
303
|
+
"""Check if the website has been initialized.
|
|
304
|
+
|
|
305
|
+
Returns:
|
|
306
|
+
True if the website is initialized (afterpython/_website exists and has package.json)
|
|
307
|
+
False otherwise
|
|
308
|
+
"""
|
|
309
|
+
import afterpython as ap
|
|
310
|
+
|
|
311
|
+
website_path = ap.paths.website_path
|
|
312
|
+
package_json = website_path / "package.json"
|
|
313
|
+
|
|
314
|
+
return website_path.exists() and package_json.exists()
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def ensure_website_gitignore_rules() -> None:
|
|
318
|
+
"""Ensure website-related gitignore rules are present in the project's .gitignore.
|
|
319
|
+
|
|
320
|
+
Adds the following rules if they don't exist:
|
|
321
|
+
- **/_build/ (ignore all build directories)
|
|
322
|
+
- !afterpython/_website/src/lib/ (un-ignore website source for customization)
|
|
323
|
+
- afterpython/_website.backup/ (ignore backup created by ap update website)
|
|
324
|
+
"""
|
|
325
|
+
import afterpython as ap
|
|
326
|
+
|
|
327
|
+
gitignore_path = ap.paths.user_path / ".gitignore"
|
|
328
|
+
|
|
329
|
+
# Rules that should be present
|
|
330
|
+
required_rules = [
|
|
331
|
+
"**/_build/",
|
|
332
|
+
"!afterpython/_website/src/lib/",
|
|
333
|
+
"afterpython/_website.backup/",
|
|
334
|
+
]
|
|
335
|
+
|
|
336
|
+
# Read existing gitignore or create empty list
|
|
337
|
+
if gitignore_path.exists():
|
|
338
|
+
existing_lines = gitignore_path.read_text().splitlines()
|
|
339
|
+
else:
|
|
340
|
+
existing_lines = []
|
|
341
|
+
|
|
342
|
+
# Find which rules are missing
|
|
343
|
+
missing_rules = []
|
|
344
|
+
for rule in required_rules:
|
|
345
|
+
# Check if rule exists (exact match or as part of a line)
|
|
346
|
+
if not any(rule in line for line in existing_lines):
|
|
347
|
+
missing_rules.append(rule)
|
|
348
|
+
|
|
349
|
+
# Add missing rules if any
|
|
350
|
+
if missing_rules:
|
|
351
|
+
# Ensure file ends with newline if it exists and has content
|
|
352
|
+
content = gitignore_path.read_text() if gitignore_path.exists() else ""
|
|
353
|
+
if content and not content.endswith("\n"):
|
|
354
|
+
content += "\n"
|
|
355
|
+
|
|
356
|
+
# Add a section header if we're adding rules
|
|
357
|
+
if content:
|
|
358
|
+
content += "\n"
|
|
359
|
+
content += "# AfterPython website rules\n"
|
|
360
|
+
content += "\n".join(missing_rules) + "\n"
|
|
361
|
+
|
|
362
|
+
gitignore_path.write_text(content)
|
|
363
|
+
click.echo(f"Added website-related rules to {gitignore_path}")
|
|
364
|
+
else:
|
|
365
|
+
click.echo("Website gitignore rules already present")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: afterpython
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: CLI tool to streamline Python package maintenance and generate a dedicated project website
|
|
5
5
|
Keywords: package-maintenance,project-website,static-site-generator,developer-tools,documentation,cli-tool,ci/cd,mystmd,semantic-release,python-packaging
|
|
6
6
|
Author: Stephen Yau
|
|
@@ -11,30 +11,31 @@ afterpython/builders/markdown.py,sha256=0ExfRqvOTWsgUkAVaGGNkiNDtNedRr7JR1yTGxpb
|
|
|
11
11
|
afterpython/builders/metadata.py,sha256=--0zWaI0ZI1wKeezcyqSUy-h1IuLqnI33ateoAHIaBU,1337
|
|
12
12
|
afterpython/cli/__init__.py,sha256=G4AB-rllhmr7tURFc5cXJfkjZZ2bXtMBg3oy4zUGEFw,84
|
|
13
13
|
afterpython/cli/commands/add.py,sha256=Ppp4msdvOwN9_-fdG5-b0-IV9p0Eef9CiIEU3srUjYk,1792
|
|
14
|
-
afterpython/cli/commands/build.py,sha256=
|
|
14
|
+
afterpython/cli/commands/build.py,sha256=HR2x7tn12qbsrSk--0Mzbnl4UbNU_RhexG_6I2mxF04,9304
|
|
15
15
|
afterpython/cli/commands/bump.py,sha256=2MZBQ1kxjr0bWhA--_xHwdwjsUlCyrXPn3pJ5NDZO4k,4088
|
|
16
16
|
afterpython/cli/commands/check.py,sha256=lrPaVThAwxxnczu-VOZT7dd7aKjstnMQfX9UpZY3Lxs,1058
|
|
17
17
|
afterpython/cli/commands/clean.py,sha256=havP43ZC1AKFzvscsRMF_to6TvOwruxGA5qzr6dMHvg,2529
|
|
18
18
|
afterpython/cli/commands/commit.py,sha256=9QOKyt4tfTJzZEdHEPAdpUc4stYMSvG3-31uADuBxn4,1420
|
|
19
19
|
afterpython/cli/commands/commitizen.py,sha256=H3jewz4VkZi5FYTWw3USVM3XosRx12kPShOQGxD3LNM,842
|
|
20
|
-
afterpython/cli/commands/dev.py,sha256=
|
|
20
|
+
afterpython/cli/commands/dev.py,sha256=LVv6WUB1RNe8w7yAQS_1TQEEn_wklbJOuduapYlg2FA,7039
|
|
21
21
|
afterpython/cli/commands/format.py,sha256=VFwCG9KDTF6j4Y_Ewp4_RpS8uNBQNOAj9HU_G97my5A,710
|
|
22
|
-
afterpython/cli/commands/init.py,sha256=
|
|
22
|
+
afterpython/cli/commands/init.py,sha256=G2zL3W1ZxbppMQEYCD7zttNIcrhAG8K2M1gZpcL4Ebo,3202
|
|
23
23
|
afterpython/cli/commands/init_branch_rules.py,sha256=fzAm8D5qbW3u4bEMpqPuRgO-0akuCGG7pu09JlKhYn4,243
|
|
24
24
|
afterpython/cli/commands/install.py,sha256=B8JuQmtU_4EZpHct2J5j30BGLkGmvwKvU26upbmabvQ,750
|
|
25
25
|
afterpython/cli/commands/lock.py,sha256=Kppu_0tnqdbP6Gbulxf123f-cFzTGIw39si2O7rDo3Q,603
|
|
26
26
|
afterpython/cli/commands/pre_commit.py,sha256=QIuzTZEfw4uPMqmQT8YmyD0yewBcwjLvcnbVjRbonQE,1978
|
|
27
|
-
afterpython/cli/commands/preview.py,sha256=
|
|
27
|
+
afterpython/cli/commands/preview.py,sha256=V3gzAYcWi95A9GUwqcQudgtSMFcKHVJPz3l4grg5vYg,833
|
|
28
28
|
afterpython/cli/commands/release.py,sha256=6SDEnPtuCL0_XUqWUlvRSKxAv011QqOD0kc5pKu7378,2479
|
|
29
29
|
afterpython/cli/commands/remove.py,sha256=Fl79JSI9IdHyzYflocXxcxgBkBPkNFAW98Yuijly26g,1812
|
|
30
30
|
afterpython/cli/commands/start.py,sha256=q4rUkIllOO8wJQ9ABtsx-dqkW1yC0vltAtSkiHN_GH4,4002
|
|
31
31
|
afterpython/cli/commands/sync.py,sha256=u9L3aq04M5VHh0FByDSpmBD7F1RYCNsIgvZFifnRZ6A,6042
|
|
32
|
-
afterpython/cli/commands/update.py,sha256=
|
|
32
|
+
afterpython/cli/commands/update.py,sha256=YhCOBTGoKkYMnUK4qg-DX-FOmq1hPNSD53_IllpnUrU,6431
|
|
33
33
|
afterpython/cli/main.py,sha256=m3BJ5rOlllUyOngD2HF2fosDLrduREzAQKpsTqcYPZc,4956
|
|
34
34
|
afterpython/const.py,sha256=B_yUBmHPyu98aOibwt7idWbhKNBBed0TeYXNBd8tPTk,157
|
|
35
35
|
afterpython/main.py,sha256=w0z6mTib3u4p2HxMrk-tIJlZtur7uRaqsbE0ewlYlSs,490
|
|
36
36
|
afterpython/pcu.py,sha256=EoEhSzFZ49b5qc9KH2RLxIHSzY8YFM5uhtw07chcrr8,6093
|
|
37
|
-
afterpython/
|
|
37
|
+
afterpython/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
38
|
+
afterpython/templates/ci-workflow-template.yml,sha256=4wnH1_a7puUV1loqMZhTT5xlKeGJ5aeercu0_vtnbDU,6289
|
|
38
39
|
afterpython/templates/cz-template.toml,sha256=2qwbQLb0nbZaA63oWXFFzvzPNBsFZHATL1C2rdNdjjs,185
|
|
39
40
|
afterpython/templates/dependabot-template.yml,sha256=CBQEgh8EsXw2X7IqzGtFI7lVT9liF6PW4DvGLB0X2LY,1136
|
|
40
41
|
afterpython/templates/deploy-workflow-template.yml,sha256=2W4K3lKMYjSTPrlXIsMweBzqP9IoLtZXAAcUu5FA5NA,2365
|
|
@@ -49,9 +50,9 @@ afterpython/tools/github_actions.py,sha256=zVmg9aqUg-EO0CnbRHl9i8TmFtXpt7nd0Vjzc
|
|
|
49
50
|
afterpython/tools/myst.py,sha256=2VO-gD25PbGSD8-v1sLI1v3Q9loahRd3ednKrW4_Utc,8113
|
|
50
51
|
afterpython/tools/pre_commit.py,sha256=oNsrUkPI13rSSBSyhyTTKPnQGhDxLIPYhxu6kL0fDmo,1206
|
|
51
52
|
afterpython/tools/pyproject.py,sha256=kb7BDn24yH_xS2F5_L0dK-GL4KgOJS-MIIUQhHnLorI,3507
|
|
52
|
-
afterpython/utils.py,sha256=
|
|
53
|
+
afterpython/utils.py,sha256=fVa3jIzCvhn7QA7N0M6d_pvojpPFrN-hae8trUYhPKU,11701
|
|
53
54
|
afterpython/version.py,sha256=hihRV1S-gc1m46OaXD32ikkEkqzs-Gtq7AcAqOQV-wY,1603
|
|
54
|
-
afterpython-0.1.
|
|
55
|
-
afterpython-0.1.
|
|
56
|
-
afterpython-0.1.
|
|
57
|
-
afterpython-0.1.
|
|
55
|
+
afterpython-0.2.1.dist-info/WHEEL,sha256=iHtWm8nRfs0VRdCYVXocAWFW8ppjHL-uTJkAdZJKOBM,80
|
|
56
|
+
afterpython-0.2.1.dist-info/entry_points.txt,sha256=roa0PDgBueM1JPbRG0G2OSxzaN394OUL_oS9iEwVLBc,80
|
|
57
|
+
afterpython-0.2.1.dist-info/METADATA,sha256=bYFDNElkzZ6Y4CHQCUJVCxF3CPzm885yD2tgkQoStyU,5780
|
|
58
|
+
afterpython-0.2.1.dist-info/RECORD,,
|
|
File without changes
|