Skip to content

Commit c086cd0

Browse files
zzstoatzzclaude
andauthored
fix: point nav at -__init__ page for packages with only private submodules (#44)
A package whose only submodules are private/internal is rendered as a leaf in the navigation tree (its children aren't in generated_modules), but the generator writes it as an "-__init__" page because those private submodules exist on disk. Navigation then emitted the bare leaf path, producing a dead link (e.g. prefect-cli-deploy in nav vs prefect-cli-deploy-__init__.mdx on disk). The leaf branch now points at whichever file was actually written: if the plain page is absent but the -__init__ variant exists, use the latter. When neither exists (e.g. pure unit tests with no files on disk) it falls back to the plain name, preserving existing behavior. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 527b129 commit c086cd0

2 files changed

Lines changed: 44 additions & 2 deletions

File tree

‎src/mdxify/navigation.py‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,18 @@ def tree_to_nav(tree: dict, parent_parts: list[str] | None = None, is_top_level:
146146
# This is a leaf module with no submodules
147147
module_name = info["_path"]
148148
filename = module_name.replace(".", "-")
149-
149+
150+
# A module whose only submodules are private/internal is rendered
151+
# as a leaf here (its public children aren't in the tree), but the
152+
# generator still wrote it as an "-__init__" page because the
153+
# private submodules exist on disk. Point navigation at whichever
154+
# file was actually written so we don't emit a dead link.
155+
if (
156+
not (output_dir / f"{filename}.mdx").exists()
157+
and (output_dir / f"{filename}-__init__.mdx").exists()
158+
):
159+
filename = f"{filename}-__init__"
160+
150161
if nav_prefix:
151162
nav_path = str(nav_prefix / filename).replace("\\", "/")
152163
else:

‎tests/test_navigation.py‎

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,4 +495,35 @@ def test_update_docs_json_with_tabs_structure(tmp_path):
495495
pages = python_sdk_anchor["pages"]
496496
assert len(pages) == 2
497497
assert "python-sdk/fastmcp-client" in pages
498-
assert "python-sdk/fastmcp-server" in pages
498+
assert "python-sdk/fastmcp-server" in pages
499+
500+
def test_leaf_module_points_to_init_file_when_only_private_submodules(tmp_path):
501+
"""A package whose only submodules are private is written as an -__init__
502+
page; navigation must point at that file, not the bare leaf name.
503+
504+
Regression test for dead links like prefect-cli-deploy (nav) vs
505+
prefect-cli-deploy-__init__.mdx (file on disk).
506+
"""
507+
# The public module list only contains the package itself; its submodules
508+
# are all private and therefore not generated.
509+
modules = ["mypackage.cli.deploy"]
510+
511+
# On disk, the generator wrote the page with an -__init__ suffix.
512+
(tmp_path / "mypackage-cli-deploy-__init__.mdx").write_text("# deploy")
513+
514+
result = build_hierarchical_navigation(modules, tmp_path, skip_empty_parents=False)
515+
516+
flat = json.dumps(result)
517+
assert "mypackage-cli-deploy-__init__" in flat
518+
# And not the bare (nonexistent) leaf path.
519+
assert '"mypackage-cli-deploy"' not in flat
520+
521+
522+
def test_leaf_module_keeps_plain_name_when_file_present(tmp_path):
523+
"""A normal leaf whose plain file exists keeps the plain nav path."""
524+
modules = ["mypackage.tasks"]
525+
(tmp_path / "mypackage-tasks.mdx").write_text("# tasks")
526+
527+
result = build_hierarchical_navigation(modules, tmp_path, skip_empty_parents=False)
528+
assert "mypackage-tasks" in json.dumps(result)
529+
assert "mypackage-tasks-__init__" not in json.dumps(result)

0 commit comments

Comments
 (0)