Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 26 additions & 21 deletions docs/source/contributing/conventions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -385,22 +385,25 @@ Three things about it are easy to get wrong:

.. note::

Re-parenting the remaining helper enumerations onto
:class:`~pcapkit.corekit.enum.EnumLookup` is **phase 2** of
`#877 <https://github.com/JarryShaw/PyPCAPKit/issues/877>`__, and it is **partly
done** rather than pending: the phase landed for 17 of the 24 non-registry
enumerations. **Seven are still outside the hierarchy**, measured by a runtime
walk over both the :mod:`enum` and :mod:`aenum` flavours: ``CommandType`` and
``ConformanceRequirement`` in :mod:`pcapkit.const.ftp.command`, ``ESPStatus`` in
:mod:`pcapkit.protocols.internet.esp`, and all four
:mod:`pcapkit.protocols.internet.mh` helpers
(``FastBindingAcknowledgmentStatus``, ``IPv6AddressPrefixCode``,
``LMAAddressCode``, ``LocalizedRoutingStatus``). Each sat in a file another pull
request held open while phase 2 ran, which is the whole reason the phase was split
in two: phase 1 is behaviour-preserving on its own, so it could land while work
was still in flight on the files a re-parent touches. Do not read the seven as a
ruling against re-parenting them -- they are the remainder of a phase, not an
exception to it.
Re-parenting every non-registry enumeration onto
:class:`~pcapkit.corekit.enum.EnumLookup` was **phase 2** of
`#877 <https://github.com/JarryShaw/PyPCAPKit/issues/877>`__, and it is now
**complete**: the phase landed for 24 of the 24 non-registry enumerations.
**Zero enumerations remain outside the hierarchy**, measured by the same runtime
walk over both the :mod:`enum` and :mod:`aenum` flavours that once found seven.

It landed in two pull requests rather than one. Seven of the 24 sat in files
other pull requests were editing around the same time: ``CommandType`` and
``ConformanceRequirement`` in :mod:`pcapkit.const.ftp.command` and its vendor
template, both touched by `#913 <https://github.com/JarryShaw/PyPCAPKit/pull/913>`__;
and ``ESPStatus`` in :mod:`pcapkit.protocols.internet.esp` plus all four
:mod:`pcapkit.protocols.internet.mh` helpers (``FastBindingAcknowledgmentStatus``,
``IPv6AddressPrefixCode``, ``LMAAddressCode``, ``LocalizedRoutingStatus``), both
files touched by `#924 <https://github.com/JarryShaw/PyPCAPKit/pull/924>`__. The
first pass (`#921 <https://github.com/JarryShaw/PyPCAPKit/pull/921>`__) is
behaviour-preserving on its own, so the other 17 could land without waiting on
those files; the remaining seven followed once both had merged
(`#930 <https://github.com/JarryShaw/PyPCAPKit/issues/930>`__).

What a Failed Lookup Raises
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -676,11 +679,13 @@ wider than a case fix:
specification's own tokens -- the measured spelling disagreement above would make
these two case-insensitive. Nothing looks them up by string today, though: the
crawler translates the CSV's lower-case letters to the upper-case member names at
generation time, and neither class inherits
:class:`~pcapkit.corekit.enum.EnumLookup` yet -- both are in the seven phase 2 has
not reached, per the note above. Re-parenting them is phase 2 of
`#877 <https://github.com/JarryShaw/PyPCAPKit/issues/877>`__, which is where the
question belongs.
generation time. Both classes now inherit
:class:`~pcapkit.corekit.enum.EnumLookup` --
`#930 <https://github.com/JarryShaw/PyPCAPKit/issues/930>`__ finished re-parenting
them, per the note above -- so a ``get`` exists on each, case-sensitive like the
base's own. Whether to fold case to match ``TransportProtocol``'s own override is a
design question for whoever writes the first string-keyed caller, not one this
audit settles.

One case fold also lives **outside** any ``get``, and so escapes this convention
entirely: ``_resolve`` in :mod:`pcapkit.protocols.internet.esp` upper-cases its
Expand Down
26 changes: 21 additions & 5 deletions pcapkit/const/ftp/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

from aenum import IntEnum, IntFlag, StrEnum, auto

from pcapkit.corekit.enum import NO_DEFAULT, EnumRegistry
from pcapkit.corekit.enum import NO_DEFAULT, EnumLookup, EnumRegistry

if TYPE_CHECKING:
from typing import Any, Optional, Type
Expand Down Expand Up @@ -183,8 +183,17 @@ def _missing_(cls, value: 'str') -> 'FEATCode':
return cls._unregistered_member(value, value.upper())


class CommandType(IntFlag):
"""Type of "kind" of command, based on :rfc:`959#section-4.1`."""
class CommandType(EnumLookup, IntFlag):
"""Type of "kind" of command, based on :rfc:`959#section-4.1`.

Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub
issue #930, finishing #877's phase 2. Pure re-parenting as far as
``get``/``get_all`` are concerned -- this class defines no ``get`` of its
own to reconcile with the base -- and its own :meth:`_missing_` range
guard below is untouched, since :class:`EnumLookup` does not touch that
hook.

"""

undefined = 0

Expand All @@ -208,8 +217,15 @@ def _missing_(cls, value: 'int') -> 'CommandType':
return super()._missing_(value)


class ConformanceRequirement(IntEnum):
"""Expectation for support in modern FTP implementations."""
class ConformanceRequirement(EnumLookup, IntEnum):
"""Expectation for support in modern FTP implementations.

Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub
issue #930, finishing #877's phase 2 -- pure re-parenting, since this
class defines neither ``get`` nor ``_missing_`` of its own to reconcile
with the base.

"""

#: Mandatory to implement.
M = auto()
Expand Down
12 changes: 8 additions & 4 deletions pcapkit/corekit/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,14 @@

.. note::

Re-parenting the remaining helper enumerations onto :class:`EnumLookup` is
**phase 2** of GitHub issue #877 and has not happened yet: introducing the
base is deliberately behaviour-preserving on its own, so that it could land
while other work was still in flight on the files the re-parent touches.
Re-parenting every non-registry enumeration onto :class:`EnumLookup` was
**phase 2** of GitHub issue #877, and it is now **complete**: introducing
the base above was deliberately behaviour-preserving on its own, so that it
could land while other work was still in flight on the files the re-parent
touches, and the phase itself landed in two pull requests for exactly that
reason -- #921 for the 17 enumerations that were free to move at once, and
`#930 <https://github.com/JarryShaw/PyPCAPKit/issues/930>`__ for the
remaining seven once the files holding them freed up.

The registry tier's own shape is the earlier ruling on GitHub issue #842,
verbatim: *"to finalise the abstraction idea, get/get_all/register/register_alias
Expand Down
12 changes: 10 additions & 2 deletions pcapkit/protocols/internet/esp.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@
from pcapkit.const.esp.integrity import Integrity
from pcapkit.const.reg.transtype import TransType as Enum_TransType
from pcapkit.corekit.context import ProtocolContext
from pcapkit.corekit.enum import EnumLookup
from pcapkit.corekit.infoclass import Info, info_final
from pcapkit.protocols.data.internet.esp import ESP as Data_ESP
from pcapkit.protocols.internet.ipsec import IPsec
Expand Down Expand Up @@ -454,8 +455,15 @@ def get(cls, value: 'Integrity | str | int') -> 'IntegritySuite':
##############################################################################


class ESPStatus(enum.IntEnum):
"""Outcome of ESP payload processing."""
class ESPStatus(EnumLookup, enum.IntEnum):
"""Outcome of ESP payload processing.

Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub
issue #930, finishing #877's phase 2 -- pure re-parenting, since this
class defines neither ``get`` nor ``_missing_`` of its own to reconcile
with the base.

"""

#: The payload was decrypted and its trailer recovered.
DECRYPTED = 0
Expand Down
119 changes: 107 additions & 12 deletions pcapkit/protocols/internet/mh.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
UpdateNotificationACKStatus as Enum_UpdateNotificationACKStatus
from pcapkit.const.mh.upn_reason import UpdateNotificationReason as Enum_UpdateNotificationReason
from pcapkit.const.reg.transtype import TransType as Enum_TransType
from pcapkit.corekit.enum import EnumLookup
from pcapkit.corekit.fields.ipaddress import parse_ip_address
from pcapkit.corekit.multidict import OrderedMultiDict
from pcapkit.protocols.data.internet.mh import MH as Data_MH
Expand Down Expand Up @@ -565,7 +566,7 @@ class PMIPv6Timestamp(collections.namedtuple('PMIPv6Timestamp', 'seconds fractio
fraction: int


class FastBindingAcknowledgmentStatus(IntEnum):
class FastBindingAcknowledgmentStatus(EnumLookup, IntEnum):
"""[FastBindingAcknowledgmentStatus] Fast Binding Acknowledgment Status Codes.

Status values of the fast binding acknowledgment (FBack) message, c.f.,
Expand All @@ -574,6 +575,23 @@ class FastBindingAcknowledgmentStatus(IntEnum):
above that it was rejected.

Note:
Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub
issue #930, finishing #877's phase 2. :meth:`get` and
:meth:`_missing_` below are untouched -- #923 already converted
:meth:`get`'s own name-miss to the in-library
:exc:`~pcapkit.utilities.exceptions.EnumKeyError`, which is exactly
the shape the base's own ``get`` uses, so there is nothing to
reconcile. Unlike :meth:`~pcapkit.const.reg.apptype.apptype.
TransportProtocol.get` and :meth:`~pcapkit.protocols.application.
ngap.Criticality.get` in GitHub issue #921, :meth:`get` keeps its
``@staticmethod`` decorator rather than becoming a delegating
``classmethod`` -- it never calls ``super().get(...)``, so the
:exc:`RuntimeError` trap a ``staticmethod`` delegating to a
``classmethod`` base would hit does not apply here, and the
resulting ``mypy`` ``[override]`` complaint about the signature
mismatch (no ``cls``, no ``default``) is silenced rather than
resolved by widening the signature.

:rfc:`5568#section-6.2.3` defines these values inline and IANA keeps no
registry of them, so the enumeration lives here rather than in
:mod:`pcapkit.const.mh`. It is also **not** interchangeable with the
Expand Down Expand Up @@ -624,9 +642,27 @@ class FastBindingAcknowledgmentStatus(IntEnum):
Incorrect_interface_identifier_length = 131

@staticmethod
def get(key: 'int | str') -> 'FastBindingAcknowledgmentStatus':
def get( # type: ignore[override] # pylint: disable=arguments-differ
key: 'int | str') -> 'FastBindingAcknowledgmentStatus':
"""Backport support for original codes.

Raises quietly on a name miss, matching the base's own
:meth:`~pcapkit.corekit.enum.EnumLookup.get`
(:mod:`pcapkit.corekit.enum`, the ``EnumKeyError`` raised at its
``str`` branch) rather than diverging from it. This override used
to raise loud instead -- logging once at :data:`logging.CRITICAL`
and setting :data:`sys.tracebacklimit` to ``0`` process-wide --
until GitHub issue #930 converged it onto house convention,
settled on GitHub issue #933's follow-up ruling, verbatim: *"Oh
wait. I meant, they should follow house convention and not to be
loud."* Re-parenting onto
:class:`~pcapkit.corekit.enum.EnumLookup` is what makes the
convergence reach further than this one method: :meth:`get_all
<pcapkit.corekit.enum.EnumLookup.get_all>` did not exist on this
class before #930 and is now inherited from the base, which calls
this ``get`` internally -- so a name miss reached through
``get_all`` is quiet too, for the same reason.

Args:
key: Key to get enum item.

Expand Down Expand Up @@ -657,7 +693,8 @@ def get(key: 'int | str') -> 'FastBindingAcknowledgmentStatus':
return FastBindingAcknowledgmentStatus[key] # type: ignore[misc]
except KeyError:
raise EnumKeyError('%r is not a valid %s' %
(key, FastBindingAcknowledgmentStatus.__name__)) from None
(key, FastBindingAcknowledgmentStatus.__name__),
quiet=True) from None

@classmethod
def _missing_(cls, value: 'int') -> 'NoReturn':
Expand All @@ -676,14 +713,31 @@ def _missing_(cls, value: 'int') -> 'NoReturn':
raise EnumValueError('%r is not a valid %s' % (value, cls.__name__))


class IPv6AddressPrefixCode(IntEnum):
class IPv6AddressPrefixCode(EnumLookup, IntEnum):
"""[IPv6AddressPrefixCode] Mobility Header IPv6 Address/Prefix Option Codes.

Option codes of the mobility header IPv6 address/prefix option, which
identify which address the option carries, c.f.,
:rfc:`5568#section-6.4.2`.

Note:
Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub
issue #930, finishing #877's phase 2. :meth:`get` and
:meth:`_missing_` below are untouched -- #923 already converted
:meth:`get`'s own name-miss to the in-library
:exc:`~pcapkit.utilities.exceptions.EnumKeyError`, which is exactly
the shape the base's own ``get`` uses, so there is nothing to
reconcile. Unlike :meth:`~pcapkit.const.reg.apptype.apptype.
TransportProtocol.get` and :meth:`~pcapkit.protocols.application.
ngap.Criticality.get` in GitHub issue #921, :meth:`get` keeps its
``@staticmethod`` decorator rather than becoming a delegating
``classmethod`` -- it never calls ``super().get(...)``, so the
:exc:`RuntimeError` trap a ``staticmethod`` delegating to a
``classmethod`` base would hit does not apply here, and the
resulting ``mypy`` ``[override]`` complaint about the signature
mismatch (no ``cls``, no ``default``) is silenced rather than
resolved by widening the signature.

:rfc:`5568#section-6.4.2` defines these values inline and IANA keeps no
registry of them, so the enumeration lives here rather than in
:mod:`pcapkit.const.mh`. The identical code space of the neighbor
Expand Down Expand Up @@ -725,9 +779,27 @@ class IPv6AddressPrefixCode(IntEnum):
NAR_Prefix = 4

@staticmethod
def get(key: 'int | str') -> 'IPv6AddressPrefixCode':
def get( # type: ignore[override] # pylint: disable=arguments-differ
key: 'int | str') -> 'IPv6AddressPrefixCode':
"""Backport support for original codes.

Raises quietly on a name miss, matching the base's own
:meth:`~pcapkit.corekit.enum.EnumLookup.get`
(:mod:`pcapkit.corekit.enum`, the ``EnumKeyError`` raised at its
``str`` branch) rather than diverging from it. This override used
to raise loud instead -- logging once at :data:`logging.CRITICAL`
and setting :data:`sys.tracebacklimit` to ``0`` process-wide --
until GitHub issue #930 converged it onto house convention,
settled on GitHub issue #933's follow-up ruling, verbatim: *"Oh
wait. I meant, they should follow house convention and not to be
loud."* Re-parenting onto
:class:`~pcapkit.corekit.enum.EnumLookup` is what makes the
convergence reach further than this one method: :meth:`get_all
<pcapkit.corekit.enum.EnumLookup.get_all>` did not exist on this
class before #930 and is now inherited from the base, which calls
this ``get`` internally -- so a name miss reached through
``get_all`` is quiet too, for the same reason.

Args:
key: Key to get enum item.

Expand Down Expand Up @@ -758,7 +830,8 @@ def get(key: 'int | str') -> 'IPv6AddressPrefixCode':
return IPv6AddressPrefixCode[key] # type: ignore[misc]
except KeyError:
raise EnumKeyError('%r is not a valid %s' %
(key, IPv6AddressPrefixCode.__name__)) from None
(key, IPv6AddressPrefixCode.__name__),
quiet=True) from None

@classmethod
def _missing_(cls, value: 'int') -> 'NoReturn':
Expand All @@ -777,14 +850,21 @@ def _missing_(cls, value: 'int') -> 'NoReturn':
raise EnumValueError('%r is not a valid %s' % (value, cls.__name__))


class LocalizedRoutingStatus(IntEnum):
class LocalizedRoutingStatus(EnumLookup, IntEnum):
"""[LocalizedRoutingStatus] Localized Routing Acknowledgment Status Codes.

Status values of the localized routing acknowledgment (LRA) message, c.f.,
:rfc:`6705#section-10.2`. Values below ``128`` indicate that the initiation
was processed successfully, values of ``128`` and above that it was rejected.

Note:
Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub
issue #930, finishing #877's phase 2 -- pure re-parenting as far as
``get``/``get_all`` are concerned, since this class defines no
``get`` of its own to reconcile with the base; its own
:meth:`_missing_` below is untouched, since :class:`EnumLookup` does
not touch that hook.

:rfc:`6705#section-10.2` defines these values inline and IANA keeps no
registry of them -- neither a dedicated one nor entries in the general
*Status Codes* registry -- so the enumeration lives here rather than in
Expand All @@ -811,11 +891,15 @@ class LocalizedRoutingStatus(IntEnum):
naming merely an unassigned byte is simply a more likely way to
reach it. See GitHub issue #880.

There is no ``get()`` backport here, unlike
There is no hand-rolled ``get()`` backport here, unlike
:class:`FastBindingAcknowledgmentStatus` and
:class:`IPv6AddressPrefixCode`: it had zero callers repo-wide -- tests
included -- so GitHub issue #880 deleted it outright rather than
rebuilding it on the immutable contract.
rebuilding it on the immutable contract. GitHub issue #930's
re-parenting above gives this class ``get``/``get_all`` again, but as
the base's own bare lookup rather than a bespoke override -- it still
cannot mint, so an unassigned value raises through ``get`` exactly as
it does through the bare constructor.

"""

Expand Down Expand Up @@ -845,13 +929,20 @@ def _missing_(cls, value: 'int') -> 'NoReturn':
raise EnumValueError('%r is not a valid %s' % (value, cls.__name__))


class LMAAddressCode(IntEnum):
class LMAAddressCode(EnumLookup, IntEnum):
"""[LMAAddressCode] Local Mobility Anchor Address Option Codes.

Option codes of the local mobility anchor address option, which say which
address family the option carries, c.f., :rfc:`5949#section-6.2.2`.

Note:
Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub
issue #930, finishing #877's phase 2 -- pure re-parenting as far as
``get``/``get_all`` are concerned, since this class defines no
``get`` of its own to reconcile with the base; its own
:meth:`_missing_` below is untouched, since :class:`EnumLookup` does
not touch that hook.

:rfc:`5949#section-6.2.2` defines these values inline and IANA keeps no
registry of them, so the enumeration lives here rather than in
:mod:`pcapkit.const.mh`.
Expand All @@ -875,11 +966,15 @@ class LMAAddressCode(IntEnum):
naming merely an unassigned byte is simply a more likely way to
reach it. See GitHub issue #880.

There is no ``get()`` backport here, unlike
There is no hand-rolled ``get()`` backport here, unlike
:class:`FastBindingAcknowledgmentStatus` and
:class:`IPv6AddressPrefixCode`: it had zero callers repo-wide -- tests
included -- so GitHub issue #880 deleted it outright rather than
rebuilding it on the immutable contract.
rebuilding it on the immutable contract. GitHub issue #930's
re-parenting above gives this class ``get``/``get_all`` again, but as
the base's own bare lookup rather than a bespoke override -- it still
cannot mint, so an unassigned value raises through ``get`` exactly as
it does through the bare constructor.

"""

Expand Down
Loading
Loading