diff --git a/pcapkit/foundation/engines/engine.py b/pcapkit/foundation/engines/engine.py index ccc1fb461..09b802fd6 100644 --- a/pcapkit/foundation/engines/engine.py +++ b/pcapkit/foundation/engines/engine.py @@ -240,6 +240,14 @@ class MyMixin(Engine): # not registered Args: extractor: :class:`~pcapkit.foundation.extraction.Extractor` instance. + .. versionchanged:: 1.3.0 + + :attr:`~EngineBase.name` and :attr:`~EngineBase.module` are properties, + read from ``__engine_name__`` and ``__engine_module__`` or else from the + class, where they were abstract class methods each engine implemented. + A subclass registers itself with + :class:`~pcapkit.foundation.extraction.Extractor` at class definition. + .. versionchanged:: 1.5.0 Registration is opt-in, under the ``engine`` class keyword, which diff --git a/pcapkit/foundation/extraction.py b/pcapkit/foundation/extraction.py index 4efd5284e..abe8395ab 100644 --- a/pcapkit/foundation/extraction.py +++ b/pcapkit/foundation/extraction.py @@ -108,6 +108,12 @@ class Extractor(Generic[_P]): For supported engines, please refer to :meth:`~pcapkit.foundation.extraction.Extractor.run`. + .. versionchanged:: 1.2.0 + + ``strict`` is renamed ``reasm_strict``, with no alias, and + ``reasm_store`` is inserted after it, so a positional argument from + ``trace`` onwards moves one place along. + .. versionchanged:: 1.5.0 ``layer`` and ``protocol`` stop the dissection where they say, which @@ -365,6 +371,11 @@ def reassembly(self) -> 'ReassemblyData': UnsupportedCall: If :attr:`self._flag_r ` is :data:`False`, as reassembly is disabled. + .. versionchanged:: 1.1.1 + + Raises :exc:`~pcapkit.utilities.exceptions.UnsupportedCall` when + reassembly is disabled, where 1.1.0 built the record regardless. + """ if self._flag_r: data = ReassemblyData( @@ -385,6 +396,11 @@ def trace(self) -> 'TraceFlowData': UnsupportedCall: If :attr:`self._flag_t ` is :data:`False`, as flow tracing is disabled. + .. versionchanged:: 1.1.1 + + Raises :exc:`~pcapkit.utilities.exceptions.UnsupportedCall` when + flow tracing is disabled, where 1.1.0 built the record regardless. + """ if self._flag_t: data = TraceFlowData( @@ -448,6 +464,11 @@ class it names, restores the shipped entry rather than storing RegistryWarning: If a different dumper is already registered for ``format``; it is overwritten. + .. versionchanged:: 1.3.0 + + ``dumper``, a module descriptor or a class, replaces the ``module`` + and ``class_`` name pair, with no alias. + """ shipped = cls._shipped_output.get(format) if isinstance(dumper, ModuleDescriptor) and (shipped is None or dumper != shipped[0]): @@ -499,6 +520,12 @@ def register_engine(cls, name: 'str', engine: 'ModuleDescriptor[Engine] | Type[E RegistryWarning: If a different class is already registered under ``name``; it is overwritten. + .. versionchanged:: 1.3.0 + + ``engine``, a module descriptor or a class, replaces the ``module`` + and ``class_`` name pair, with no alias, and the engine name it + took as ``engine`` is ``name``. + """ # The shipped built-in is matched before the descriptor is resolved, so # restoring an optional engine does not import it (#1363). @@ -587,6 +614,11 @@ def register_reassembly(cls, protocol: 'str', reassembly: 'ModuleDescriptor[Reas RegistryWarning: If a different class is already registered under ``protocol``; it is overwritten. + .. versionchanged:: 1.3.0 + + ``reassembly``, a module descriptor or a class, replaces the + ``module`` and ``class_`` name pair, with no alias. + """ shipped = cls._shipped_reassembly.get(protocol) if isinstance(reassembly, ModuleDescriptor) and reassembly != shipped: @@ -668,6 +700,11 @@ def register_traceflow(cls, protocol: 'str', traceflow: 'ModuleDescriptor[TraceF RegistryWarning: If a different class is already registered under ``protocol``; it is overwritten. + .. versionchanged:: 1.3.0 + + ``traceflow``, a module descriptor or a class, replaces the + ``module`` and ``class_`` name pair, with no alias. + """ shipped = cls._shipped_traceflow.get(protocol) if isinstance(traceflow, ModuleDescriptor) and traceflow != shipped: diff --git a/pcapkit/foundation/reassembly/ipv6.py b/pcapkit/foundation/reassembly/ipv6.py index fbf77927b..7615511ba 100644 --- a/pcapkit/foundation/reassembly/ipv6.py +++ b/pcapkit/foundation/reassembly/ipv6.py @@ -135,9 +135,12 @@ def _rectify_header(self, header: 'bytes', proto: 'TransType') -> 'bytes': the reassembled packet, and that the Next Header field of the last header of the unfragmentable part comes from the Fragment header's. Left alone, the reassembled datagram would advertise a Fragment header on a datagram - that is by definition no longer a fragment. Every toolkit adapter leaves - the Fragment header's *octets* out of ``header``, but none rewrites the - field that points at it, so only that field is left to fix. + that is by definition no longer a fragment. The four toolkit adapters + that build IPv6 reassembly data, :mod:`~pcapkit.toolkit.pcap`, + :mod:`~pcapkit.toolkit.pcapng`, :mod:`~pcapkit.toolkit.dpkt` and + :mod:`~pcapkit.toolkit.scapy`, leave the Fragment header's *octets* out + of ``header``, but none rewrites the field that points at it, so only + that field is left to fix. Args: header: Raw header octets of the fragment at fragment offset zero. diff --git a/pcapkit/foundation/reassembly/reassembly.py b/pcapkit/foundation/reassembly/reassembly.py index 9336211b0..a4532109f 100644 --- a/pcapkit/foundation/reassembly/reassembly.py +++ b/pcapkit/foundation/reassembly/reassembly.py @@ -541,6 +541,15 @@ class MyMixin(Reassembly): # not registered timeout: reassembly timeout in seconds, on the capture's own clock; :data:`None` selects the protocol's :attr:`__timeout__` default + .. versionchanged:: 1.3.0 + + :attr:`name` and :attr:`protocol` are read from ``__protocol_name__`` + and ``__protocol_type__``, where they were abstract properties each + reassembly implemented, and the built-in names are short: ``'IPv4'`` + rather than ``'Internet Protocol version 4'``. A subclass registers + itself with :class:`~pcapkit.foundation.extraction.Extractor` at class + definition. + .. versionchanged:: 1.5.0 Registration is opt-in, under the ``protocol`` class keyword; 1.4.x diff --git a/pcapkit/foundation/registry/foundation.py b/pcapkit/foundation/registry/foundation.py index 0bb9bda78..d22eae483 100644 --- a/pcapkit/foundation/registry/foundation.py +++ b/pcapkit/foundation/registry/foundation.py @@ -85,6 +85,10 @@ def register_extractor_engine(name: 'str', module: 'ModuleDescriptor[Engine] | T the engine ``name`` shipped with, which restores it) class\_: class name + .. versionchanged:: 1.3.0 + + The engine name, which was ``engine``, is ``name``, with no alias. + """ if isinstance(module, str): module = cast('ModuleDescriptor[Engine]', ModuleDescriptor(module, class_)) @@ -127,6 +131,10 @@ def register_dumper(format: 'str', module: 'ModuleDescriptor[Dumper] | Type[Dump * :func:`pcapkit.foundation.registry.foundation.register_extractor_dumper` * :func:`pcapkit.foundation.registry.foundation.register_traceflow_dumper` + .. versionchanged:: 1.3.0 + + ``ext`` is keyword-only. + """ if isinstance(module, str): module = cast('ModuleDescriptor[Dumper]', ModuleDescriptor(module, class_)) @@ -161,6 +169,10 @@ def register_extractor_dumper(format: 'str', module: 'ModuleDescriptor[Dumper] | class\_: class name ext: file extension + .. versionchanged:: 1.3.0 + + ``ext`` is keyword-only. + """ if isinstance(module, str): module = cast('ModuleDescriptor[Dumper]', ModuleDescriptor(module, class_)) @@ -194,6 +206,10 @@ def register_traceflow_dumper(format: 'str', module: 'ModuleDescriptor[Dumper] | class\_: class name ext: file extension + .. versionchanged:: 1.3.0 + + ``ext`` is keyword-only. + """ if isinstance(module, str): module = cast('ModuleDescriptor[Dumper]', ModuleDescriptor(module, class_)) diff --git a/pcapkit/foundation/registry/protocols.py b/pcapkit/foundation/registry/protocols.py index 1b8b35d03..a2d0b9e9f 100644 --- a/pcapkit/foundation/registry/protocols.py +++ b/pcapkit/foundation/registry/protocols.py @@ -200,7 +200,8 @@ class rather than supplied by a caller, and this function is the funnel :class:`~pcapkit.foundation.reassembly.reassembly.ReassemblyMeta` and :class:`~pcapkit.foundation.traceflow.traceflow.TraceFlowMeta` fall back to :class:`~pcapkit.protocols.misc.raw.Raw`. The registry redesign of - :issue:`514` kept this key, so the collision is reported here rather than + :issue:`514` left this key unchanged and recorded the shared namespace as a + risk it did not fix, so the collision is reported here rather than resolved. Args: @@ -1036,6 +1037,10 @@ def register_apptype(code: 'int | Enum_AppType', module: 'str | ModuleDescriptor * :func:`pcapkit.foundation.registry.register_udp` * :func:`pcapkit.foundation.registry.register_sctp` + .. versionremoved:: 1.3.1 + + ``register_port``, which this replaces with no alias. + .. versionchanged:: 1.5.0 The keyword-only ``proto`` is replaced by ``*transport``, one transport diff --git a/pcapkit/foundation/traceflow/traceflow.py b/pcapkit/foundation/traceflow/traceflow.py index 40868a559..865034e14 100644 --- a/pcapkit/foundation/traceflow/traceflow.py +++ b/pcapkit/foundation/traceflow/traceflow.py @@ -242,6 +242,15 @@ class it names, restores the shipped entry rather than storing dumper: module descriptor or a :class:`dictdumper.dumper.Dumper` subclass ext: file extension + .. versionremoved:: 1.2.0 + + ``register``, which this replaces with no alias. + + .. versionchanged:: 1.3.0 + + ``dumper``, a module descriptor or a class, replaces the ``module`` + and ``class_`` name pair, with no alias. + """ from pcapkit.interface.registry import ( # pylint: disable=import-outside-toplevel restore_shipped_dumper, same_entry) @@ -509,6 +518,15 @@ class MyMixin(TraceFlow): # not registered bidirectional: trace both halves of a conversation as one flow analyse: reassemble each flow's application layer + .. versionchanged:: 1.3.0 + + :attr:`name` and :attr:`protocol` are read from ``__protocol_name__`` + and ``__protocol_type__``, where they were abstract properties each + flow tracing class implemented, and the built-in name is short: + ``'TCP'`` rather than ``'Transmission Control Protocol'``. A subclass + registers itself with :class:`~pcapkit.foundation.extraction.Extractor` + at class definition. + .. versionchanged:: 1.5.0 Registration is opt-in, under the ``protocol`` class keyword; 1.4.x diff --git a/pcapkit/interface/core.py b/pcapkit/interface/core.py index 05d87920b..5a58cf420 100644 --- a/pcapkit/interface/core.py +++ b/pcapkit/interface/core.py @@ -156,6 +156,12 @@ def extract(fin: 'Optional[str | IO[bytes]]' = None, fout: 'Optional[str]' = Non Returns: An :class:`~pcapkit.foundation.extraction.Extractor` object. + .. versionchanged:: 1.2.0 + + ``strict`` is renamed ``reasm_strict``, with no alias, and + ``reasm_store`` is inserted after it, so a positional argument from + ``trace`` onwards moves one place along. + .. versionchanged:: 1.5.0 ``reasm_timeout``, ``trace_bidirectional`` and ``trace_analyse`` are diff --git a/pcapkit/utilities/config.py b/pcapkit/utilities/config.py index e67357978..8a6d0cad4 100644 --- a/pcapkit/utilities/config.py +++ b/pcapkit/utilities/config.py @@ -217,9 +217,9 @@ def read_flag(name: 'str', default: 'bool' = False) -> 'bool': IPV6_TCP_WARNED_LIMIT = read_limit('IPV6_TCP_WARNED_LIMIT', 32, risk=( 'each capture remembered pins one of its packets in memory')) -#: int: Most objects :meth:`DictDumper._append_fallback -#: ` expands for one -#: top-level object, counting an object once per time it is met, +#: int: Most objects +#: :meth:`DictDumper._append_fallback ` +#: expands for one top-level object, counting an object once per time it is met, #: :envvar:`PCAPKIT_FALLBACK_LIMIT`; ``-1`` expands without bound. #: #: No fallback object in the ``foundation``, ``dumpkit`` or ``interface`` test @@ -261,9 +261,9 @@ def read_flag(name: 'str', default: 'bool' = False) -> 'bool': READ_CHUNK = read_limit('READ_CHUNK', 1 << 20, minimum=1, risk=( 'a bogus record length allocates up to that many octets in one read')) -#: int: Ceiling on the zero-padding :meth:`FieldBase.unpack -#: ` will still perform for a -#: field whose declared length outruns its buffer. +#: int: Ceiling on the zero-padding +#: :meth:`FieldBase.unpack ` +#: will still perform for a field whose declared length outruns its buffer. #: #: This is libpcap's own ``MAXIMUM_SNAPLEN`` -- the point past which libpcap #: itself treats a capture's declared snapshot length as corrupt or @@ -299,9 +299,9 @@ def read_flag(name: 'str', default: 'bool' = False) -> 'bool': MAX_ZERO_PAD_LENGTH = read_limit('MAX_ZERO_PAD_LENGTH', 0x40_000, risk=( 'a hostile capture can declare a field that long and have it zero-filled in memory')) -#: int: Shortfall :meth:`FieldBase.unpack -#: ` will always zero-pad for, -#: whatever else a parse has already padded. +#: int: Shortfall +#: :meth:`FieldBase.unpack ` +#: will always zero-pad for, whatever else a parse has already padded. #: #: :data:`MAX_ZERO_PAD_LENGTH` bounds each field on its own, and a packet holds #: many fields, so it leaves the *sum* unbounded: a declared length just under the