diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f2f9e7f2b..efc6288f20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,10 @@ This is the resolution of #548, which reported `TransType.L2TP` (115) as registe - **Added** -- `tests/protocols/transport/test_tcp_mptcp_join_flag_ordering_unit.py`, covering all three MP_JOIN layouts through the *public* constructor, the construct-pack-parse cycle for each, the stale-flags case that rules out a zero-valued default, the statement order itself, and controls that the parse path and the flag-independent options are unaffected. The gap it closes is why 100% statement and branch coverage of the two changed modules coexisted with a completely broken public path: the pre-existing cases reach `_make_mptcp_join` by assigning a Python `set` to `_flags` on a bare `TCP.__new__(TCP)`, which executes every branch while bypassing both the ordering and the accumulator's type. The now-stale `tcp-mptcp/MP_JOIN` entry is deleted from `EXPECTED_FAILURES`, and the MP_JOIN exclusion in `test_tcp_mptcp_subtype_unit.py` is lifted (#587). - **Fixed** -- `NumberField.pre_process` sized a value with floor division dressed up as a ceiling. When a field is packed while its `length` is still the `-1` placeholder, the width is derived from the value, and it was derived with `math.ceil(value.bit_length() // 8)`. `math.ceil` of an integer is that integer, so the `//` had already floored the quotient and the outer call did nothing at all; the expression was plain floor division and the width came out one octet short. `256` was sized at one octet, `65536` at two, `16777216` at three, and both `int.to_bytes` and `struct.pack` refuse a value that does not fit the width they are given. **The reach is wider than "just past a boundary"**: floor division is wrong for every bit length that is not an exact multiple of eight, so `1` -- bit length 1, floored to *zero* octets -- failed too, and every value from 1 to 127 with it. Now written as the ceiling it was meant to be, matching the `math.ceil(n / 8)` idiom used elsewhere in the package. The repair is reached only by packing a field the caller never resolved, since a schema resolves every field before packing it and `__call__` installs a real width; that narrowness is why the defect survived the suite added for #591, whose five repair-path values -- `0xFF`, `0xFFFF`, `0xFFFFFFFF`, `0xFFFFFFFFFFFFFFFF` and `0x800001` -- have bit lengths of 8, 16, 32, 64 and 24 and so sat exactly where floor division and the ceiling agree. #591's own fix neither caused nor masked this, but it did change what the failure looks like: with `_need_process` now recomputed from the width in force, a mis-sized 1, 2 or 4 octets surfaces from `struct.pack` as `'B' format requires 0 <= number <= 255` where it used to surface from `int.to_bytes` as `OverflowError`, which is why the exception named in the report is no longer the one a mis-sized octet boundary raises. Two things on this path are deliberately left alone, both independent of the arithmetic: a signed field is sized without room for its sign bit, so an unresolved signed field still cannot pack `128`; and an unresolved field's bit mask is `-1`, which makes the masking and the sign remap above no-ops. The identical `math.ceil(x.bit_length() // 8)` expression also survives at the two ILNP nonce option builders in `hopopt.py` and `ipv6_opts.py`, which are a separate change (#599). - **Added** -- `tests/corekit/test_fields_numbers_width_repair.py`, covering each octet boundary in its own method rather than one parametrised sweep, since the defect is a pattern and a single case would pass against a fix that special-cased the reported width. Each boundary is asserted as a pair -- the value below it, which always packed, and the value above it, which did not -- so that a width shifted by one in the other direction fails too. Also swept over all eight boundaries, pinned as the `ceil(bit_length / 8)` invariant, checked for the smallest mis-sized value being `1`, round-tripped through pack and unpack, and given controls for the bit lengths that divide by eight and for the reachability of the repair at all. The suite deliberately asserts widths and octets rather than exception types, because the exception depends on whether the mis-sized width happens to have a native `struct` code (#599). +- **Fixed** -- the string-keyed `get()` in `pcapkit.const.ftp.command` and `pcapkit.const.http.method` tested membership with the raw key but registered `key.upper()`, so the *first* lowercase or mixed-case token raised `TypeError: 'RETR' already in use` rather than resolving. Reachable from wire data for FTP: `pcapkit.protocols.application.ftp` compiles its request pattern with `re.I` and passes the match verbatim, and [RFC 959 Section 5.3](https://datatracker.ietf.org/doc/html/rfc959#section-5.3) makes FTP commands case-insensitive -- "Upper and lower case alphabetic characters are to be treated identically", listing `RETR Retr retr ReTr rETr` as the same command -- so `retr file.txt` was a valid request this library could not parse. Both `get()` and `_missing_` now look the key up under the same canonical upper-case name they register it under, so every casing resolves to the one member that already exists instead of colliding with it. Resolving rather than registering a second member matters beyond not crashing -- a duplicate `GET` would carry neither the `safe` nor the `idempotent` attribute of the real one (#582, #583). +- **Fixed** -- `httpv1`'s `_RE_METHOD` was unanchored and `re.match` anchors only at the start, so it prefix-matched, and the request-line reader then passed the whole `para1` to `Method.get` rather than the captured `method` group. Together those meant `b'Get'` matched on the single character `G`, satisfied the guard that decides a start-line is a request, and handed the entire mixed-case token to a lookup that raised on it. Fixing either half alone still gives a wrong answer -- normalising the lookup would parse `b'Get'` as `GET` off a one-character match, and passing the group would parse it as a method named `G`. The pattern is now anchored at both ends and the captured group is what is looked up, so a token that is not a method is a malformed request line rather than a mis-parsed one. Method tokens are case-sensitive per [RFC 9110 Section 9.1](https://datatracker.ietf.org/doc/html/rfc9110#section-9.1), so no `re.I` was added: `GET` parses, `Get` and `get` are rejected (#583). +- **Fixed** -- `_RE_STATUS` in the same reader carried the same unanchored prefix defect, found by auditing `_RE_METHOD`'s siblings, and it escaped as the wrong exception type. That pattern is only a guard -- the value is taken from `int(para2)` on the raw token -- so a prefix match let a malformed status past the guard and then out of `int()` uncaught, where `_read_http_header` documents `ProtocolError`. Measured: a status of `200x` raised `ValueError: invalid literal for int() with base 10: b'200x'`, and one of `2000` raised `ValueError: 2000 is not a valid StatusCode`; both are now `ProtocolError`. [RFC 9112 Section 4](https://datatracker.ietf.org/doc/html/rfc9112#section-4) gives `status-code = 3DIGIT`, exactly three, so the anchor is what the grammar already said -- the production lives in HTTP/1.1 because `status-code` is part of its `status-line`, while [RFC 9110 Section 15](https://datatracker.ietf.org/doc/html/rfc9110#section-15) covers the code semantics and the IANA registry rather than the syntax. `_RE_VERSION` was audited at the same time and is safe as it stands, because both of its call sites read the captured group rather than the raw token (#583). +- **Fixed** -- `get()`'s documented `default` was ignored on the integer path throughout the generated `pcapkit.const` tree, because `get` delegated the lookup to the enum call and `_missing_` has no access to the caller's `default` -- so `Hardware.get(99999, 0)` raised `ValueError: 99999 is not a valid Hardware` instead of returning the fallback it was handed. The integer path now consults `default` before letting the lookup error escape. `-1`, the placeholder the generated signature already carried, is what separates "no default was supplied" from "a default was supplied and should be used", so a caller that asked for no fallback still gets the error rather than a silent substitution. The sweep #584 asked for puts the scope at 110 of the 118 integer registries, not the three the issue named; the two carrying a bespoke integer fallback of their own, `pcapng` `OptionType` and `reg` `AppType`, are deliberately left alone, since neither drops a default by raising. Not reachable from wire data -- every value a wire field can carry already resolves -- so this is a contract fix rather than a parse fix. Applied to the nine vendor templates as well as the 113 generated modules, and a new test renders the shared template and compares it against the module generated from it, so a regeneration cannot quietly undo it (#584). Preceded by `1.5.0a1` (2026-09-15), `1.5.0b1` and `1.5.0b2` (both 2026-09-18) and `1.5.0b3` (2026-09-19), all published as prereleases and so resolved only by `pip install --pre`. `1.5.0b1` half-shipped: the tag, the GitHub release and the Conda deployments landed, but PyPI rejected the wheel because `twine check` found a Sphinx-only `:mod:` role in `README.rst`, which `pyproject.toml` declares as the dynamic long description. `1.5.0b2` is what reshipped it -- the release workflow is version-driven, so an existing version cannot republish -- and `1.5.0b3` followed the CI change that stops a TestPyPI outage from costing a release its wheels (#497, #498). diff --git a/docs/source/changelog/1.5.0.rst b/docs/source/changelog/1.5.0.rst index 0a24545b83..7c4fd583e6 100644 --- a/docs/source/changelog/1.5.0.rst +++ b/docs/source/changelog/1.5.0.rst @@ -688,6 +688,70 @@ pull requests between #326 and #509. and for the reachability of the repair at all. The suite deliberately asserts widths and octets rather than exception types, because the exception depends on whether the mis-sized width happens to have a native ``struct`` code (#599). +* **Fixed** -- the string-keyed ``get()`` in ``pcapkit.const.ftp.command`` and + ``pcapkit.const.http.method`` tested membership with the raw key but + registered ``key.upper()``, so the *first* lowercase or mixed-case token + raised ``TypeError: 'RETR' already in use`` rather than resolving. Reachable + from wire data for FTP: ``pcapkit.protocols.application.ftp`` compiles its + request pattern with ``re.I`` and passes the match verbatim, and + :rfc:`959#section-5.3` makes FTP commands case-insensitive -- "Upper and lower + case alphabetic characters are to be treated identically", listing + ``RETR Retr retr ReTr rETr`` as the same command -- so ``retr file.txt`` was a + valid request this library could not parse. Both ``get()`` and ``_missing_`` + now look the key up under the same canonical upper-case name they register it + under, so every casing resolves to the one member that already exists instead + of colliding with it. Resolving rather than registering a second member + matters beyond not crashing -- a duplicate ``GET`` would carry neither the + ``safe`` nor the ``idempotent`` attribute of the real one (#582, #583). +* **Fixed** -- ``httpv1``'s ``_RE_METHOD`` was unanchored and ``re.match`` + anchors only at the start, so it prefix-matched, and the request-line reader + then passed the whole ``para1`` to ``Method.get`` rather than the captured + ``method`` group. Together those meant ``b'Get'`` matched on the single + character ``G``, satisfied the guard that decides a start-line is a request, + and handed the entire mixed-case token to a lookup that raised on it. Fixing + either half alone still gives a wrong answer -- normalising the lookup would + parse ``b'Get'`` as ``GET`` off a one-character match, and passing the group + would parse it as a method named ``G``. The pattern is now anchored at both + ends and the captured group is what is looked up, so a token that is not a + method is a malformed request line rather than a mis-parsed one. Method tokens + are case-sensitive per :rfc:`9110#section-9.1`, so no ``re.I`` was added: + ``GET`` parses, ``Get`` and ``get`` are rejected (#583). +* **Fixed** -- ``_RE_STATUS`` in the same reader carried the same unanchored + prefix defect, found by auditing ``_RE_METHOD``'s siblings, and it escaped as + the wrong exception type. That pattern is only a guard -- the value is taken + from ``int(para2)`` on the raw token -- so a prefix match let a malformed + status past the guard and then out of ``int()`` uncaught, where + ``_read_http_header`` documents ``ProtocolError``. Measured: a status of + ``200x`` raised + ``ValueError: invalid literal for int() with base 10: b'200x'``, and one of + ``2000`` raised ``ValueError: 2000 is not a valid StatusCode``; + both are now ``ProtocolError``. + :rfc:`9112#section-4` gives ``status-code = 3DIGIT``, exactly three, so the + anchor is what the grammar already said -- the production lives in HTTP/1.1 + because ``status-code`` is part of its ``status-line``, while + :rfc:`9110#section-15` covers the code semantics and the IANA registry rather + than the syntax. ``_RE_VERSION`` was audited at the same time and is safe as + it stands, because both of its call sites read the captured group rather than + the raw token (#583). +* **Fixed** -- ``get()``'s documented ``default`` was ignored on the integer + path throughout the generated ``pcapkit.const`` tree, because ``get`` + delegated the lookup to the enum call and ``_missing_`` has no access to the + caller's ``default`` -- so ``Hardware.get(99999, 0)`` raised + ``ValueError: 99999 is not a valid Hardware`` instead of returning the + fallback it was handed. The integer path now consults ``default`` before + letting the lookup error escape. ``-1``, the placeholder the generated + signature already carried, is what separates "no default was supplied" from + "a default was supplied and should be used", so a caller that asked for no + fallback still gets the error rather than a silent substitution. The sweep + #584 asked for puts the scope at 110 of the 118 integer registries, not the + three the issue named; the two carrying a bespoke integer fallback of their + own, ``pcapng`` ``OptionType`` and ``reg`` ``AppType``, are deliberately left + alone, since neither drops a default by raising. Not reachable from wire data + -- every value a wire field can carry already resolves -- so this is a + contract fix rather than a parse fix. Applied to the nine vendor templates as + well as the 113 generated modules, and a new test renders the shared template + and compares it against the module generated from it, so a regeneration + cannot quietly undo it (#584). Preceded by ``1.5.0a1`` (2026-09-15), ``1.5.0b1`` and ``1.5.0b2`` (both 2026-09-18) and ``1.5.0b3`` (2026-09-19), all published as prereleases and so diff --git a/pcapkit/const/arp/hardware.py b/pcapkit/const/arp/hardware.py index 813a498391..eb65bcdc9c 100644 --- a/pcapkit/const/arp/hardware.py +++ b/pcapkit/const/arp/hardware.py @@ -152,12 +152,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Hardware': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Hardware(key) + try: + return Hardware(key) + except ValueError: + if default == -1: + raise + return Hardware(default) if key not in Hardware._member_map_: # pylint: disable=no-member return extend_enum(Hardware, key, default) return Hardware[key] # type: ignore[misc] diff --git a/pcapkit/const/arp/operation.py b/pcapkit/const/arp/operation.py index 9b181d44e5..be4b7caffe 100644 --- a/pcapkit/const/arp/operation.py +++ b/pcapkit/const/arp/operation.py @@ -105,12 +105,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Operation': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Operation(key) + try: + return Operation(key) + except ValueError: + if default == -1: + raise + return Operation(default) if key not in Operation._member_map_: # pylint: disable=no-member return extend_enum(Operation, key, default) return Operation[key] # type: ignore[misc] diff --git a/pcapkit/const/esp/cipher.py b/pcapkit/const/esp/cipher.py index 779b561e90..9c5ea0315c 100644 --- a/pcapkit/const/esp/cipher.py +++ b/pcapkit/const/esp/cipher.py @@ -222,12 +222,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Cipher': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Cipher(key) + try: + return Cipher(key) + except ValueError: + if default == -1: + raise + return Cipher(default) if key not in Cipher._member_map_: # pylint: disable=no-member return extend_enum(Cipher, key, default) return Cipher[key] # type: ignore[misc] diff --git a/pcapkit/const/esp/integrity.py b/pcapkit/const/esp/integrity.py index 7d5101d542..7e2a4cee76 100644 --- a/pcapkit/const/esp/integrity.py +++ b/pcapkit/const/esp/integrity.py @@ -111,12 +111,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Integrity': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Integrity(key) + try: + return Integrity(key) + except ValueError: + if default == -1: + raise + return Integrity(default) if key not in Integrity._member_map_: # pylint: disable=no-member return extend_enum(Integrity, key, default) return Integrity[key] # type: ignore[misc] diff --git a/pcapkit/const/ftp/command.py b/pcapkit/const/ftp/command.py index ffb9ad7f0d..8f53e56a08 100644 --- a/pcapkit/const/ftp/command.py +++ b/pcapkit/const/ftp/command.py @@ -289,21 +289,27 @@ def get(key: 'str', default: 'Optional[str]' = None) -> 'Command': """Backport support for original codes. Args: - key: Key to get enum item. + key: Key to get enum item. Looked up case-insensitively, since + member names are canonicalised to upper case on registration. default: Default value if not found. :meta private: """ - if key not in Command._member_map_: # pylint: disable=no-member - return extend_enum(Command, key.upper(), default if default is not None else key) - return Command[key] # type: ignore[misc] + name = key.upper() + if name not in Command._member_map_: # pylint: disable=no-member + return extend_enum(Command, name, default if default is not None else key) + return Command[name] # type: ignore[misc] @classmethod def _missing_(cls, value: 'str') -> 'Command': """Lookup function used when value is not found. Args: - value: Value to get enum item. + value: Value to get enum item. Matched case-insensitively against + the canonical upper-case member names. """ - return extend_enum(cls, value.upper(), value) + name = value.upper() + if name in cls._member_map_: + return cls._member_map_[name] # type: ignore[return-value] + return extend_enum(cls, name, value) diff --git a/pcapkit/const/ftp/return_code.py b/pcapkit/const/ftp/return_code.py index 453af8146b..d140014d82 100644 --- a/pcapkit/const/ftp/return_code.py +++ b/pcapkit/const/ftp/return_code.py @@ -286,12 +286,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ReturnCode': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ReturnCode(key) + try: + return ReturnCode(key) + except ValueError: + if default == -1: + raise + return ReturnCode(default) if key not in ReturnCode._member_map_: # pylint: disable=no-member return extend_enum(ReturnCode, key, default) return ReturnCode[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/certificate.py b/pcapkit/const/hip/certificate.py index 6ea9168636..e1df1f2fb5 100644 --- a/pcapkit/const/hip/certificate.py +++ b/pcapkit/const/hip/certificate.py @@ -51,12 +51,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Certificate': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Certificate(key) + try: + return Certificate(key) + except ValueError: + if default == -1: + raise + return Certificate(default) if key not in Certificate._member_map_: # pylint: disable=no-member return extend_enum(Certificate, key, default) return Certificate[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/cipher.py b/pcapkit/const/hip/cipher.py index ac36128fb6..018e7a7079 100644 --- a/pcapkit/const/hip/cipher.py +++ b/pcapkit/const/hip/cipher.py @@ -39,12 +39,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Cipher': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Cipher(key) + try: + return Cipher(key) + except ValueError: + if default == -1: + raise + return Cipher(default) if key not in Cipher._member_map_: # pylint: disable=no-member return extend_enum(Cipher, key, default) return Cipher[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/di.py b/pcapkit/const/hip/di.py index c651d6f28f..875441e5e1 100644 --- a/pcapkit/const/hip/di.py +++ b/pcapkit/const/hip/di.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'DITypes': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return DITypes(key) + try: + return DITypes(key) + except ValueError: + if default == -1: + raise + return DITypes(default) if key not in DITypes._member_map_: # pylint: disable=no-member return extend_enum(DITypes, key, default) return DITypes[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/ecdsa_curve.py b/pcapkit/const/hip/ecdsa_curve.py index 7a953541db..90bf93b480 100644 --- a/pcapkit/const/hip/ecdsa_curve.py +++ b/pcapkit/const/hip/ecdsa_curve.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ECDSACurve': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ECDSACurve(key) + try: + return ECDSACurve(key) + except ValueError: + if default == -1: + raise + return ECDSACurve(default) if key not in ECDSACurve._member_map_: # pylint: disable=no-member return extend_enum(ECDSACurve, key, default) return ECDSACurve[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/ecdsa_low_curve.py b/pcapkit/const/hip/ecdsa_low_curve.py index 16c29f7262..55183d806c 100644 --- a/pcapkit/const/hip/ecdsa_low_curve.py +++ b/pcapkit/const/hip/ecdsa_low_curve.py @@ -30,12 +30,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ECDSALowCurve': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ECDSALowCurve(key) + try: + return ECDSALowCurve(key) + except ValueError: + if default == -1: + raise + return ECDSALowCurve(default) if key not in ECDSALowCurve._member_map_: # pylint: disable=no-member return extend_enum(ECDSALowCurve, key, default) return ECDSALowCurve[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/eddsa_curve.py b/pcapkit/const/hip/eddsa_curve.py index d3174ff8cb..569af9503a 100644 --- a/pcapkit/const/hip/eddsa_curve.py +++ b/pcapkit/const/hip/eddsa_curve.py @@ -39,12 +39,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'EdDSACurve': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return EdDSACurve(key) + try: + return EdDSACurve(key) + except ValueError: + if default == -1: + raise + return EdDSACurve(default) if key not in EdDSACurve._member_map_: # pylint: disable=no-member return extend_enum(EdDSACurve, key, default) return EdDSACurve[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/esp_transform_suite.py b/pcapkit/const/hip/esp_transform_suite.py index e9782ce8c4..040108b7ff 100644 --- a/pcapkit/const/hip/esp_transform_suite.py +++ b/pcapkit/const/hip/esp_transform_suite.py @@ -72,12 +72,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ESPTransformSuite': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ESPTransformSuite(key) + try: + return ESPTransformSuite(key) + except ValueError: + if default == -1: + raise + return ESPTransformSuite(default) if key not in ESPTransformSuite._member_map_: # pylint: disable=no-member return extend_enum(ESPTransformSuite, key, default) return ESPTransformSuite[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/group.py b/pcapkit/const/hip/group.py index 4d7a52c20a..e769b044d8 100644 --- a/pcapkit/const/hip/group.py +++ b/pcapkit/const/hip/group.py @@ -60,12 +60,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Group': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Group(key) + try: + return Group(key) + except ValueError: + if default == -1: + raise + return Group(default) if key not in Group._member_map_: # pylint: disable=no-member return extend_enum(Group, key, default) return Group[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/hi_algorithm.py b/pcapkit/const/hip/hi_algorithm.py index 0e61333f56..dc7f342cbb 100644 --- a/pcapkit/const/hip/hi_algorithm.py +++ b/pcapkit/const/hip/hi_algorithm.py @@ -57,12 +57,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'HIAlgorithm': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return HIAlgorithm(key) + try: + return HIAlgorithm(key) + except ValueError: + if default == -1: + raise + return HIAlgorithm(default) if key not in HIAlgorithm._member_map_: # pylint: disable=no-member return extend_enum(HIAlgorithm, key, default) return HIAlgorithm[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/hit_suite.py b/pcapkit/const/hip/hit_suite.py index a7e75494f9..eac9ca362b 100644 --- a/pcapkit/const/hip/hit_suite.py +++ b/pcapkit/const/hip/hit_suite.py @@ -42,12 +42,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'HITSuite': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return HITSuite(key) + try: + return HITSuite(key) + except ValueError: + if default == -1: + raise + return HITSuite(default) if key not in HITSuite._member_map_: # pylint: disable=no-member return extend_enum(HITSuite, key, default) return HITSuite[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/nat_traversal.py b/pcapkit/const/hip/nat_traversal.py index 62350e1cbc..2edb6e7e2c 100644 --- a/pcapkit/const/hip/nat_traversal.py +++ b/pcapkit/const/hip/nat_traversal.py @@ -36,12 +36,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'NATTraversal': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return NATTraversal(key) + try: + return NATTraversal(key) + except ValueError: + if default == -1: + raise + return NATTraversal(default) if key not in NATTraversal._member_map_: # pylint: disable=no-member return extend_enum(NATTraversal, key, default) return NATTraversal[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/notify_message.py b/pcapkit/const/hip/notify_message.py index 88f8894efb..884cafaf57 100644 --- a/pcapkit/const/hip/notify_message.py +++ b/pcapkit/const/hip/notify_message.py @@ -138,12 +138,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'NotifyMessage': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return NotifyMessage(key) + try: + return NotifyMessage(key) + except ValueError: + if default == -1: + raise + return NotifyMessage(default) if key not in NotifyMessage._member_map_: # pylint: disable=no-member return extend_enum(NotifyMessage, key, default) return NotifyMessage[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/packet.py b/pcapkit/const/hip/packet.py index 620d829cfb..518a72dd11 100644 --- a/pcapkit/const/hip/packet.py +++ b/pcapkit/const/hip/packet.py @@ -57,12 +57,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Packet': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Packet(key) + try: + return Packet(key) + except ValueError: + if default == -1: + raise + return Packet(default) if key not in Packet._member_map_: # pylint: disable=no-member return extend_enum(Packet, key, default) return Packet[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/parameter.py b/pcapkit/const/hip/parameter.py index d7f7b647b3..0e52d098c8 100644 --- a/pcapkit/const/hip/parameter.py +++ b/pcapkit/const/hip/parameter.py @@ -210,12 +210,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Parameter': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Parameter(key) + try: + return Parameter(key) + except ValueError: + if default == -1: + raise + return Parameter(default) if key not in Parameter._member_map_: # pylint: disable=no-member return extend_enum(Parameter, key, default) return Parameter[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/registration.py b/pcapkit/const/hip/registration.py index 85f77d2db3..0f6246b14a 100644 --- a/pcapkit/const/hip/registration.py +++ b/pcapkit/const/hip/registration.py @@ -39,12 +39,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Registration': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Registration(key) + try: + return Registration(key) + except ValueError: + if default == -1: + raise + return Registration(default) if key not in Registration._member_map_: # pylint: disable=no-member return extend_enum(Registration, key, default) return Registration[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/registration_failure.py b/pcapkit/const/hip/registration_failure.py index b2bdad9582..cc3c8058e6 100644 --- a/pcapkit/const/hip/registration_failure.py +++ b/pcapkit/const/hip/registration_failure.py @@ -55,12 +55,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'RegistrationFailure': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return RegistrationFailure(key) + try: + return RegistrationFailure(key) + except ValueError: + if default == -1: + raise + return RegistrationFailure(default) if key not in RegistrationFailure._member_map_: # pylint: disable=no-member return extend_enum(RegistrationFailure, key, default) return RegistrationFailure[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/suite.py b/pcapkit/const/hip/suite.py index fbcd64fa54..1cd457f0c8 100644 --- a/pcapkit/const/hip/suite.py +++ b/pcapkit/const/hip/suite.py @@ -45,12 +45,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Suite': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Suite(key) + try: + return Suite(key) + except ValueError: + if default == -1: + raise + return Suite(default) if key not in Suite._member_map_: # pylint: disable=no-member return extend_enum(Suite, key, default) return Suite[key] # type: ignore[misc] diff --git a/pcapkit/const/hip/transport.py b/pcapkit/const/hip/transport.py index d5955d86de..751bf24e27 100644 --- a/pcapkit/const/hip/transport.py +++ b/pcapkit/const/hip/transport.py @@ -36,12 +36,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Transport': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Transport(key) + try: + return Transport(key) + except ValueError: + if default == -1: + raise + return Transport(default) if key not in Transport._member_map_: # pylint: disable=no-member return extend_enum(Transport, key, default) return Transport[key] # type: ignore[misc] diff --git a/pcapkit/const/http/error_code.py b/pcapkit/const/http/error_code.py index 2de2ca5bea..c05fd19e51 100644 --- a/pcapkit/const/http/error_code.py +++ b/pcapkit/const/http/error_code.py @@ -68,12 +68,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ErrorCode': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ErrorCode(key) + try: + return ErrorCode(key) + except ValueError: + if default == -1: + raise + return ErrorCode(default) if key not in ErrorCode._member_map_: # pylint: disable=no-member return extend_enum(ErrorCode, key, default) return ErrorCode[key] # type: ignore[misc] diff --git a/pcapkit/const/http/frame.py b/pcapkit/const/http/frame.py index 4ab1c6059e..73453d1d58 100644 --- a/pcapkit/const/http/frame.py +++ b/pcapkit/const/http/frame.py @@ -66,12 +66,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Frame': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Frame(key) + try: + return Frame(key) + except ValueError: + if default == -1: + raise + return Frame(default) if key not in Frame._member_map_: # pylint: disable=no-member return extend_enum(Frame, key, default) return Frame[key] # type: ignore[misc] diff --git a/pcapkit/const/http/method.py b/pcapkit/const/http/method.py index 2291e74922..9b3f27c859 100644 --- a/pcapkit/const/http/method.py +++ b/pcapkit/const/http/method.py @@ -167,21 +167,27 @@ def get(key: 'str', default: 'Optional[str]' = None) -> 'Method': """Backport support for original codes. Args: - key: Key to get enum item. + key: Key to get enum item. Looked up case-insensitively, since + member names are canonicalised to upper case on registration. default: Default value if not found. :meta private: """ - if key not in Method._member_map_: # pylint: disable=no-member - return extend_enum(Method, key.upper(), default if default is not None else key) - return Method[key] # type: ignore[misc] + name = key.upper() + if name not in Method._member_map_: # pylint: disable=no-member + return extend_enum(Method, name, default if default is not None else key) + return Method[name] # type: ignore[misc] @classmethod def _missing_(cls, value: 'str') -> 'Method': """Lookup function used when value is not found. Args: - value: Value to get enum item. + value: Value to get enum item. Matched case-insensitively against + the canonical upper-case member names. """ - return extend_enum(cls, value.upper(), value) + name = value.upper() + if name in cls._member_map_: + return cls._member_map_[name] # type: ignore[return-value] + return extend_enum(cls, name, value) diff --git a/pcapkit/const/http/setting.py b/pcapkit/const/http/setting.py index 61c7f10c1e..96344fe936 100644 --- a/pcapkit/const/http/setting.py +++ b/pcapkit/const/http/setting.py @@ -64,12 +64,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Setting': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Setting(key) + try: + return Setting(key) + except ValueError: + if default == -1: + raise + return Setting(default) if key not in Setting._member_map_: # pylint: disable=no-member return extend_enum(Setting, key, default) return Setting[key] # type: ignore[misc] diff --git a/pcapkit/const/http/status_code.py b/pcapkit/const/http/status_code.py index 5371831858..9a50ac8fa8 100644 --- a/pcapkit/const/http/status_code.py +++ b/pcapkit/const/http/status_code.py @@ -252,12 +252,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'StatusCode': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return StatusCode(key) + try: + return StatusCode(key) + except ValueError: + if default == -1: + raise + return StatusCode(default) if key not in StatusCode._member_map_: # pylint: disable=no-member extend_enum(StatusCode, key, default) return StatusCode[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv4/classification_level.py b/pcapkit/const/ipv4/classification_level.py index 163e9948eb..07965a36cb 100644 --- a/pcapkit/const/ipv4/classification_level.py +++ b/pcapkit/const/ipv4/classification_level.py @@ -40,12 +40,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ClassificationLevel': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ClassificationLevel(key) + try: + return ClassificationLevel(key) + except ValueError: + if default == -1: + raise + return ClassificationLevel(default) if key not in ClassificationLevel._member_map_: # pylint: disable=no-member return extend_enum(ClassificationLevel, key, default) return ClassificationLevel[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv4/option_class.py b/pcapkit/const/ipv4/option_class.py index 591f7d797a..02be2b06c4 100644 --- a/pcapkit/const/ipv4/option_class.py +++ b/pcapkit/const/ipv4/option_class.py @@ -32,12 +32,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'OptionClass': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return OptionClass(key) + try: + return OptionClass(key) + except ValueError: + if default == -1: + raise + return OptionClass(default) if key not in OptionClass._member_map_: # pylint: disable=no-member return extend_enum(OptionClass, key, default) return OptionClass[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv4/option_number.py b/pcapkit/const/ipv4/option_number.py index f67a9cdae5..f5130a161f 100644 --- a/pcapkit/const/ipv4/option_number.py +++ b/pcapkit/const/ipv4/option_number.py @@ -114,12 +114,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'OptionNumber': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return OptionNumber(key) + try: + return OptionNumber(key) + except ValueError: + if default == -1: + raise + return OptionNumber(default) if key not in OptionNumber._member_map_: # pylint: disable=no-member return extend_enum(OptionNumber, key, default) return OptionNumber[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv4/protection_authority.py b/pcapkit/const/ipv4/protection_authority.py index d5c2848524..31bf47da3e 100644 --- a/pcapkit/const/ipv4/protection_authority.py +++ b/pcapkit/const/ipv4/protection_authority.py @@ -40,12 +40,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ProtectionAuthority': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ProtectionAuthority(key) + try: + return ProtectionAuthority(key) + except ValueError: + if default == -1: + raise + return ProtectionAuthority(default) if key not in ProtectionAuthority._member_map_: # pylint: disable=no-member return extend_enum(ProtectionAuthority, key, default) return ProtectionAuthority[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv4/qs_function.py b/pcapkit/const/ipv4/qs_function.py index d2de05f434..66ddbc4cc4 100644 --- a/pcapkit/const/ipv4/qs_function.py +++ b/pcapkit/const/ipv4/qs_function.py @@ -28,12 +28,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'QSFunction': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return QSFunction(key) + try: + return QSFunction(key) + except ValueError: + if default == -1: + raise + return QSFunction(default) if key not in QSFunction._member_map_: # pylint: disable=no-member return extend_enum(QSFunction, key, default) return QSFunction[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv4/router_alert.py b/pcapkit/const/ipv4/router_alert.py index 4376120e8b..78af61a5f4 100644 --- a/pcapkit/const/ipv4/router_alert.py +++ b/pcapkit/const/ipv4/router_alert.py @@ -225,12 +225,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'RouterAlert': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return RouterAlert(key) + try: + return RouterAlert(key) + except ValueError: + if default == -1: + raise + return RouterAlert(default) if key not in RouterAlert._member_map_: # pylint: disable=no-member return extend_enum(RouterAlert, key, default) return RouterAlert[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv4/tos_del.py b/pcapkit/const/ipv4/tos_del.py index 27c06a83ec..e2ad4ed47d 100644 --- a/pcapkit/const/ipv4/tos_del.py +++ b/pcapkit/const/ipv4/tos_del.py @@ -28,12 +28,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ToSDelay': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ToSDelay(key) + try: + return ToSDelay(key) + except ValueError: + if default == -1: + raise + return ToSDelay(default) if key not in ToSDelay._member_map_: # pylint: disable=no-member return extend_enum(ToSDelay, key, default) return ToSDelay[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv4/tos_ecn.py b/pcapkit/const/ipv4/tos_ecn.py index 562d0bea0f..78ad77181c 100644 --- a/pcapkit/const/ipv4/tos_ecn.py +++ b/pcapkit/const/ipv4/tos_ecn.py @@ -32,12 +32,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ToSECN': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ToSECN(key) + try: + return ToSECN(key) + except ValueError: + if default == -1: + raise + return ToSECN(default) if key not in ToSECN._member_map_: # pylint: disable=no-member return extend_enum(ToSECN, key, default) return ToSECN[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv4/tos_pre.py b/pcapkit/const/ipv4/tos_pre.py index b0d3581495..dc60da648c 100644 --- a/pcapkit/const/ipv4/tos_pre.py +++ b/pcapkit/const/ipv4/tos_pre.py @@ -40,12 +40,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ToSPrecedence': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ToSPrecedence(key) + try: + return ToSPrecedence(key) + except ValueError: + if default == -1: + raise + return ToSPrecedence(default) if key not in ToSPrecedence._member_map_: # pylint: disable=no-member return extend_enum(ToSPrecedence, key, default) return ToSPrecedence[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv4/tos_rel.py b/pcapkit/const/ipv4/tos_rel.py index 49b7074100..2340f14756 100644 --- a/pcapkit/const/ipv4/tos_rel.py +++ b/pcapkit/const/ipv4/tos_rel.py @@ -28,12 +28,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ToSReliability': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ToSReliability(key) + try: + return ToSReliability(key) + except ValueError: + if default == -1: + raise + return ToSReliability(default) if key not in ToSReliability._member_map_: # pylint: disable=no-member return extend_enum(ToSReliability, key, default) return ToSReliability[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv4/tos_thr.py b/pcapkit/const/ipv4/tos_thr.py index 7b0e5e96f2..127d3e8b68 100644 --- a/pcapkit/const/ipv4/tos_thr.py +++ b/pcapkit/const/ipv4/tos_thr.py @@ -28,12 +28,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ToSThroughput': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ToSThroughput(key) + try: + return ToSThroughput(key) + except ValueError: + if default == -1: + raise + return ToSThroughput(default) if key not in ToSThroughput._member_map_: # pylint: disable=no-member return extend_enum(ToSThroughput, key, default) return ToSThroughput[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv4/ts_flag.py b/pcapkit/const/ipv4/ts_flag.py index 29c18452f5..2fe1a2a101 100644 --- a/pcapkit/const/ipv4/ts_flag.py +++ b/pcapkit/const/ipv4/ts_flag.py @@ -30,12 +30,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'TSFlag': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return TSFlag(key) + try: + return TSFlag(key) + except ValueError: + if default == -1: + raise + return TSFlag(default) if key not in TSFlag._member_map_: # pylint: disable=no-member return extend_enum(TSFlag, key, default) return TSFlag[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv6/extension_header.py b/pcapkit/const/ipv6/extension_header.py index 34c2d7d162..c1bf2786c0 100644 --- a/pcapkit/const/ipv6/extension_header.py +++ b/pcapkit/const/ipv6/extension_header.py @@ -60,10 +60,17 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ExtensionHeader': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ExtensionHeader(key) + try: + return ExtensionHeader(key) + except ValueError: + if default == -1: + raise + return ExtensionHeader(default) return ExtensionHeader[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv6/option.py b/pcapkit/const/ipv6/option.py index 66b84c43b7..839533166c 100644 --- a/pcapkit/const/ipv6/option.py +++ b/pcapkit/const/ipv6/option.py @@ -114,12 +114,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Option': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Option(key) + try: + return Option(key) + except ValueError: + if default == -1: + raise + return Option(default) if key not in Option._member_map_: # pylint: disable=no-member return extend_enum(Option, key, default) return Option[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv6/option_action.py b/pcapkit/const/ipv6/option_action.py index c4821e17da..13a169111c 100644 --- a/pcapkit/const/ipv6/option_action.py +++ b/pcapkit/const/ipv6/option_action.py @@ -32,12 +32,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'OptionAction': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return OptionAction(key) + try: + return OptionAction(key) + except ValueError: + if default == -1: + raise + return OptionAction(default) if key not in OptionAction._member_map_: # pylint: disable=no-member return extend_enum(OptionAction, key, default) return OptionAction[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv6/qs_function.py b/pcapkit/const/ipv6/qs_function.py index bcc5cf8632..faa1057e13 100644 --- a/pcapkit/const/ipv6/qs_function.py +++ b/pcapkit/const/ipv6/qs_function.py @@ -28,12 +28,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'QSFunction': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return QSFunction(key) + try: + return QSFunction(key) + except ValueError: + if default == -1: + raise + return QSFunction(default) if key not in QSFunction._member_map_: # pylint: disable=no-member return extend_enum(QSFunction, key, default) return QSFunction[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv6/router_alert.py b/pcapkit/const/ipv6/router_alert.py index 8820e4338c..cbbfa0403e 100644 --- a/pcapkit/const/ipv6/router_alert.py +++ b/pcapkit/const/ipv6/router_alert.py @@ -237,12 +237,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'RouterAlert': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return RouterAlert(key) + try: + return RouterAlert(key) + except ValueError: + if default == -1: + raise + return RouterAlert(default) if key not in RouterAlert._member_map_: # pylint: disable=no-member return extend_enum(RouterAlert, key, default) return RouterAlert[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv6/routing.py b/pcapkit/const/ipv6/routing.py index eb75f3968c..8b25e740bc 100644 --- a/pcapkit/const/ipv6/routing.py +++ b/pcapkit/const/ipv6/routing.py @@ -54,12 +54,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Routing': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Routing(key) + try: + return Routing(key) + except ValueError: + if default == -1: + raise + return Routing(default) if key not in Routing._member_map_: # pylint: disable=no-member return extend_enum(Routing, key, default) return Routing[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv6/seed_id.py b/pcapkit/const/ipv6/seed_id.py index 512674f1c5..678d620380 100644 --- a/pcapkit/const/ipv6/seed_id.py +++ b/pcapkit/const/ipv6/seed_id.py @@ -32,12 +32,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'SeedID': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return SeedID(key) + try: + return SeedID(key) + except ValueError: + if default == -1: + raise + return SeedID(default) if key not in SeedID._member_map_: # pylint: disable=no-member return extend_enum(SeedID, key, default) return SeedID[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv6/smf_dpd_mode.py b/pcapkit/const/ipv6/smf_dpd_mode.py index 2082414261..cfc7544151 100644 --- a/pcapkit/const/ipv6/smf_dpd_mode.py +++ b/pcapkit/const/ipv6/smf_dpd_mode.py @@ -28,12 +28,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'SMFDPDMode': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return SMFDPDMode(key) + try: + return SMFDPDMode(key) + except ValueError: + if default == -1: + raise + return SMFDPDMode(default) if key not in SMFDPDMode._member_map_: # pylint: disable=no-member return extend_enum(SMFDPDMode, key, default) return SMFDPDMode[key] # type: ignore[misc] diff --git a/pcapkit/const/ipv6/tagger_id.py b/pcapkit/const/ipv6/tagger_id.py index 062c9c6e88..3ab9033bb5 100644 --- a/pcapkit/const/ipv6/tagger_id.py +++ b/pcapkit/const/ipv6/tagger_id.py @@ -36,12 +36,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'TaggerID': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return TaggerID(key) + try: + return TaggerID(key) + except ValueError: + if default == -1: + raise + return TaggerID(default) if key not in TaggerID._member_map_: # pylint: disable=no-member return extend_enum(TaggerID, key, default) return TaggerID[key] # type: ignore[misc] diff --git a/pcapkit/const/ipx/packet.py b/pcapkit/const/ipx/packet.py index f8e04fbae3..3241f033a1 100644 --- a/pcapkit/const/ipx/packet.py +++ b/pcapkit/const/ipx/packet.py @@ -49,12 +49,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Packet': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Packet(key) + try: + return Packet(key) + except ValueError: + if default == -1: + raise + return Packet(default) if key not in Packet._member_map_: # pylint: disable=no-member return extend_enum(Packet, key, default) return Packet[key] # type: ignore[misc] diff --git a/pcapkit/const/ipx/socket.py b/pcapkit/const/ipx/socket.py index 45ab895e71..0f9c4a0b42 100644 --- a/pcapkit/const/ipx/socket.py +++ b/pcapkit/const/ipx/socket.py @@ -69,12 +69,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Socket': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Socket(key) + try: + return Socket(key) + except ValueError: + if default == -1: + raise + return Socket(default) if key not in Socket._member_map_: # pylint: disable=no-member return extend_enum(Socket, key, default) return Socket[key] # type: ignore[misc] diff --git a/pcapkit/const/l2tp/type.py b/pcapkit/const/l2tp/type.py index a58fd0f981..9711a69729 100644 --- a/pcapkit/const/l2tp/type.py +++ b/pcapkit/const/l2tp/type.py @@ -28,12 +28,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Type': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Type(key) + try: + return Type(key) + except ValueError: + if default == -1: + raise + return Type(default) if key not in Type._member_map_: # pylint: disable=no-member return extend_enum(Type, key, default) return Type[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/access_type.py b/pcapkit/const/mh/access_type.py index acfc16e557..2a5eb279aa 100644 --- a/pcapkit/const/mh/access_type.py +++ b/pcapkit/const/mh/access_type.py @@ -66,12 +66,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'AccessType': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return AccessType(key) + try: + return AccessType(key) + except ValueError: + if default == -1: + raise + return AccessType(default) if key not in AccessType._member_map_: # pylint: disable=no-member return extend_enum(AccessType, key, default) return AccessType[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/ack_status_code.py b/pcapkit/const/mh/ack_status_code.py index 99ce88577c..bbacbbfb43 100644 --- a/pcapkit/const/mh/ack_status_code.py +++ b/pcapkit/const/mh/ack_status_code.py @@ -42,12 +42,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ACKStatusCode': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ACKStatusCode(key) + try: + return ACKStatusCode(key) + except ValueError: + if default == -1: + raise + return ACKStatusCode(default) if key not in ACKStatusCode._member_map_: # pylint: disable=no-member return extend_enum(ACKStatusCode, key, default) return ACKStatusCode[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/ani_suboption.py b/pcapkit/const/mh/ani_suboption.py index 9acdef4d44..56c3f2aba1 100644 --- a/pcapkit/const/mh/ani_suboption.py +++ b/pcapkit/const/mh/ani_suboption.py @@ -48,12 +48,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'ANISuboption': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return ANISuboption(key) + try: + return ANISuboption(key) + except ValueError: + if default == -1: + raise + return ANISuboption(default) if key not in ANISuboption._member_map_: # pylint: disable=no-member return extend_enum(ANISuboption, key, default) return ANISuboption[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/auth_subtype.py b/pcapkit/const/mh/auth_subtype.py index 18fdad0add..139fc72e3b 100644 --- a/pcapkit/const/mh/auth_subtype.py +++ b/pcapkit/const/mh/auth_subtype.py @@ -30,12 +30,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'AuthSubtype': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return AuthSubtype(key) + try: + return AuthSubtype(key) + except ValueError: + if default == -1: + raise + return AuthSubtype(default) if key not in AuthSubtype._member_map_: # pylint: disable=no-member return extend_enum(AuthSubtype, key, default) return AuthSubtype[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/binding_ack_flag.py b/pcapkit/const/mh/binding_ack_flag.py index 923b3b76eb..4cac255962 100644 --- a/pcapkit/const/mh/binding_ack_flag.py +++ b/pcapkit/const/mh/binding_ack_flag.py @@ -45,12 +45,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'BindingACKFlag': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return BindingACKFlag(key) + try: + return BindingACKFlag(key) + except ValueError: + if default == -1: + raise + return BindingACKFlag(default) return BindingACKFlag[key] # type: ignore[misc] @classmethod diff --git a/pcapkit/const/mh/binding_error.py b/pcapkit/const/mh/binding_error.py index 43394863e5..62d3c18b7e 100644 --- a/pcapkit/const/mh/binding_error.py +++ b/pcapkit/const/mh/binding_error.py @@ -28,12 +28,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'BindingError': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return BindingError(key) + try: + return BindingError(key) + except ValueError: + if default == -1: + raise + return BindingError(default) if key not in BindingError._member_map_: # pylint: disable=no-member return extend_enum(BindingError, key, default) return BindingError[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/binding_revocation.py b/pcapkit/const/mh/binding_revocation.py index 7545399509..aebe3daf86 100644 --- a/pcapkit/const/mh/binding_revocation.py +++ b/pcapkit/const/mh/binding_revocation.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'BindingRevocation': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return BindingRevocation(key) + try: + return BindingRevocation(key) + except ValueError: + if default == -1: + raise + return BindingRevocation(default) if key not in BindingRevocation._member_map_: # pylint: disable=no-member return extend_enum(BindingRevocation, key, default) return BindingRevocation[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/binding_update_flag.py b/pcapkit/const/mh/binding_update_flag.py index 4ec9d8444c..dd635f98cb 100644 --- a/pcapkit/const/mh/binding_update_flag.py +++ b/pcapkit/const/mh/binding_update_flag.py @@ -60,12 +60,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'BindingUpdateFlag': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return BindingUpdateFlag(key) + try: + return BindingUpdateFlag(key) + except ValueError: + if default == -1: + raise + return BindingUpdateFlag(default) return BindingUpdateFlag[key] # type: ignore[misc] @classmethod diff --git a/pcapkit/const/mh/cga_extension.py b/pcapkit/const/mh/cga_extension.py index f4590e5879..3c65a86ddd 100644 --- a/pcapkit/const/mh/cga_extension.py +++ b/pcapkit/const/mh/cga_extension.py @@ -36,12 +36,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'CGAExtension': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return CGAExtension(key) + try: + return CGAExtension(key) + except ValueError: + if default == -1: + raise + return CGAExtension(default) if key not in CGAExtension._member_map_: # pylint: disable=no-member return extend_enum(CGAExtension, key, default) return CGAExtension[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/cga_sec.py b/pcapkit/const/mh/cga_sec.py index 5a5acc49b8..49da223ede 100644 --- a/pcapkit/const/mh/cga_sec.py +++ b/pcapkit/const/mh/cga_sec.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'CGASec': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return CGASec(key) + try: + return CGASec(key) + except ValueError: + if default == -1: + raise + return CGASec(default) if key not in CGASec._member_map_: # pylint: disable=no-member return extend_enum(CGASec, key, default) return CGASec[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/cga_type.py b/pcapkit/const/mh/cga_type.py index 981092154b..325d3ecbef 100644 --- a/pcapkit/const/mh/cga_type.py +++ b/pcapkit/const/mh/cga_type.py @@ -45,12 +45,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'CGAType': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return CGAType(key) + try: + return CGAType(key) + except ValueError: + if default == -1: + raise + return CGAType(default) if key not in CGAType._member_map_: # pylint: disable=no-member return extend_enum(CGAType, key, default) return CGAType[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/dhcp_support_mode.py b/pcapkit/const/mh/dhcp_support_mode.py index d782db9f29..25830e90e4 100644 --- a/pcapkit/const/mh/dhcp_support_mode.py +++ b/pcapkit/const/mh/dhcp_support_mode.py @@ -30,12 +30,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'DHCPSupportMode': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return DHCPSupportMode(key) + try: + return DHCPSupportMode(key) + except ValueError: + if default == -1: + raise + return DHCPSupportMode(default) if key not in DHCPSupportMode._member_map_: # pylint: disable=no-member return extend_enum(DHCPSupportMode, key, default) return DHCPSupportMode[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/dns_status_code.py b/pcapkit/const/mh/dns_status_code.py index daa3daf76e..3fa81aaa7d 100644 --- a/pcapkit/const/mh/dns_status_code.py +++ b/pcapkit/const/mh/dns_status_code.py @@ -36,12 +36,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'DNSStatusCode': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return DNSStatusCode(key) + try: + return DNSStatusCode(key) + except ValueError: + if default == -1: + raise + return DNSStatusCode(default) if key not in DNSStatusCode._member_map_: # pylint: disable=no-member return extend_enum(DNSStatusCode, key, default) return DNSStatusCode[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/dsmip6_tls_packet.py b/pcapkit/const/mh/dsmip6_tls_packet.py index 37d0639821..ebd18058fd 100644 --- a/pcapkit/const/mh/dsmip6_tls_packet.py +++ b/pcapkit/const/mh/dsmip6_tls_packet.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'DSMIP6TLSPacket': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return DSMIP6TLSPacket(key) + try: + return DSMIP6TLSPacket(key) + except ValueError: + if default == -1: + raise + return DSMIP6TLSPacket(default) if key not in DSMIP6TLSPacket._member_map_: # pylint: disable=no-member return extend_enum(DSMIP6TLSPacket, key, default) return DSMIP6TLSPacket[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/dsmipv6_home_address.py b/pcapkit/const/mh/dsmipv6_home_address.py index 6593f5872d..3ed901c058 100644 --- a/pcapkit/const/mh/dsmipv6_home_address.py +++ b/pcapkit/const/mh/dsmipv6_home_address.py @@ -45,12 +45,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'DSMIPv6HomeAddress': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return DSMIPv6HomeAddress(key) + try: + return DSMIPv6HomeAddress(key) + except ValueError: + if default == -1: + raise + return DSMIPv6HomeAddress(default) if key not in DSMIPv6HomeAddress._member_map_: # pylint: disable=no-member return extend_enum(DSMIPv6HomeAddress, key, default) return DSMIPv6HomeAddress[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/enumerating_algorithm.py b/pcapkit/const/mh/enumerating_algorithm.py index e513dc35a7..a5996ad85b 100644 --- a/pcapkit/const/mh/enumerating_algorithm.py +++ b/pcapkit/const/mh/enumerating_algorithm.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'EnumeratingAlgorithm': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return EnumeratingAlgorithm(key) + try: + return EnumeratingAlgorithm(key) + except ValueError: + if default == -1: + raise + return EnumeratingAlgorithm(default) if key not in EnumeratingAlgorithm._member_map_: # pylint: disable=no-member return extend_enum(EnumeratingAlgorithm, key, default) return EnumeratingAlgorithm[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/fb_ack_status.py b/pcapkit/const/mh/fb_ack_status.py index 8e2ecf404b..98d3d04df3 100644 --- a/pcapkit/const/mh/fb_ack_status.py +++ b/pcapkit/const/mh/fb_ack_status.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'FlowBindingACKStatus': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return FlowBindingACKStatus(key) + try: + return FlowBindingACKStatus(key) + except ValueError: + if default == -1: + raise + return FlowBindingACKStatus(default) if key not in FlowBindingACKStatus._member_map_: # pylint: disable=no-member return extend_enum(FlowBindingACKStatus, key, default) return FlowBindingACKStatus[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/fb_action.py b/pcapkit/const/mh/fb_action.py index c7f0b559f0..c2776be2f4 100644 --- a/pcapkit/const/mh/fb_action.py +++ b/pcapkit/const/mh/fb_action.py @@ -42,12 +42,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'FlowBindingAction': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return FlowBindingAction(key) + try: + return FlowBindingAction(key) + except ValueError: + if default == -1: + raise + return FlowBindingAction(default) if key not in FlowBindingAction._member_map_: # pylint: disable=no-member return extend_enum(FlowBindingAction, key, default) return FlowBindingAction[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/fb_indication_trigger.py b/pcapkit/const/mh/fb_indication_trigger.py index 4ff65a8231..6472ea6c1c 100644 --- a/pcapkit/const/mh/fb_indication_trigger.py +++ b/pcapkit/const/mh/fb_indication_trigger.py @@ -36,12 +36,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'FlowBindingIndicationTrigger' Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return FlowBindingIndicationTrigger(key) + try: + return FlowBindingIndicationTrigger(key) + except ValueError: + if default == -1: + raise + return FlowBindingIndicationTrigger(default) if key not in FlowBindingIndicationTrigger._member_map_: # pylint: disable=no-member return extend_enum(FlowBindingIndicationTrigger, key, default) return FlowBindingIndicationTrigger[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/fb_type.py b/pcapkit/const/mh/fb_type.py index d67dfe232e..d21b937e19 100644 --- a/pcapkit/const/mh/fb_type.py +++ b/pcapkit/const/mh/fb_type.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'FlowBindingType': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return FlowBindingType(key) + try: + return FlowBindingType(key) + except ValueError: + if default == -1: + raise + return FlowBindingType(default) if key not in FlowBindingType._member_map_: # pylint: disable=no-member return extend_enum(FlowBindingType, key, default) return FlowBindingType[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/flow_id_status.py b/pcapkit/const/mh/flow_id_status.py index 6984e6c15c..38f4999f87 100644 --- a/pcapkit/const/mh/flow_id_status.py +++ b/pcapkit/const/mh/flow_id_status.py @@ -45,12 +45,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'FlowIDStatus': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return FlowIDStatus(key) + try: + return FlowIDStatus(key) + except ValueError: + if default == -1: + raise + return FlowIDStatus(default) if key not in FlowIDStatus._member_map_: # pylint: disable=no-member return extend_enum(FlowIDStatus, key, default) return FlowIDStatus[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/flow_id_suboption.py b/pcapkit/const/mh/flow_id_suboption.py index fd1358c52b..c9298677d0 100644 --- a/pcapkit/const/mh/flow_id_suboption.py +++ b/pcapkit/const/mh/flow_id_suboption.py @@ -42,12 +42,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'FlowIDSuboption': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return FlowIDSuboption(key) + try: + return FlowIDSuboption(key) + except ValueError: + if default == -1: + raise + return FlowIDSuboption(default) if key not in FlowIDSuboption._member_map_: # pylint: disable=no-member return extend_enum(FlowIDSuboption, key, default) return FlowIDSuboption[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/handoff_type.py b/pcapkit/const/mh/handoff_type.py index 59d0eb09c3..32345c073e 100644 --- a/pcapkit/const/mh/handoff_type.py +++ b/pcapkit/const/mh/handoff_type.py @@ -45,12 +45,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'HandoffType': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return HandoffType(key) + try: + return HandoffType(key) + except ValueError: + if default == -1: + raise + return HandoffType(default) if key not in HandoffType._member_map_: # pylint: disable=no-member return extend_enum(HandoffType, key, default) return HandoffType[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/handover_ack_flag.py b/pcapkit/const/mh/handover_ack_flag.py index 0a054bc610..dc086e5d26 100644 --- a/pcapkit/const/mh/handover_ack_flag.py +++ b/pcapkit/const/mh/handover_ack_flag.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'HandoverACKFlag': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return HandoverACKFlag(key) + try: + return HandoverACKFlag(key) + except ValueError: + if default == -1: + raise + return HandoverACKFlag(default) return HandoverACKFlag[key] # type: ignore[misc] @classmethod diff --git a/pcapkit/const/mh/handover_ack_status.py b/pcapkit/const/mh/handover_ack_status.py index e6d0814cce..5540e8043b 100644 --- a/pcapkit/const/mh/handover_ack_status.py +++ b/pcapkit/const/mh/handover_ack_status.py @@ -63,12 +63,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'HandoverACKStatus': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return HandoverACKStatus(key) + try: + return HandoverACKStatus(key) + except ValueError: + if default == -1: + raise + return HandoverACKStatus(default) if key not in HandoverACKStatus._member_map_: # pylint: disable=no-member return extend_enum(HandoverACKStatus, key, default) return HandoverACKStatus[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/handover_initiate_flag.py b/pcapkit/const/mh/handover_initiate_flag.py index d8ecf2efc7..816603076e 100644 --- a/pcapkit/const/mh/handover_initiate_flag.py +++ b/pcapkit/const/mh/handover_initiate_flag.py @@ -36,12 +36,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'HandoverInitiateFlag': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return HandoverInitiateFlag(key) + try: + return HandoverInitiateFlag(key) + except ValueError: + if default == -1: + raise + return HandoverInitiateFlag(default) return HandoverInitiateFlag[key] # type: ignore[misc] @classmethod diff --git a/pcapkit/const/mh/handover_initiate_status.py b/pcapkit/const/mh/handover_initiate_status.py index 9d294ec0d8..fc08579fd3 100644 --- a/pcapkit/const/mh/handover_initiate_status.py +++ b/pcapkit/const/mh/handover_initiate_status.py @@ -36,12 +36,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'HandoverInitiateStatus': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return HandoverInitiateStatus(key) + try: + return HandoverInitiateStatus(key) + except ValueError: + if default == -1: + raise + return HandoverInitiateStatus(default) if key not in HandoverInitiateStatus._member_map_: # pylint: disable=no-member return extend_enum(HandoverInitiateStatus, key, default) return HandoverInitiateStatus[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/home_address_reply.py b/pcapkit/const/mh/home_address_reply.py index b4c58b6d6e..c21b6a29d7 100644 --- a/pcapkit/const/mh/home_address_reply.py +++ b/pcapkit/const/mh/home_address_reply.py @@ -42,12 +42,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'HomeAddressReply': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return HomeAddressReply(key) + try: + return HomeAddressReply(key) + except ValueError: + if default == -1: + raise + return HomeAddressReply(default) if key not in HomeAddressReply._member_map_: # pylint: disable=no-member return extend_enum(HomeAddressReply, key, default) return HomeAddressReply[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/lla_code.py b/pcapkit/const/mh/lla_code.py index 65763d87ef..1b74b8b366 100644 --- a/pcapkit/const/mh/lla_code.py +++ b/pcapkit/const/mh/lla_code.py @@ -40,12 +40,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'LLACode': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return LLACode(key) + try: + return LLACode(key) + except ValueError: + if default == -1: + raise + return LLACode(default) if key not in LLACode._member_map_: # pylint: disable=no-member return extend_enum(LLACode, key, default) return LLACode[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/lma_mag_suboption.py b/pcapkit/const/mh/lma_mag_suboption.py index def3fd165a..45c0c46ab3 100644 --- a/pcapkit/const/mh/lma_mag_suboption.py +++ b/pcapkit/const/mh/lma_mag_suboption.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'LMAControlledMAGSuboption': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return LMAControlledMAGSuboption(key) + try: + return LMAControlledMAGSuboption(key) + except ValueError: + if default == -1: + raise + return LMAControlledMAGSuboption(default) if key not in LMAControlledMAGSuboption._member_map_: # pylint: disable=no-member return extend_enum(LMAControlledMAGSuboption, key, default) return LMAControlledMAGSuboption[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/mn_group_id.py b/pcapkit/const/mh/mn_group_id.py index 79467924a5..e44c57482f 100644 --- a/pcapkit/const/mh/mn_group_id.py +++ b/pcapkit/const/mh/mn_group_id.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'MNGroupID': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return MNGroupID(key) + try: + return MNGroupID(key) + except ValueError: + if default == -1: + raise + return MNGroupID(default) if key not in MNGroupID._member_map_: # pylint: disable=no-member return extend_enum(MNGroupID, key, default) return MNGroupID[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/mn_id_subtype.py b/pcapkit/const/mh/mn_id_subtype.py index 2f17f18e9e..a41eeeea98 100644 --- a/pcapkit/const/mh/mn_id_subtype.py +++ b/pcapkit/const/mh/mn_id_subtype.py @@ -48,12 +48,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'MNIDSubtype': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return MNIDSubtype(key) + try: + return MNIDSubtype(key) + except ValueError: + if default == -1: + raise + return MNIDSubtype(default) if key not in MNIDSubtype._member_map_: # pylint: disable=no-member return extend_enum(MNIDSubtype, key, default) return MNIDSubtype[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/operator_id.py b/pcapkit/const/mh/operator_id.py index f8e2ecbdcf..bbc17ee336 100644 --- a/pcapkit/const/mh/operator_id.py +++ b/pcapkit/const/mh/operator_id.py @@ -37,12 +37,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'OperatorID': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return OperatorID(key) + try: + return OperatorID(key) + except ValueError: + if default == -1: + raise + return OperatorID(default) if key not in OperatorID._member_map_: # pylint: disable=no-member return extend_enum(OperatorID, key, default) return OperatorID[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/option.py b/pcapkit/const/mh/option.py index 789db34fee..e5aeada3d8 100644 --- a/pcapkit/const/mh/option.py +++ b/pcapkit/const/mh/option.py @@ -237,12 +237,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Option': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Option(key) + try: + return Option(key) + except ValueError: + if default == -1: + raise + return Option(default) if key not in Option._member_map_: # pylint: disable=no-member return extend_enum(Option, key, default) return Option[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/packet.py b/pcapkit/const/mh/packet.py index 6dcdd9fb1a..d6841f06fd 100644 --- a/pcapkit/const/mh/packet.py +++ b/pcapkit/const/mh/packet.py @@ -96,12 +96,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Packet': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Packet(key) + try: + return Packet(key) + except ValueError: + if default == -1: + raise + return Packet(default) if key not in Packet._member_map_: # pylint: disable=no-member return extend_enum(Packet, key, default) return Packet[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/qos_attribute.py b/pcapkit/const/mh/qos_attribute.py index bd2a2a9788..20ec5e4917 100644 --- a/pcapkit/const/mh/qos_attribute.py +++ b/pcapkit/const/mh/qos_attribute.py @@ -63,12 +63,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'QoSAttribute': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return QoSAttribute(key) + try: + return QoSAttribute(key) + except ValueError: + if default == -1: + raise + return QoSAttribute(default) if key not in QoSAttribute._member_map_: # pylint: disable=no-member return extend_enum(QoSAttribute, key, default) return QoSAttribute[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/revocation_status_code.py b/pcapkit/const/mh/revocation_status_code.py index 7f5380a4d9..920b1251dd 100644 --- a/pcapkit/const/mh/revocation_status_code.py +++ b/pcapkit/const/mh/revocation_status_code.py @@ -54,12 +54,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'RevocationStatusCode': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return RevocationStatusCode(key) + try: + return RevocationStatusCode(key) + except ValueError: + if default == -1: + raise + return RevocationStatusCode(default) if key not in RevocationStatusCode._member_map_: # pylint: disable=no-member return extend_enum(RevocationStatusCode, key, default) return RevocationStatusCode[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/revocation_trigger.py b/pcapkit/const/mh/revocation_trigger.py index 99793bcedc..82d06bd93b 100644 --- a/pcapkit/const/mh/revocation_trigger.py +++ b/pcapkit/const/mh/revocation_trigger.py @@ -54,12 +54,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'RevocationTrigger': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return RevocationTrigger(key) + try: + return RevocationTrigger(key) + except ValueError: + if default == -1: + raise + return RevocationTrigger(default) if key not in RevocationTrigger._member_map_: # pylint: disable=no-member return extend_enum(RevocationTrigger, key, default) return RevocationTrigger[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/status_code.py b/pcapkit/const/mh/status_code.py index 35076031c3..b95f7a9fa3 100644 --- a/pcapkit/const/mh/status_code.py +++ b/pcapkit/const/mh/status_code.py @@ -205,12 +205,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'StatusCode': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return StatusCode(key) + try: + return StatusCode(key) + except ValueError: + if default == -1: + raise + return StatusCode(default) if key not in StatusCode._member_map_: # pylint: disable=no-member return extend_enum(StatusCode, key, default) return StatusCode[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/traffic_selector.py b/pcapkit/const/mh/traffic_selector.py index 98ee11e089..4a1fb1c995 100644 --- a/pcapkit/const/mh/traffic_selector.py +++ b/pcapkit/const/mh/traffic_selector.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'TrafficSelector': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return TrafficSelector(key) + try: + return TrafficSelector(key) + except ValueError: + if default == -1: + raise + return TrafficSelector(default) if key not in TrafficSelector._member_map_: # pylint: disable=no-member return extend_enum(TrafficSelector, key, default) return TrafficSelector[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/upa_status.py b/pcapkit/const/mh/upa_status.py index 24d7fb59be..915a2aac6d 100644 --- a/pcapkit/const/mh/upa_status.py +++ b/pcapkit/const/mh/upa_status.py @@ -42,12 +42,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'UpdateNotificationACKStatus': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return UpdateNotificationACKStatus(key) + try: + return UpdateNotificationACKStatus(key) + except ValueError: + if default == -1: + raise + return UpdateNotificationACKStatus(default) if key not in UpdateNotificationACKStatus._member_map_: # pylint: disable=no-member return extend_enum(UpdateNotificationACKStatus, key, default) return UpdateNotificationACKStatus[key] # type: ignore[misc] diff --git a/pcapkit/const/mh/upn_reason.py b/pcapkit/const/mh/upn_reason.py index 14ab172945..83009e133d 100644 --- a/pcapkit/const/mh/upn_reason.py +++ b/pcapkit/const/mh/upn_reason.py @@ -54,12 +54,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'UpdateNotificationReason': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return UpdateNotificationReason(key) + try: + return UpdateNotificationReason(key) + except ValueError: + if default == -1: + raise + return UpdateNotificationReason(default) if key not in UpdateNotificationReason._member_map_: # pylint: disable=no-member return extend_enum(UpdateNotificationReason, key, default) return UpdateNotificationReason[key] # type: ignore[misc] diff --git a/pcapkit/const/ospf/authentication.py b/pcapkit/const/ospf/authentication.py index ac380e510c..000e012cf6 100644 --- a/pcapkit/const/ospf/authentication.py +++ b/pcapkit/const/ospf/authentication.py @@ -36,12 +36,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Authentication': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Authentication(key) + try: + return Authentication(key) + except ValueError: + if default == -1: + raise + return Authentication(default) if key not in Authentication._member_map_: # pylint: disable=no-member return extend_enum(Authentication, key, default) return Authentication[key] # type: ignore[misc] diff --git a/pcapkit/const/ospf/packet.py b/pcapkit/const/ospf/packet.py index d78966cf66..9c6321ea33 100644 --- a/pcapkit/const/ospf/packet.py +++ b/pcapkit/const/ospf/packet.py @@ -42,12 +42,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Packet': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Packet(key) + try: + return Packet(key) + except ValueError: + if default == -1: + raise + return Packet(default) if key not in Packet._member_map_: # pylint: disable=no-member return extend_enum(Packet, key, default) return Packet[key] # type: ignore[misc] diff --git a/pcapkit/const/pcapng/block_type.py b/pcapkit/const/pcapng/block_type.py index 6dcd52c190..982f8bb059 100644 --- a/pcapkit/const/pcapng/block_type.py +++ b/pcapkit/const/pcapng/block_type.py @@ -114,12 +114,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'BlockType': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return BlockType(key) + try: + return BlockType(key) + except ValueError: + if default == -1: + raise + return BlockType(default) if key not in BlockType._member_map_: # pylint: disable=no-member return extend_enum(BlockType, key, default) return BlockType[key] # type: ignore[misc] diff --git a/pcapkit/const/pcapng/filter_type.py b/pcapkit/const/pcapng/filter_type.py index 068b78cbd9..466fcfa3b8 100644 --- a/pcapkit/const/pcapng/filter_type.py +++ b/pcapkit/const/pcapng/filter_type.py @@ -25,12 +25,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'FilterType': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return FilterType(key) + try: + return FilterType(key) + except ValueError: + if default == -1: + raise + return FilterType(default) if key not in FilterType._member_map_: # pylint: disable=no-member return extend_enum(FilterType, key, default) return FilterType[key] # type: ignore[misc] diff --git a/pcapkit/const/pcapng/hash_algorithm.py b/pcapkit/const/pcapng/hash_algorithm.py index 622de466fe..a0b47bfa08 100644 --- a/pcapkit/const/pcapng/hash_algorithm.py +++ b/pcapkit/const/pcapng/hash_algorithm.py @@ -36,12 +36,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'HashAlgorithm': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return HashAlgorithm(key) + try: + return HashAlgorithm(key) + except ValueError: + if default == -1: + raise + return HashAlgorithm(default) if key not in HashAlgorithm._member_map_: # pylint: disable=no-member return extend_enum(HashAlgorithm, key, default) return HashAlgorithm[key] # type: ignore[misc] diff --git a/pcapkit/const/pcapng/record_type.py b/pcapkit/const/pcapng/record_type.py index 3d60f3bcc0..1774f22139 100644 --- a/pcapkit/const/pcapng/record_type.py +++ b/pcapkit/const/pcapng/record_type.py @@ -33,12 +33,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'RecordType': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return RecordType(key) + try: + return RecordType(key) + except ValueError: + if default == -1: + raise + return RecordType(default) if key not in RecordType._member_map_: # pylint: disable=no-member return extend_enum(RecordType, key, default) return RecordType[key] # type: ignore[misc] diff --git a/pcapkit/const/pcapng/secrets_type.py b/pcapkit/const/pcapng/secrets_type.py index e6a0db58f2..229519d509 100644 --- a/pcapkit/const/pcapng/secrets_type.py +++ b/pcapkit/const/pcapng/secrets_type.py @@ -32,12 +32,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'SecretsType': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return SecretsType(key) + try: + return SecretsType(key) + except ValueError: + if default == -1: + raise + return SecretsType(default) if key not in SecretsType._member_map_: # pylint: disable=no-member return extend_enum(SecretsType, key, default) return SecretsType[key] # type: ignore[misc] diff --git a/pcapkit/const/pcapng/verdict_type.py b/pcapkit/const/pcapng/verdict_type.py index faa80bfff5..9b4823e955 100644 --- a/pcapkit/const/pcapng/verdict_type.py +++ b/pcapkit/const/pcapng/verdict_type.py @@ -30,12 +30,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'VerdictType': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return VerdictType(key) + try: + return VerdictType(key) + except ValueError: + if default == -1: + raise + return VerdictType(default) if key not in VerdictType._member_map_: # pylint: disable=no-member return extend_enum(VerdictType, key, default) return VerdictType[key] # type: ignore[misc] diff --git a/pcapkit/const/reg/ethertype.py b/pcapkit/const/reg/ethertype.py index b1eb193368..a0f5f55608 100644 --- a/pcapkit/const/reg/ethertype.py +++ b/pcapkit/const/reg/ethertype.py @@ -522,12 +522,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'EtherType': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return EtherType(key) + try: + return EtherType(key) + except ValueError: + if default == -1: + raise + return EtherType(default) if key not in EtherType._member_map_: # pylint: disable=no-member return extend_enum(EtherType, key, default) return EtherType[key] # type: ignore[misc] diff --git a/pcapkit/const/reg/linktype.py b/pcapkit/const/reg/linktype.py index fcbb00e19b..6a38455c15 100644 --- a/pcapkit/const/reg/linktype.py +++ b/pcapkit/const/reg/linktype.py @@ -752,12 +752,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'LinkType': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return LinkType(key) + try: + return LinkType(key) + except ValueError: + if default == -1: + raise + return LinkType(default) if key not in LinkType._member_map_: # pylint: disable=no-member return extend_enum(LinkType, key, default) return LinkType[key] # type: ignore[misc] diff --git a/pcapkit/const/reg/transtype.py b/pcapkit/const/reg/transtype.py index f3be536b1a..091e17754d 100644 --- a/pcapkit/const/reg/transtype.py +++ b/pcapkit/const/reg/transtype.py @@ -500,12 +500,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'TransType': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return TransType(key) + try: + return TransType(key) + except ValueError: + if default == -1: + raise + return TransType(default) if key not in TransType._member_map_: # pylint: disable=no-member return extend_enum(TransType, key, default) return TransType[key] # type: ignore[misc] diff --git a/pcapkit/const/sctp/cause_code.py b/pcapkit/const/sctp/cause_code.py index ff0afc3f13..72bd4a0d55 100644 --- a/pcapkit/const/sctp/cause_code.py +++ b/pcapkit/const/sctp/cause_code.py @@ -97,12 +97,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'CauseCode': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return CauseCode(key) + try: + return CauseCode(key) + except ValueError: + if default == -1: + raise + return CauseCode(default) if key not in CauseCode._member_map_: # pylint: disable=no-member return extend_enum(CauseCode, key, default) return CauseCode[key] # type: ignore[misc] diff --git a/pcapkit/const/sctp/chunk.py b/pcapkit/const/sctp/chunk.py index 6ea087ae13..50e5f579d6 100644 --- a/pcapkit/const/sctp/chunk.py +++ b/pcapkit/const/sctp/chunk.py @@ -115,12 +115,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Chunk': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Chunk(key) + try: + return Chunk(key) + except ValueError: + if default == -1: + raise + return Chunk(default) if key not in Chunk._member_map_: # pylint: disable=no-member return extend_enum(Chunk, key, default) return Chunk[key] # type: ignore[misc] diff --git a/pcapkit/const/sctp/parameter.py b/pcapkit/const/sctp/parameter.py index 8b128b8599..be1276c072 100644 --- a/pcapkit/const/sctp/parameter.py +++ b/pcapkit/const/sctp/parameter.py @@ -121,12 +121,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Parameter': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Parameter(key) + try: + return Parameter(key) + except ValueError: + if default == -1: + raise + return Parameter(default) if key not in Parameter._member_map_: # pylint: disable=no-member return extend_enum(Parameter, key, default) return Parameter[key] # type: ignore[misc] diff --git a/pcapkit/const/sctp/payload_protocol_identifier.py b/pcapkit/const/sctp/payload_protocol_identifier.py index a8d162d9e3..8c0bb36054 100644 --- a/pcapkit/const/sctp/payload_protocol_identifier.py +++ b/pcapkit/const/sctp/payload_protocol_identifier.py @@ -270,12 +270,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'PayloadProtocolIdentifier': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return PayloadProtocolIdentifier(key) + try: + return PayloadProtocolIdentifier(key) + except ValueError: + if default == -1: + raise + return PayloadProtocolIdentifier(default) if key not in PayloadProtocolIdentifier._member_map_: # pylint: disable=no-member return extend_enum(PayloadProtocolIdentifier, key, default) return PayloadProtocolIdentifier[key] # type: ignore[misc] diff --git a/pcapkit/const/tcp/checksum.py b/pcapkit/const/tcp/checksum.py index 6b0ab0dc9c..57d9e75758 100644 --- a/pcapkit/const/tcp/checksum.py +++ b/pcapkit/const/tcp/checksum.py @@ -32,12 +32,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Checksum': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Checksum(key) + try: + return Checksum(key) + except ValueError: + if default == -1: + raise + return Checksum(default) if key not in Checksum._member_map_: # pylint: disable=no-member return extend_enum(Checksum, key, default) return Checksum[key] # type: ignore[misc] diff --git a/pcapkit/const/tcp/flags.py b/pcapkit/const/tcp/flags.py index 24ca7d3436..d011864b93 100644 --- a/pcapkit/const/tcp/flags.py +++ b/pcapkit/const/tcp/flags.py @@ -64,10 +64,17 @@ def get(key: 'int | str', default: 'Optional[int]' = -1) -> 'Flags': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Flags(key) + try: + return Flags(key) + except ValueError: + if default == -1: + raise + return Flags(default) return Flags[key] # type: ignore[misc] diff --git a/pcapkit/const/tcp/mp_tcp_option.py b/pcapkit/const/tcp/mp_tcp_option.py index 8d8815bc37..a3cb7c1f0f 100644 --- a/pcapkit/const/tcp/mp_tcp_option.py +++ b/pcapkit/const/tcp/mp_tcp_option.py @@ -54,12 +54,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'MPTCPOption': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return MPTCPOption(key) + try: + return MPTCPOption(key) + except ValueError: + if default == -1: + raise + return MPTCPOption(default) if key not in MPTCPOption._member_map_: # pylint: disable=no-member return extend_enum(MPTCPOption, key, default) return MPTCPOption[key] # type: ignore[misc] diff --git a/pcapkit/const/tcp/option.py b/pcapkit/const/tcp/option.py index 785904a0df..38c17c9cd0 100644 --- a/pcapkit/const/tcp/option.py +++ b/pcapkit/const/tcp/option.py @@ -161,12 +161,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'Option': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Option(key) + try: + return Option(key) + except ValueError: + if default == -1: + raise + return Option(default) if key not in Option._member_map_: # pylint: disable=no-member return extend_enum(Option, key, default) return Option[key] # type: ignore[misc] diff --git a/pcapkit/const/vlan/priority_level.py b/pcapkit/const/vlan/priority_level.py index 09fc304056..5d7358b2e3 100644 --- a/pcapkit/const/vlan/priority_level.py +++ b/pcapkit/const/vlan/priority_level.py @@ -48,12 +48,19 @@ def get(key: 'int | str', default: 'int' = -1) -> 'PriorityLevel': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return PriorityLevel(key) + try: + return PriorityLevel(key) + except ValueError: + if default == -1: + raise + return PriorityLevel(default) if key not in PriorityLevel._member_map_: # pylint: disable=no-member return extend_enum(PriorityLevel, key, default) return PriorityLevel[key] # type: ignore[misc] diff --git a/pcapkit/protocols/application/httpv1.py b/pcapkit/protocols/application/httpv1.py index 6e4d9e54cb..7cb7208fdd 100644 --- a/pcapkit/protocols/application/httpv1.py +++ b/pcapkit/protocols/application/httpv1.py @@ -53,12 +53,23 @@ __all__ = ['HTTP'] -# Regular expression to match HTTP methods. -_RE_METHOD = re.compile(rb"(?P[A-Z][A-Z-]*)") # RFC 9110, section 16.1.1, 9.1, 5.6.2 +# Regular expression to match HTTP methods. Anchored at both ends: :func:`re.match` +# anchors only at the start, so an unanchored pattern prefix-matches and accepts the +# leading ``G`` of ``Get`` as a whole method token. Method tokens are case-sensitive +# per :rfc:`9110#section-9.1`, so ``Get`` is not ``GET`` and must not parse as one. +_RE_METHOD = re.compile(rb"(?P[A-Z][A-Z-]*)\Z") # RFC 9110, section 16.1.1, 9.1, 5.6.2 # Regular expression to match HTTP version string. _RE_VERSION = re.compile(rb"HTTP/(?P\d\.\d)") -# Regular expression to match HTTP status code. -_RE_STATUS = re.compile(rb'\d{3}') +# Regular expression to match HTTP status code. Anchored for the same reason as +# ``_RE_METHOD``, and it matters more here: this pattern is only a guard, and the +# value is taken from ``int(para2)`` on the raw token, so an unanchored prefix +# match let ``200x`` and ``2000`` past the guard and then out of ``int()`` as a +# bare ``ValueError`` -- where ``_read_http_header`` documents ``ProtocolError``. +# :rfc:`9112#section-4` gives ``status-code = 3DIGIT``, exactly three -- the +# grammar is in HTTP/1.1 because ``status-code`` is part of its ``status-line`` +# production; :rfc:`9110#section-15` covers the code semantics and registry, not +# the syntax. +_RE_STATUS = re.compile(rb'\d{3}\Z') class Type(StrEnum): @@ -289,7 +300,7 @@ def _read_http_header(self, header: 'bytes') -> 'tuple[Data_Header, OrderedMulti if match1 and match2: header_line = Data_RequestHeader( type=Type.REQUEST, - method=Enum_Method.get(self.decode(para1)), + method=Enum_Method.get(self.decode(match1.group('method'))), uri=self.decode(para2), version=self.decode(match2.group('version')), ) diff --git a/pcapkit/vendor/default.py b/pcapkit/vendor/default.py index d812db54a4..b4d7ec8e40 100644 --- a/pcapkit/vendor/default.py +++ b/pcapkit/vendor/default.py @@ -79,12 +79,19 @@ def get(key: 'int | str', default: 'int' = -1) -> '{NAME}': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return {NAME}(key) + try: + return {NAME}(key) + except ValueError: + if default == -1: + raise + return {NAME}(default) if key not in {NAME}._member_map_: # pylint: disable=no-member return extend_enum({NAME}, key, default) return {NAME}[key] # type: ignore[misc] diff --git a/pcapkit/vendor/ftp/command.py b/pcapkit/vendor/ftp/command.py index 2063d5ee05..0afc4d7f4a 100644 --- a/pcapkit/vendor/ftp/command.py +++ b/pcapkit/vendor/ftp/command.py @@ -151,24 +151,30 @@ def get(key: 'str', default: 'Optional[str]' = None) -> '{NAME}': """Backport support for original codes. Args: - key: Key to get enum item. + key: Key to get enum item. Looked up case-insensitively, since + member names are canonicalised to upper case on registration. default: Default value if not found. :meta private: """ - if key not in {NAME}._member_map_: # pylint: disable=no-member - return extend_enum({NAME}, key.upper(), default if default is not None else key) - return {NAME}[key] # type: ignore[misc] + name = key.upper() + if name not in {NAME}._member_map_: # pylint: disable=no-member + return extend_enum({NAME}, name, default if default is not None else key) + return {NAME}[name] # type: ignore[misc] @classmethod def _missing_(cls, value: 'str') -> '{NAME}': """Lookup function used when value is not found. Args: - value: Value to get enum item. + value: Value to get enum item. Matched case-insensitively against + the canonical upper-case member names. """ - return extend_enum(cls, value.upper(), value) + name = value.upper() + if name in cls._member_map_: + return cls._member_map_[name] # type: ignore[return-value] + return extend_enum(cls, name, value) '''.strip() # type: Callable[[str, str, str, str], str] diff --git a/pcapkit/vendor/ftp/return_code.py b/pcapkit/vendor/ftp/return_code.py index 67e831672e..3c1ff844ef 100644 --- a/pcapkit/vendor/ftp/return_code.py +++ b/pcapkit/vendor/ftp/return_code.py @@ -142,12 +142,19 @@ def get(key: 'int | str', default: 'int' = -1) -> '{NAME}': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return {NAME}(key) + try: + return {NAME}(key) + except ValueError: + if default == -1: + raise + return {NAME}(default) if key not in {NAME}._member_map_: # pylint: disable=no-member return extend_enum({NAME}, key, default) return {NAME}[key] # type: ignore[misc] diff --git a/pcapkit/vendor/http/method.py b/pcapkit/vendor/http/method.py index a044b77167..21ba94be75 100644 --- a/pcapkit/vendor/http/method.py +++ b/pcapkit/vendor/http/method.py @@ -72,24 +72,30 @@ def get(key: 'str', default: 'Optional[str]' = None) -> '{NAME}': """Backport support for original codes. Args: - key: Key to get enum item. + key: Key to get enum item. Looked up case-insensitively, since + member names are canonicalised to upper case on registration. default: Default value if not found. :meta private: """ - if key not in {NAME}._member_map_: # pylint: disable=no-member - return extend_enum({NAME}, key.upper(), default if default is not None else key) - return {NAME}[key] # type: ignore[misc] + name = key.upper() + if name not in {NAME}._member_map_: # pylint: disable=no-member + return extend_enum({NAME}, name, default if default is not None else key) + return {NAME}[name] # type: ignore[misc] @classmethod def _missing_(cls, value: 'str') -> '{NAME}': """Lookup function used when value is not found. Args: - value: Value to get enum item. + value: Value to get enum item. Matched case-insensitively against + the canonical upper-case member names. """ - return extend_enum(cls, value.upper(), value) + name = value.upper() + if name in cls._member_map_: + return cls._member_map_[name] # type: ignore[return-value] + return extend_enum(cls, name, value) '''.strip() # type: Callable[[str, str, str, str], str] diff --git a/pcapkit/vendor/http/status_code.py b/pcapkit/vendor/http/status_code.py index 4013a9d29d..16d8696ecf 100644 --- a/pcapkit/vendor/http/status_code.py +++ b/pcapkit/vendor/http/status_code.py @@ -75,12 +75,19 @@ def get(key: 'int | str', default: 'int' = -1) -> '{NAME}': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return {NAME}(key) + try: + return {NAME}(key) + except ValueError: + if default == -1: + raise + return {NAME}(default) if key not in {NAME}._member_map_: # pylint: disable=no-member extend_enum({NAME}, key, default) return {NAME}[key] # type: ignore[misc] diff --git a/pcapkit/vendor/ipv6/extension_header.py b/pcapkit/vendor/ipv6/extension_header.py index 03f335be76..37a9f37b03 100644 --- a/pcapkit/vendor/ipv6/extension_header.py +++ b/pcapkit/vendor/ipv6/extension_header.py @@ -52,12 +52,19 @@ def get(key: 'int | str', default: 'int' = -1) -> '{NAME}': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return {NAME}(key) + try: + return {NAME}(key) + except ValueError: + if default == -1: + raise + return {NAME}(default) return {NAME}[key] # type: ignore[misc] ''' # type: Callable[[str, str, str, str], str] diff --git a/pcapkit/vendor/mh/binding_ack_flag.py b/pcapkit/vendor/mh/binding_ack_flag.py index 834c135595..a47106dd2e 100644 --- a/pcapkit/vendor/mh/binding_ack_flag.py +++ b/pcapkit/vendor/mh/binding_ack_flag.py @@ -51,12 +51,19 @@ def get(key: 'int | str', default: 'int' = -1) -> '{NAME}': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return {NAME}(key) + try: + return {NAME}(key) + except ValueError: + if default == -1: + raise + return {NAME}(default) return {NAME}[key] # type: ignore[misc] @classmethod diff --git a/pcapkit/vendor/mh/binding_update_flag.py b/pcapkit/vendor/mh/binding_update_flag.py index 9734cf9311..9dd22ef185 100644 --- a/pcapkit/vendor/mh/binding_update_flag.py +++ b/pcapkit/vendor/mh/binding_update_flag.py @@ -50,12 +50,19 @@ def get(key: 'int | str', default: 'int' = -1) -> '{NAME}': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return {NAME}(key) + try: + return {NAME}(key) + except ValueError: + if default == -1: + raise + return {NAME}(default) return {NAME}[key] # type: ignore[misc] @classmethod diff --git a/pcapkit/vendor/mh/handover_ack_flag.py b/pcapkit/vendor/mh/handover_ack_flag.py index 5df5d0f018..fe9a4080d7 100644 --- a/pcapkit/vendor/mh/handover_ack_flag.py +++ b/pcapkit/vendor/mh/handover_ack_flag.py @@ -51,12 +51,19 @@ def get(key: 'int | str', default: 'int' = -1) -> '{NAME}': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return {NAME}(key) + try: + return {NAME}(key) + except ValueError: + if default == -1: + raise + return {NAME}(default) return {NAME}[key] # type: ignore[misc] @classmethod diff --git a/pcapkit/vendor/mh/handover_initiate_flag.py b/pcapkit/vendor/mh/handover_initiate_flag.py index a106835308..2f069fcdc2 100644 --- a/pcapkit/vendor/mh/handover_initiate_flag.py +++ b/pcapkit/vendor/mh/handover_initiate_flag.py @@ -51,12 +51,19 @@ def get(key: 'int | str', default: 'int' = -1) -> '{NAME}': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return {NAME}(key) + try: + return {NAME}(key) + except ValueError: + if default == -1: + raise + return {NAME}(default) return {NAME}[key] # type: ignore[misc] @classmethod diff --git a/pcapkit/vendor/tcp/flags.py b/pcapkit/vendor/tcp/flags.py index 6dad3cee4e..0c1bc8706b 100644 --- a/pcapkit/vendor/tcp/flags.py +++ b/pcapkit/vendor/tcp/flags.py @@ -67,12 +67,19 @@ def get(key: 'int | str', default: 'Optional[int]' = -1) -> '{NAME}': Args: key: Key to get enum item. - default: Default value if not found. + default: Default value if not found. The placeholder ``-1`` stands + for *no default*, in which case an unresolvable key propagates + the lookup error instead of falling back. :meta private: """ if isinstance(key, int): - return Flags(key) + try: + return Flags(key) + except ValueError: + if default == -1: + raise + return Flags(default) return {NAME}[key] # type: ignore[misc] '''.strip() # type: Callable[[str, str, str, str], str] diff --git a/tests/const/test_const_enum_get.py b/tests/const/test_const_enum_get.py new file mode 100644 index 0000000000..26a65126a7 --- /dev/null +++ b/tests/const/test_const_enum_get.py @@ -0,0 +1,292 @@ +# -*- coding: utf-8 -*- +"""Registry-wide regression tests for ``get()``'s ``default`` parameter. + +GitHub issue #584: the ``default`` parameter that every generated ``get()`` +documents was never consulted on the integer path, because ``get`` delegated the +lookup straight to the enum call and ``_missing_`` has no access to the caller's +``default``:: + + >>> Hardware.get(99999, 0) + ValueError: 99999 is not a valid Hardware + +Only the ``str`` path passed ``default`` through to :func:`~aenum.extend_enum`. +The integer path -- the one every numeric lookup takes -- could not. + +The sweep below is the one #584 asked for before fixing ("the real scope is +likely wider since most ``const/`` modules are generated from the same +skeleton"). Measured: of the 118 :class:`~aenum.IntEnum` and +:class:`~aenum.IntFlag` registries defined under :mod:`pcapkit.const`, the +defect was live in 110 -- not just the three the issue named. Three of the +remaining eight never raise on an out-of-range integer because they auto-extend +the whole space, and five carry no ``get(key, default)`` at all. + +Two more registries are outside this sweep because they are +:class:`~aenum.StrEnum` rather than integer enums, and both were deliberately +left alone: :class:`~pcapkit.const.pcapng.option_type.OptionType` and +:class:`~pcapkit.const.reg.apptype.AppType` each carry a bespoke integer +fallback that already resolves every value, so neither drops a default by +raising. The two string-keyed registries +:class:`~pcapkit.const.ftp.command.Command` and +:class:`~pcapkit.const.http.method.Method` have no integer path at all; they are +the subject of #582 and #583 instead. + +``-1`` is the placeholder the generated signature carries, and it is what +separates "no default was supplied" from "a default was supplied and should be +used". Both halves are pinned here, because a fix that made an unresolvable key +fall back *silently* when the caller asked for no fallback would be a worse +defect than the one it replaced. + +These modules are generated from :mod:`pcapkit.vendor`, so +``test_the_vendor_template_still_emits_the_fix`` renders the shared template and +compares it against a generated module. Without it a regeneration would quietly +undo the fix and the rest of this suite would still pass, because the *tree* is +what is committed and the *template* is what rebuilds it. + +""" +from __future__ import annotations + +import importlib +import importlib.util +import inspect +import pkgutil +import re +import unittest +from typing import TYPE_CHECKING + +from aenum import IntEnum, IntFlag + +from tests._support import purge_modules + +#: An integer no wire field in the library is wide enough to carry, so every +#: registry that bounds its own domain rejects it. Deliberately far outside the +#: ``0..0xFF`` range the Mobility Header flag registries check, because a value +#: *inside* an unbounded-but-undefined span reaches a separate, pre-existing +#: recursion in their ``_missing_`` (``return cls(value)``) that is not what +#: this module is about. +UNRESOLVABLE = 1 << 70 + +#: Enums whose integer path resolves *anything* rather than raising, so there is +#: no fallback for ``default`` to supply: all three auto-extend their unassigned +#: spans across the full integer range. +EXPECTED_TO_RESOLVE_ANYTHING = frozenset({ + 'pcapkit.const.ipv4.protection_authority.ProtectionAuthority', + 'pcapkit.const.mh.cga_type.CGAType', + 'pcapkit.const.tcp.flags.Flags', +}) + +#: Enums carrying no ``get(key, default)``, so there is no ``default`` to drop. +#: The first four are helper enums describing a registry's columns rather than +#: registries themselves and have no ``get`` at all; +#: :class:`~pcapkit.const.reg.apptype.TransportProtocol` has a ``get`` whose +#: signature takes no ``default`` -- which is why the rewrite had to check the +#: signature rather than pattern-match the body. +EXPECTED_WITHOUT_AN_INTEGER_DEFAULT = frozenset({ + 'pcapkit.const.ftp.command.CommandType', + 'pcapkit.const.ftp.command.ConformanceRequirement', + 'pcapkit.const.ftp.return_code.GroupingInformation', + 'pcapkit.const.ftp.return_code.ResponseKind', + 'pcapkit.const.reg.apptype.TransportProtocol', +}) + + +def _iter_const_enums() -> 'list[type]': + """Every :class:`~aenum.IntEnum` and :class:`~aenum.IntFlag` under :mod:`pcapkit.const`. + + Wider than the sweep in :mod:`tests.const.test_const_enum_lookup`, which + excludes :class:`~aenum.IntFlag` because ``Enum(0)`` is a different contract + for a flag registry. ``get()``'s integer path is not: the flag registries + carry the same generated ``get`` and dropped ``default`` the same way, so + they belong in this sweep. + + Collects only classes *defined* in the module being walked, so a + re-exported registry is counted once. + + Returns: + The discovered enum classes, in walk order. + + """ + import pcapkit.const as const_pkg + + classes = [] # type: list[type] + for module_info in pkgutil.walk_packages(const_pkg.__path__, const_pkg.__name__ + '.'): + module = importlib.import_module(module_info.name) + for _, obj in vars(module).items(): + if (inspect.isclass(obj) and issubclass(obj, (IntEnum, IntFlag)) + and obj.__module__ == module_info.name): + classes.append(obj) + return classes + + +def _qualname(obj: 'type') -> 'str': + """The fully qualified name used as a sweep key.""" + return f'{obj.__module__}.{obj.__qualname__}' + + +class ConstEnumGetDefaultTests(unittest.TestCase): + """``get(key, default)`` must consult ``default`` on the integer path.""" + + if TYPE_CHECKING: + enums: 'list[type]' + + @classmethod + def setUpClass(cls) -> None: + purge_modules(['pcapkit']) + cls.enums = _iter_const_enums() + # ``test_the_always_resolving_registries_have_nothing_to_fall_back_to`` + # probes registries whose ``_missing_`` extends for *any* integer, which + # permanently registers a junk member on a module-global class. Drop the + # whole package afterwards so that pollution cannot leak into another + # module, rather than relying on the next test's own ``setUp`` to purge + # it -- that protection is incidental, and this class should not depend + # on it. Class-level rather than per-test, so ``cls.enums`` stays valid + # for every test in this class. + cls.addClassCleanup(purge_modules, ['pcapkit']) + + def test_the_reported_case_returns_the_default(self) -> None: + """#584's own repro, on the enum it was reported against.""" + from pcapkit.const.arp.hardware import Hardware + + # Before the fix this raised ValueError('99999 is not a valid Hardware'), + # dropping the caller's default entirely. + self.assertIs(Hardware.get(99999, 0), Hardware(0)) + self.assertIs(Hardware.get(99999, 1), Hardware.Ethernet) + + # The default is genuinely consulted rather than merely swallowing the + # error: a default that is itself unresolvable is now what fails, and + # the message names it rather than the original key. #584 passed a + # ``str`` where the signature says ``int``, and that is still invalid. + with self.assertRaises(ValueError) as caught: + Hardware.get(99999, 'X') + self.assertIn('X', str(caught.exception)) + self.assertNotIn('99999', str(caught.exception)) + + # A resolvable key is untouched. + self.assertIs(Hardware.get(1), Hardware.Ethernet) + self.assertIs(Hardware.get(40), Hardware(40)) + self.assertIs(Hardware.get('Ethernet'), Hardware.Ethernet) + + def test_the_placeholder_still_raises(self) -> None: + """``-1`` means *no default*, so the lookup error must still propagate.""" + from pcapkit.const.arp.hardware import Hardware + from pcapkit.const.arp.operation import Operation + + for enum in (Hardware, Operation): + with self.subTest(enum=_qualname(enum)): + with self.assertRaises(ValueError) as caught: + enum.get(99999) + self.assertIn('99999', str(caught.exception)) + # Explicitly passing the placeholder is the same as omitting it. + with self.assertRaises(ValueError): + enum.get(99999, -1) + + def test_the_two_unverified_enums_from_the_issue(self) -> None: + """#584 named ``Operation`` and ``LinkType`` but verified only ``Hardware``.""" + from pcapkit.const.arp.operation import Operation + from pcapkit.const.reg.linktype import LinkType + + self.assertIs(Operation.get(99999, 1), Operation.REQUEST) + self.assertIs(LinkType.get(-5, 1), LinkType.ETHERNET) + + def test_the_sweep_size_is_pinned(self) -> None: + # If this drifts, a const enum was added, removed or renamed, and the + # two exception sets below need a fresh look rather than a silent pass. + names = {_qualname(obj) for obj in self.enums} + self.assertEqual(len(self.enums), 118) + for expected in (EXPECTED_TO_RESOLVE_ANYTHING, EXPECTED_WITHOUT_AN_INTEGER_DEFAULT): + self.assertTrue(expected.issubset(names), + f'sweep is missing: {expected - names}') + + def test_every_integer_path_consults_the_default(self) -> None: + """The registry-wide form of #584, across all 118 integer registries.""" + covered = 0 + for obj in self.enums: + qualname = _qualname(obj) + if qualname in EXPECTED_WITHOUT_AN_INTEGER_DEFAULT: + # Assert the reason they are excused, so the set cannot quietly + # start covering a registry that does take a ``default``. + get = getattr(obj, 'get', None) + self.assertTrue( + get is None or 'default' not in inspect.signature(get).parameters, + f'{qualname} does take a `default` and belongs in the sweep') + continue + if qualname in EXPECTED_TO_RESOLVE_ANYTHING: + # Covered by its own test below. Probing them here would extend + # a module-global registry as a side effect of a sweep whose + # subject is something else, and for these three the ``try`` + # never raises, so it would assert nothing about the fix. + continue + with self.subTest(enum=qualname): + with self.assertRaises(ValueError): + obj.get(UNRESOLVABLE) + fallback = next(iter(obj)).value + self.assertIs(obj.get(UNRESOLVABLE, fallback), obj(fallback)) + covered += 1 + self.assertEqual(covered, 110) + + def test_the_always_resolving_registries_have_nothing_to_fall_back_to(self) -> None: + """The three registries excused from the sweep, and why. + + Their ``_missing_`` extends for *any* integer, so the integer path never + raises and ``default`` has nothing to supply. Asserted rather than merely + listed, so ``EXPECTED_TO_RESOLVE_ANYTHING`` cannot quietly grow to hide a + registry that does raise. + + Kept out of the sweep because probing the two :class:`~aenum.IntEnum` + ones *mutates* the registry: the call permanently registers a member on + a module-global class. That is done deliberately here, and ``setUpClass`` + registers a class cleanup that purges :mod:`pcapkit` afterwards so the + pollution cannot reach another module. + + Measured: ``ProtectionAuthority`` grows 8 members to 9 and ``CGAType`` 7 + to 8, because their ``_missing_`` calls ``extend_enum``. ``Flags`` does + not grow at all -- it is an :class:`~aenum.IntFlag` and returns a + pseudo-member instead -- which is why the shared assertion below is + "resolves", not "extends". + """ + for qualname in sorted(EXPECTED_TO_RESOLVE_ANYTHING): + module_name, _, class_name = qualname.rpartition('.') + obj = getattr(importlib.import_module(module_name), class_name) + with self.subTest(enum=qualname): + # Resolving an out-of-range integer at all is the property that + # excuses them from the sweep. + resolved = obj.get(UNRESOLVABLE) + self.assertIsNotNone(resolved) + self.assertEqual(int(resolved), UNRESOLVABLE) + # It resolves with or without a default, so the sentinel branch + # this change added is never reached for these three. + self.assertIs(resolved, obj.get(UNRESOLVABLE, 0)) + + @unittest.skipUnless(importlib.util.find_spec('requests') is not None, + 'pcapkit.vendor needs requests') + def test_the_vendor_template_still_emits_the_fix(self) -> None: + """A regeneration must not undo the fix. + + :mod:`pcapkit.const` is generated from :mod:`pcapkit.vendor`, so the + committed tree passing is not evidence that the template agrees with it. + Renders the shared template and compares its ``get()`` block, character + for character, against the module generated from it. + """ + import pathlib + + from pcapkit.vendor.default import LINE + + rendered = LINE('Hardware', 'Hardware Type [:rfc:`826`]', + 'isinstance(value, int) and 0 <= value <= 65535', + "PLACEHOLDER = 'enum'", ' return None', + 'pcapkit.vendor.arp.hardware') + + import pcapkit.const.arp.hardware as generated_module + generated = pathlib.Path(generated_module.__file__).read_text(encoding='utf-8') + + block = re.compile(r' @staticmethod\n def get\(.*?\n(?= @)', re.S) + from_template = block.search(rendered) + from_generated = block.search(generated) + + self.assertIsNotNone(from_template, 'the template rendered no get() block') + self.assertIsNotNone(from_generated, 'the generated module has no get() block') + self.assertIn('except ValueError:', from_template.group(0)) + self.assertEqual(from_template.group(0), from_generated.group(0)) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/protocols/application/test_ftp_unit.py b/tests/protocols/application/test_ftp_unit.py index fa2b434596..d7f801fd9c 100644 --- a/tests/protocols/application/test_ftp_unit.py +++ b/tests/protocols/application/test_ftp_unit.py @@ -63,6 +63,66 @@ def test_ftp_read_parses_request_response_and_rejects_invalid(self) -> None: with self.assertRaises(ProtocolError): ftp.read(length=4) + def test_command_get_is_case_insensitive(self) -> None: + """``Command.get`` normalised the key it registered but not the key it + looked up, so the first lowercase command raised ``TypeError`` instead + of resolving -- #582. + + :rfc:`959#section-5.3` makes FTP commands case-insensitive -- "Upper and + lower case alphabetic characters are to be treated identically. Thus, any + of the following may represent the retrieve command: ``RETR Retr retr + ReTr rETr``" -- so every casing of a registered command has to resolve to + the *same* member rather than to a second one registered alongside it. + + The citation is section 5.3 (COMMANDS, which gives the command syntax), + not section 4.1 (FTP COMMANDS, which only lists the per-command + semantics); #582 cited 4.1 and a cross-review caught it. Verified against + the RFC text: the sentence sits between the 5.3 and 5.4 headings. The + ``:rfc:`959#section-4.1``` citations in + :mod:`pcapkit.const.ftp.command` are a different claim -- the command + *kind* (access control, transfer parameter, service) -- and are correct. + """ + from pcapkit.const.ftp.command import Command + + for key in ('RETR', 'retr', 'ReTr', 'rEtR'): + with self.subTest(key=key): + self.assertIs(Command.get(key), Command.RETR) + + # ``_missing_`` carried the identical mismatch, so the value-lookup + # form raised too. + self.assertIs(Command('retr'), Command.RETR) + + # A genuinely unknown command still registers, under its canonical + # upper-case name, and does not create a case-variant duplicate. + unknown = Command.get('xyzw') + self.assertEqual(unknown._name_, 'XYZW') + self.assertIs(Command.get('XYZW'), unknown) + self.assertEqual([name for name in Command._member_map_ + if name.upper() == 'RETR'], ['RETR']) + + def test_ftp_read_parses_a_lowercase_request(self) -> None: + """The case-insensitivity is reachable from wire data: ``ftp.py`` + compiles ``FTP_REQUEST`` with :data:`re.I` and passes the match + verbatim, so a lowercase request used to crash the parse -- #582. + """ + from pcapkit.const.ftp.command import Command + from pcapkit.protocols.application.ftp import FTP, Type + + ftp = object.__new__(FTP) + ftp.__cached__ = {} + + for raw, command, args in ((b'retr file.txt\r\n', Command.RETR, 'file.txt'), + (b'Retr file.txt\r\n', Command.RETR, 'file.txt'), + (b'user guest\r\n', Command.USER, 'guest'), + (b'RETR file.txt\r\n', Command.RETR, 'file.txt')): + with self.subTest(raw=raw): + ftp.__header__ = SimpleNamespace(data=raw) + ftp._data = raw + request = ftp.read(length=len(raw)) + self.assertEqual(request.type, Type.REQUEST) + self.assertIs(request.cmmd, command) + self.assertEqual(request.args, args) + def test_ftp_make_builds_request_and_response_packets(self) -> None: from pcapkit.const.ftp.command import Command from pcapkit.const.ftp.return_code import ReturnCode diff --git a/tests/protocols/application/test_http_unit.py b/tests/protocols/application/test_http_unit.py index 31e508c4ab..603c6ecf8c 100644 --- a/tests/protocols/application/test_http_unit.py +++ b/tests/protocols/application/test_http_unit.py @@ -375,6 +375,126 @@ def test_httpv1_id_make_data_and_request_construction(self) -> None: with self.assertRaises(ProtocolError): proto._read_http_header(b'BAD nope nope\r\nHost: example') + def test_method_get_is_case_insensitive(self) -> None: + """``Method.get`` tested the raw key and registered the upper-cased one, + so a mixed-case method raised ``TypeError`` -- #583, item 1. + + The same mismatch as #582 in :mod:`pcapkit.const.ftp.command`. Resolving + to the existing member matters beyond not crashing: a duplicate + registered alongside ``GET`` would carry neither its ``safe`` nor its + ``idempotent`` attribute. + """ + from pcapkit.const.http.method import Method + + for key in ('GET', 'Get', 'get', 'gEt'): + with self.subTest(key=key): + self.assertIs(Method.get(key), Method.GET) + + self.assertIs(Method('Get'), Method.GET) + self.assertTrue(Method.get('Get').safe) + self.assertEqual([name for name in Method._member_map_ + if name.upper() == 'GET'], ['GET']) + + unknown = Method.get('frob') + self.assertEqual(unknown._name_, 'FROB') + self.assertIs(Method.get('FROB'), unknown) + + def test_httpv1_method_regex_is_anchored(self) -> None: + """``_RE_METHOD`` was unanchored and :func:`re.match` anchors only at the + start, so it prefix-matched ``b'Get'`` down to ``b'G'`` -- #583, item 2. + + Method tokens are case-sensitive per :rfc:`9110#section-9.1`, so ``Get`` + is not ``GET`` and must not be accepted as one. + """ + import re + + from pcapkit.protocols.application.httpv1 import _RE_METHOD + + for probe, expected in ((b'GET', b'GET'), + (b'POST', b'POST'), + (b'BASELINE-CONTROL', b'BASELINE-CONTROL'), + (b'Get', None), + (b'get', None), + (b'GET ', None)): + with self.subTest(probe=probe): + match = re.match(_RE_METHOD, probe) + self.assertEqual(match.group('method') if match else None, expected) + + def test_httpv1_read_header_uses_the_captured_method(self) -> None: + """``httpv1.py`` handed the whole ``para1`` to ``Method.get`` rather than + the captured group, so a prefix match let a bad token through -- #583. + + Both halves are asserted together because either alone still gives a + wrong answer: normalising ``Method.get`` alone would parse ``b'Get'`` as + ``GET`` off a one-character match, and passing the captured group alone + would parse it as a method named ``G``. + """ + from pcapkit.const.http.method import Method + from pcapkit.protocols.application.httpv1 import HTTP as HTTPv1 + from pcapkit.utilities.exceptions import ProtocolError + + proto = object.__new__(HTTPv1) + + header, _ = proto._read_http_header(b'GET /index.html HTTP/1.1\r\nHost: example.test') + self.assertIs(header.method, Method.GET) + self.assertEqual(header.uri, '/index.html') + + # A mixed- or lower-case token is not a registered method and no longer + # masquerades as a prefix of one; it is a malformed request line. + for raw in (b'Get / HTTP/1.1\r\nHost: example.test', + b'get / HTTP/1.1\r\nHost: example.test'): + with self.subTest(raw=raw): + with self.assertRaises(ProtocolError): + proto._read_http_header(raw) + + # No case-variant member was registered on the way through. + self.assertEqual([name for name in Method._member_map_ + if name.upper() == 'GET'], ['GET']) + + # The response path is untouched. + response, _ = proto._read_http_header(b'HTTP/1.1 404 Not Found\r\nServer: example') + self.assertEqual(response.status, 404) + + def test_httpv1_status_regex_is_anchored(self) -> None: + """``_RE_STATUS`` carried the same unanchored-prefix defect as + ``_RE_METHOD``, and it escaped as the wrong exception type. + + Found while auditing ``_RE_METHOD``'s siblings for #583. The pattern is + only a guard -- the value comes from ``int(para2)`` on the *raw* token -- + so a prefix match let a malformed status past the guard and then out of + ``int()`` as a bare ``ValueError``, where ``_read_http_header`` documents + ``ProtocolError``. :rfc:`9112#section-4` gives ``status-code = 3DIGIT``, + exactly three, so anchoring is what the grammar says. + + The citation is RFC 9112, not RFC 9110: the production belongs to + HTTP/1.1's ``status-line = HTTP-version SP status-code SP + [ reason-phrase ]``, and :rfc:`9110#section-15` covers what the codes + *mean* plus the IANA registry. RFC 9112 section 4 says so itself -- + "HTTP's core status codes are defined in Section 15 of [HTTP]". A + cross-review caught the first draft citing 9110 for the grammar. + + Measured before the fix: + ``b'HTTP/1.1 200x OK'`` -> ``ValueError: invalid literal for int() with + base 10: b'200x'``, and ``b'HTTP/1.1 2000 OK'`` -> ``ValueError: 2000 is + not a valid StatusCode``. + """ + from pcapkit.protocols.application.httpv1 import HTTP as HTTPv1 + from pcapkit.utilities.exceptions import ProtocolError + + proto = object.__new__(HTTPv1) + + good, _ = proto._read_http_header(b'HTTP/1.1 200 OK\r\nServer: example') + self.assertEqual(good.status, 200) + + for raw in (b'HTTP/1.1 200x OK\r\nServer: example', + b'HTTP/1.1 2000 OK\r\nServer: example', + b'HTTP/1.1 20 OK\r\nServer: example'): + with self.subTest(raw=raw): + # ProtocolError, not ValueError: a malformed start line is a + # protocol error, which is what the method documents. + with self.assertRaises(ProtocolError): + proto._read_http_header(raw) + def test_httpv1_response_construction_and_missing_request_uri_error(self) -> None: from pcapkit.const.http.status_code import StatusCode from pcapkit.protocols.application.httpv1 import HTTP as HTTPv1