Skip to content

fix(protocols): resolve a str enum name when its argument defaults to None (#2356) - #2393

Merged
JarryShaw merged 1 commit into
mainfrom
fix/2356-make-index-str-none-default
Oct 27, 2026
Merged

JarryShaw merged 1 commit into
mainfrom
fix/2356-make-index-str-none-default

Conversation

@JarryShaw

Copy link
Copy Markdown
Owner

What is the purpose of your pull request?

  • fix — bug fix

Description

Closes #2356.

  • Problem: _make_index infers the enum namespace to search for a str name from the resolved argument's own default value. hopopt/ipv6_opts's seed_type and tid_type, and httpv1's status, all default to None rather than a member, so a str name (e.g. 'SEEDID_16_BIT_UNSIGNED_INTEGER', 'CODE_404') raised ProtocolNotImplemented instead of resolving — the member and int forms of the same call already worked.
  • Fix: the fix(mh): _make_opt_lmaa emits an LMAA code that contradicts the address family #2280 pattern (namespace=X if X is not None else <Enum>) at the 5 affected call sites: hopopt/ipv6_opts's _make_opt_mpl and _make_opt_smf_dpd, and httpv1._make_start_line.
  • Scope note: a wider scan found 12 more affected sites in hip.py with the same symptom but a different shape — a loop variable over a list argument, not a bare None-default name — and 5 of the enums needed there are imported only under TYPE_CHECKING, so fixing them means promoting imports to runtime rather than a one-line change. Left out of this PR; worth its own issue.
  • Fail-without-fix: 5 failed, isolated to exactly the 5 fixed sites.
  • Test: the 5 new cases in tests/protocols/test_make_index_str_unit.py, plus two stale-prose repairs in the same file that pinned the old broken behaviour's rationale rather than its actual cause.

… None (#2356)

_make_index infers the enum namespace to search for a str name from the
resolved argument's own default value. hopopt/ipv6_opts's seed_type and
tid_type, and httpv1's status, all default to None rather than a member,
so a str name ('SEEDID_16_BIT_UNSIGNED_INTEGER', 'CODE_404', ...) raised
ProtocolNotImplemented instead of resolving -- the member and int forms
of the same call already worked.

Apply the #2280 fix (namespace=X if X is not None else <Enum>) at the
5 call sites: hopopt/ipv6_opts _make_opt_mpl and _make_opt_smf_dpd,
httpv1._make_start_line.

A wider scan found 12 more affected sites in hip.py, same symptom but a
different shape (a loop variable over a list argument, not a bare
None-default name) -- left out of this fix and filed separately as
#2356's enums are imported only under TYPE_CHECKING there, so fixing
them means promoting imports to runtime rather than a one-line change.

Tests: the 5 fixed sites in test_make_index_str_unit.py, plus two
stale-prose repairs in the same file that pinned the old broken
behaviour's rationale rather than its actual cause.
@JarryShaw JarryShaw added fix Pull requests that fix a defect (fix: subject prefix) python Pull requests that update Python code review: running A cross-review is in flight against the current head - no verdict yet labels Oct 27, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

Review: GOOD TO GO at b93f10a13 (Sonnet). Independently confirmed: the chosen enum per site matches the parse side exactly (Enum_SeedID/Enum_TaggerID/HTTP StatusCode, not MH's); all 5 imports are module-level, none TYPE_CHECKING-gated; fail-without-fix re-derived (all 5 sites raise ProtocolNotImplemented on main, resolve identically to the member/int forms on this head); an AST audit of all 112 _make_index calls repo-wide found exactly these 5 affected on main and 0 on this head, matching #2356's list exactly. 805 passed/15000 subtests/0 failed; pylint (97 msgs) and mypy (10 errors) unchanged on both trees; hip.py confirmed byte-identical (untouched). Two non-blocking nits: a docstring miscounts NONE_DEFAULT_CASES' 4 entries as "one per argument", and the HTTP test pins a literal that happens to carry the existing no-reason-phrase quirk rather than asserting the real invariant (status==404). Filing a follow-up issue for the 12-site hip.py family now, as recommended.

@JarryShaw JarryShaw added review: good-to-go Cross-review at the current head says ready; CI state is separate and removed review: running A cross-review is in flight against the current head - no verdict yet labels Oct 27, 2026
@JarryShaw JarryShaw moved this to In review in PyPCAPKit Oct 27, 2026
@github-actions github-actions Bot added this to the PyPCAPKit v1.5 milestone Oct 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Coverage: 91.67% (unit tier, Python 3.15, b93f10a13, Unit Tests run success)

Package Statements Missed Branches Partial Cover
pcapkit (top level) 104 4 20 2 95.16%
pcapkit/const 19601 880 2620 867 92.12%
pcapkit/corekit 2596 74 818 37 96.51%
pcapkit/dumpkit 282 3 102 3 98.44%
pcapkit/foundation 3044 23 1060 25 98.83%
pcapkit/interface 138 4 52 3 96.32%
pcapkit/protocols 17482 209 4602 178 98.24%
pcapkit/toolkit 914 36 334 10 95.51%
pcapkit/utilities 502 7 144 5 98.14%
pcapkit/vendor 4434 1961 1018 167 52.49%

Per-file detail: the coverage-html artifact of this run.

@JarryShaw
JarryShaw merged commit 00fd65b into main Oct 27, 2026
68 checks passed
@JarryShaw
JarryShaw deleted the fix/2356-make-index-str-none-default branch October 27, 2026 22:28
@github-project-automation github-project-automation Bot moved this from In review to Done in PyPCAPKit Oct 27, 2026
JarryShaw added a commit that referenced this pull request Oct 27, 2026
Follow-up to #2356/#2393. That fix covered scalar _make_index arguments
whose own default is None, so the namespace couldn't be inferred. A
separate 12-site family in hip.py has the same symptom but a different
shape: the str name is a loop variable over a list parameter (e.g.
_make_param_dh_group_list(groups=['Group_384_bit_group'])), so the
member and int forms of the same call already worked while the str-name
form raised ProtocolNotImplemented.

Each of the 12 makers gets `if X_namespace is None: X_namespace = Enum_Y`
hoisted above its build loop, next to the existing `if X is None: X = []`
-- one decision per parameter rather than one per item, and every
original _make_index call line stays unchanged (an inline conditional at
that indentation pushed 10 of 12 lines past 120 columns).

_make_param_transport_format_list's list holds parameter codes, so its
namespace is Enum_Parameter -- the same enum its own code argument
carries, not a namespace of its own. _make_param_reg_failed's scalar
sibling failure_type already resolved by inference (its default is a
real enum member); left alone, since the two arguments there now resolve
against different enums.

5 of the 9 enums these makers need (Enum_Suite, Enum_NATTraversal,
Enum_Registration, Enum_ESPTransformSuite, Enum_Transport) were imported
only under TYPE_CHECKING, next to Enum_RegistrationFailure from the same
pcapkit.const.hip package already imported at runtime. Promoted all 5:
pcapkit/const/hip/*.py never imports from pcapkit/protocols, so this
cannot create a cycle -- verified with a cold import of
pcapkit.protocols.internet.hip as the very first import, not just
`import pcapkit`.

Tests: tests/protocols/internet/test_hip_list_argument_str_names_2394_unit.py,
7 tests / 17 subtests -- str/member/int parity for all 12 sites, a mixed
list, the scalar sibling's inference, an explicit namespace override, an
unknown-name raise, the 5 promoted enums, and an AST walk asserting every
list-argument _make_index call in hip.py has a covering case.
@JarryShaw JarryShaw removed the review: good-to-go Cross-review at the current head says ready; CI state is separate label Oct 28, 2026
JarryShaw added a commit that referenced this pull request Oct 28, 2026
Problem: of the 60 pull requests merged in the #2312-#2407 range, only
#2334, #2336, #2337, #2340 and #2348 wrote a 1.5.0 changelog entry, and
#2398 and #2403 only reworded lines that were already there. Every other
user-visible change in the range -- wire-semantics fixes, maker guards,
reassembly behaviour, public-API and error-message changes -- went
unrecorded, so the entry no longer describes the release.

Fix: one entry per user-visible pull request, in each module section's
existing style and ordered by the issue it closes. Two pairs share a
bullet, since each is the direct follow-up of the other: #2393 with
#2401, and #2405 with #2407. The diff on the entry file is purely
additive.

Internal-only work is left out deliberately: dependency and action bumps
(#2387 to #2391), test-only and docs-prose passes (#2333, #2376, #2379,
#2380, #2402), the unreachable-branch removal (#2378), and the #: comment
marker the HIP Group and Packet crawlers now write (#2381). That last one
renders nothing either way: the marker lands inside the generated
_missing_ body, conf.py's exclude-members drops _missing_ from autodoc,
and a comment in a method body is not an attribute comment to begin with.

#2392 and #2403 are recorded together, under Added rather than Fixed, for
the declarations they introduce: __proto_key__ on the seven classes owning
a __proto__ registry (#2392), __proto_dest__ on the four enum registries
and Vendor.PROTO_DEST to generate it (#2403). Both PRs added the autodoc
entries, so both are rendered public attributes. #2392's rejection-message
change is deliberately not recorded as a fix: the bare "code must be ..."
text it prefixed came from _check_code, which #2193 introduced and which
is in no release tag -- absent at v1.5.0b14 -- so no released version ever
emitted it. #2403 is no longer skipped as internal because it reworded an
existing bullet to name __proto_dest__ while nothing credited the
attribute's introduction.

Four claims are corrected against the source rather than carried over:
FTP_DATA shipped in pcapkit/protocols/application/ftp.py from 1.0.0, not
1.4.0 (class FTP_DATA(Raw) is there at v1.0.0); #2365's pre-fix fallback
read cmmd.value, so a .value-carrying object was accepted unchecked
rather than raising; #2399 left the dpkt adapter and the adapters'
ModuleNotFound raises alone, so it claims no universal prefix; and
#2397's old tail did name the version it got, so the entry quotes it and
gains the :issue:`2302` it was missing. #2370's "a Section Header Block
... still fails" sentence is dropped: #2369 settles the byte order first,
and an SHB built from raw octets with ctx=None now rebuilds byte-exact in
both byte orders.

CHANGELOG.md is regenerated with util/changelog_md.py.

Test: tests/project/ in full, 0 failures, including test_changelog_md.py's
in-step and supported-subset checks; util/changelog_md.py --check reports
the two files in step; the entry parses under docutils with no structural
warning.
JarryShaw added a commit that referenced this pull request Oct 28, 2026
Problem: of the 60 pull requests merged in the #2312-#2407 range, only
#2334, #2336, #2337, #2340 and #2348 wrote a 1.5.0 changelog entry, and
#2398 and #2403 only reworded lines that were already there. Every other
user-visible change in the range -- wire-semantics fixes, maker guards,
reassembly behaviour, public-API and error-message changes -- went
unrecorded, so the entry no longer describes the release.

Fix: one entry per user-visible pull request, in each module section's
existing style and ordered by the issue it closes. Three pairs share a
bullet, since each is the direct follow-up or counterpart of the other:
#2393 with #2401, #2405 with #2407, and #2392 with #2403. The diff on the
entry file is purely additive.

Internal-only work is left out deliberately: dependency and action bumps
(#2387 to #2391), test-only and docs-prose passes (#2333, #2376, #2379,
#2380, #2402), the unreachable-branch removal (#2378), and the #: comment
marker the HIP Group and Packet crawlers now write (#2381). That last one
renders nothing either way: the marker lands inside the generated
_missing_ body, conf.py's exclude-members drops _missing_ from autodoc,
and a comment in a method body is not an attribute comment to begin with.

#2392 and #2403 are recorded together, under Added rather than Fixed, for
the declarations they introduce: __proto_key__ on each class owning a
__proto__ registry (#2392), __proto_dest__ on the enum registries and
Vendor.PROTO_DEST to generate it (#2403). The bullet names those classes
and registries rather than counting them, per the no-counted-numbers rule
for the unreleased entry. Both PRs added the autodoc entries, so both are
rendered public attributes. #2392's rejection-message
change is deliberately not recorded as a fix: the bare "code must be ..."
text it prefixed came from _check_code, which #2193 introduced and which
is in no release tag -- absent at v1.5.0b14 -- so no released version ever
emitted it. #2403 is no longer skipped as internal because it reworded an
existing bullet to name __proto_dest__ while nothing credited the
attribute's introduction.

Four claims are corrected against the source rather than carried over:
FTP_DATA shipped in pcapkit/protocols/application/ftp.py from 1.0.0, not
1.4.0 (class FTP_DATA(Raw) is there at v1.0.0); #2365's pre-fix fallback
read cmmd.value, so a .value-carrying object was accepted unchecked
rather than raising; #2399 left the dpkt adapter and the adapters'
ModuleNotFound raises alone, so it claims no universal prefix; and
#2397's old tail did name the version it got, so the entry quotes it and
gains the :issue:`2302` it was missing. #2370's "a Section Header Block
... still fails" sentence is dropped: #2369 settles the byte order first,
and an SHB built from raw octets with ctx=None now rebuilds byte-exact in
both byte orders.

CHANGELOG.md is regenerated with util/changelog_md.py.

Test: tests/project/ in full, 0 failures, including test_changelog_md.py's
in-step and supported-subset checks; util/changelog_md.py --check reports
the two files in step; the entry parses under docutils with no structural
warning.
JarryShaw added a commit that referenced this pull request Oct 28, 2026
Problem: of the 60 pull requests merged in the #2312-#2407 range, only
#2334, #2336, #2337, #2340 and #2348 wrote a 1.5.0 changelog entry, and
#2398 and #2403 only reworded lines that were already there. Every other
user-visible change in the range -- wire-semantics fixes, maker guards,
reassembly behaviour, public-API and error-message changes -- went
unrecorded, so the entry no longer describes the release.

Fix: one entry per user-visible pull request, in each module section's
existing style and ordered by the issue it closes. Three pairs share a
bullet, since each is the direct follow-up or counterpart of the other:
#2393 with #2401, #2405 with #2407, and #2392 with #2403. The diff on the
entry file is purely additive.

Internal-only work is left out deliberately: dependency and action bumps
(#2387 to #2391), test-only and docs-prose passes (#2333, #2376, #2379,
#2380, #2402), the unreachable-branch removal (#2378), and the #: comment
marker the HIP Group and Packet crawlers now write (#2381). That last one
renders nothing either way: the marker lands inside the generated
_missing_ body, conf.py's exclude-members drops _missing_ from autodoc,
and a comment in a method body is not an attribute comment to begin with.

#2392 and #2403 are recorded together, under Added rather than Fixed, for
the declarations they introduce: __proto_key__ on each class owning a
__proto__ registry (#2392), __proto_dest__ on the enum registries and
Vendor.PROTO_DEST to generate it (#2403). The bullet names those classes
and registries rather than counting them, per the no-counted-numbers rule
for the unreleased entry. Both PRs added the autodoc entries, so both are
rendered public attributes. #2392's rejection-message
change is deliberately not recorded as a fix: the bare "code must be ..."
text it prefixed came from _check_code, which #2193 introduced and which
is in no release tag -- absent at v1.5.0b14 -- so no released version ever
emitted it. #2403 is no longer skipped as internal because it reworded an
existing bullet to name __proto_dest__ while nothing credited the
attribute's introduction.

Four claims are corrected against the source rather than carried over:
FTP_DATA shipped in pcapkit/protocols/application/ftp.py from 1.0.0, not
1.4.0 (class FTP_DATA(Raw) is there at v1.0.0); #2365's pre-fix fallback
read cmmd.value, so a .value-carrying object was accepted unchecked
rather than raising; #2399 left the dpkt adapter and the adapters'
ModuleNotFound raises alone, so it claims no universal prefix; and
#2397's old tail did name the version it got, so the entry quotes it and
gains the :issue:`2302` it was missing. #2370's "a Section Header Block
... still fails" sentence is dropped: #2369 settles the byte order first,
and an SHB built from raw octets with ctx=None now rebuilds byte-exact in
both byte orders.

CHANGELOG.md is regenerated with util/changelog_md.py.

Test: tests/project/ in full, 0 failures, including test_changelog_md.py's
in-step and supported-subset checks; util/changelog_md.py --check reports
the two files in step; the entry parses under docutils with no structural
warning.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix Pull requests that fix a defect (fix: subject prefix) python Pull requests that update Python code

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

fix: several makers reject a str enum name when their argument defaults to None

1 participant