Skip to content

fix(const,vendor): give Method's registered members their str payload (#870) - #871

Merged
JarryShaw merged 1 commit into
mainfrom
fix-870-method-str-payload
Sep 28, 2026
Merged

JarryShaw merged 1 commit into
mainfrom
fix-870-method-str-payload

Conversation

@JarryShaw

@JarryShaw JarryShaw commented Sep 28, 2026 •

Copy link
Copy Markdown
Owner

Please follow the guide below

  • You will be asked some questions, please read them carefully and answer honestly

  • Put an x into all the boxes [ ] relevant to your pull request (like that [x])

  • Use Preview tab to see how your pull request will actually look like

  • Searched for similar pull requests

  • Followed the coding style (make pylint, make mypy, make isort)

  • make test passes, and a test case covers the change

  • Added a changelog entry under docs/source/changelog/ and regenerated CHANGELOG.md, if the change is user-visible

What is the purpose of your pull request?

Tick the commit type your subject line carries.

  • 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

Fixes #870. Method.__new__ called str.__new__(cls) with no argument, so every one of the 40 registered members' str payload was permanently empty regardless of its declared value: str(Method.GET) == '', Method.GET == 'GET' was False. _value_/.value were always correct. #869 fixed this class's unregistered path only, exposing the asymmetry: str(Method('frob')) == 'frob' but str(Method.GET) == ''.

Fixed to str.__new__(cls, value), mirroring Command.__new__ (never had this defect), in both the generator (pcapkit/vendor/http/method.py) and the generated module; a second regeneration is byte-identical.

Surveyed every hand-rolled __new__ under pcapkit/const/: Command already passes its value, FEATCode has no custom __new__, OptionType/AppType deliberately store a formatted display string as their value — none share this defect.

Behaviour changes, all in the correcting direction and all measured: Method.GET == 'GET' is now True for all 40 members (was False); bool(Method.GET) flips False → True, because an empty payload made every member falsy; json.dumps(Method.GET) emits "GET" where it emitted ""; sorted() over members is now lexicographic rather than input-order-stable; and a member-keyed dict/set no longer collapses — {m: … for m in Method} has 40 entries where it had 1, since str.__hash__ wins the MRO and all 40 members previously hashed as '' and compared == to one another. Nothing under pcapkit/protocols relied on the old behaviour — checked httpv1.py/httpv2.py; the one caller only reads .value via Method.get().

Added tests/const/test_const_str_payload_870_unit.py (repro, 40-member sweep, and a registry-wide sweep of Command/FEATCode/Method, with OptionType exempted and why). Verified each assertion fails on unfixed code, passes with the fix. Updated test_const_enum_no_mint.py, which had pinned the old empty-payload behaviour as accepted-but-unfixed.

make test unchecked above: ran targeted suites instead (it OOMs locally) — the new file, test_const_enum_no_mint/get/lookup/builtin_parity, test_const_registry_protocol, test_const_apptype_split_unit (220 methods), plus tests/protocols/application/test_http_unit.py, test_ftp_unit.py, test_httpv2_* (96 methods) — all green.

Changelog: N/A — changelog centralised in #657.

…#870)

`Method.__new__` built every registered member with `str.__new__(cls)`
(no argument), so the underlying str payload was permanently empty
regardless of the declared value -- `str(Method.GET) == ''` and
`Method.GET == 'GET'` was False for all 40 members, even though
`_value_`/`.value` were always correct. #869 fixed the same class's
*unregistered* path only, which exposed the inconsistency: after #869,
`str(Method('frob')) == 'frob'` but `str(Method.GET) == ''`.

- Fix `__new__` to `str.__new__(cls, value)`, mirroring
  `Command.__new__`, which never had this defect. Fixed in both the
  generator (`pcapkit/vendor/http/method.py`) and the generated module
  (`pcapkit/const/http/method.py`); a second regeneration is
  byte-identical.
- Surveyed every other hand-rolled `__new__` under `pcapkit/const/`:
  `Command` already passes its value, `FEATCode` has no custom
  `__new__`, and `OptionType`/`AppType` deliberately store a formatted
  display string as their value -- none share this defect.
- Added `tests/const/test_const_str_payload_870_unit.py`: the exact
  repro, a sweep of all 40 `Method` members, and a registry-wide sweep
  of `Command`/`FEATCode`/`Method` (`OptionType` explicitly exempted,
  with a comment, since its value already *is* the display string).
  Verified each new assertion fails on unfixed `__new__` and passes
  with the fix.
- Updated `tests/const/test_const_enum_no_mint.py`, which had pinned
  the old empty-payload behavior as an accepted-but-unfixed asymmetry;
  it now expects the fixed behavior.

Behaviour change: `Method.GET == 'GET'` is now True (was False) for
all 40 public members; no code under `pcapkit/protocols` compared a
Method member this way. Build and targeted tests green (315 methods
across const/http/ftp suites).
@JarryShaw JarryShaw added fix Pull requests that fix a defect (fix: subject prefix) const Regenerated IANA or vendor constant tables; members keep their numeric values breaking Breaks public-facing behaviour or API (apply alongside the type label) review: pending No verdict for the current head - never reviewed, or the head moved since the last one labels Sep 28, 2026
@JarryShaw

Copy link
Copy Markdown
Owner Author

GOOD TO GO on f4d82cc8d — cross-review (opus; author sonnet). Two words of code, and I re-derived every load-bearing claim rather than taking the report.

The fix is str.__new__(cls, value) in both pcapkit/const/http/method.py and its generator pcapkit/vendor/http/method.py. Measured on the head: all 40 registered members satisfy str(m) == m.value, Method.GET == 'GET' → True, unregistered Method('frob') → str='frob' with __members__ still 40, and Command/FEATCode have zero mismatches.

Generator fidelity proven, not assumed — the #866 failure mode is a const file whose generator still emits the old text. Rendering the committed LINE template with a sentinel in the {ENUM} hole and comparing against the committed const module reconstructs it byte-for-byte, prefix and suffix both identical, with str.__new__(cls, value) present on both sides.

The behaviour surface is wider than the body originally said, so I have updated the body. Beyond the documented == 'GET', four more changes are real and all in the correcting direction: bool(member) flips False → True; json.dumps emits the verb instead of ""; sorted() becomes lexicographic; and a member-keyed dict/set no longer collapses — {m: … for m in Method} has 40 entries where it had 1, because str.__hash__ wins the MRO and all 40 members previously hashed as '' and compared == to each other. Unchanged: repr, .value, pickle, deepcopy, identity (Method('GET') is Method.GET), member count.

No in-repo reliance on the old behaviour — the sole consumer is pcapkit/protocols/application/httpv1.py:272, whose isinstance(method, Enum_Method) branch precedes the str branch and reads .value; its guards are is not None / is None, identity rather than truthiness, so the pre-fix falsiness was never exercised. No dict/set keyed on members, no sorted() of them, no if method: anywhere in httpv1.py/httpv2.py.

Tests genuinely pin it: reverting the two words fails 4 of 6 new methods (82 subTest records); the other two deliberately pin contracts the fix does not touch. The OptionType exemption is justified in the module docstring and backed by its own test. Sweep coverage re-derived by walking pkgutil over 138 pcapkit.const modules: exactly 4 str-valued EnumRegistry subclasses — Command 60, FEATCode 15, Method 40, OptionType 40 — confirming the test's 115 and the sibling survey. 220 methods across tests/const/, 59 in test_http_unit.py, 0 failures.

Left deliberately: a spurious # pylint: disable=singleton-comparison at tests/const/test_const_str_payload_870_unit.py:84 — that checker fires on == True/False/None, not == 'GET'. Harmless, and not worth a revision that would invalidate this verdict.

Separately filed: the regeneration CLI swallows exceptions and still exits 0 — see the new issue linked below. CI on this head: 55 green, 0 failed, 3 still running; I will confirm when they land.

@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 28, 2026
@JarryShaw
JarryShaw merged commit 16879c3 into main Sep 28, 2026
63 checks passed
@JarryShaw
JarryShaw deleted the fix-870-method-str-payload branch September 28, 2026 13:46
@JarryShaw JarryShaw removed the review: good-to-go Cross-review at the current head says ready; CI state is separate label Sep 28, 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) const Regenerated IANA or vendor constant tables; members keep their numeric values fix Pull requests that fix a defect (fix: subject prefix)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Method registered members carry an empty str payload, so Method.GET == GET is False

1 participant