afterpython 0.3.14__tar.gz → 0.3.16__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 (64) hide show
  1. {afterpython-0.3.14 → afterpython-0.3.16}/PKG-INFO +1 -1
  2. {afterpython-0.3.14 → afterpython-0.3.16}/pyproject.toml +1 -1
  3. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/builders/jupyter_notebook.py +1 -1
  4. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/builders/marimo_notebook.py +1 -1
  5. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/builders/url_md.py +6 -1
  6. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/sync.py +22 -16
  7. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/tools/myst.py +4 -5
  8. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/utils.py +20 -3
  9. {afterpython-0.3.14 → afterpython-0.3.16}/README.md +0 -0
  10. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/__init__.py +0 -0
  11. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/_io/toml.py +0 -0
  12. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/_io/yaml.py +0 -0
  13. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/_paths.py +0 -0
  14. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/_typing.py +0 -0
  15. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/builders/__init__.py +0 -0
  16. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/builders/build_pdoc.py +0 -0
  17. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/builders/content_json.py +0 -0
  18. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/builders/faq_json.py +0 -0
  19. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/builders/index_md.py +0 -0
  20. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/builders/llms_txt.py +0 -0
  21. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/builders/markdown.py +0 -0
  22. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/builders/metadata.py +0 -0
  23. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/__init__.py +0 -0
  24. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/add.py +0 -0
  25. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/build.py +0 -0
  26. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/bump.py +0 -0
  27. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/check.py +0 -0
  28. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/clean.py +0 -0
  29. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/commit.py +0 -0
  30. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/commitizen.py +0 -0
  31. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/dev.py +0 -0
  32. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/format.py +0 -0
  33. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/init.py +0 -0
  34. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/init_branch_rules.py +0 -0
  35. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/install.py +0 -0
  36. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/lock.py +0 -0
  37. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/pre_commit.py +0 -0
  38. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/preview.py +0 -0
  39. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/release.py +0 -0
  40. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/remove.py +0 -0
  41. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/serve.py +0 -0
  42. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/start.py +0 -0
  43. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/commands/update.py +0 -0
  44. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/cli/main.py +0 -0
  45. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/const.py +0 -0
  46. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/main.py +0 -0
  47. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/pcu.py +0 -0
  48. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/py.typed +0 -0
  49. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/templates/ci-workflow-template.yml +0 -0
  50. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/templates/cz-template.toml +0 -0
  51. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/templates/dependabot-template.yml +0 -0
  52. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/templates/deploy-workflow-template.yml +0 -0
  53. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/templates/pdoc/frame.html.jinja2 +0 -0
  54. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/templates/pre-commit-config-template.yaml +0 -0
  55. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/templates/release-workflow-template.yml +0 -0
  56. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/templates/ruff-template.toml +0 -0
  57. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/tools/_afterpython.py +0 -0
  58. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/tools/_git.py +0 -0
  59. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/tools/branch_rules.py +0 -0
  60. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/tools/commitizen.py +0 -0
  61. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/tools/github_actions.py +0 -0
  62. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/tools/pre_commit.py +0 -0
  63. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/tools/pyproject.py +0 -0
  64. {afterpython-0.3.14 → afterpython-0.3.16}/src/afterpython/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: afterpython
3
- Version: 0.3.14
3
+ Version: 0.3.16
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.3.14"
3
+ version = "0.3.16"
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 = [
@@ -222,7 +222,7 @@ def build_jupyter_notebooks():
222
222
  from afterpython.tools._afterpython import get_default_thumbnail
223
223
 
224
224
  # Check if molab badge feature is enabled
225
- add_molab_badge = os.getenv("AP_MOLAB_BADGE", "1") == "1"
225
+ add_molab_badge = os.getenv("AP_MOLAB_BADGE", "0") == "1"
226
226
 
227
227
  # Get GitHub URL once if needed for molab badges
228
228
  github_url = None
@@ -130,7 +130,7 @@ def build_marimo_notebook(
130
130
  if mode == "wasm":
131
131
  return
132
132
 
133
- add_molab_badge = os.getenv("AP_MOLAB_BADGE", "1") == "1"
133
+ add_molab_badge = os.getenv("AP_MOLAB_BADGE", "0") == "1"
134
134
  if not add_molab_badge:
135
135
  return
136
136
 
@@ -74,7 +74,12 @@ def _publish_for_type(content_type: tContentType) -> int:
74
74
 
75
75
  count = 0
76
76
  for source in sorted(source_dir.rglob("*")):
77
- if "_build" in source.parts:
77
+ # Skip MyST build output and any hidden tool directory. The latter is
78
+ # essential: jupyterlab-lsp writes `.virtual_documents/*.ipynb` and
79
+ # jupyter writes `.ipynb_checkpoints/*.ipynb` — these carry an `.ipynb`
80
+ # extension but are NOT notebooks (the virtual-documents ones are raw
81
+ # Python source), so jupytext.read() chokes on them.
82
+ if "_build" in source.parts or any(p.startswith(".") for p in source.parts):
78
83
  continue
79
84
  if not source.is_file():
80
85
  continue
@@ -6,7 +6,11 @@ from pyproject_metadata import StandardMetadata
6
6
  from tomlkit.toml_document import TOMLDocument
7
7
 
8
8
  import afterpython as ap
9
- from afterpython.utils import convert_author_name_to_id, normalize_static_path
9
+ from afterpython.utils import (
10
+ build_author_name,
11
+ convert_author_name_to_id,
12
+ normalize_static_path,
13
+ )
10
14
 
11
15
 
12
16
  def _myst_favicon_path(path: str) -> str:
@@ -23,20 +27,21 @@ def _sync_authors_yml(authors: list[tuple[str, str | None]]):
23
27
 
24
28
  # read myst.yml from docs path to get "version"
25
29
  doc_myst_yml = read_yaml(ap.paths.afterpython_path / "doc" / "myst.yml")
30
+ entries = []
31
+ for author in authors:
32
+ # author is a tuple of (name, email)
33
+ name = str(author[0]).strip()
34
+ entries.append(
35
+ {
36
+ "id": convert_author_name_to_id(name),
37
+ "name": build_author_name(name),
38
+ "email": str(author[1]),
39
+ # "github": ...
40
+ }
41
+ )
26
42
  data = {
27
43
  "version": doc_myst_yml["version"],
28
- "project": {
29
- "contributors": [
30
- # NOTE: author is a tuple of (name, email), so author[0] is the name and author[1] is the email
31
- {
32
- "id": convert_author_name_to_id(str(author[0])),
33
- "name": str(author[0]),
34
- "email": str(author[1]),
35
- # "github": ...
36
- }
37
- for author in authors
38
- ]
39
- },
44
+ "project": {"authors": entries},
40
45
  }
41
46
  update_authors_yml(data)
42
47
  click.echo("✓ Synced authors.yml with pyproject.toml")
@@ -114,7 +119,8 @@ def sync():
114
119
  # nav_bar_per_content_type = [
115
120
  # item for item in nav_bar if item["title"] != content_type.capitalize() + "s"
116
121
  # ]
117
- title = project_name + f"'s {content_type.capitalize()}"
122
+ project_title = content_type.capitalize()
123
+ site_title = project_name + f"'s {content_type.capitalize()}"
118
124
  data = {
119
125
  "project": {
120
126
  # using author ids defined in authors.yml
@@ -127,7 +133,7 @@ def sync():
127
133
  "url": company_url,
128
134
  },
129
135
  "copyright": f"© {company_name or project_name} {datetime.now().year}. All rights reserved.",
130
- "title": "",
136
+ "title": project_title,
131
137
  "description": str(pyproject.description),
132
138
  "keywords": list(map(str, pyproject.keywords)),
133
139
  "github": github_url,
@@ -136,7 +142,7 @@ def sync():
136
142
  else "",
137
143
  },
138
144
  "site": {
139
- "title": title,
145
+ "title": site_title,
140
146
  "options": {
141
147
  "favicon": "../static" + myst_favicon if myst_favicon else "",
142
148
  "logo": "../static" + website_logo if website_logo else "",
@@ -30,8 +30,7 @@ def update_authors_yml(data_update: dict):
30
30
  # merge authors, keep the author with more fields (e.g. github, x, etc.) to avoid duplication
31
31
  merged_authors = {}
32
32
  for author in (
33
- existing_data["project"]["contributors"]
34
- + data_update["project"]["contributors"]
33
+ existing_data["project"].get("authors", []) + data_update["project"]["authors"]
35
34
  ):
36
35
  author_id = author["id"]
37
36
  if author_id not in merged_authors:
@@ -40,14 +39,14 @@ def update_authors_yml(data_update: dict):
40
39
  # keep the author with more fields (e.g. github, x, etc.)
41
40
  if len(author.keys()) > len(merged_authors[author_id].keys()):
42
41
  merged_authors[author_id] = author
43
- existing_data["project"]["contributors"] = list(merged_authors.values())
42
+ existing_data["project"]["authors"] = list(merged_authors.values())
44
43
 
45
44
  # set comments for project section for convenience
46
45
  if "project" in existing_data and not existing_data["project"].ca.items.get(
47
- "contributors"
46
+ "authors"
48
47
  ):
49
48
  existing_data["project"].yaml_set_comment_before_after_key(
50
- "contributors",
49
+ "authors",
51
50
  before="See more at: https://mystmd.org/guide/frontmatter#frontmatter-authors",
52
51
  )
53
52
  write_yaml(file_path, existing_data)
@@ -149,6 +149,25 @@ def convert_author_name_to_id(name: str) -> str:
149
149
  return name.replace(" ", "_").lower()
150
150
 
151
151
 
152
+ def build_author_name(name: str) -> dict:
153
+ """Build a MyST name object from a display name.
154
+
155
+ A multi-word name ("Stephen Yau") is split into ``given``/``surname`` so MyST
156
+ can render and cite it properly. A single-token name (e.g. a username like
157
+ "softwareentrepreneer") uses ``literal`` so MyST treats it as the full name
158
+ verbatim instead of warning about a missing given name.
159
+
160
+ Examples:
161
+ - "Stephen Yau" -> {"given": "Stephen", "surname": "Yau"}
162
+ - "softwareentrepreneer" -> {"literal": "softwareentrepreneer"}
163
+ """
164
+ name = name.strip()
165
+ if " " in name:
166
+ given, surname = name.split(" ", 1)
167
+ return {"given": given, "surname": surname}
168
+ return {"literal": name}
169
+
170
+
152
171
  def find_available_port(
153
172
  start_port: int = 3000, max_port: int = 3100, host: str = "localhost"
154
173
  ) -> int:
@@ -188,9 +207,7 @@ def find_available_port(
188
207
  def has_content_for_myst(content_path: Path) -> bool:
189
208
  """Check if a content directory has any content files"""
190
209
  return any(
191
- content_path.glob("*.md")
192
- or content_path.glob("*.ipynb")
193
- or content_path.glob("*.tex")
210
+ any(content_path.glob(pattern)) for pattern in ("*.md", "*.ipynb", "*.tex")
194
211
  )
195
212
 
196
213
 
File without changes