Skip to content

Docs: run examples as doctests, fix drifted calls, link API objects#540

Merged
tony merged 10 commits into
masterfrom
docs/agents-md-compliance
Jul 3, 2026
Merged

Docs: run examples as doctests, fix drifted calls, link API objects#540
tony merged 10 commits into
masterfrom
docs/agents-md-compliance

Conversation

@tony

@tony tony commented Jul 2, 2026

Copy link
Copy Markdown
Member

Summary

  • Fix seven documented calls that raise TypeError or return nothing when copied — branches.create() and set_url() shown positionally where keywords are required, notes.add(object=...)/get(object=...) for what is named object_sha, reflog.ls(ref=...) and expire(ref=...) parameters that don't exist, worktrees.add(branch=...), and QueryList filter examples using attributes the objects don't have
  • Convert every runnable-shaped ```python block under docs/ into fixture-backed doctests, so pytest executes docs examples on every run — the drift above went unnoticed precisely because these blocks never ran
  • Add first-mention MyST cross-references for classes, methods, and exceptions across topic, hub, and reference pages per the docs/AGENTS.md linking rule; man-page citations link to upstream docs
  • Repair url/registry.md: its narration sat inside one fenced code block, rendering as monospace with unprocessed markup — now three self-contained, narrated doctest stories
  • Rewrite concept-first openings for url/index.md and the cmd/sync hub pages; one-line stub pages state what each module does
  • Fix project/workflow.md commands that don't work (uv install -E …uv sync, bare uv run ruff) and replace its stale RST-era Releasing section with a pointer to the current release page

docs/AGENTS.md codifies the voice and cross-reference standard distilled from topics/traversing_git.md; this brings the remaining pages into compliance — and doubles as a regression net, since examples that execute can't silently drift from the API again.

Changes by area

Executable examples

  • docs/cmd/git/*.md: each subcommand page's example is a doctest session against example_git_repo, with prose introducing each block instead of inline comments; the API-drifted calls were corrected in the process
  • docs/quickstart.md: init/clone/status and Manager examples run; a new Parse URLs section delivers the URL parsing the landing-page card promises
  • docs/index.md: the "At a glance" GitURL block executes
  • docs/internals/query_list.md: filter examples use real attributes (branch_name) and demonstrate nested lookups with plain data
  • docs/topics/traversing_git.md: the one forbidden # doctest: +SKIP replaced with a deterministic loop

Cross-references

  • First prose mentions of QueryList, filter(), get(), ObjectDoesNotExist, MultipleObjectsReturned, GitURL/HgURL/SvnURL, is_valid(), to_url(), BaseSync, and urllib.parse carry the most specific role
  • "Manager/Cmd pattern" mentions link to the traversing-git-repos topic; .md-style links replaced with {ref}/{doc} roles
  • Man pages linked uniformly across the cmd/ and url/ families; external projects (Django, pip VCS support, pytest-xdist, Mercurial, Subversion) linked at first mention

Page voice

  • docs/url/registry.md: concept-first intro naming ParserMatch/VCSRegistry, real headings replacing bold pseudo-headings, is_explicit explained
  • docs/url/index.md: precision fixes ride along — Python-2 urlparseurllib.parse, mismatched cb: shorthand example, truncated sentence, comment inside a console block, garbled clone transcript
  • Hubs and stubs: cmd/index.md and sync/index.md open with what the layer does before external comparisons; one-line stubs name and link their class

Meta pages

  • docs/project/workflow.md: working setup/lint commands; Releasing section deduplicated to a pointer at the release page
  • docs/index.md, docs/api/index.md: pin examples refreshed to the current release range
  • CHANGES: two Documentation deliverables recorded under the unreleased header

Design decisions

  • Shape assertions over exact output: doctests assert stable shapes (len(...) >= 1, isinstance, +ELLIPSIS) or reuse expected output from already-passing docstring doctests, keeping them robust across git versions while still executing every call
  • One story per fence: each fenced block under docs/ collects as its own doctest item with fresh fixtures, so multi-step narratives stay inside a single self-contained block rather than sharing state across fences
  • Submodule add not demonstrated inline: git blocks file:// submodules by default (protocol.file.allow), so the page defers to the autodoc'd runnable examples for add/init/update instead of a doctest that would have to tolerate a fatal error

Verification

No skipped doctests remain under docs:

rg 'doctest: \+SKIP' docs

No placeholder repositories remain in examples:

rg "path='/path/to/repo'" docs

Test plan

  • uv run py.test --reruns 0 — full suite including every docs doctest (docs/ and README.md are pytest testpaths)
  • uv run ruff check ., uv run ruff format ., uv run mypy . — clean
  • just build-docs — all new {class}/{meth}/{exc}/{ref}/{doc} targets resolve; the only warning is the pre-existing doc-pytest-plugin directive notice on an untouched page
  • Rendered url/registry page shows narration as paragraphs with three separate code blocks (was one monolithic block)

tony added 7 commits July 1, 2026 22:50
why: Non-running ```python blocks with placeholder repo paths dodged
pytest execution and hid API errors that raise TypeError or return
empty results when readers copy them.

what:
- Convert docs/cmd/git/* Example blocks to fixture-backed doctests
  (example_git_repo, tmp_path), with prose replacing inline comments
- Convert quickstart.md, index.md "At a glance", and
  internals/query_list.md blocks the same way
- Fix API errors the dead blocks hid: branches.create() called
  positionally (keyword-only branch=), notes.add/get object= (real
  name object_sha), reflog.ls(ref=) and expire(ref=) (no such
  params), remote set_url() called positionally (keyword-only url=),
  worktrees.add(branch=) (no such param), QueryList filter examples
  using nonexistent attributes (name, is_remote, commit__sha)
- Replace forbidden `# doctest: +SKIP` in traversing_git.md with a
  deterministic running loop
why: docs/AGENTS.md requires the first prose mention of any symbol
with a destination to carry the most specific MyST role; most pages
predate the guide and left objects, methods, and exceptions as plain
backticks or bare text.

what:
- Add {class}/{meth}/{exc}/{mod} roles for QueryList, filter(),
  get(), ObjectDoesNotExist, MultipleObjectsReturned, GitURL, HgURL,
  SvnURL, to_url(), is_valid(), BaseSync, urllib.parse, list
- Link the Manager/Cmd pattern to traversing-git-repos wherever
  pages mention it (quickstart, cmd hubs, stash/submodule notes,
  query_list internals)
- Replace .md/path links with {ref}/{doc} roles (index, contributing)
- Link man-page references across docs/cmd/git/ and url/git.md
  uniformly to git-scm.com
- Link external projects at first mention: Django, pip VCS support,
  pytest-xdist, URL registry doc page
why: url/registry.md trapped its explanatory prose inside one fenced
code block (rendered as monospace, markup unprocessed); url/index.md
opened with first-person musing before the concept; hub and stub
pages led with comparison links or bare fragments instead of saying
what the module does.

what:
- url/registry.md: split the monolithic fence into three
  self-contained doctest stories with real prose between them,
  concept-first intro, real headings, linked Rule/RuleMap/
  VCSRegistry/ParserMatch, and an API Reference heading
- url/index.md: concept-first intro; prose leads for the tab
  sections; explain is_explicit; fix "how to we get" and truncated
  "For orgs on ," sentences; correct the cb: shorthand example and
  the failing git-clone transcript; drop the comment inside the
  console block; {mod}`urlparse` -> {mod}`urllib.parse`; merge the
  Matchers stub sections into one "How matching resolves" section
- cmd/index.md, sync/index.md: one-sentence concept line above the
  Compare-to links; sync hub names and links GitSync/HgSync/SvnSync
- Stub one-liners (cmd/{hg,svn}, sync/{base,git,hg,svn},
  url/{hg,svn}): concept sentence linking the class, the external
  project, and the man page; capitalize proper nouns
why: workflow.md documented a uv command that does not exist and a
Releasing flow that contradicts project/releasing.md and the current
CHANGES format; pin examples cited a version range two releases old;
quickstart never delivered the URL parsing its index card promises.

what:
- workflow.md: `uv install -E ...` -> `uv sync`; `uv run ruff` ->
  `uv run ruff check .`; "From home directory" -> project root;
  split run-on helper sentences; replace the stale Releasing section
  (RST-era changelog format, old paths, multi-command literal block)
  with a pointer to {ref}`releasing`
- index.md, api/index.md: refresh pin example to the current range
- quickstart.md: add a Parse URLs section with a runnable GitURL
  example linking {ref}`url-parsing`; fix developmental-release
  wording
why: Users of published releases copied documented calls that raise
TypeError or return nothing; the changelog should record that every
docs example now executes and that the drifted calls were corrected.

what:
- Add Documentation deliverable covering the doctest conversion and
  the API drift it surfaced
why: Readers navigating the docs gain links from prose to API pages;
the changelog should record the cross-reference and page-voice pass.

what:
- Add Documentation deliverable covering first-mention linking,
  man-page links, the registry guide restructure, and hub openings
why: The changelog convention places the pull request number in each
deliverable heading; the number was unknown until the branch went up
for review.

what:
- Add (#540) to both Documentation deliverable headings
@codecov

codecov Bot commented Jul 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 61.26%. Comparing base (36eb81d) to head (663c940).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #540      +/-   ##
==========================================
+ Coverage   61.18%   61.26%   +0.07%     
==========================================
  Files          40       40              
  Lines        6557     6557              
  Branches     1103     1103              
==========================================
+ Hits         4012     4017       +5     
+ Misses       1948     1946       -2     
+ Partials      597      594       -3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

tony added 2 commits July 2, 2026 18:23
why: The branch links every git and hg man-page citation to upstream
documentation and CHANGES claims as much, but the three svn pages
left svn(1) as plain code text.

what:
- Link svn(1) to the svn command reference in the SVN book on
  cmd/svn.md, sync/svn.md, and url/svn.md
why: de3011e added a doctest proving a custom VCSRegistry leaves the
module-level registry untouched, placed beside the custom registry's
construction; the page restructure had moved it to the end of the
second story, away from the example it guards.

what:
- Show registry.match() resolving to plain GitURL immediately after
  vcs_matcher is built in the first custom-rule story, contrasting
  with MyGitURLParser on the next call
- Drop the duplicate proof and its lead-in from the KDE story
@tony

tony commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

Code review

Found 1 issue:

  1. The new changelog entry groups reflog.ls(ref=...) together with expire(ref=...) as parameters that don't exist, but GitReflogManager.ls does accept ref (ref: str = "HEAD") — only expire (keyword-only, no ref) is actually broken. The entry misstates the reflog.ls() API surface. (bug due to src/libvcs/cmd/git.py: def ls(self, ref: str = "HEAD", *, number=...))

libvcs/CHANGES

Lines 29 to 35 in a1900a0

conversion surfaced and fixed documented calls that had drifted from the
API: `git.branches.create()` and `remote.set_url()` shown positionally
where keyword arguments are required, `notes.add(object=...)` for what is
named `object_sha`, `reflog.ls(ref=...)` and `expire(ref=...)` parameters
that don't exist, `worktrees.add(branch=...)` for `new_branch`, and
{class}`~libvcs._internal.query_list.QueryList` filter examples using
attribute names the objects don't have.

Source evidence that reflog.ls accepts ref:

libvcs/src/libvcs/cmd/git.py

Lines 8244 to 8249 in a1900a0

def ls(
self,
ref: str = "HEAD",
*,
number: int | None = None,
) -> QueryList[GitReflogEntry]:

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

why: The branch added a runnable "Parse URLs" section to the
quickstart that the existing Documentation entries did not record.

what:
- Add "Quickstart now demonstrates URL parsing" entry under the
  Documentation section, citing GitURL and the url-parsing guide
@tony tony merged commit 22760f2 into master Jul 3, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant