From 8cc33011dba2c7576e16d7eff37fe364bf852c54 Mon Sep 17 00:00:00 2001 From: Jarry Shaw Date: Sun, 25 Oct 2026 03:28:35 -0400 Subject: [PATCH] fix(docs): drop dpkt.py's duplicate DPKT target and let the epilog test see #: comments (#2177) Problem: the TIMESTAMP_ATTR and BUFFER_ATTR #: comments in pcapkit/toolkit/dpkt.py define `.. _DPKT:` again, though rst_epilog already defines it. test_no_file_defines_an_epilog_name_again read raw file text, so its TARGET and SUBST patterns could not match behind a #: prefix. Fix: delete both targets; the epilog's DPKT target serves the references. The test now scans _rendered() text (docstrings and #: comments, the prefix blanked), through a new _redefinitions() helper. Test: test_no_file_defines_an_epilog_name_again fails on origin/main's dpkt.py (lines 58 and 71) and passes with the fix; test_a_doc_comment_redefinition_is_seen pins the #: case. --- pcapkit/toolkit/dpkt.py | 4 -- .../test_docs_epilog_links_1936_unit.py | 37 +++++++++++++++---- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/pcapkit/toolkit/dpkt.py b/pcapkit/toolkit/dpkt.py index ce3c233e4b..9d7d0854f4 100644 --- a/pcapkit/toolkit/dpkt.py +++ b/pcapkit/toolkit/dpkt.py @@ -54,8 +54,6 @@ #: A `DPKT`_ packet carries a :attr:`~object.__dict__`, so this is an ordinary #: attribute rather than anything exotic; the name is spelled out here so that #: nothing has to know it by hand. -#: -#: .. _DPKT: https://dpkt.readthedocs.io TIMESTAMP_ATTR = '__pcapkit_timestamp__' #: Attribute a frame's record octets are stashed under. @@ -67,8 +65,6 @@ #: the wire octets out of this buffer instead, which #: :class:`~pcapkit.foundation.engines.dpkt.DPKT` attaches alongside #: :data:`TIMESTAMP_ATTR`. -#: -#: .. _DPKT: https://dpkt.readthedocs.io BUFFER_ATTR = '__pcapkit_buffer__' diff --git a/tests/project/test_docs_epilog_links_1936_unit.py b/tests/project/test_docs_epilog_links_1936_unit.py index 8c89ba9c18..76ede7160c 100644 --- a/tests/project/test_docs_epilog_links_1936_unit.py +++ b/tests/project/test_docs_epilog_links_1936_unit.py @@ -25,6 +25,7 @@ import io import pathlib import re +import tempfile import tokenize import unittest @@ -125,6 +126,25 @@ def _line(text: 'str', offset: 'int') -> 'int': return text.count('\n', 0, offset) + 1 +def _redefinitions(path: 'pathlib.Path', substs: 'set[str]', targets: 'set[str]', *, + rel: 'str | None' = None) -> 'list[str]': + """Substitutions in *substs* and targets in *targets* that *path* defines again. + + Read from :func:`_rendered`, so a definition in a ``#:`` comment counts. + + """ + rel = _rel(path) if rel is None else rel + text = _rendered(path) + found = [] + for match in SUBST.finditer(text): + if match.group(1) in substs: + found.append(f'{rel}:{_line(text, match.start())}: |{match.group(1)}|') + for match in TARGET.finditer(text): + if _norm(match.group(1)) in targets: + found.append(f'{rel}:{_line(text, match.start())}: _{match.group(1)}') + return found + + class EpilogTests(unittest.TestCase): """``rst_epilog`` pairs each substitution with a target.""" @@ -224,15 +244,18 @@ def test_no_file_defines_an_epilog_name_again(self) -> 'None': targets = {_norm(name) for name, _ in TARGET.findall(epilog)} offenders = [] for path in _sources(changelog=True): - text = path.read_text(encoding='utf-8') - for match in SUBST.finditer(text): - if match.group(1) in substs: - offenders.append(f'{_rel(path)}:{_line(text, match.start())}: |{match.group(1)}|') - for match in TARGET.finditer(text): - if _norm(match.group(1)) in targets: - offenders.append(f'{_rel(path)}:{_line(text, match.start())}: _{match.group(1)}') + offenders.extend(_redefinitions(path, substs, targets)) self.assertEqual(offenders, []) + def test_a_doc_comment_redefinition_is_seen(self) -> 'None': + """A ``#:`` comment renders, so a definition in one counts (:issue:`2177`).""" + with tempfile.TemporaryDirectory() as tmp: + path = pathlib.Path(tmp) / 'mod.py' + path.write_text('#: A `DPKT`_ packet.\n#:\n#: .. _DPKT: https://dpkt.readthedocs.io\n' + '#: .. |dpkt| replace:: ``dpkt``\nATTR = 1\n', encoding='utf-8') + found = _redefinitions(path, {'dpkt'}, {'dpkt'}, rel=path.name) + self.assertEqual(found, ['mod.py:4: |dpkt|', 'mod.py:3: _DPKT']) + if __name__ == '__main__': unittest.main()