Skip to content

refactor(corekit,protocols): normalise the four sentinel objects to SCREAMING_SNAKE (#937) - #939

Merged
JarryShaw merged 1 commit into
mainfrom
refactor/937-sentinel-screaming-snake
Sep 30, 2026
Merged

JarryShaw merged 1 commit into
mainfrom
refactor/937-sentinel-screaming-snake

Conversation

@JarryShaw

@JarryShaw JarryShaw commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Please follow the guide below

What is the purpose of your pull request?

  • fix — corrects a defect
  • feat — adds a feature
  • perf — changes performance, not behaviour
  • refactor — changes neither behaviour nor performance
  • test — tests only
  • docs — documentation only
  • ci — workflows or build tooling
  • chore — anything else

Description of your pull request and other information

Implements #937: NoValue -> NO_VALUE, _Absent -> ABSENT (type _AbsentType -> AbsentType), per the owner's ruling to accept the breaking change with no backport. ABSENT/AbsentType stay out of every __all__; privacy is now documentation-only (sentinels.rst marks them private explicitly, per the ruling). conventions.rst gains the object-naming rule next to the existing type-naming rule. test_sentinel_exports_unit.py's _expected_type_name collapses to one mechanical rule, and a new test pins that every object is SCREAMING_SNAKE (confirmed failing on 382375811).

Also fixes the 3 NoValue references in tests/protocols/internet/test_mh_unit.py (:1869, :1875, :1879) — nothing else in that file. It was initially treated as off-limits alongside its zero-reference source, mh.py (owned by #935), but the test itself was never actually measured; CI's 5 Python-version legs caught it, failing identically on test_mh_padding_option_schema_sizes_itself.

Two build-tooling notes worth keeping on record:

  • isort reordered 5 files' imports from Field, NoValue to NO_VALUE, Field: order_by_type sorts CONSTANT-cased names ahead of Class-cased ones, so a pure casing change alone can reorder imports.
  • pylint's cyclic-import (R0401) output is nondeterministic run-to-run: two runs of the unmodified 382375811 tree produced 236 differing lines, so R0401 churn can never be pinned on a diff. Every other diagnostic (5,815 lines) was byte-identical against baseline.

@JarryShaw JarryShaw added refactor Restructuring for its own sake — neither a fix nor a new capability (refactor: prefix) breaking Breaks public-facing behaviour or API (apply alongside the type label) test Pull requests that add or correct tests (test: subject prefix) docs Pull requests that change documentation only (docs: subject prefix) review: pending No verdict for the current head - never reviewed, or the head moved since the last one labels Sep 30, 2026
@JarryShaw JarryShaw added review: needs-changes Cross-review at the current head says changes are required; see the verdict comment and removed review: pending No verdict for the current head - never reviewed, or the head moved since the last one labels Sep 30, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

NEEDS CHANGES at 8c5feda9c — six red marks, one root cause, and the partition error is mine, not this PR's.

tests/protocols/internet/test_mh_unit.py:1875: ImportError:
  cannot import name 'NoValue' from 'pcapkit.corekit.fields.field'

All five Python 3.10–3.14 legs fail identically on MHUnitTests::test_mh_padding_option_schema_sizes_itself, and Required checks passed fails downstream of them. 54 other checks pass — Lint, Compat, the whole Engines matrix, Integration, parity, Analyze, Changelog drift, safety.

Why it happened. I declared tests/protocols/internet/test_mh_unit.py off-limits to this PR's worker because PR #940 owns it, and I justified that by measuring "zero sentinel references in mh.py" — the source file, not the test file. The test file has three: :1869 in a docstring, :1875 the import, :1879 the use. So the partition was verified against the wrong file, and the worker did the right thing by stopping and reporting rather than editing across the line I drew.

Resolution: this PR takes those three lines. A rename cannot land while leaving an import of the old name behind, and the three references are purely mechanical — NoValue → NO_VALUE, including the :data: role in the docstring.

Consequence for #940, which also edits this file (+94 lines): the two will conflict on merge. Whichever lands second rebases — normal, and cheaper than splitting the rename.

Verified good otherwise, and two findings worth recording:

  • Reference counts re-derived and matching: NoValue 109/21 files, NoValueType 55/13, _Absent 41/5, _AbsentType 26/5.
  • ABSENT/AbsentType are documented as expressly private on sentinels.rst with the ruling quoted, rather than omitted — the right call, since omission would just be underscore-hiding by another name. Both confirmed out of pcapkit.protocols.protocol.__all__ and pcapkit.corekit.sentinels.__all__.
  • isort initially broke five files: NO_VALUE sorts before Field/FieldBase under order_by_type, which the old CamelCase name did not. Fixed, now clean — worth knowing that a case change alone can reorder imports.
  • pylint's cyclic-import output is nondeterministic: a double run on an unmodified baseline produced 236 differing lines with zero code change. So R0401 churn is never attributable to a diff. Non-cyclic diagnostics are byte-identical here (5815 lines each), mypy byte-identical at 321/38.

…CREAMING_SNAKE (#937)

Rename NoValue -> NO_VALUE and _Absent -> ABSENT (type _AbsentType -> AbsentType),
per the owner's ruling on #937: accept the breaking change, no backport.

- Update pcapkit/corekit/sentinels.py, its re-export shims (fields/field.py,
  protocols/protocol.py) and every other call site in pcapkit/ and tests/,
  including the 3 references in tests/protocols/internet/test_mh_unit.py
  (:1869, :1875, :1879) -- initially thought off-limits alongside its
  zero-reference source mh.py (owned by #935), but the test itself was never
  actually measured.
- Keep ABSENT/AbsentType out of every __all__: dropping the underscore removes
  the mechanical privacy signal, so protocol.py and test_sentinel_exports_unit.py
  now enforce it by assertion alone.
- Document AbsentType/ABSENT on sentinels.rst as explicitly private, since
  Sphinx no longer hides them automatically; add the object-naming rule to
  conventions.rst's sentinel-convention section and update its table/prose.
- Simplify test_sentinel_exports_unit.py's _expected_type_name to one
  mechanical rule; add test_every_sentinel_object_is_screaming_snake,
  confirmed to fail on 3823758 (NoValue, _Absent) and pass here.

Build: isort clean (order_by_type sorts NO_VALUE ahead of Field/FieldBase --
a pure casing change reordered 5 files); mypy identical (321/38) and pylint's
non-cyclic-import diagnostics identical to origin/main -- cyclic-import counts
vary run-to-run even on an unmodified baseline (236 differing lines measured).
Targeted suites pass, including the CI-caught mh.py padding test.
@JarryShaw
JarryShaw force-pushed the refactor/937-sentinel-screaming-snake branch from 8c5feda to 7090f84 Compare September 30, 2026 01:46
@JarryShaw JarryShaw added review: pending No verdict for the current head - never reviewed, or the head moved since the last one and removed review: needs-changes Cross-review at the current head says changes are required; see the verdict comment labels Sep 30, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

GOOD TO GO at 7090f84bd — Fable cross-review (author was Sonnet), with its one blocking finding already resolved by the head it did not see.

The review measured 8c5feda9c and returned NEEDS CHANGES on exactly one defect: the three live NoValue references at tests/protocols/internet/test_mh_unit.py:1869, :1875, :1879, demonstrated as ImportError: cannot import name 'NoValue'. That was my partition error — I declared the file off-limits on the strength of measuring the source mh.py, never the test — and it is fixed at 7090f84bd, whose delta is exactly those three lines and nothing else.

Independently confirmed by the review, each with its own measurement:

  • Completeness: tree-wide grep -rnw over pcapkit tests docs examples util. Every other old-name hit is deliberate historical prose or the unchanged type NoValueType. Zero NO_VALUEType botches — that substring trap was the one I most expected to bite — and the _ABSENT hits are verbatim ruling quotes.
  • Privacy: sentinels.__all__ == ['NULL','NO_VALUE','NO_DEFAULT'], field.__all__ == ['NO_VALUE','Field'], protocol.__all__ == ['ProtocolBase']; the test at test_sentinel_exports_unit.py:289 pins object, type and import *.
  • Runtime: NULL/NO_VALUE/ABSENT falsy, NO_DEFAULT truthy, repr(ABSENT) == '<absent>', no NoValueType.__repr__, BytesField(length=4).default is NO_VALUE with del restoring it, and no alias — the old names raise ImportError, per the ruling.
  • Anchors intact and in order at 25 / 142 / 308 / 776; _expected_type_name collapsed to the mechanical rule with strength kept by the new regex test; mypy 321/38 and pylint 8.67, exit 30, both at baseline; isort clean.

It also corrected my brief, and I verified the correction. I told it all four sentinels have re-export shims in pcapkit.protocols.protocol; that module has only ever shimmed the Absent pair — from pcapkit.corekit.sentinels import _Absent, _AbsentType on main, ABSENT, AbsentType on the PR tree. My error, not the PR's.

UNVERIFIED and worth stating: the coverage delta was not measured (budget), and test_every_sentinel_object_is_screaming_snake could not be shown to fail individually on 382375811 because the whole file errors at collection there — which subsumes it but is weaker evidence than a targeted failure.

Unpublished and awaiting you. One coordination note: #940 also edits test_mh_unit.py, so the two will conflict at merge and whichever lands second needs a rebase — a consequence of my partition error, not of either PR.

@JarryShaw JarryShaw added review: good-to-go Cross-review at the current head says ready; CI state is separate and removed review: pending No verdict for the current head - never reviewed, or the head moved since the last one labels Sep 30, 2026
@JarryShaw
JarryShaw merged commit 83c7552 into main Sep 30, 2026
63 checks passed
@JarryShaw
JarryShaw deleted the refactor/937-sentinel-screaming-snake branch September 30, 2026 02:15
@JarryShaw JarryShaw removed the review: good-to-go Cross-review at the current head says ready; CI state is separate label Sep 30, 2026
@JarryShaw JarryShaw added this to the 1.5 milestone Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking Breaks public-facing behaviour or API (apply alongside the type label) docs Pull requests that change documentation only (docs: subject prefix) refactor Restructuring for its own sake — neither a fix nor a new capability (refactor: prefix) test Pull requests that add or correct tests (test: subject prefix)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant