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
17 changes: 17 additions & 0 deletions docs/source/contributing/conventions/registry-protocol.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,23 @@ generated registries spell by hand in ``_missing_``:
if not (isinstance(value, int) and 0 <= value <= 0xFF):
raise EnumValueError(f'{value!r} is not a valid {cls.__name__}')

**Every registry overrides it**, so that ``register`` refuses what ``get`` refuses
(:issue:`1816`). Each vendor generator emits the override from the check it already
writes at the top of ``_missing_``, with the same message. That is the ``FLAG`` of most
crawlers, but a bespoke template's own range where its ``_missing_`` checks something
else: ``0``-``999`` for :class:`~pcapkit.const.http.status_code.StatusCode` and
:class:`~pcapkit.const.ftp.return_code.ReturnCode`, and :class:`str` for the
string-valued registries.
:class:`~pcapkit.const.pcapng.tls_key_label.TLSKeyLabel` and
:class:`~pcapkit.const.ipv6.extension_header.ExtensionHeader` have no ``_missing_`` to
copy from, because their constructor refuses every value no member carries, so the
first checks its member type and the second the 8-bit Next Header field the type is
sent in. The ``AppType`` transports inherit ``AppType``'s own.

The check is the *range*, not everything ``_missing_`` decides. A value inside the range
that matches neither a member nor an unassigned range -- ``CauseCode(0)``, say -- still
fails to resolve through ``get``, and ``register`` may mint it.

Three things about it are easy to get wrong:

* **It guards, it does not convert.** The return type is :obj:`None` deliberately, so
Expand Down
28 changes: 28 additions & 0 deletions pcapkit/const/arp/hardware.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@

"""

from typing import TYPE_CHECKING

from aenum import IntEnum

from pcapkit.corekit.enum import EnumRegistry
from pcapkit.utilities.exceptions import EnumValueError

if TYPE_CHECKING:
from typing import Any

__all__ = ['Hardware']

Expand Down Expand Up @@ -148,6 +154,28 @@ class Hardware(EnumRegistry, IntEnum):
#: Reserved [:rfc:`5494`]
Reserved_65535 = 65535

@classmethod
def _validate_value(cls, value: 'Any') -> 'None':
"""Reject ``value`` unless it passes the range check :meth:`_missing_` makes.

Overrides :meth:`~pcapkit.corekit.enum.EnumLookup._validate_value`
with that check and the message it raises, so
:meth:`~pcapkit.corekit.enum.EnumRegistry.register` refuses exactly the
values :meth:`~pcapkit.corekit.enum.EnumLookup.get` refuses, in the
same words (:issue:`1816`).

Args:
value: Value about to be looked up or minted.

Raises:
EnumValueError: If ``value`` fails that check. A
:exc:`ValueError`, so an ``except ValueError`` caller is
unaffected.

"""
if not (isinstance(value, int) and 0 <= value <= 65535):
raise EnumValueError('%r is not a valid %s' % (value, cls.__name__))

@classmethod
def _missing_(cls, value: 'int') -> 'Hardware':
"""Lookup function used when value is not found.
Expand Down
28 changes: 28 additions & 0 deletions pcapkit/const/arp/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@

"""

from typing import TYPE_CHECKING

from aenum import IntEnum

from pcapkit.corekit.enum import EnumRegistry
from pcapkit.utilities.exceptions import EnumValueError

if TYPE_CHECKING:
from typing import Any

__all__ = ['Operation']

Expand Down Expand Up @@ -101,6 +107,28 @@ class Operation(EnumRegistry, IntEnum):
#: Reserved [:rfc:`5494`]
Reserved_65535 = 65535

@classmethod
def _validate_value(cls, value: 'Any') -> 'None':
"""Reject ``value`` unless it passes the range check :meth:`_missing_` makes.

Overrides :meth:`~pcapkit.corekit.enum.EnumLookup._validate_value`
with that check and the message it raises, so
:meth:`~pcapkit.corekit.enum.EnumRegistry.register` refuses exactly the
values :meth:`~pcapkit.corekit.enum.EnumLookup.get` refuses, in the
same words (:issue:`1816`).

Args:
value: Value about to be looked up or minted.

Raises:
EnumValueError: If ``value`` fails that check. A
:exc:`ValueError`, so an ``except ValueError`` caller is
unaffected.

"""
if not (isinstance(value, int) and 0 <= value <= 65535):
raise EnumValueError('%r is not a valid %s' % (value, cls.__name__))

@classmethod
def _missing_(cls, value: 'int') -> 'Operation':
"""Lookup function used when value is not found.
Expand Down
28 changes: 28 additions & 0 deletions pcapkit/const/esp/cipher.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@

"""

from typing import TYPE_CHECKING

from aenum import IntEnum

from pcapkit.corekit.enum import EnumRegistry
from pcapkit.utilities.exceptions import EnumValueError

if TYPE_CHECKING:
from typing import Any

__all__ = ['Cipher']

Expand Down Expand Up @@ -218,6 +224,28 @@ class Cipher(EnumRegistry, IntEnum):
#: Alias of :attr:`Cipher.ENCR_MAGMA_MGM_MAC_KTREE`.
MAGMA_MGM_MAC_KTREE = 35

@classmethod
def _validate_value(cls, value: 'Any') -> 'None':
"""Reject ``value`` unless it passes the range check :meth:`_missing_` makes.

Overrides :meth:`~pcapkit.corekit.enum.EnumLookup._validate_value`
with that check and the message it raises, so
:meth:`~pcapkit.corekit.enum.EnumRegistry.register` refuses exactly the
values :meth:`~pcapkit.corekit.enum.EnumLookup.get` refuses, in the
same words (:issue:`1816`).

Args:
value: Value about to be looked up or minted.

Raises:
EnumValueError: If ``value`` fails that check. A
:exc:`ValueError`, so an ``except ValueError`` caller is
unaffected.

"""
if not (isinstance(value, int) and 0 <= value <= 65535):
raise EnumValueError('%r is not a valid %s' % (value, cls.__name__))

@classmethod
def _missing_(cls, value: 'int') -> 'Cipher':
"""Lookup function used when value is not found.
Expand Down
28 changes: 28 additions & 0 deletions pcapkit/const/esp/integrity.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@

"""

from typing import TYPE_CHECKING

from aenum import IntEnum

from pcapkit.corekit.enum import EnumRegistry
from pcapkit.utilities.exceptions import EnumValueError

if TYPE_CHECKING:
from typing import Any

__all__ = ['Integrity']

Expand Down Expand Up @@ -107,6 +113,28 @@ class Integrity(EnumRegistry, IntEnum):
#: Alias of :attr:`Integrity.AUTH_HMAC_SHA2_512_256`.
HMAC_SHA2_512_256 = 14

@classmethod
def _validate_value(cls, value: 'Any') -> 'None':
"""Reject ``value`` unless it passes the range check :meth:`_missing_` makes.

Overrides :meth:`~pcapkit.corekit.enum.EnumLookup._validate_value`
with that check and the message it raises, so
:meth:`~pcapkit.corekit.enum.EnumRegistry.register` refuses exactly the
values :meth:`~pcapkit.corekit.enum.EnumLookup.get` refuses, in the
same words (:issue:`1816`).

Args:
value: Value about to be looked up or minted.

Raises:
EnumValueError: If ``value`` fails that check. A
:exc:`ValueError`, so an ``except ValueError`` caller is
unaffected.

"""
if not (isinstance(value, int) and 0 <= value <= 65535):
raise EnumValueError('%r is not a valid %s' % (value, cls.__name__))

@classmethod
def _missing_(cls, value: 'int') -> 'Integrity':
"""Lookup function used when value is not found.
Expand Down
45 changes: 45 additions & 0 deletions pcapkit/const/ftp/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from pcapkit.corekit.enum import EnumLookup, EnumRegistry
from pcapkit.corekit.sentinels import NO_DEFAULT
from pcapkit.utilities.exceptions import EnumValueError

if TYPE_CHECKING:
from typing import Any, Optional, Type
Expand Down Expand Up @@ -175,6 +176,28 @@ def get(cls, key: 'Any', default: 'Any' = NO_DEFAULT) -> 'FEATCode':
return member
return super().get(key, default)

@classmethod
def _validate_value(cls, value: 'Any') -> 'None':
"""Reject ``value`` unless it is a :class:`str`, as :meth:`_missing_` does.

Overrides :meth:`~pcapkit.corekit.enum.EnumLookup._validate_value`
with the check :meth:`_missing_` makes, and the message it raises, so
:meth:`~pcapkit.corekit.enum.EnumRegistry.register` refuses exactly the
values :meth:`get` refuses, in the same words (:issue:`1816`). Any
:class:`str` passes, since :meth:`_missing_` resolves every one.

Args:
value: Value about to be looked up or minted.

Raises:
EnumValueError: If ``value`` is not a :class:`str`. A
:exc:`ValueError`, so an ``except ValueError`` caller is
unaffected.

"""
if not isinstance(value, str):
raise EnumValueError(f'{value!r} is not a valid {cls.__name__}')

@classmethod
def _missing_(cls, value: 'str') -> 'FEATCode':
"""Lookup function used when value is not found.
Expand Down Expand Up @@ -575,6 +598,28 @@ def get(key: 'str', default: 'Optional[str]' = None) -> 'Command':
return Command._unregistered_member(default if default is not None else key, name)
return Command[name] # type: ignore[misc]

@classmethod
def _validate_value(cls, value: 'Any') -> 'None':
"""Reject ``value`` unless it is a :class:`str`, as :meth:`_missing_` does.

Overrides :meth:`~pcapkit.corekit.enum.EnumLookup._validate_value`
with the check :meth:`_missing_` makes, and the message it raises, so
:meth:`register` refuses a value the constructor refuses, in the same
words (:issue:`1816`). Any :class:`str` passes, since
:meth:`_missing_` resolves every one.

Args:
value: Value about to be minted.

Raises:
EnumValueError: If ``value`` is not a :class:`str`. A
:exc:`ValueError`, so an ``except ValueError`` caller is
unaffected.

"""
if not isinstance(value, str):
raise EnumValueError(f'{value!r} is not a valid {cls.__name__}')

@classmethod
def _missing_(cls, value: 'str') -> 'Command':
"""Lookup function used when value is not found.
Expand Down
73 changes: 72 additions & 1 deletion pcapkit/const/ftp/return_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
from aenum import IntEnum

from pcapkit.corekit.enum import EnumRegistry
from pcapkit.utilities.exceptions import EnumValueError

if TYPE_CHECKING:
from typing import Optional, Type
from typing import Any, Optional, Type

__all__ = ['ReturnCode']

Expand All @@ -43,6 +44,29 @@ class ResponseKind(EnumRegistry, IntEnum):
PermanentNegativeCompletion = 5
Protected = 6

@classmethod
def _validate_value(cls, value: 'Any') -> 'None':
"""Reject ``value`` unless it is a digit, which :meth:`_missing_` accepts.

Overrides :meth:`~pcapkit.corekit.enum.EnumLookup._validate_value`
with the range :meth:`_missing_` resolves, and the message the
constructor raises outside it, so
:meth:`~pcapkit.corekit.enum.EnumRegistry.register` refuses exactly the
values :meth:`~pcapkit.corekit.enum.EnumLookup.get` refuses, in the
same words (:issue:`1816`).

Args:
value: Value about to be looked up or minted.

Raises:
EnumValueError: If ``value`` is not an :class:`int` in ``0``-``9``.
A :exc:`ValueError`, so an ``except ValueError`` caller is
unaffected.

"""
if not (isinstance(value, int) and 0 <= value <= 9):
raise EnumValueError('%r is not a valid %s' % (value, cls.__name__))

@classmethod
def _missing_(cls, value: 'int') -> 'ResponseKind':
"""Lookup function used when value is not found.
Expand All @@ -67,6 +91,29 @@ class GroupingInformation(EnumRegistry, IntEnum):
Unspecified = 4
FileSystem = 5

@classmethod
def _validate_value(cls, value: 'Any') -> 'None':
"""Reject ``value`` unless it is a digit, which :meth:`_missing_` accepts.

Overrides :meth:`~pcapkit.corekit.enum.EnumLookup._validate_value`
with the range :meth:`_missing_` resolves, and the message the
constructor raises outside it, so
:meth:`~pcapkit.corekit.enum.EnumRegistry.register` refuses exactly the
values :meth:`~pcapkit.corekit.enum.EnumLookup.get` refuses, in the
same words (:issue:`1816`).

Args:
value: Value about to be looked up or minted.

Raises:
EnumValueError: If ``value`` is not an :class:`int` in ``0``-``9``.
A :exc:`ValueError`, so an ``except ValueError`` caller is
unaffected.

"""
if not (isinstance(value, int) and 0 <= value <= 9):
raise EnumValueError('%r is not a valid %s' % (value, cls.__name__))

@classmethod
def _missing_(cls, value: 'int') -> 'GroupingInformation':
"""Lookup function used when value is not found.
Expand Down Expand Up @@ -308,6 +355,30 @@ def _unregistered_member(cls, value: 'int', name: 'str') -> 'ReturnCode':
obj.group = GroupingInformation(int(code[1]))
return obj

@classmethod
def _validate_value(cls, value: 'Any') -> 'None':
"""Reject ``value`` unless it is a three-digit reply code.

Overrides :meth:`~pcapkit.corekit.enum.EnumLookup._validate_value`
with the range check :meth:`_missing_` makes, and the message it
raises, so :meth:`~pcapkit.corekit.enum.EnumRegistry.register` refuses
exactly the values :meth:`~pcapkit.corekit.enum.EnumLookup.get`
refuses, in the same words (:issue:`1816`). That range is ``0``-``999``
rather than the registry's own, since :meth:`_missing_` resolves a code
outside the registry to ``Unknown`` rather than refusing it.

Args:
value: Value about to be looked up or minted.

Raises:
EnumValueError: If ``value`` is not an :class:`int` in
``0``-``999``. A :exc:`ValueError`, so an ``except ValueError``
caller is unaffected.

"""
if not (isinstance(value, int) and 0 <= value <= 999):
raise EnumValueError('%r is not a valid %s' % (value, cls.__name__))

@classmethod
def _missing_(cls, value: 'int') -> 'ReturnCode':
"""Lookup function used when value is not found.
Expand Down
Loading
Loading