Repository navigation
fix(const): value-lookup in Method.get, so BASELINE-CONTROL/VERSION-CONTROL resolve (#908) - #915
Conversation
c59ee55 to
d6663df
Compare
|
Cross-review on opus (author sonnet) returned NEEDS CHANGES, and it was right. Fixed in
The bytes row is a return-to-raise change, not merely a different exception type, and bytes is the plausible mistake here: The reviewer also corrected me on the Confirmed clean by the reviewer with its own derivation: the Unverified and stated: the author's 100% coverage figure did not reproduce at the reviewer's narrower scope (94%, missing lines 57/312/316), and |
…ONTROL resolve (#908) `Method.get` checked only `_member_map_` (names), never `_value2member_map_` (values), so `BASELINE_CONTROL`/`'BASELINE-CONTROL'` and `VERSION_CONTROL`/`'VERSION-CONTROL'` -- whose name and value differ, a hyphen being unusable in an identifier -- fell through to an unregistered member with the wrong `safe`/`idempotent`. `httpv1.py`'s permissive method regex lets a real capture reach this. - Delegate to the base `EnumLookup.get`, keeping the override only for the unregistered fallback; moved `staticmethod` -> `classmethod` since zero-argument `super()` needs `cls` to bind. - Kept `default`'s existing meaning (the fallback member's value) rather than the base's `NO_DEFAULT`/registered-value-only semantics, which would be caller-visible. - Case-sensitivity (#896/#907) and caller's-own-casing (#860) are unchanged, each pinned by its own test; fixed in the crawler template and the generated file together, verified byte-identical. Added an end-to-end `httpv1` test and a template/generated-file parity test. Build: `coverage run -m unittest` over `tests/const/` and `test_http_unit.py`, all passing. Document and pin the non-`str` surface, which this fix moves as a side effect. Delegating to the base routes a non-`str` key through `cls(key)` and so `_missing_`, which raises `ValueError`; `except KeyError` catches only a failed *name* lookup, so that `ValueError` reaches the caller. Measured before and after: get(42) AttributeError: 'int' object has no attribute 'upper' -> ValueError: 42 is not a valid Method get(None) AttributeError -> ValueError get(b'GET') RETURNED name=b'GET' value=b'GET' -> ValueError: b'GET' is not a valid Method The bytes row is a return-to-raise change, and bytes is the plausible mistake: `_RE_METHOD` is a bytes pattern and `httpv1` is bytes throughout, so `httpv1.py:434` is safe only because it wraps the match in `self.decode(...)`. Raising is the intended behaviour -- a bytes-valued `Method` is not something this registry should hand back -- so the fix is a `Raises:` clause plus four pins in a new `NonStrKeyTests`, all four of which fail against unmodified main (failures=2, errors=2; four distinct method names). The docstring pin reads the source via `inspect.getsource(Method.get)` rather than `Method.get.__func__`, which a `staticmethod` does not carry -- against the pre-fix module the `__func__` form died with `AttributeError` before any assertion ran, so it pinned `classmethod`-ness rather than the clause it is named for. Added to the crawler template as well as the generated module, so regeneration cannot drop it.
d6663df to
c6695e0
Compare
|
GOOD TO GO — the re-review closed its own finding on It attacked the hole I asked about — a non- It also confirmed Coverage rose on exactly the line raised: And it was right about a weakness in a test I wrote, so I fixed it rather than accept "not worth a revision". My Unverified and stated: the author's original 100% coverage figure at its own wider scope was never reproduced (96% at the reviewer's narrower scope, residual lines explained); the Sphinx build against the rewritten docstrings; and |
…up (#877) Phase 2 of #877, the 11 classes across 8 files not held by #913/#904: TransportProtocol, FinalisedState, Completion, ftp.Type, httpv1.Type, Criticality, PDUKind, PacketDirection, PacketReception, WireGuardKeyLabel, and FrameType.Flags (carrying its 6 per-frame subclasses transitively). Each now mixes in EnumLookup ahead of its enum base for the shared get/get_all contract. TransportProtocol and Criticality already had their own get, both as a staticmethod against EnumLookup.get's classmethod (the #908/#915 trap). Both are now classmethods delegating to super().get(), keeping only what the base does not reproduce -- TransportProtocol's case-fold and no-mint refusal, Criticality's case-sensitive miss -- each re-raised as the ValueError callers already depend on rather than the base's KeyError. Each gained a default parameter forwarded to the base, since dropping one the base declares is a real classmethod-override violation under mypy. Updated test_const_enum_get.py's exclusion set for TransportProtocol's new default, and added test_enum_lookup_reparent_877_unit.py pinning the re-parenting, both preserved overrides, and no member-table growth.
…up (#877) Phase 2 of #877, the 11 classes across 8 files not held by #913/#904: TransportProtocol, FinalisedState, Completion, ftp.Type, httpv1.Type, Criticality, PDUKind, PacketDirection, PacketReception, WireGuardKeyLabel, and FrameType.Flags (carrying its 6 per-frame subclasses transitively). Each now mixes in EnumLookup ahead of its enum base for the shared get/get_all contract. TransportProtocol and Criticality already had their own get, both as a staticmethod against EnumLookup.get's classmethod (the #908/#915 trap). Both are now classmethods delegating to super().get(), keeping only what the base does not reproduce -- TransportProtocol's case-fold and no-mint refusal, Criticality's case-sensitive miss -- each re-raised as the ValueError callers already depend on rather than the base's KeyError. Each gained a default parameter forwarded to the base, since dropping one the base declares is a real classmethod-override violation under mypy. Updated test_const_enum_get.py's exclusion set for TransportProtocol's new default, and added test_enum_lookup_reparent_877_unit.py pinning the re-parenting, both preserved overrides, and no member-table growth.
…up (#877) (#921) Phase 2 of #877, the 11 classes across 8 files not held by #913/#904: TransportProtocol, FinalisedState, Completion, ftp.Type, httpv1.Type, Criticality, PDUKind, PacketDirection, PacketReception, WireGuardKeyLabel, and FrameType.Flags (carrying its 6 per-frame subclasses transitively). Each now mixes in EnumLookup ahead of its enum base for the shared get/get_all contract. TransportProtocol and Criticality already had their own get, both as a staticmethod against EnumLookup.get's classmethod (the #908/#915 trap). Both are now classmethods delegating to super().get(), keeping only what the base does not reproduce -- TransportProtocol's case-fold and no-mint refusal, Criticality's case-sensitive miss -- each re-raised as the ValueError callers already depend on rather than the base's KeyError. Each gained a default parameter forwarded to the base, since dropping one the base declares is a real classmethod-override violation under mypy. Updated test_const_enum_get.py's exclusion set for TransportProtocol's new default, and added test_enum_lookup_reparent_877_unit.py pinning the re-parenting, both preserved overrides, and no member-table growth.
Please follow the guide below
make pylint,make mypy,make isort)make testpasses, and a test case covers the changedocs/source/changelog/and regeneratedCHANGELOG.md, if the change is user-visible -- N/A -- changelog centralised in docs(changelog): shared 1.5.0 changelog — long-lived, merges last (#610, #616, #617, #618, #620) #657What is the purpose of your pull request?
fix— corrects a defectDescription of your pull request and other information
Closes #908.
Method.getchecked only_member_map_(names), never_value2member_map_(values), so the two methods whose name differs from their value --BASELINE_CONTROL/'BASELINE-CONTROL'andVERSION_CONTROL/'VERSION-CONTROL'-- fell through to an unregistered member with the wrongsafe/idempotent.httpv1.py's permissive method regex ([A-Z][A-Z-]*) lets a real capture reach this, so a successful parse silently reported wrong metadata.Delegated to the base
EnumLookup.get, keeping the override only for the unregistered-member fallback -- the issue's own suggested one-liner neededgetto move fromstaticmethodtoclassmethodfirst, since zero-argumentsuper()has no first argument to bind otherwise. Keptdefault's existing meaning (the unregistered member's value) rather than the base'sNO_DEFAULT/registered-value-only semantics, since that would be caller-visible.Case-sensitivity (#896/#907) and caller's-own-casing (#860) are unchanged, each pinned by its own test. Fixed in the crawler template (
pcapkit/vendor/http/method.py) and the generated file together, verified byte-identical by rendering the template against the committed file. Added an end-to-endhttpv1test pinning the real parse path, plus a template/generated-file parity test so a regeneration can't drop the fix.