From 5b52fc0d2f96cdb9d9ae0e7bed2e18958484cdbc Mon Sep 17 00:00:00 2001 From: Jarry Shaw Date: Thu, 15 Oct 2026 11:38:14 -0400 Subject: [PATCH] docs(corekit): version directives and render fixes (#1103) Version directives, all 1.5.0: - versionadded: corekit.enum, .sentinels, .decorators, .fields.byteorder, parse_ip_address, PortEnumField, MultiInfo, OrderedMultiInfo, TLSKeyLabel. - versionchanged: FieldBase.length/unpack, SeekableReader, info_final, Info.to_dict, EnumField.post_process, OptionField.unpack, the ipaddress fields, OrderedMultiDict.deepcopy, and the generated Flags, ExtensionHeader and Method (template and output alike). - versionremoved: SeekableReader.writeable, field.NoValue and utilities.decorators; the beta-only _READ_CHUNK and zero-pad directives go. Rendering: cross-reference targets split across lines are joined, the NO_DEFAULT and AppType targets point at their documented homes, enum.rst and infoclass.rst stop rendering five members twice, and the SMF_DPD bold title no longer nests a literal. Prose: timed context is rewritten in sentinels, numbers, collections, io, the ExtensionHeader crawler and the decorators page. Refs #1103 --- docs/source/pcapkit/const/ipv6.rst | 2 +- docs/source/pcapkit/corekit/decorators.rst | 10 ++-- docs/source/pcapkit/corekit/enum.rst | 12 +++-- .../pcapkit/corekit/fields/byteorder.rst | 5 ++ docs/source/pcapkit/corekit/fields/field.rst | 17 +----- .../pcapkit/corekit/fields/ipaddress.rst | 7 +++ docs/source/pcapkit/corekit/infoclass.rst | 3 -- docs/source/pcapkit/corekit/io.rst | 6 --- docs/source/pcapkit/corekit/multidict.rst | 2 + docs/source/pcapkit/corekit/sentinels.rst | 6 +++ docs/source/pcapkit/vendor/ipv6.rst | 2 +- pcapkit/const/ftp/command.py | 5 +- pcapkit/const/http/method.py | 20 ++++--- pcapkit/const/http/status_code.py | 5 +- pcapkit/const/ipv6/extension_header.py | 9 +++- pcapkit/const/pcapng/tls_key_label.py | 8 ++- pcapkit/const/reg/apptype/apptype.py | 9 ++-- pcapkit/const/tcp/flags.py | 9 +++- pcapkit/corekit/decorators.py | 8 +++ pcapkit/corekit/enum.py | 11 +++- pcapkit/corekit/fields/byteorder.py | 5 ++ pcapkit/corekit/fields/collections.py | 12 +++-- pcapkit/corekit/fields/field.py | 33 ++++++------ pcapkit/corekit/fields/ipaddress.py | 20 ++++++- pcapkit/corekit/fields/numbers.py | 44 ++++++++++------ pcapkit/corekit/infoclass.py | 16 ++++++ pcapkit/corekit/io.py | 28 ++++++---- pcapkit/corekit/multidict.py | 5 ++ pcapkit/corekit/sentinels.py | 16 ++++-- pcapkit/vendor/ftp/command.py | 5 +- pcapkit/vendor/http/method.py | 20 ++++--- pcapkit/vendor/http/status_code.py | 5 +- pcapkit/vendor/ipv6/extension_header.py | 52 +++++++++++-------- pcapkit/vendor/ipv6/smf_dpd_mode.py | 2 +- pcapkit/vendor/ngap/procedure_code.py | 10 ++-- pcapkit/vendor/ngap/protocol_ie.py | 5 +- pcapkit/vendor/pcapng/tls_key_label.py | 8 ++- pcapkit/vendor/reg/apptype/apptype.py | 9 ++-- pcapkit/vendor/tcp/flags.py | 9 +++- 39 files changed, 297 insertions(+), 163 deletions(-) diff --git a/docs/source/pcapkit/const/ipv6.rst b/docs/source/pcapkit/const/ipv6.rst index 972811136a..a029100f37 100644 --- a/docs/source/pcapkit/const/ipv6.rst +++ b/docs/source/pcapkit/const/ipv6.rst @@ -125,7 +125,7 @@ Simplified Multicast Forwarding Duplicate Packet Detection (``SMF_DPD``) Options .. module:: pcapkit.const.ipv6.smf_dpd_mode -This module contains the constant enumeration for **Simplified Multicast Forwarding Duplicate Packet Detection (``SMF_DPD``) Options**, +This module contains the constant enumeration for **Simplified Multicast Forwarding Duplicate Packet Detection (SMF_DPD) Options**, which is automatically generated from :class:`pcapkit.vendor.ipv6.smf_dpd_mode.SMFDPDMode`. .. autoclass:: pcapkit.const.ipv6.smf_dpd_mode.SMFDPDMode diff --git a/docs/source/pcapkit/corekit/decorators.rst b/docs/source/pcapkit/corekit/decorators.rst index 5fceeb4101..2ae71d6904 100644 --- a/docs/source/pcapkit/corekit/decorators.rst +++ b/docs/source/pcapkit/corekit/decorators.rst @@ -8,11 +8,13 @@ decorators, including :func:`~pcapkit.corekit.decorators.seekset`, :func:`~pcapkit.corekit.decorators.beholder` and :func:`~pcapkit.corekit.decorators.prepare`. -.. note:: +.. versionadded:: 1.5.0 - This module was ``pcapkit.utilities.decorators`` until :issue:`1735` moved it - here, and :mod:`pcapkit.utilities` no longer exports the three decorators. - Nothing is left at the old path, so import them from this module. +.. versionremoved:: 1.5.0 + + ``pcapkit.utilities.decorators``, now :mod:`pcapkit.corekit.decorators` + (:issue:`1735`). :mod:`pcapkit.utilities` does not export the three + decorators either. .. autodecorator:: pcapkit.corekit.decorators.seekset diff --git a/docs/source/pcapkit/corekit/enum.rst b/docs/source/pcapkit/corekit/enum.rst index 6f62a69a20..1a220ebb0b 100644 --- a/docs/source/pcapkit/corekit/enum.rst +++ b/docs/source/pcapkit/corekit/enum.rst @@ -8,15 +8,17 @@ library inherits from: :class:`EnumLookup`, the *lookup* half shared by open registries and closed sets alike, and its subclass :class:`EnumRegistry`, which adds the *mutating* half every registry under :mod:`pcapkit.const` inherits. +.. versionadded:: 1.5.0 + + The ``get`` each :mod:`pcapkit.const` enumeration carried as generated text + moves onto :class:`EnumLookup`, and :class:`EnumRegistry` adds ``register``, + which is how a member is minted at runtime: outside ``CGAType``, looking up + an unknown value does not mint one (:issue:`775`). + .. autoclass:: pcapkit.corekit.enum.EnumLookup :members: :show-inheritance: - .. automethod:: _validate_value - .. autoclass:: pcapkit.corekit.enum.EnumRegistry :members: :show-inheritance: - - .. automethod:: _extend - .. automethod:: _unregistered_member diff --git a/docs/source/pcapkit/corekit/fields/byteorder.rst b/docs/source/pcapkit/corekit/fields/byteorder.rst index f926519914..bdb122fa96 100644 --- a/docs/source/pcapkit/corekit/fields/byteorder.rst +++ b/docs/source/pcapkit/corekit/fields/byteorder.rst @@ -8,6 +8,11 @@ a capture file's byte order out of the packet data. It is shared by the PCAP frame header (:mod:`~pcapkit.protocols.schema.misc.pcap.frame`) and the PCAP-NG blocks (:mod:`~pcapkit.protocols.schema.misc.pcapng`). +.. versionadded:: 1.5.0 + + :func:`byteorder_callback` moves here from + :mod:`pcapkit.protocols.schema.misc.pcap.frame` (:issue:`1711`). + Auxiliary Functions ------------------- diff --git a/docs/source/pcapkit/corekit/fields/field.rst b/docs/source/pcapkit/corekit/fields/field.rst index 804785fa16..718e5746e0 100644 --- a/docs/source/pcapkit/corekit/fields/field.rst +++ b/docs/source/pcapkit/corekit/fields/field.rst @@ -3,25 +3,12 @@ Base Fields .. module:: pcapkit.corekit.fields.field -.. versionremoved:: 1.5.0 - - Moved to :mod:`pcapkit.utilities.config` (:issue:`1726`): - - * ``pcapkit.corekit.fields.field._MAX_ZERO_PAD_LENGTH``, now - :data:`pcapkit.utilities.config.MAX_ZERO_PAD_LENGTH`, set with - :envvar:`PCAPKIT_MAX_ZERO_PAD_LENGTH`; - * ``pcapkit.corekit.fields.field._MAX_ZERO_PAD_SHORTFALL``, now - :data:`pcapkit.utilities.config.MAX_ZERO_PAD_SHORTFALL`, set with - :envvar:`PCAPKIT_MAX_ZERO_PAD_SHORTFALL`; - * ``pcapkit.corekit.fields.field._ZERO_PAD_BUDGET_RATIO``, now - :data:`pcapkit.utilities.config.ZERO_PAD_BUDGET_RATIO`, set with - :envvar:`PCAPKIT_ZERO_PAD_BUDGET_RATIO`. - .. versionremoved:: 1.5.0 ``pcapkit.corekit.fields.field.NoValueType``, now :class:`pcapkit.corekit.sentinels.NoValueType` (:issue:`922`, - :issue:`1744`). + :issue:`1744`), and ``pcapkit.corekit.fields.field.NoValue``, now + :data:`pcapkit.corekit.sentinels.NO_VALUE` (:issue:`937`). .. autoclass:: pcapkit.corekit.fields.field.Field :members: diff --git a/docs/source/pcapkit/corekit/fields/ipaddress.rst b/docs/source/pcapkit/corekit/fields/ipaddress.rst index d14d112ebd..04ad0266cb 100644 --- a/docs/source/pcapkit/corekit/fields/ipaddress.rst +++ b/docs/source/pcapkit/corekit/fields/ipaddress.rst @@ -3,6 +3,13 @@ IP Address Fields .. module:: pcapkit.corekit.fields.ipaddress +.. versionchanged:: 1.5.0 + + Every field here rejects a :obj:`bool` with + :exc:`~pcapkit.utilities.exceptions.FieldValueError`, where an IPv4 field + packed :obj:`True` and :obj:`False` as ``0.0.0.1`` and ``0.0.0.0`` + (:issue:`491`). + IP Addresses ~~~~~~~~~~~~ diff --git a/docs/source/pcapkit/corekit/infoclass.rst b/docs/source/pcapkit/corekit/infoclass.rst index 3fc0c7d9c5..9a1ed3ee83 100644 --- a/docs/source/pcapkit/corekit/infoclass.rst +++ b/docs/source/pcapkit/corekit/infoclass.rst @@ -17,9 +17,6 @@ classes :class:`~pcapkit.corekit.infoclass.MultiInfo` and :param \*args: Arbitrary positional arguments. :param \*\*kwargs: Arbitrary keyword arguments. - .. automethod:: __init_subclass__ - .. automethod:: __post_init__ - .. autoattribute:: __additional__ :no-value: .. autoattribute:: __excluded__ diff --git a/docs/source/pcapkit/corekit/io.rst b/docs/source/pcapkit/corekit/io.rst index f4dde51809..7f8c0e26e7 100644 --- a/docs/source/pcapkit/corekit/io.rst +++ b/docs/source/pcapkit/corekit/io.rst @@ -10,12 +10,6 @@ I/O Objects stream, and :class:`~pcapkit.corekit.io.NamedStream`, which gives a stream a ``name``. -.. versionremoved:: 1.5.0 - - ``pcapkit.corekit.io._READ_CHUNK``, now - :data:`pcapkit.utilities.config.READ_CHUNK`, set with - :envvar:`PCAPKIT_READ_CHUNK` (:issue:`1726`). - .. autoclass:: pcapkit.corekit.io.SeekableReader :no-members: :show-inheritance: diff --git a/docs/source/pcapkit/corekit/multidict.rst b/docs/source/pcapkit/corekit/multidict.rst index 67ae8aab10..582be07b8b 100644 --- a/docs/source/pcapkit/corekit/multidict.rst +++ b/docs/source/pcapkit/corekit/multidict.rst @@ -35,6 +35,8 @@ values per key, based on the `Werkzeug`_ project. :no-special-members: __init__ :show-inheritance: + .. automethod:: deepcopy + Type Variables -------------- diff --git a/docs/source/pcapkit/corekit/sentinels.rst b/docs/source/pcapkit/corekit/sentinels.rst index c2fc2f0dcd..fca1f74e19 100644 --- a/docs/source/pcapkit/corekit/sentinels.rst +++ b/docs/source/pcapkit/corekit/sentinels.rst @@ -11,6 +11,12 @@ caller might legitimately pass. All four are defined here, and this is their only import path: the modules that use them do not re-export them (:issue:`1744`). +.. versionadded:: 1.5.0 + + :class:`NoValueType` moves here from :mod:`pcapkit.corekit.fields.field` + (:issue:`911`), and :data:`NO_VALUE` replaces its ``NoValue`` there + (:issue:`937`). + .. autoclass:: pcapkit.corekit.sentinels.NullType .. autodata:: pcapkit.corekit.sentinels.NULL diff --git a/docs/source/pcapkit/vendor/ipv6.rst b/docs/source/pcapkit/vendor/ipv6.rst index 119c38615a..47f75c6057 100644 --- a/docs/source/pcapkit/vendor/ipv6.rst +++ b/docs/source/pcapkit/vendor/ipv6.rst @@ -118,7 +118,7 @@ Simplified Multicast Forwarding Duplicate Packet Detection (``SMF_DPD``) Options .. module:: pcapkit.vendor.ipv6.smf_dpd_mode -This module contains the vendor crawler for **Simplified Multicast Forwarding Duplicate Packet Detection (``SMF_DPD``) Options**, +This module contains the vendor crawler for **Simplified Multicast Forwarding Duplicate Packet Detection (SMF_DPD) Options**, which is automatically generating :class:`pcapkit.const.ipv6.smf_dpd_mode.SMFDPDMode`. .. autoclass:: pcapkit.vendor.ipv6.smf_dpd_mode.SMFDPDMode diff --git a/pcapkit/const/ftp/command.py b/pcapkit/const/ftp/command.py index 97414ffd00..88e978fb7a 100644 --- a/pcapkit/const/ftp/command.py +++ b/pcapkit/const/ftp/command.py @@ -469,8 +469,9 @@ def _unregistered_member(cls, value: 'str', name: 'str') -> 'Command': Leaves :attr:`feat`, :attr:`desc`, :attr:`type` and :attr:`conf` at the same defaults :meth:`__new__` itself would, rather than missing - entirely -- :meth:`~pcapkit.corekit.enum.EnumRegistry. - _unregistered_member` bypasses :meth:`__new__` (it calls + entirely -- + :meth:`~pcapkit.corekit.enum.EnumRegistry._unregistered_member` + bypasses :meth:`__new__` (it calls :class:`str`'s directly), so those four attributes would otherwise be absent and :meth:`__repr__` (which reads :attr:`desc`) would raise on the result. There is no more specific value to reconstruct diff --git a/pcapkit/const/http/method.py b/pcapkit/const/http/method.py index 42528114a8..8d6d4c6159 100644 --- a/pcapkit/const/http/method.py +++ b/pcapkit/const/http/method.py @@ -24,16 +24,14 @@ class Method(EnumRegistry, StrEnum): """[Method] HTTP Method - .. note:: + .. versionchanged:: 1.5.0 - Neither ``_missing_`` nor ``get()`` mints any more. The owner ruled on - GitHub issue :issue:`860` that ``get`` should not mint: only IANA-registered - values are legitimate members, a new one is properly created through - :meth:`register`, and ``get`` is not given enough information to create - one. Concretely true here -- a bare wire method verb carries no - :attr:`safe`/:attr:`idempotent`, so minting one used to register a - permanent member with both hollowed out to their defaults; - :meth:`register` is the path that can actually supply them. + Neither ``_missing_`` nor ``get()`` mints a member, per the owner's + ruling on GitHub issue :issue:`860`: only IANA-registered values are + legitimate members, and a new one is created through :meth:`register`, + which can supply :attr:`safe` and :attr:`idempotent` where a bare wire + method verb carries neither. ``get()`` matches ``key`` case-sensitively, + as :rfc:`9110` makes the method token (:issue:`896`). """ @@ -263,8 +261,8 @@ def get(cls, key: 'str', default: 'Optional[str]' = None) -> 'Method': Args: key: Key to get enum item. Looked up case-**sensitively**, per :rfc:`9110#section-9.1` -- the method token is - case-sensitive, unlike :meth:`~pcapkit.const.ftp.command. - Command.get`'s equivalent override, which stays + case-sensitive, unlike + :meth:`~pcapkit.const.ftp.command.Command.get`'s equivalent override, which stays case-insensitive because :rfc:`959#section-5` says FTP command codes are not. Checked against both member names and values, via the base's own precedence -- name before diff --git a/pcapkit/const/http/status_code.py b/pcapkit/const/http/status_code.py index eff1d1ad7d..8cb122a02a 100644 --- a/pcapkit/const/http/status_code.py +++ b/pcapkit/const/http/status_code.py @@ -253,8 +253,9 @@ def _unregistered_member(cls, value: 'int', name: 'str') -> 'StatusCode': """Build a member absent from this registry's own lookup tables. Reconstructs :attr:`message` the same way :meth:`__new__` would, - rather than leaving it unset -- :meth:`~pcapkit.corekit.enum. - EnumRegistry._unregistered_member` bypasses :meth:`__new__` entirely + rather than leaving it unset -- + :meth:`~pcapkit.corekit.enum.EnumRegistry._unregistered_member` + bypasses :meth:`__new__` entirely (it calls :class:`int`'s directly), so :attr:`message` would otherwise be missing from the result and :meth:`__str__` would raise on it. diff --git a/pcapkit/const/ipv6/extension_header.py b/pcapkit/const/ipv6/extension_header.py index ee954f0709..3c391ae0ee 100644 --- a/pcapkit/const/ipv6/extension_header.py +++ b/pcapkit/const/ipv6/extension_header.py @@ -18,7 +18,14 @@ class ExtensionHeader(EnumRegistry, IntEnum): - """[ExtensionHeader] IPv6 Extension Header Types""" + """[ExtensionHeader] IPv6 Extension Header Types + + .. versionchanged:: 1.5.0 + + Generated from IANA's *IPv6 Extension Header Types* registry, where it + was generated from the protocol-numbers registry (:issue:`925`). + + """ #: HOPOPT, IPv6 Hop-by-Hop Option [:rfc:`8200`] HOPOPT = 0 diff --git a/pcapkit/const/pcapng/tls_key_label.py b/pcapkit/const/pcapng/tls_key_label.py index f4826111ab..50aab2d67b 100644 --- a/pcapkit/const/pcapng/tls_key_label.py +++ b/pcapkit/const/pcapng/tls_key_label.py @@ -18,7 +18,13 @@ class TLSKeyLabel(EnumRegistry, StrEnum): - """[TLSKeyLabel] TLS Key Log Labels""" + """[TLSKeyLabel] TLS Key Log Labels + + .. versionadded:: 1.5.0 + + Moved here from ``pcapkit.protocols.misc.pcapng`` (:issue:`886`). + + """ #: NSS-historical: not a registered label of :rfc:`9850#section-4.2`'s "TLS #: SSLKEYLOGFILE Labels" registry. Defined by the Mozilla NSS diff --git a/pcapkit/const/reg/apptype/apptype.py b/pcapkit/const/reg/apptype/apptype.py index 93df93f727..2e7f12bd7f 100644 --- a/pcapkit/const/reg/apptype/apptype.py +++ b/pcapkit/const/reg/apptype/apptype.py @@ -148,8 +148,8 @@ def get(cls, key: 'int | str', default: 'Any' = NO_DEFAULT) -> 'TransportProtoco Args: key: Key to get enum item. default: An already-registered value to fall back to when - ``key`` resolves to nothing. :data:`~pcapkit.corekit.enum. - NO_DEFAULT`, the default, means *no default* -- see + ``key`` resolves to nothing. + :data:`~pcapkit.corekit.sentinels.NO_DEFAULT`, the default, means *no default* -- see :meth:`~pcapkit.corekit.enum.EnumLookup.get`. Raises: @@ -2905,8 +2905,9 @@ def _unregistered_member(cls, value: 'int', name: 'str', caller-named path that still does. Reconstructs :attr:`svc`, :attr:`port` and :attr:`proto` the same way - :meth:`__new__` would: :meth:`~pcapkit.corekit.enum. - EnumRegistry._unregistered_member` bypasses :meth:`__new__` entirely + :meth:`__new__` would: + :meth:`~pcapkit.corekit.enum.EnumRegistry._unregistered_member` + bypasses :meth:`__new__` entirely (it builds through ``cls._member_type_.__new__`` directly), so this class's own three attributes would otherwise be missing and every method reading them (:meth:`__repr__`, :meth:`__str__`, :meth:`__int__`, diff --git a/pcapkit/const/tcp/flags.py b/pcapkit/const/tcp/flags.py index 80a0957539..7285a760bf 100644 --- a/pcapkit/const/tcp/flags.py +++ b/pcapkit/const/tcp/flags.py @@ -17,7 +17,14 @@ __all__ = ['Flags'] class Flags(EnumRegistry, IntFlag): - """[Flags] TCP Header Flags""" + """[Flags] TCP Header Flags + + .. versionchanged:: 1.5.0 + + A value outside the 16-bit field raises :exc:`ValueError`, where + :mod:`aenum` composed a pseudo-member for any integer. + + """ #: Reserved for future use [:rfc:`9293`] Reserved_4 = 1 << 4 diff --git a/pcapkit/corekit/decorators.py b/pcapkit/corekit/decorators.py index f17b407d76..2ee0662183 100644 --- a/pcapkit/corekit/decorators.py +++ b/pcapkit/corekit/decorators.py @@ -15,6 +15,14 @@ so they live with the packet model rather than in :mod:`pcapkit.utilities` (:issue:`1735`). +.. versionadded:: 1.5.0 + +.. versionremoved:: 1.5.0 + + ``pcapkit.utilities.decorators``, now :mod:`pcapkit.corekit.decorators` + (:issue:`1735`). :mod:`pcapkit.utilities` does not export the three + decorators either. + """ import functools import io diff --git a/pcapkit/corekit/enum.py b/pcapkit/corekit/enum.py index f310a16a33..18488ef5e9 100644 --- a/pcapkit/corekit/enum.py +++ b/pcapkit/corekit/enum.py @@ -86,6 +86,13 @@ guessed; ``register_alias`` (and ``register_aliases``) adds further alias names to a given member's mapping. +.. versionadded:: 1.5.0 + + The ``get`` each :mod:`pcapkit.const` enumeration carried as generated text + moves onto :class:`EnumLookup`, and :class:`EnumRegistry` adds ``register``, + which is how a member is minted at runtime: outside ``CGAType``, looking up + an unknown value does not mint one (:issue:`775`). + """ from typing import TYPE_CHECKING @@ -269,8 +276,8 @@ def get(cls, key: 'Any', default: 'Any' = NO_DEFAULT) -> 'Self': constructor would let a mere ``get()`` call mint a permanent member where it should just raise. Defensive rather than observed: none of the ``str``-valued registries that reach this method - (:class:`~pcapkit.const.ftp.command.Command`, :class:`~pcapkit.const. - ftp.command.FEATCode`, :class:`~pcapkit.const.http.method.Method`, + (:class:`~pcapkit.const.ftp.command.Command`, + :class:`~pcapkit.const.ftp.command.FEATCode`, :class:`~pcapkit.const.http.method.Method`, :class:`~pcapkit.const.pcapng.option_type.OptionType`, :class:`~pcapkit.const.reg.apptype.apptype.AppType` and its four transport subclasses :class:`~pcapkit.const.reg.apptype.tcp.TCP`, diff --git a/pcapkit/corekit/fields/byteorder.py b/pcapkit/corekit/fields/byteorder.py index 49fc9a5870..271be47160 100644 --- a/pcapkit/corekit/fields/byteorder.py +++ b/pcapkit/corekit/fields/byteorder.py @@ -10,6 +10,11 @@ nested schema, so it lives with the fields rather than with either schema (:issue:`1711`). +.. versionadded:: 1.5.0 + + :func:`byteorder_callback` moves here from + :mod:`pcapkit.protocols.schema.misc.pcap.frame` (:issue:`1711`). + """ import sys diff --git a/pcapkit/corekit/fields/collections.py b/pcapkit/corekit/fields/collections.py index 54f68ecff5..e347e6c601 100644 --- a/pcapkit/corekit/fields/collections.py +++ b/pcapkit/corekit/fields/collections.py @@ -412,6 +412,12 @@ def unpack(self, buffer: 'bytes | IO[bytes]', packet: 'dict[str, Any]') -> 'list ProtocolError: If an option that begins with octets present reads past the end of the data. + .. versionchanged:: 1.5.0 + + An option that begins with octets present and reads past the end of + the data raises :exc:`~pcapkit.utilities.exceptions.ProtocolError`, + where it was parsed from zero-filled octets (:issue:`1325`). + """ length = self._length if isinstance(buffer, bytes): @@ -432,9 +438,9 @@ def unpack(self, buffer: 'bytes | IO[bytes]', packet: 'dict[str, Any]') -> 'list # # Remembering where the previous option ended gives the loop a measure of # progress that does not depend on what a schema reports, and one octet of - # it per iteration is what bounds the iteration count. ``length`` is still - # decremented by ``len(data)``, so that an option area which parses today - # parses identically. + # it per iteration is what bounds the iteration count. ``length`` is + # decremented by ``len(data)`` as well, so the guard changes nothing for + # an option area that parses. # # ``start`` is where the option area itself begins. The comparison needs # stream positions, but the diagnostic wants an offset into the area, and diff --git a/pcapkit/corekit/fields/field.py b/pcapkit/corekit/fields/field.py index 855ec9c05b..302d398651 100644 --- a/pcapkit/corekit/fields/field.py +++ b/pcapkit/corekit/fields/field.py @@ -6,25 +6,12 @@ :mod:`pcapkit.corekit.fields.field` contains the base field classes. -.. versionremoved:: 1.5.0 - - Moved to :mod:`pcapkit.utilities.config` (:issue:`1726`): - - * ``pcapkit.corekit.fields.field._MAX_ZERO_PAD_LENGTH``, now - :data:`pcapkit.utilities.config.MAX_ZERO_PAD_LENGTH`, set with - :envvar:`PCAPKIT_MAX_ZERO_PAD_LENGTH`; - * ``pcapkit.corekit.fields.field._MAX_ZERO_PAD_SHORTFALL``, now - :data:`pcapkit.utilities.config.MAX_ZERO_PAD_SHORTFALL`, set with - :envvar:`PCAPKIT_MAX_ZERO_PAD_SHORTFALL`; - * ``pcapkit.corekit.fields.field._ZERO_PAD_BUDGET_RATIO``, now - :data:`pcapkit.utilities.config.ZERO_PAD_BUDGET_RATIO`, set with - :envvar:`PCAPKIT_ZERO_PAD_BUDGET_RATIO`. - .. versionremoved:: 1.5.0 ``pcapkit.corekit.fields.field.NoValueType``, now :class:`pcapkit.corekit.sentinels.NoValueType` (:issue:`922`, - :issue:`1744`). + :issue:`1744`), and ``pcapkit.corekit.fields.field.NoValue``, now + :data:`pcapkit.corekit.sentinels.NO_VALUE` (:issue:`937`). """ @@ -246,6 +233,12 @@ def length(self) -> 'int': :func:`struct.calcsize`'s own error says -- rather than by the error message. See :issue:`825`. + .. versionchanged:: 1.5.0 + + Raises :exc:`~pcapkit.utilities.exceptions.ProtocolError` where + :func:`struct.calcsize` raised a bare :exc:`struct.error` + (:issue:`805`, :issue:`825`). + """ try: return struct.calcsize(self.template) @@ -306,8 +299,9 @@ def __copy__(self) -> 'Self': directly rather than :func:`copy.copy(self) `. :func:`copy.copy` still has to *find* this method before it can call it -- ``getattr(cls, '__copy__', None)`` -- and that lookup alone - was profiled at 55,846 calls (~1.7% of an :func:`~pcapkit.interface. - core.extract` run) on ``examples/captures/http.pcap``, one per field + was profiled at 55,846 calls (~1.7% of an + :func:`~pcapkit.interface.core.extract` run) on + ``examples/captures/http.pcap``, one per field per packet, all from this exact path. Calling ``__copy__`` directly is exactly what :func:`copy.copy` would have done once it found it, so this changes nothing about *when* a field is copied or @@ -408,6 +402,11 @@ def unpack(self, buffer: 'bytes | IO[bytes]', packet: 'dict[str, Any]') -> '_T': :data:`~pcapkit.utilities.config.MAX_ZERO_PAD_SHORTFALL` is always padded and never raises. + .. versionchanged:: 1.5.0 + + A short read is zero-filled on the tail, where its missing octets + are, rather than on the head (:issue:`604`). + """ # NOTE: ``length`` recomputes struct.calcsize() on every read, so it is # read once here. diff --git a/pcapkit/corekit/fields/ipaddress.py b/pcapkit/corekit/fields/ipaddress.py index d0ff9e789c..c955180eaa 100644 --- a/pcapkit/corekit/fields/ipaddress.py +++ b/pcapkit/corekit/fields/ipaddress.py @@ -1,5 +1,14 @@ # -*- coding: utf-8 -*- -"""IP address field class""" +"""IP address field class + +.. versionchanged:: 1.5.0 + + Every field here rejects a :obj:`bool` with + :exc:`~pcapkit.utilities.exceptions.FieldValueError`, where an IPv4 field + packed :obj:`True` and :obj:`False` as ``0.0.0.1`` and ``0.0.0.0`` + (:issue:`491`). + +""" import abc import contextlib @@ -189,6 +198,8 @@ def parse_ip_address(value: 'IPv4Address | IPv6Address | bytes | int | str', ValueError``, and nothing in the library catches either one specifically. + .. versionadded:: 1.5.0 + """ _reject_bool(value, description) @@ -542,6 +553,13 @@ class IPv4InterfaceField(_IPInterfaceField[ipaddress.IPv4Interface]): callback: Callback function to be called upon :meth:`self.__call__ `. + .. versionchanged:: 1.5.0 + + A mask that is not a contiguous netmask unpacks to an + :class:`~ipaddress.IPv4Interface` subclass that keeps its four octets, + where a hostmask-shaped one was read as a prefix length and any other + raised (:issue:`1294`). + """ @property diff --git a/pcapkit/corekit/fields/numbers.py b/pcapkit/corekit/fields/numbers.py index d747586725..8b5b4dd0cf 100644 --- a/pcapkit/corekit/fields/numbers.py +++ b/pcapkit/corekit/fields/numbers.py @@ -45,7 +45,8 @@ class _CapturedInt(int): It equals, hashes and renders as the plain :obj:`int` it holds, and any arithmetic on it yields a plain :obj:`int`, which is what lets a value a - caller derives from a parsed one keep today's truncating semantics. See + caller derives from a parsed one keep a plain :obj:`int`'s truncating + semantics. See GitHub issue :issue:`1488`. """ @@ -734,10 +735,11 @@ def post_process(self, value: 'int | bytes', packet: 'dict[str, Any]') -> 'Stdli unconditional ``except ValueError: pass``. No registry under :mod:`pcapkit.const` raises an in-library error - from its guard today, and deliberately so: a generated guard raises a - bare, unlogged :exc:`ValueError` precisely because the generated - ``get()``'s ``except ValueError`` fallback has to keep catching it - (GitHub issues :issue:`584` and :issue:`647`). The registries that + from its guard, and deliberately so: a generated guard raises a + bare, unlogged :exc:`ValueError` precisely because the ``except + ValueError`` fallback of :meth:`~pcapkit.corekit.enum.EnumLookup.get` + has to keep catching it (GitHub issues :issue:`584` and + :issue:`647`). The registries that *do* bound themselves to a width and reject outside it are the bit-flag ones -- :class:`pcapkit.const.tcp.flags.Flags` among them -- and none of those is named as the namespace of a plain @@ -754,6 +756,12 @@ def post_process(self, value: 'int | bytes', packet: 'dict[str, Any]') -> 'Stdli registry and equality with the member still hold, identity does not. See GitHub issue :issue:`1488`. + .. versionchanged:: 1.5.0 + + A value the registry has no member for resolves to a nameless + pseudo-member, where :mod:`aenum`'s bare :exc:`ValueError` escaped + (:issue:`701`). + """ value = super().post_process(value, packet) record = _capture_record(value) @@ -841,7 +849,7 @@ def _unregistered_member(namespace: 'Type[StdlibEnum] | Type[AenumEnum]', parse or reconstruction path does that to a value it just resolved this way, which is what keeps this safe to return from ``post_process``. A direct call to - :meth:`~pcapkit.const.reg.apptype.AppType.get` for the same port + :meth:`~pcapkit.const.reg.apptype.apptype.AppType.get` for the same port is a different matter and deliberately so: asking the registry for a name is an explicit request for a named member, so it still mints one -- measured on this tree, @@ -850,7 +858,7 @@ def _unregistered_member(namespace: 'Type[StdlibEnum] | Type[AenumEnum]', with the same port returns that member rather than raising. Two unregistered members for the same value also compare equal without being identical, since - :class:`~pcapkit.const.reg.apptype.AppType` and + :class:`~pcapkit.const.reg.apptype.apptype.AppType` and :class:`~pcapkit.const.pcapng.option_type.OptionType` both define ``__eq__``/``__hash__`` off an attribute (``.port`` / ``.opt_value``) rather than object identity -- harmless for every @@ -895,7 +903,7 @@ def _unregistered_member(namespace: 'Type[StdlibEnum] | Type[AenumEnum]', ancestor; it never gains an entry in any of its own tables. value: The value ``namespace``'s own constructor would have wrapped -- e.g. the crafted string - :meth:`~pcapkit.const.reg.apptype.AppType.__new__` builds from + :meth:`~pcapkit.const.reg.apptype.apptype.AppType.__new__` builds from a name, a port and a transport, or :meth:`~pcapkit.const.pcapng.option_type.OptionType.__new__`'s equivalent -- kept the same shape here so a rendered or @@ -904,7 +912,7 @@ def _unregistered_member(namespace: 'Type[StdlibEnum] | Type[AenumEnum]', other nameless value this package produces. **attrs: Extra attributes to set on the returned member, matching the shape the caller's registry gives its real members -- - :class:`~pcapkit.const.reg.apptype.AppType`'s ``.port``, + :class:`~pcapkit.const.reg.apptype.apptype.AppType`'s ``.port``, ``.svc`` and ``.proto``, or :class:`~pcapkit.const.pcapng.option_type.OptionType`'s ``.opt_name`` and ``.opt_value``. @@ -1015,18 +1023,20 @@ class PortEnumField(EnumField): byteorder: Field byte order. bit_length: Field bit length. namespace: The port registry, i.e. - :class:`~pcapkit.const.reg.apptype.AppType`. + :class:`~pcapkit.const.reg.apptype.apptype.AppType`. callback: Callback function to be called upon :meth:`self.__call__ `. proto: The transport protocol whose ports this field carries -- a single - :class:`~pcapkit.const.reg.apptype.TransportProtocol` member, which + :class:`~pcapkit.const.reg.apptype.apptype.TransportProtocol` member, which is what tells e.g. TCP/80 from UDP/80. The TCP, UDP and SCTP schemas each pass their own. Important: - This class is specifically designed for :class:`~pcapkit.const.reg.apptype.AppType` + This class is specifically designed for :class:`~pcapkit.const.reg.apptype.apptype.AppType` as it is actually a :class:`~enum.StrEnum` class. + .. versionadded:: 1.5.0 + """ if TYPE_CHECKING: _namespace: 'Type[AppType]' @@ -1077,16 +1087,16 @@ def post_process(self, value: 'int | bytes', packet: 'dict[str, Any]') -> 'AppTy the port itself, when the registry declares none. Notes: - :meth:`~pcapkit.const.reg.apptype.AppType.get` mints a fresh + :meth:`~pcapkit.const.reg.apptype.apptype.AppType.get` mints a fresh member -- via :func:`aenum.extend_enum` -- for any port neither an existing row nor one of :meth:`_missing_`'s documented IANA spans accounts for, which in practice means the ephemeral/dynamic range. Calling it on every parsed port would therefore grow the registry without bound. This peeks at the registry - :meth:`~pcapkit.const.reg.apptype.AppType.get` itself would + :meth:`~pcapkit.const.reg.apptype.apptype.AppType.get` itself would consult -- its per-port rows via ``__registry__.getlist``, then its documented spans via ``_missing_`` -- and only calls - :meth:`~pcapkit.const.reg.apptype.AppType.get` once one of those is + :meth:`~pcapkit.const.reg.apptype.apptype.AppType.get` once one of those is already known to hold, so a genuine miss gets :meth:`EnumField._unregistered_member` instead of a mint. @@ -1094,7 +1104,7 @@ def post_process(self, value: 'int | bytes', packet: 'dict[str, Any]') -> 'AppTy that, rather than being let through to :meth:`_missing_` and caught alongside a genuine miss. Both are a bare :exc:`ValueError` with nothing to tell them apart by type, and - :meth:`~pcapkit.const.reg.apptype.AppType.get` rejects the + :meth:`~pcapkit.const.reg.apptype.apptype.AppType.get` rejects the out-of-range case deliberately, so that it is never minted over -- a catch keyed on exception type alone cannot see the difference between that and :mod:`aenum`'s own "no member has this value", @@ -1103,7 +1113,7 @@ def post_process(self, value: 'int | bytes', packet: 'dict[str, Any]') -> 'AppTy distinction at all. ``self.length`` is the field's own declared byte width (``2`` for every caller of this class, hence ``0``-``65535``) rather than a hard-coded ``65535`` borrowed from - :meth:`~pcapkit.const.reg.apptype.AppType._missing_`'s own guard, + :meth:`~pcapkit.const.reg.apptype.apptype.AppType._missing_`'s own guard, so the two stay in lockstep by construction. """ diff --git a/pcapkit/corekit/infoclass.py b/pcapkit/corekit/infoclass.py index 379d249a57..4dcbd26e8d 100644 --- a/pcapkit/corekit/infoclass.py +++ b/pcapkit/corekit/infoclass.py @@ -108,6 +108,12 @@ def info_final(cls: 'ST', *, _finalised: 'bool' = True) -> 'ST': :attr:`FinalisedState.FINAL` in its own ``__dict__``. The class is returned untouched. + .. versionchanged:: 1.5.0 + + ``@final`` is enforced at runtime: a class marked with it but never + passed through this decorator is refused at first construction + (:issue:`778`). + :meta decorator: """ # NOTE: keyed on ``__finalised__`` rather than on @@ -695,6 +701,12 @@ def to_dict(self) -> 'OrderedMultiDict[str, VT]': :class:`~pcapkit.corekit.multidict.OrderedMultiDict` it was written as in. + .. versionchanged:: 1.5.0 + + Returns an :class:`~pcapkit.corekit.multidict.OrderedMultiDict` + rather than a :obj:`dict`, so a key held more than once keeps every + value (:issue:`1484`). + """ dict_ = _OrderedMultiDict() # type: OrderedMultiDict[str, Any] for (key, value) in self.__items_multi(): @@ -864,6 +876,8 @@ class MultiInfo(_MultiInfo[KT, VT], MultiDict[KT, VT]): mapping: The initial value, as for :class:`~pcapkit.corekit.multidict.MultiDict`. + .. versionadded:: 1.5.0 + """ # NOTE: :class:`Info` and :class:`~collections.abc.Mapping` precede @@ -955,6 +969,8 @@ class OrderedMultiInfo(_MultiInfo[KT, VT], OrderedMultiDict[KT, VT]): mapping: The initial value, as for :class:`~pcapkit.corekit.multidict.OrderedMultiDict`. + .. versionadded:: 1.5.0 + """ # NOTE: as for :class:`MultiInfo`, the mapping protocol is bound back to diff --git a/pcapkit/corekit/io.py b/pcapkit/corekit/io.py index 1a7bf9e492..bcca11ca9d 100644 --- a/pcapkit/corekit/io.py +++ b/pcapkit/corekit/io.py @@ -11,12 +11,6 @@ seekable stream, and :class:`~pcapkit.corekit.io.NamedStream`, which gives a stream a ``name``. -.. versionremoved:: 1.5.0 - - ``pcapkit.corekit.io._READ_CHUNK``, now - :data:`pcapkit.utilities.config.READ_CHUNK`, set with - :envvar:`PCAPKIT_READ_CHUNK` (:issue:`1726`). - """ import io import tempfile @@ -56,6 +50,20 @@ class SeekableReader(io.BufferedReader): buffer_path: Path to save buffer. stream_closing: Whether the stream should be closed upon exiting. + .. versionchanged:: 1.5.0 + + :meth:`truncate` raises + :exc:`~pcapkit.utilities.exceptions.UnsupportedOperation`, as + :meth:`writable` returns :data:`False` (:issue:`645`). A refused + :meth:`seek` leaves the position where it was, and a position the + lookback buffer has dropped raises instead of reading from it + (:issue:`643`, :issue:`644`). + + .. versionremoved:: 1.5.0 + + ``writeable()``, a misspelling that never overrode + :meth:`io.IOBase.writable`; use :meth:`writable` (:issue:`645`). + """ if TYPE_CHECKING: @@ -439,10 +447,10 @@ def seek(self, offset: 'int', whence: 'int' = io.SEEK_SET, /) -> 'int': as far as :meth:`_read_ahead` reads past the position: ``_read_ahead_size`` octets, a buffer's worth by default, or to the real end if that comes first. The frame readers measure what is left this way, and the engines set that size - to the next record, so a record is measured whole, however long. The end used to - be the buffer's far edge, which once the buffer has filled is just how far the - stream has been read, so the first record ending there was taken for the end of - the capture (:issue:`1586`). The read slides the buffer, so a position before + to the next record, so a record is measured whole, however long. The buffer's far + edge will not do as the end: once the buffer has filled it is just how far the + stream has been read, so the first record ending there would be taken for the end + of the capture (:issue:`1586`). The read slides the buffer, so a position before the one :data:`~io.SEEK_END` was sought from may then be refused, as :meth:`_read_ahead` says. diff --git a/pcapkit/corekit/multidict.py b/pcapkit/corekit/multidict.py index 464c58b97d..c06ea27e2c 100644 --- a/pcapkit/corekit/multidict.py +++ b/pcapkit/corekit/multidict.py @@ -506,6 +506,11 @@ def deepcopy(self, memo: 'Optional[dict]' = None) -> 'OrderedMultiDict[_KT, _VT] ``items(multi=True)`` instead, so the copy keeps the insertion order of interleaved keys. :meth:`__deepcopy__` reaches it too. + .. versionchanged:: 1.5.0 + + Keeps the insertion order of interleaved keys, where the copy grouped + the values by key (:issue:`1295`). + """ return self.__class__(copy.deepcopy(list(self.items(multi=True)), memo=memo)) diff --git a/pcapkit/corekit/sentinels.py b/pcapkit/corekit/sentinels.py index 28f6789a0e..1e0d6c278f 100644 --- a/pcapkit/corekit/sentinels.py +++ b/pcapkit/corekit/sentinels.py @@ -14,17 +14,23 @@ The owner's ruling on GitHub issue :issue:`911` chose one shared module over one module per sentinel, and this module is the only import path for all -four. The re-export each one used to keep at the module of the class that -uses it was dropped under :issue:`1744`, per the ruling on :issue:`1715` that a -moved name keeps no re-export at its old path. :mod:`pcapkit.corekit.module`, +four: the module of the class that uses each one does not re-export it +(:issue:`1744`), per the ruling on :issue:`1715` that a moved name keeps no +re-export at its old path. :mod:`pcapkit.corekit.module`, :mod:`pcapkit.corekit.fields.field`, :mod:`pcapkit.corekit.enum` and -:mod:`pcapkit.protocols.protocol` still import the object they use from here, -but none lists it in ``__all__`` or documents it, and none binds the type. +:mod:`pcapkit.protocols.protocol` import the object they use from here, but +none lists it in ``__all__`` or documents it, and none binds the type. ``ABSENT`` is private to :mod:`pcapkit.protocols.protocol` -- nothing outside that module ever reads it. It carries no leading underscore; :class:`AbsentType`'s docstring says what marks it private instead. +.. versionadded:: 1.5.0 + + :class:`NoValueType` moves here from :mod:`pcapkit.corekit.fields.field` + (:issue:`911`), and :data:`NO_VALUE` replaces its ``NoValue`` there + (:issue:`937`). + """ from typing import TYPE_CHECKING diff --git a/pcapkit/vendor/ftp/command.py b/pcapkit/vendor/ftp/command.py index 83da90c285..866eb65b1e 100644 --- a/pcapkit/vendor/ftp/command.py +++ b/pcapkit/vendor/ftp/command.py @@ -303,8 +303,9 @@ def _unregistered_member(cls, value: 'str', name: 'str') -> '{NAME}': Leaves :attr:`feat`, :attr:`desc`, :attr:`type` and :attr:`conf` at the same defaults :meth:`__new__` itself would, rather than missing - entirely -- :meth:`~pcapkit.corekit.enum.EnumRegistry. - _unregistered_member` bypasses :meth:`__new__` (it calls + entirely -- + :meth:`~pcapkit.corekit.enum.EnumRegistry._unregistered_member` + bypasses :meth:`__new__` (it calls :class:`str`'s directly), so those four attributes would otherwise be absent and :meth:`__repr__` (which reads :attr:`desc`) would raise on the result. There is no more specific value to reconstruct diff --git a/pcapkit/vendor/http/method.py b/pcapkit/vendor/http/method.py index e18de7630d..c2e02234a5 100644 --- a/pcapkit/vendor/http/method.py +++ b/pcapkit/vendor/http/method.py @@ -48,16 +48,14 @@ class {NAME}(EnumRegistry, StrEnum): """[{NAME}] {DOCS} - .. note:: + .. versionchanged:: 1.5.0 - Neither ``_missing_`` nor ``get()`` mints any more. The owner ruled on - GitHub issue :issue:`860` that ``get`` should not mint: only IANA-registered - values are legitimate members, a new one is properly created through - :meth:`register`, and ``get`` is not given enough information to create - one. Concretely true here -- a bare wire method verb carries no - :attr:`safe`/:attr:`idempotent`, so minting one used to register a - permanent member with both hollowed out to their defaults; - :meth:`register` is the path that can actually supply them. + Neither ``_missing_`` nor ``get()`` mints a member, per the owner's + ruling on GitHub issue :issue:`860`: only IANA-registered values are + legitimate members, and a new one is created through :meth:`register`, + which can supply :attr:`safe` and :attr:`idempotent` where a bare wire + method verb carries neither. ``get()`` matches ``key`` case-sensitively, + as :rfc:`9110` makes the method token (:issue:`896`). """ @@ -168,8 +166,8 @@ def get(cls, key: 'str', default: 'Optional[str]' = None) -> '{NAME}': Args: key: Key to get enum item. Looked up case-**sensitively**, per :rfc:`9110#section-9.1` -- the method token is - case-sensitive, unlike :meth:`~pcapkit.const.ftp.command. - Command.get`'s equivalent override, which stays + case-sensitive, unlike + :meth:`~pcapkit.const.ftp.command.Command.get`'s equivalent override, which stays case-insensitive because :rfc:`959#section-5` says FTP command codes are not. Checked against both member names and values, via the base's own precedence -- name before diff --git a/pcapkit/vendor/http/status_code.py b/pcapkit/vendor/http/status_code.py index ffd74d0f6a..7faa39acc8 100644 --- a/pcapkit/vendor/http/status_code.py +++ b/pcapkit/vendor/http/status_code.py @@ -76,8 +76,9 @@ def _unregistered_member(cls, value: 'int', name: 'str') -> '{NAME}': """Build a member absent from this registry's own lookup tables. Reconstructs :attr:`message` the same way :meth:`__new__` would, - rather than leaving it unset -- :meth:`~pcapkit.corekit.enum. - EnumRegistry._unregistered_member` bypasses :meth:`__new__` entirely + rather than leaving it unset -- + :meth:`~pcapkit.corekit.enum.EnumRegistry._unregistered_member` + bypasses :meth:`__new__` entirely (it calls :class:`int`'s directly), so :attr:`message` would otherwise be missing from the result and :meth:`__str__` would raise on it. diff --git a/pcapkit/vendor/ipv6/extension_header.py b/pcapkit/vendor/ipv6/extension_header.py index ce8dec0340..7fbaa01446 100644 --- a/pcapkit/vendor/ipv6/extension_header.py +++ b/pcapkit/vendor/ipv6/extension_header.py @@ -44,7 +44,14 @@ class {NAME}(EnumRegistry, IntEnum): - """[{NAME}] {DOCS}""" + """[{NAME}] {DOCS} + + .. versionchanged:: 1.5.0 + + Generated from IANA's *IPv6 Extension Header Types* registry, where it + was generated from the protocol-numbers registry (:issue:`925`). + + """ {ENUM} ''' # type: Callable[[str, str, str, str], str] @@ -58,14 +65,15 @@ class ExtensionHeader(Vendor): #: (``protocol-numbers-1.csv``, this crawler's :attr:`LINK` before GitHub #: issue :issue:`925`) paired each of these headers with a short ``Keyword`` #: column value, e.g. ``IPv6-Route`` for header 43. The registry - #: :attr:`LINK` now points at -- IANA's authoritative *IPv6 Extension + #: :attr:`LINK` points at -- IANA's authoritative *IPv6 Extension #: Header Types* registry -- has no such column, only a verbose #: ``Description`` (``Routing Header for IPv6`` for the same header), so #: deriving names the same way :meth:`process` does for every other - #: 3-column registry (see e.g. :class:`~pcapkit.vendor.ipv6.router_alert. - #: RouterAlert`) would silently rename these members. This mapping keeps - #: the existing, shorter names instead; any header not listed here still - #: falls back to a name derived from its description, same as always. + #: 3-column registry (see e.g. + #: :class:`~pcapkit.vendor.ipv6.router_alert.RouterAlert`) + #: would silently rename these members. This mapping keeps + #: the shorter names instead; any header not listed here falls back to a + #: name derived from its description. NAMES = { 0: 'HOPOPT', 43: 'IPv6-Route', @@ -81,24 +89,22 @@ class ExtensionHeader(Vendor): #: #: .. note:: #: - #: Until GitHub issue :issue:`925`, this pointed at the *Protocol Numbers* - #: registry (``protocol-numbers/protocol-numbers-1.csv``), filtered on - #: its ``IPv6 Extension Header`` column -- a derived signal, not the - #: registry :rfc:`8200#section-4` names as authoritative for this - #: enumeration. That registry disagreed with this one on header 147 - #: (``BIT-EMU``): it flagged 147 as an IPv6 extension header, citing - #: :rfc:`9801`, while this registry omits 147 entirely -- see the issue - #: for the reading of :rfc:`9801` that makes the omission look - #: intentional rather than an erratum. Fixing :attr:`LINK` also let - #: :class:`~pcapkit.const.ipv6.extension_header.ExtensionHeader` drop - #: ``BIT_EMU``: :attr:`pcapkit.protocols.internet.ipv6.IPv6 - #: ._decode_next_layer`'s walk used to rely on ``ExtensionHeader(147)`` - #: resolving, but its own test (``tests.protocols.internet - #: .test_ipv6_ext_unit.IPv6ExtUnitTests + #: This is the registry :rfc:`8200#section-4` names as authoritative for + #: this enumeration, rather than the *Protocol Numbers* registry + #: (``protocol-numbers/protocol-numbers-1.csv``) filtered on its ``IPv6 + #: Extension Header`` column, which is a derived signal (GitHub issue + #: :issue:`925`). The two disagree on header 147 (``BIT-EMU``): the + #: Protocol Numbers registry flags 147 as an IPv6 extension header, + #: citing :rfc:`9801`, while this registry omits 147 entirely -- see the + #: issue for the reading of :rfc:`9801` that makes the omission look + #: intentional rather than an erratum. So + #: :class:`~pcapkit.const.ipv6.extension_header.ExtensionHeader` has no + #: ``BIT_EMU``, and the walk in :meth:`IPv6._decode_next_layer + #: ` does not + #: depend on ``ExtensionHeader(147)`` resolving: its test + #: (``tests.protocols.internet.test_ipv6_ext_unit.IPv6ExtUnitTests #: .test_unimplemented_terminal_code_stops_the_walk_not_the_packet``) - #: now exercises the identical code path on 253 -- a code this - #: registry *does* list -- so nothing outside this package depends on - #: 147 resolving any more. + #: exercises that code path on 253, a code this registry *does* list. LINK = 'https://www.iana.org/assignments/ipv6-parameters/extension-header.csv' def count(self, data: 'list[str]') -> 'Counter[str]': diff --git a/pcapkit/vendor/ipv6/smf_dpd_mode.py b/pcapkit/vendor/ipv6/smf_dpd_mode.py index f529826b84..d7fddf5d0a 100644 --- a/pcapkit/vendor/ipv6/smf_dpd_mode.py +++ b/pcapkit/vendor/ipv6/smf_dpd_mode.py @@ -4,7 +4,7 @@ .. module:: pcapkit.vendor.ipv6.smf_dpd_mode -This module contains the vendor crawler for **Simplified Multicast Forwarding Duplicate Packet Detection (``SMF_DPD``) Options**, +This module contains the vendor crawler for **Simplified Multicast Forwarding Duplicate Packet Detection (SMF_DPD) Options**, which is automatically generating :class:`pcapkit.const.ipv6.smf_dpd_mode.SMFDPDMode`. """ diff --git a/pcapkit/vendor/ngap/procedure_code.py b/pcapkit/vendor/ngap/procedure_code.py index 5d73a0d93b..bce363429b 100644 --- a/pcapkit/vendor/ngap/procedure_code.py +++ b/pcapkit/vendor/ngap/procedure_code.py @@ -118,8 +118,9 @@ def _request(self) -> 'list[tuple[str, int]]': # type: ignore[override] a ``(module, type)`` pair), a private ``_name`` holding the ASN.1 identifier verbatim (``'id-AMFConfigurationUpdate'``), and a private ``_val`` holding the assigned integer. None of the three has a public - accessor that survives this far: :meth:`~pycrate_asn1rt.asnobj.ASN1Obj. - get_typeref` resolves to the *referenced type object* rather than its + accessor that survives this far: + :meth:`~pycrate_asn1rt.asnobj.ASN1Obj.get_typeref` + resolves to the *referenced type object* rather than its ``(module, name)`` pair, and that object's own :meth:`get_name` reads :obj:`None` here despite :func:`repr` showing the name -- measured against pycrate 0.8.1. Reading the private attributes directly is @@ -166,8 +167,9 @@ def count(self, data: 'list[tuple[str, int]]') -> 'Counter[str]': # type: ignor Unlike a hand-scraped CSV, |pycrate|_'s compiled specification names each assignment once -- measured, zero duplicate names and zero - duplicate values across all 81 -- so :meth:`~pcapkit.vendor.default. - Vendor.rename`'s per-name counter has nothing to disambiguate and this + duplicate values across all 81 -- so + :meth:`~pcapkit.vendor.default.Vendor.rename`'s + per-name counter has nothing to disambiguate and this crawler never calls it. """ diff --git a/pcapkit/vendor/ngap/protocol_ie.py b/pcapkit/vendor/ngap/protocol_ie.py index 7db2792b3a..398f70ab78 100644 --- a/pcapkit/vendor/ngap/protocol_ie.py +++ b/pcapkit/vendor/ngap/protocol_ie.py @@ -11,8 +11,9 @@ See :mod:`pcapkit.vendor.ngap.procedure_code`'s module docstring for why this crawler's source is |pycrate|_'s already-installed, compiled NGAP specification rather than a network registry, and why an in-range value it has -not seen answers through :meth:`~pcapkit.corekit.enum.EnumRegistry. -_unregistered_member` rather than raising or minting a permanent, shared-value +not seen answers through +:meth:`~pcapkit.corekit.enum.EnumRegistry._unregistered_member` +rather than raising or minting a permanent, shared-value member -- the same GitHub issue :issue:`880` ruling, applied to the sibling registry. .. |pycrate| replace:: ``pycrate`` diff --git a/pcapkit/vendor/pcapng/tls_key_label.py b/pcapkit/vendor/pcapng/tls_key_label.py index cf0eca8de5..8d3cc7ebbe 100644 --- a/pcapkit/vendor/pcapng/tls_key_label.py +++ b/pcapkit/vendor/pcapng/tls_key_label.py @@ -58,7 +58,13 @@ class {NAME}(EnumRegistry, StrEnum): - """[{NAME}] {DOCS}""" + """[{NAME}] {DOCS} + + .. versionadded:: 1.5.0 + + Moved here from ``pcapkit.protocols.misc.pcapng`` (:issue:`886`). + + """ {ENUM} ''' # type: Callable[[str, str, str, str], str] diff --git a/pcapkit/vendor/reg/apptype/apptype.py b/pcapkit/vendor/reg/apptype/apptype.py index f115ffa090..3a0a67f329 100644 --- a/pcapkit/vendor/reg/apptype/apptype.py +++ b/pcapkit/vendor/reg/apptype/apptype.py @@ -241,8 +241,8 @@ def get(cls, key: 'int | str', default: 'Any' = NO_DEFAULT) -> 'TransportProtoco Args: key: Key to get enum item. default: An already-registered value to fall back to when - ``key`` resolves to nothing. :data:`~pcapkit.corekit.enum. - NO_DEFAULT`, the default, means *no default* -- see + ``key`` resolves to nothing. + :data:`~pcapkit.corekit.sentinels.NO_DEFAULT`, the default, means *no default* -- see :meth:`~pcapkit.corekit.enum.EnumLookup.get`. Raises: @@ -860,8 +860,9 @@ def _unregistered_member(cls, value: 'int', name: 'str', caller-named path that still does. Reconstructs :attr:`svc`, :attr:`port` and :attr:`proto` the same way - :meth:`__new__` would: :meth:`~pcapkit.corekit.enum. - EnumRegistry._unregistered_member` bypasses :meth:`__new__` entirely + :meth:`__new__` would: + :meth:`~pcapkit.corekit.enum.EnumRegistry._unregistered_member` + bypasses :meth:`__new__` entirely (it builds through ``cls._member_type_.__new__`` directly), so this class's own three attributes would otherwise be missing and every method reading them (:meth:`__repr__`, :meth:`__str__`, :meth:`__int__`, diff --git a/pcapkit/vendor/tcp/flags.py b/pcapkit/vendor/tcp/flags.py index 030aecf032..3e4662d7c3 100644 --- a/pcapkit/vendor/tcp/flags.py +++ b/pcapkit/vendor/tcp/flags.py @@ -54,7 +54,14 @@ __all__ = ['{NAME}'] class {NAME}(EnumRegistry, IntFlag): - """[{NAME}] {DOCS}""" + """[{NAME}] {DOCS} + + .. versionchanged:: 1.5.0 + + A value outside the 16-bit field raises :exc:`ValueError`, where + :mod:`aenum` composed a pseudo-member for any integer. + + """ {ENUM}