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
25 changes: 5 additions & 20 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1247,26 +1247,11 @@ def read_own_enum_new(obj: type, name: str, *defargs: 'Any') -> 'Any':
return safe_getattr(obj, name, *defargs)


# NB: handlers used to sit here -- ``remove_module_docstring``,
# ``process_docstring``, ``process_fields`` and ``source_read`` -- each with its
# ``app.connect`` call commented out in ``setup`` below, so none of them had run
# for as long as they had been in the file. They are deleted rather than restored,
# because restoring them would either duplicate work done properly elsewhere or make the
# build unusable:
#
# ``remove_module_docstring`` and ``process_docstring`` were both attempts at the
# same thing -- flipping :data:`typing.TYPE_CHECKING` and reloading each module
# so autodoc could see the ``if TYPE_CHECKING:`` names. ``bind_type_checking_names``
# above solves that, per module and without mutating a global mid-build.
#
# ``process_fields`` only ever printed; the ``lines.append`` that was its point
# was itself commented out.
#
# ``source_read`` printed every document's entire source text, which on this
# project is several thousand pages of build log.
#
# If the ``TYPE_CHECKING`` behaviour is ever wanted again, ``bind_type_checking_names``
# is where it belongs, not a reload hook.
# NB: the ``TYPE_CHECKING`` names belong to ``bind_type_checking_names`` above,
# not to a hook that flips :data:`typing.TYPE_CHECKING` and reloads each module:
# the binding does the same per module, without mutating a global mid-build. Nor
# should a ``source-read`` handler print each document: on this project that is
# several thousand pages of build log.


def setup(app: 'Sphinx') -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,8 @@ was left behind, and that was deliberate. The owner ruled that the
``IPv6_GenericExt`` name goes for good: it was an intermediate state, and it was never
released.

What makes that safe rather than merely decided: the old name existed on ``main`` from
``b3551cb63`` to ``93cf940b3``, under four hours on one day, and no release tag falls
What makes that safe rather than merely decided: ``IPv6_GenericExt`` existed on
``main`` from ``b3551cb63`` to ``93cf940b3``, under four hours on one day, and no release tag falls
between the two commits -- ``git tag --contains`` names the same tags for both -- so it
appears in **no** release and the break has no callers to inconvenience. Do not
reintroduce it as an alias, and do not cite it as a former public name.
Expand Down
4 changes: 2 additions & 2 deletions docs/source/contributing/conventions/mint-criterion.rst
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ than one range block -- and
:mod:`pcapkit.const.ipx.socket`'s ``Registered by Xerox``. A company name is the
assignment, for the reason in the next section.

Further ranges in that file carry a suffixed name without being company names at
all: ``IEEE802.3 Length Field``, which names a field in a standard, and
Further ranges in :mod:`pcapkit.const.reg.ethertype` carry a suffixed name without
being company names at all: ``IEEE802.3 Length Field``, which names a field in a standard, and
``Berkeley Trailer encap/IP``, which names an encapsulation. Neither is among the company names, and
neither is suffixed for the reason the next section gives.

Expand Down
4 changes: 2 additions & 2 deletions docs/source/contributing/conventions/process.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ once:
``PyShark``, ``PyPCAPFile``, ``PyPCAP`` and ``PCAP_CT`` are not core addons, so
they are on demand -- one extra at a time, ``pip install pypcapkit[Scapy]`` and so
on. This holds however easy they are to install, and it is what the ruling
changed: some of them used to be in ``all``.
* ``PyPCAP`` **and** ``PCAP_CT`` **were already excluded for installability**, which the
changed: the 1.4 ``all`` carried some of them.
* ``PyPCAP`` **and** ``PCAP_CT`` **are also excluded for installability**, a reason the
ruling leaves untouched. ``pypcap`` is an sdist-only C extension needing a
compiler and the libpcap development files; ``pcap-ct`` and ``libpcap`` are
published only as pre-releases, and ``all`` should not be how somebody acquires a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,12 @@ Each is deliberate. Do not "fix" any of them.

**A parsing base may live in another subpackage.**
:mod:`pcapkit.protocols.application.rarp` imports
:class:`~pcapkit.protocols.link.arp.ARP` from :mod:`pcapkit.protocols.link.arp`. This
is the first ``application/ → link/`` dependency in the package, and it is the honest
consequence of letting layer and parser disagree.
:class:`~pcapkit.protocols.link.arp.ARP` from :mod:`pcapkit.protocols.link.arp`. That
``application/ → link/`` dependency is the honest consequence of letting layer and
parser disagree.

**The dispatch tier is decoupled from the subpackage.** A protocol's subpackage says
nothing about which registry reaches it, and the move did not touch any dispatch key:
nothing about which registry reaches it, and no dispatch key depends on it:

.. list-table::
:header-rows: 1
Expand Down
30 changes: 15 additions & 15 deletions docs/source/contributing/conventions/registry-protocol.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ The owner ruled on :issue:`877` that a registry may subclass a bare base enum ou
subclassing that base in turn for use by the mutable ones. So a **closed** set
inherits :class:`~pcapkit.corekit.enum.EnumLookup`
directly and is never handed a ``register`` it would have to refuse; an **open**
registry inherits :class:`~pcapkit.corekit.enum.EnumRegistry` exactly as before.
registry inherits :class:`~pcapkit.corekit.enum.EnumRegistry`.

What settled the split is the owner's own second thought about carrying ``register``
on the base: if the base carries ``register``, there is no principled reason for it
Expand All @@ -54,9 +54,9 @@ Following that through leaves :class:`~pcapkit.corekit.enum.EnumRegistry` holdin
a few methods, too thin to justify a second class -- so the two tiers collapse into one,
which is the opposite of what was ruled.

**Both tiers are plain classes, and that is load-bearing.** Inserting a parent above
:class:`~pcapkit.corekit.enum.EnumRegistry` leaves the member data type exactly where
it was -- ``LinkType -> EnumRegistry -> EnumLookup -> IntEnum -> int`` -- so
**Both tiers are plain classes, and that is load-bearing.** The parent above
:class:`~pcapkit.corekit.enum.EnumRegistry` leaves the member data type with the enum
base -- ``LinkType -> EnumRegistry -> EnumLookup -> IntEnum -> int`` -- so
``_member_type_`` still comes from the enum base. Had either tier subclassed
``aenum.Enum`` in order to "be an enum", it would have become the member type
itself and broken ``int``, ``str`` and flag registries at once.
Expand Down Expand Up @@ -348,15 +348,15 @@ resolvable.

And a folding override carries **only** the fold.
:meth:`TransportProtocol.get <pcapkit.const.reg.apptype.apptype.TransportProtocol.get>` is
the worked example: since :issue:`923` it lowers ``key``, forwards ``default`` verbatim
and delegates to ``super().get()``, and that is all it does. It used to convert the base's
name-miss :exc:`KeyError` into a :exc:`ValueError` as well, and :issue:`923`'s ruling
retired that; the :issue:`808` refusal to extend the class at all is untouched by the
retirement, since only the exception class moved. ``Criticality.get`` went further and was
the worked example: it lowers ``key``, forwards ``default`` verbatim and delegates to
``super().get()``, and that is all it does. :issue:`923`'s ruling retired the conversion
of the base's name-miss :exc:`KeyError` into a :exc:`ValueError` that it also carried;
the :issue:`808` refusal to extend the class at all is untouched by the retirement,
since only the exception class moved. ``Criticality.get`` went further and was
deleted: conversion was the *only* thing it added over the base, so once that went there
was nothing left for an override to hold, and the class inherits
:meth:`~pcapkit.corekit.enum.EnumLookup.get` unchanged. **An override that would now be
empty is deleted, not kept as a pass-through** -- a ``get`` that only calls
:meth:`~pcapkit.corekit.enum.EnumLookup.get` unchanged. **An override left with nothing
to add is deleted, not kept as a pass-through** -- a ``get`` that only calls
``super().get()`` reads as though it were doing something, and the next reader has to diff
it against the base to find out that it is not.

Expand Down Expand Up @@ -525,10 +525,9 @@ That leaves the classes with something to decide:
:class:`~pcapkit.protocols.internet.mh.LocalizedRoutingStatus` never carried a
``get`` at all, so they had no string lookup to fold.
:class:`~pcapkit.protocols.application.ngap.Criticality` had one when this audit
was taken and no longer does: :issue:`877` re-parented it onto
was taken and inherits ``get`` unchanged: :issue:`877` re-parented it onto
:class:`~pcapkit.corekit.enum.EnumLookup` and :issue:`923` retired the exception
conversion that was the override's only remaining job, so it inherits ``get``
unchanged.
conversion that was the override's only remaining job.
- **case-sensitive** -- conforms
* - :class:`~pcapkit.protocols.misc.pcapng.WireGuardKeyLabel`
- ``draft-tuexen-opsawg-pcapng``
Expand Down Expand Up @@ -609,7 +608,8 @@ rather than changing it.
: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` and
:class:`~pcapkit.const.pcapng.option_type.OptionType`,
:class:`~pcapkit.const.reg.apptype.apptype.TransportProtocol` and
:class:`~pcapkit.const.reg.apptype.apptype.AppType` -- and probing one of those
measures the override rather than the base. The unconditionally clean witness is
``tests/corekit/test_enum_lookup_base_unit.py``'s own ``_Str``, a purpose-built
Expand Down
5 changes: 2 additions & 3 deletions docs/source/contributing/conventions/sentinel-convention.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,11 @@ leaves the type out of it. The type stays importable by its dotted path there, f
annotation or an ``is`` guard; it is only ``import *`` that does not offer it. The
``__all__`` there does name :class:`~pcapkit.corekit.sentinels.Sentinel`, the abstract
base every sentinel type shares, since that is no sentinel's own type. A private
sentinel such as ``ABSENT`` is in neither, which is what private means here -- dropping
its leading underscore did not add it to either list, and
sentinel such as ``ABSENT`` is in neither, which is what private means here, and
:class:`~pcapkit.corekit.sentinels.AbsentType` and
:data:`~pcapkit.corekit.sentinels.ABSENT` are documented on
:doc:`the sentinels API page </pcapkit/corekit/sentinels>` as private and not for
public use rather than left off it, since the name alone no longer says so.
public use rather than left off it, since nothing in the name says so.

.. note::

Expand Down
7 changes: 5 additions & 2 deletions docs/source/contributing/conventions/test-coverage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ known-failure table keep their cases in a generator, beside the captures it also
* - :file:`tests/protocols/test_dispatch_registry_unit.py`
- :file:`examples/generators/dispatch.py`
- every ``__proto__`` entry dispatches to the class ``PINNED_TARGETS`` names;
known failures in ``KNOWN_DEGRADED`` (:issue:`496`)
known degrades in ``DispatchRegistryTests.KNOWN_DEGRADED``, which the
generator's own ``KNOWN_DEGRADED`` mirrors for its command-line report
(:issue:`496`)

The rules those tables carry:

Expand All @@ -56,7 +58,8 @@ The rules those tables carry:
Routing a case around a defect hides it: the generator's ``HIP_COPIES`` once put two
parameters in every HIP packet, so the unrepresentable length of a lone one
(:issue:`651`) was never constructed.
``KNOWN_DEGRADED`` entries have a different shape -- a fragment and a reason -- and
``KNOWN_DEGRADED`` entries have a different shape -- the fragments of the probe's
``'error'`` value the entry accepts, any one of which may match, and a reason -- and
they record why the probe's placeholder payload cannot reach the target, not a
defect to fix, so the name-and-issue rule does not apply to them.
* **A regression is fixed; a pre-existing defect is recorded.** A case that a change
Expand Down
32 changes: 16 additions & 16 deletions docs/source/contributing/pep.rst
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ What is left, and why:
It wants a registry of its own rather than
:meth:`~pcapkit.protocols.protocol.Protocol._decode_next_layer`, which is
only ever called at a layer boundary and appends to the frame's protocol chain.
An MLD address record inside a mobility option did not follow MH on the wire,
An MLD address record inside a mobility option does not follow MH on the wire,
so putting it in that chain would make ``layer=`` and ``protocol=`` limits
behave wrongly. Changing the parsed shape from :obj:`bytes` to
:class:`~pcapkit.protocols.misc.raw.Raw` also changes what existing captures dump to, so
Expand Down Expand Up @@ -276,7 +276,7 @@ complaint and yields nothing useful.
:attr:`TCP.__proto__ <pcapkit.protocols.transport.tcp.TCP.__proto__>` and
:attr:`UDP.__proto__ <pcapkit.protocols.transport.udp.UDP.__proto__>`, out of
a registry carrying every IANA service name: TCP 20 to FTP-DATA and 21 to FTP,
ports 80 and 8080 to HTTP on both TCP and UDP, and UDP 1701 to L2TP.
ports 80 and 8080 to HTTP on both TCP and UDP, and UDP 1701 to L2TPv2.
* :class:`~pcapkit.const.sctp.payload_protocol_identifier.PayloadProtocolIdentifier`
-- the values in :attr:`SCTP.__proto__
<pcapkit.protocols.transport.sctp.SCTP.__proto__>`: PPIDs 60 and 66, each to
Expand Down Expand Up @@ -386,8 +386,8 @@ suspect -- is 0.0% of its own cost and 4.4% of a parse, and the logging
integration is 0.03% even in the heaviest shape, since every call site is a lazy
``%s``. The IO-batching idea the thread proposed was never the bottleneck.

The larger wins this section listed, all outside the parse path, have landed in
full or in part:
The larger costs this section listed all lie outside the parse path, and each is
addressed in full or in part:

* **The flow dumper reopens its output file once per frame**, in
:class:`~pcapkit.dumpkit.pcap.PCAPIO`'s ``__call__``. It does not
Expand All @@ -407,11 +407,11 @@ full or in part:
measured at 86% of the IP-reassembly cost plus a 133 ms garbage-collection
bill. Whether unfragmented frames should be emitted at all is the design
question that is left, and it is worth settling deliberately.
* **Done.** Every option was parsed twice -- 2274 schema unpacks for 1137
options, the pre-parse always discarded, about 15% of a PCAP-NG extraction.
:class:`~pcapkit.corekit.fields.collections.OptionField` reads only the base
schema's type field to choose the option schema, rather than unpacking the
whole base schema and throwing it away.
* **Done.** :class:`~pcapkit.corekit.fields.collections.OptionField` reads only
the base schema's type field to choose the option schema, rather than unpacking
the whole base schema and throwing it away. Unpacking it parsed every option
twice -- 2274 schema unpacks for 1137 options, the pre-parse always discarded,
about 15% of a PCAP-NG extraction.

Some traps for anyone benchmarking this library. ``reassembly=True`` and
``trace=True`` are **no-ops** without ``ip=``/``tcp=``, so a benchmark that passes
Expand All @@ -423,10 +423,10 @@ Recursive Dissection, With a Depth Limit

**Decided, open to revisit.** Each layer dissects the next from inside
its own parse, so dissecting a frame recurses once per layer, at 9 to 12 Python
frames a layer. Deep nesting -- IP in IP, stacked 802.1Q tags, long chains of
IPv6 extension headers -- used to exhaust the recursion limit and leave the rest
of the frame raw, silently, at a depth that varied with the interpreter and the
caller's stack (:issue:`1604`, :issue:`1610`).
frames a layer. Without a bound, deep nesting -- IP in IP, stacked 802.1Q tags,
long chains of IPv6 extension headers -- exhausts the recursion limit and leaves the
rest of the frame raw, silently, at a depth that varies with the interpreter and
the caller's stack (:issue:`1604`, :issue:`1610`).

Recursion stays, with a counted bound:
:data:`~pcapkit.utilities.config.FRAME_LAYER_LIMIT` caps a frame at 64 layers by
Expand Down Expand Up @@ -622,9 +622,9 @@ Anyone wanting to run the tests wants the repository, which is where they are.

``dictdumper``'s ``PLIST`` writer formats every :class:`~datetime.datetime` as
``'%Y-%m-%dT%H:%M:%S.%fZ'``, always with six fractional digits, and
:mod:`plistlib`'s ``<date>`` pattern admits none, so :func:`plistlib.load`
failed on every ``format='plist'`` report with ``AttributeError: 'NoneType'
object has no attribute 'groupdict'``. The upstream defect is
:mod:`plistlib`'s ``<date>`` pattern admits none, so without the workaround
below :func:`plistlib.load` fails on every ``format='plist'`` report with
``AttributeError: 'NoneType' object has no attribute 'groupdict'``. The upstream defect is
`JarryShaw/DictDumper#122 <https://github.com/JarryShaw/DictDumper/issues/122>`__.
:func:`pcapkit.dumpkit.common.make_dumper` works around it (:issue:`1448`): it
writes each date in UTC to whole seconds, as :func:`plistlib.dump` does. The
Expand Down
Loading
Loading