afterpython 0.1.4__tar.gz → 0.2.0__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.
Files changed (57) hide show
  1. {afterpython-0.1.4 → afterpython-0.2.0}/PKG-INFO +1 -1
  2. {afterpython-0.1.4 → afterpython-0.2.0}/pyproject.toml +1 -1
  3. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/build.py +8 -0
  4. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/dev.py +8 -1
  5. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/init.py +9 -4
  6. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/preview.py +8 -1
  7. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/update.py +4 -1
  8. afterpython-0.2.0/src/afterpython/py.typed +0 -0
  9. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/utils.py +66 -0
  10. {afterpython-0.1.4 → afterpython-0.2.0}/README.md +0 -0
  11. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/__init__.py +0 -0
  12. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/_io/toml.py +0 -0
  13. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/_io/yaml.py +0 -0
  14. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/_paths.py +0 -0
  15. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/_typing.py +0 -0
  16. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/builders/__init__.py +0 -0
  17. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/builders/content_json.py +0 -0
  18. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/builders/index_md.py +0 -0
  19. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/builders/jupyter_notebook.py +0 -0
  20. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/builders/markdown.py +0 -0
  21. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/builders/metadata.py +0 -0
  22. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/__init__.py +0 -0
  23. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/add.py +0 -0
  24. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/bump.py +0 -0
  25. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/check.py +0 -0
  26. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/clean.py +0 -0
  27. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/commit.py +0 -0
  28. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/commitizen.py +0 -0
  29. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/format.py +0 -0
  30. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/init_branch_rules.py +0 -0
  31. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/install.py +0 -0
  32. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/lock.py +0 -0
  33. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/pre_commit.py +0 -0
  34. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/release.py +0 -0
  35. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/remove.py +0 -0
  36. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/start.py +0 -0
  37. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/commands/sync.py +0 -0
  38. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/cli/main.py +0 -0
  39. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/const.py +0 -0
  40. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/main.py +0 -0
  41. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/pcu.py +0 -0
  42. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/templates/ci-workflow-template.yml +0 -0
  43. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/templates/cz-template.toml +0 -0
  44. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/templates/dependabot-template.yml +0 -0
  45. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/templates/deploy-workflow-template.yml +0 -0
  46. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/templates/pre-commit-config-template.yaml +0 -0
  47. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/templates/release-workflow-template.yml +0 -0
  48. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/templates/ruff-template.toml +0 -0
  49. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/tools/_afterpython.py +0 -0
  50. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/tools/_git.py +0 -0
  51. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/tools/branch_rules.py +0 -0
  52. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/tools/commitizen.py +0 -0
  53. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/tools/github_actions.py +0 -0
  54. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/tools/myst.py +0 -0
  55. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/tools/pre_commit.py +0 -0
  56. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/tools/pyproject.py +0 -0
  57. {afterpython-0.1.4 → afterpython-0.2.0}/src/afterpython/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: afterpython
3
- Version: 0.1.4
3
+ Version: 0.2.0
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "afterpython"
3
- version = "0.1.4"
3
+ version = "0.2.0"
4
4
  description = "CLI tool to streamline Python package maintenance and generate a dedicated project website"
5
5
  license = "Apache-2.0"
6
6
  authors = [
@@ -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
 
@@ -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
 
@@ -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
- # TODO: init faq.yml
77
-
78
- init_website()
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:
File without changes
@@ -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")
File without changes