docs: resolve ambiguous cross-references and the five autodoc signature failures - #416
Merged
Merged
Conversation
Clean Sphinx build goes from 234 warnings/errors to 92. The five ``error while formatting signature`` failures were the worst of it: autodoc dropped ``Protocol.__schema__`` and four ``__protocol_type__`` attributes from their pages entirely. ``sphinx_autodoc_typehints`` keys its signature handler off ``callable(obj)``, sees the class each of those attributes holds as its value, and hands Sphinx 9.1 a signature it stores with ``signatures[0] = ...`` on a list it never populated. ``conf.py`` now claims that event first for class-valued attributes, and the members render again. The 156 ``more than one target found`` warnings had one dominant cause. Autodoc reads a class attribute's type with ``typing.get_type_hints``; one unresolvable ``TYPE_CHECKING`` name makes that raise for the whole class, and Sphinx falls back to the raw ``__annotations__`` strings. ``pre: 'ToSPrecedence'`` therefore became a bare word that the Python domain had to resolve by suffix-matching, with ``pcapkit.const...ToSPrecedence`` and its ``pcapkit.vendor`` generator both matching -- so roughly half of those links pointed at the crawler rather than the enumeration. Binding each module's guarded imports up front lets ``get_type_hints`` succeed and the annotations carry their full dotted path. 125 of the 156 go away; the rest are qualified by hand or listed in the PR. Also fixed, all at source rather than by suppression: * 12 unresolvable forward references -- ``ipv6_route`` never imported ``NoReturn``, ``ProtoChain`` or ``Protocol``; ``ipv6`` never imported ``Schema``; ``extraction`` never imported ``ProtocolContext``; and the ``CallbackFn``/``FrameConstructor`` aliases quoted names that only their own module could resolve, which broke every consumer. * ``PCAP_CT.run`` losing its trailing ``Note:`` body, because an injected ``:rtype: None`` landed between the directive and its content. * ``rank:' int'`` in ``data.internet.hopopt`` -- Python 3.14 rejects the stray space outright and aborts the build once the name resolves. Docs build and the full test suite (782 passed, 17 skipped) both green.
…workaround `conf.py` was normalising `rank: ' int'` at build time because the file holding the second instance was thought to be off-limits to this branch. It is not: #413 edits `pcapkit/protocols/internet/ipv6_opts.py`, and the defect is in `pcapkit/protocols/data/internet/ipv6_opts.py` -- a different file that no open PR touches. So it is fixed at source and `strip_annotation_whitespace` is gone, along with the warning it emitted on every build. A sweep of the package finds no third instance. The reason the trailing space matters is kept, moved onto `bind_type_checking_names` where it belongs: resolving the guarded names is what turns a malformed annotation from harmless into fatal, since these used to fail earlier with `NameError` (which Sphinx catches) and now reach 3.14's `annotationlib`, which raises `SyntaxError` (which Sphinx does not). A third such typo should stop the build rather than be papered over here. Clean build after: 91 warning/error lines, 0 signature failures, 0 stray-whitespace notices, 516 pages. Unit tier 649 passed, 5 skipped.
There was a problem hiding this comment.
🟢 Approval recommended
The changes are consistent with the pinned Sphinx toolchain, are scoped to documentation/type-resolution behavior, and resolve concrete build failures without altering runtime semantics.
Pull request overview
This PR improves the reliability and correctness of the Sphinx documentation build by eliminating a set of signature-rendering failures and substantially reducing ambiguous cross-references, primarily by making type information resolvable during autodoc and by disambiguating several types in docs and doc-comments.
Changes:
- Adds Sphinx build-time hooks in
docs/source/conf.pyto (a) executeTYPE_CHECKINGguarded imports acrosspcapkitmodules and (b) prevent class-valued attributes from being treated as callables with signatures. - Fixes multiple forward-reference / guarded-import issues in
TYPE_CHECKINGblocks so autodoc can resolve types (plus fixes two malformed quoted annotations that would become fatal once resolvable). - Updates several docs and
#:type comment lines to use fully-qualified targets to avoid ambiguous cross-references.
File summaries
| File | Description |
|---|---|
| pcapkit/protocols/transport/udp.py | Disambiguates Type in doc-comment type text for protocol mapping. |
| pcapkit/protocols/transport/tcp.py | Disambiguates Type in doc-comment type text for protocol mapping. |
| pcapkit/protocols/transport/sctp.py | Disambiguates Type in doc-comment type text for protocol mapping. |
| pcapkit/protocols/misc/pcapng.py | Disambiguates Type in doc-comment type text for link-type protocol mapping. |
| pcapkit/protocols/misc/pcap/frame.py | Disambiguates Type in doc-comment type text for link-type protocol mapping. |
| pcapkit/protocols/link/link.py | Disambiguates Type in doc-comment type text for next-layer protocol mapping. |
| pcapkit/protocols/internet/ipv6.py | Adds missing Schema import under TYPE_CHECKING for resolvable annotations. |
| pcapkit/protocols/internet/ipv6_route.py | Adds missing TYPE_CHECKING imports to resolve forward references in annotations. |
| pcapkit/protocols/internet/internet.py | Disambiguates Type in doc-comment type text for next-layer protocol mapping. |
| pcapkit/protocols/data/internet/ipv6_opts.py | Fixes malformed quoted annotation (' int' → 'int') that can break doc builds once resolved. |
| pcapkit/protocols/data/internet/hopopt.py | Fixes malformed quoted annotation (' int' → 'int') that can break doc builds once resolved. |
| pcapkit/protocols/application/httpv2.py | Fixes a quoted forward reference in a TYPE_CHECKING alias to be resolvable by consumers. |
| pcapkit/protocols/init.py | Disambiguates Type in doc-comment type text for the protocol registry. |
| pcapkit/foundation/traceflow/traceflow.py | Moves TypeVar definitions above TYPE_CHECKING so exported aliases can be resolved across modules. |
| pcapkit/foundation/reassembly/reassembly.py | Moves TypeVar definitions above TYPE_CHECKING so exported aliases can be resolved across modules. |
| pcapkit/foundation/extraction.py | Adds missing ProtocolContext import under TYPE_CHECKING for resolvable annotations. |
| docs/source/pcapkit/protocols/internet/ipv4.rst | Fully-qualifies :type: targets to prevent ambiguous cross-references. |
| docs/source/pcapkit/foundation/traceflow/traceflow.rst | Adjusts type and data targets to resolve correctly within the module context. |
| docs/source/conf.py | Adds build-time hooks to pre-bind guarded names and to prevent signature-processing crashes for class-valued attributes. |
Review details
- Files reviewed: 17/19 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A clean Sphinx build went from 234 warning/error lines to 91, with nothing suppressed — no
:noindex:, nonitpick_ignore, nosuppress_warnings. Counts verified by two independent clean builds.WARNING/ERRORlineserror while formatting signaturemore than one target foundCannot resolve forward referenceContent block expected for the "note" directive(ERROR)ERRORlinesduplicate object descriptionThe five signature failures were the worst of it, and they weren't about links
Autodoc was dropping members from their pages entirely —
Protocol.__schema__and four__protocol_type__attributes. Traced to a repro:sphinx_autodoc_typehints.process_signaturegates oncallable(obj)alone, sees the class those attributes hold as their value, and returns a signature. Sphinx 9.1 then doessignatures[0] = ...on a list it never populated →IndexError, which autodoc reports as "error while formatting signature" and skips the member.conf.pynow claims that event first for class-valued attributes, at priority 400 so it wins against the extension's default 500. All five render again.125 of the 156 ambiguous references had one root cause
Autodoc reads an attribute's type with
typing.get_type_hints, and one unresolvableTYPE_CHECKINGname makes it raise for the whole class — Sphinx then falls back to raw__annotations__strings. Sopre: 'ToSPrecedence'rendered as a bare word that the Python domain resolves by suffix-matching, and bothpcapkit.const.ipv4.tos_pre.ToSPrecedenceand itspcapkit.vendorgenerator match. Roughly half the links pointed at the crawler rather than the enumeration.conf.pynow executes each module's guarded-import block up front, reusingsphinx-autodoc-typehints' own resolver (which does this lazily but skips classes, since it keys off__globals__). Verified in the HTML:ToSField.pre→pcapkit/const/ipv4.html#…ToSPrecedence.12 forward references were real source bugs
ipv6_route.pynever importedNoReturn,ProtoChainorProtocol— its siblingah.py, with identical properties, does.ipv6.pynever importedSchema;extraction.pynever importedProtocolContext. AndCallbackFn/FrameConstructorquoted names resolvable only from their defining module, which broke every consumer — fixed by moving the TypeVars above theTYPE_CHECKINGblock and unquoting.Every source change is inside a
TYPE_CHECKINGblock or a#:doc comment, so there is no runtime effect. Unit tier: 649 passed, 5 skipped.A latent build-breaker, and why it was latent
rank: ' int'— the space that belongs after the colon typed one character late. Meaningless to a type checker, and previously harmless here because these annotations failed earlier withNameError, whichsphinx.util.typing.get_type_hintscatches. Once they resolve, Python 3.14'sannotationlibrejects the leading space with aSyntaxErrorthat Sphinx does not catch, and it aborts the whole build.Both instances are fixed at source (
data/internet/hopopt.py,data/internet/ipv6_opts.py); a sweep finds no third. The reasoning lives onbind_type_checking_names, because a third such typo should stop the build rather than be worked around inconf.py.A judgement call worth recording
napoleon_type_aliases = {'Type': '~typing.Type'}would have replaced eight hand edits with one line. Not used:pcapkit/protocols/application/httpv1.py:81has#: Type: Type of HTTP receipt.whereTypemeans its own class, and a global alias would mislink it.Not fixed, with what each needs
const/reg/apptype.py(19) andconst/sctp/payload_protocol_identifier.py(1). Napoleon parses every attribute docstring astype: description, splitting on the first unprotected colon — so#: Echo (ECHO) [https://…]splits insidehttps:and renders the description as//www.nntb.no/~dreibh/rserpool/]. These pages are visibly wrong, not merely mislinked. Napoleon has no switch for it; the fix belongs in thepcapkit/vendor/reg/apptype.pycrawler, followed by regenerating a 26k-line const file — which needs IANA network access._AT,Type, and three whose targets are doubled.. data::names inreassembly.rst:92-102). Same one-line fixes as the traceflow ones; apply after docs: fix 45 places where the documentation contradicts the code #413 lands.Duplicate target name: "libpcap"infoundation/engines/index.rst, which docs: fix 45 places where the documentation contradicts the code #413 already fixes (2 targets → 1). They clear on merge.type— Sphinx'sclass→data→attrfallback matches the project's own attributes namedtypebefore intersphinx is consulted. Would needbuiltins.typespelled out; judged not worth the noise.One caveat on the counts
6
Failed guarded type importand 10 forward references are environment, not repo defects. The venv available here lackspcap,pcapfileandlibpcap, all of which thePipfile's[dev-packages]lists —pipenvwas never provisioned on this host. Under a realpipenv install --devthose 16 should not appear, so the true after-count is likely 75, not 91. I did not install into the shared venv to find out.