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
38 changes: 17 additions & 21 deletions pcapkit/const/ftp/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class FEATCode(EnumRegistry, StrEnum):
turns up on the wire but names none of these -- the extendability the
owner conditionally asked to keep on GitHub issue :issue:`860`: unsure what a
FEAT value absent from the RFC's list means in the CSV table, the owner
said that if the expected handling is our current approach, as industry
said that if the expected handling is this registry's approach, as industry
convention has it, the registry stays extendable as is, and then approved
declaring the registry's keywords as real members with ``_missing_``
still covering the rest. No custom ``__new__`` here, so the base's
Expand Down Expand Up @@ -120,7 +120,7 @@ def get(cls, key: 'Any', default: 'Any' = NO_DEFAULT) -> 'FEATCode':
recommendation, while some of this registry's codes are registered in
lower case -- measured on the IANA CSV: ``base``, ``feat``, ``hist``,
``nat6`` and ``secu``, against all-upper-case keywords for the rest,
with none mixed. Without this override ``get('BASE')`` raised
with none mixed. Without this override ``get('BASE')`` raises
:exc:`KeyError`, which is the defect GitHub issue :issue:`903`'s audit found.

The obvious objection, answered: :rfc:`5797` uses case *presentationally*
Expand All @@ -141,9 +141,9 @@ def get(cls, key: 'Any', default: 'Any' = NO_DEFAULT) -> 'FEATCode':
own precedence -- name before value -- and its non-minting ``str``
path both survive: nothing here calls ``cls(key)``, so a key matching
no member, folded or not, still raises rather than growing the
registry. ``get('ZZ-NOT-REAL')`` therefore still raises
:exc:`KeyError` while ``FEATCode('ZZ-NOT-REAL')`` still yields an
unregistered member, exactly as before.
registry. ``get('ZZ-NOT-REAL')`` therefore raises
:exc:`KeyError` while ``FEATCode('ZZ-NOT-REAL')`` yields an
unregistered member.

Args:
key: Name or value to look up. A non-``str`` key is passed
Expand Down Expand Up @@ -214,12 +214,11 @@ def _missing_(cls, value: 'str') -> 'FEATCode':
class CommandType(EnumLookup, IntFlag):
"""Type of "kind" of command, based on :rfc:`959#section-4`.

Re-parented onto :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub
issue :issue:`930`, finishing :issue:`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:`~pcapkit.corekit.enum.EnumLookup` does not touch that
hook.
Built on :class:`~pcapkit.corekit.enum.EnumLookup` per GitHub issue
:issue:`930`, which finished :issue:`877`'s phase 2. This class defines no
``get`` of its own, so ``get``/``get_all`` are the base's, and its own
:meth:`_missing_` range guard below stands as written, since
:class:`~pcapkit.corekit.enum.EnumLookup` does not touch that hook.

"""

Expand Down Expand Up @@ -248,10 +247,9 @@ def _missing_(cls, value: 'int') -> 'CommandType':
class ConformanceRequirement(EnumLookup, IntEnum):
"""Expectation for support in modern FTP implementations.

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

"""

Expand Down Expand Up @@ -611,23 +609,21 @@ def get(cls, key: 'str', default: 'Optional[str]' = None) -> 'Command':
"""
if not isinstance(key, str):
# NOTE: unreachable only by the ``str`` annotation, which a caller
# at run time need not honour -- this is the path GitHub issue
# #1824 fixed.
# at run time need not honour (GitHub issue #1824).
return super().get(key) # type: ignore[unreachable]
name = key.upper()
if name not in cls._member_map_: # pylint: disable=no-member
# NOTE: the value is ``default`` if the caller supplied one, or
# else ``key`` exactly as given -- never ``name`` -- so an
# unregistered member's value is the caller's own casing, the
# same convention :meth:`_unregistered_member` documents and
# :class:`~pcapkit.const.ftp.command.FEATCode` already followed
# :class:`~pcapkit.const.ftp.command.FEATCode` follows
# unchanged. Two calls naming the same command in different
# case, e.g. ``get('xyzw')`` and ``get('XYZW')``, therefore build
# results that are *not* equal -- each is exactly what its own
# caller passed. Minting instead returned, through the
# caller passed. Minting instead would return, through the
# ``_member_map_`` cache, the *first* casing seen for every later
# call regardless of case; that is the one observable behaviour
# change in GitHub issue #860's conversion.
# call regardless of case (GitHub issue #860).
return cls._unregistered_member(default if default is not None else key, name)
return cls._member_map_[name] # pylint: disable=no-member

Expand Down
4 changes: 2 additions & 2 deletions pcapkit/const/http/method.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,13 @@ def get(cls, key: 'str', default: 'Optional[str]' = None) -> 'Method':
# else ``key`` exactly as given -- never its upper-cased form --
# so an unregistered member's value is the caller's own casing,
# the same convention :meth:`_unregistered_member` documents and
# :class:`~pcapkit.const.ftp.command.FEATCode` already followed.
# :class:`~pcapkit.const.ftp.command.FEATCode` follows.
# The name is always the canonical upper-case form, matching
# :meth:`_missing_` and every registered member's own name. Two
# calls naming the same method in different case, e.g.
# ``get('frob')`` and ``get('FROB')``, therefore build results
# that are *not* equal -- each is exactly what its own caller
# passed, per GitHub issue #860's conversion away from minting.
# passed, since ``get`` does not mint (GitHub issue #860).
return cls._unregistered_member(default if default is not None else key, key.upper())

@classmethod
Expand Down
11 changes: 6 additions & 5 deletions pcapkit/const/reg/apptype/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,19 @@

#: Registries imported on first use rather than with this package, as submodule
#: name to class name -- GitHub issue :issue:`1538`. Generated from IANA's
#: registry, the two hold about 49,700 lines of members and were about 30% of
#: ``import pcapkit``, while SCTP's and DCCP's cost a few milliseconds and stay
#: eager.
#: registry, the two hold about 49,700 lines of members, about 30% of
#: ``import pcapkit`` when imported eagerly, while SCTP's and DCCP's cost a few
#: milliseconds and stay eager.
_LAZY = {'tcp': 'TCP', 'udp': 'UDP'}


class _Registries(dict):
""":attr:`AppType.__registries__ <pcapkit.const.reg.apptype.apptype.AppType.__registries__>`,
importing a lazy registry the first time its value is read.

Every key is present from the start, in the order the eager imports used to
insert them, so :func:`len`, ``in`` and iteration import nothing. A lazy
Every key is present from the start, in the order
:class:`~pcapkit.const.reg.apptype.apptype.TransportProtocol` declares them,
so :func:`len`, ``in`` and iteration import nothing. A lazy
registry's value is a :class:`~pcapkit.corekit.module.ModuleDescriptor`
until the first read replaces it with the class. Every way of reading a
value is overridden, :meth:`__iter__` included: overriding it is what makes
Expand Down
Loading
Loading