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
6 changes: 3 additions & 3 deletions docs/source/pcapkit/utilities/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ User Defined Exceptions

.. module:: pcapkit.utilities.exceptions

:mod:`pcapkit.utilities.exceptions` refined built-in exceptions.
Make it possible to show only user error stack information [*]_,
when exception raised on user's operation.
:mod:`pcapkit.utilities.exceptions` holds refined built-in exceptions,
which make it possible to show only user error stack information [*]_
when an exception is raised on user's operation.

Loud and Quiet Errors
---------------------
Expand Down
2 changes: 1 addition & 1 deletion docs/source/pcapkit/utilities/warnings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ User Defined Warnings

.. module:: pcapkit.utilities.warnings

:mod:`pcapkit.utilities.warnings` refined built-in warnings.
:mod:`pcapkit.utilities.warnings` holds refined built-in warnings.

.. versionremoved:: 1.5.0

Expand Down
6 changes: 3 additions & 3 deletions pcapkit/foundation/engines/dpkt.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,9 @@ def _read_packet(self, buf: 'bytes', block_type: 'int',

Returns:
Timestamp in seconds since the UNIX epoch, and the packet data. The
timestamp is a :class:`~pcapkit.toolkit.dpkt.Timestamp`: the
:obj:`float` this reader always yielded, which also carries the exact
value, the interface's resolution and the packet's original length,
timestamp is a :class:`~pcapkit.toolkit.dpkt.Timestamp`: a
:obj:`float` that also carries the exact value, the interface's
resolution and the packet's original length,
for the PCAP frame record of the packet (:issue:`1507`).

Raises:
Expand Down
4 changes: 2 additions & 2 deletions pcapkit/foundation/engines/pcap_ct.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ class PCAP_CT(EngineBase['RawFrame']):
apart, and :doc:`the engine documentation
</pcapkit/foundation/engines/3rdparty>` for which one to install.

It exists because upstream `PyPCAP`_ cannot be installed on a current
interpreter: it ships no wheels and its ``pcap.c`` was pre-generated by
It exists because upstream `PyPCAP`_ cannot be installed on Python 3.12 or
newer: it ships no wheels and its ``pcap.c`` was pre-generated by
Cython 0.29.32, which does not compile against the Python 3.12+ C API.
`pcap-ct`_ and `libpcap`_ both publish ``py3-none-any`` wheels, so **installing**
this engine needs no compiler and no ``pcap.h``.
Expand Down
4 changes: 2 additions & 2 deletions pcapkit/foundation/engines/scapy.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def _reader_type() -> 'Type[PcapReader]':
PCAP-NG specification defines a section: an interface ID counts the Interface
Description Blocks of its own section only. `Scapy`_'s reader keeps appending
to one table across Section Header Blocks, so a later section's interface 0
resolved to the first section's, with its link type and resolution (:issue:`1522`).
resolves to the first section's, with its link type and resolution (:issue:`1522`).

And it dates packets that `Scapy`_ misdates. A Simple Packet
Block has no timestamp, and `Scapy`_ leaves its packet with the time it was
Expand Down Expand Up @@ -182,7 +182,7 @@ def close(self) -> 'None':

class _Uncapped(PcapReader):
# ``sniff`` calls ``recv()``, and Scapy's default ``size`` of ``MTU``
# cut every record to 65,535 octets (#1717); an explicit one is kept
# cuts every record to 65,535 octets (#1717); an explicit one is kept
def recv(self, size: 'int' = _CAPLEN_MAX, **kwargs: 'Any') -> 'ScapyPacket': # type: ignore[override]
return super().recv(size, **kwargs)

Expand Down
12 changes: 6 additions & 6 deletions pcapkit/foundation/extraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -1114,7 +1114,7 @@ def _open_output(self, **kwargs: 'Any') -> 'None':

The built-in engines call this at their global-header step. The PCAP
engine passes the header's fields as ``protocol``, ``byteorder``,
``nanosecond``, ``thiszone``, ``sigfigs`` and ``snaplen``:
``nanosecond``, ``version``, ``thiszone``, ``sigfigs`` and ``snaplen``:
:class:`~pcapkit.dumpkit.pcap.PCAPIO` writes its own global header from
them, and the other writers ignore them. The PCAP-NG engine passes none.
:meth:`run` calls it again, without arguments, after the engine has
Expand Down Expand Up @@ -1621,7 +1621,7 @@ def __exit__(self, exc_type: 'Type[BaseException] | None', exc_value: 'BaseExcep
class owns it* -- the rule of :issue:`610`, as :meth:`_owns_input` writes
it down and :meth:`_cleanup` and the backstops already follow. A stream
the caller supplied stays open for the caller to close, so leaving the
block no longer closes it behind the caller's back (:issue:`1999`).
block does not close it behind the caller's back (:issue:`1999`).

For a caller's non-seekable stream, the stream this class owns is the
:class:`~pcapkit.corekit.io.SeekableReader` wrapped around it, and that
Expand Down Expand Up @@ -1776,10 +1776,10 @@ def _note_eof_progress(self) -> 'bool':
being appended to ends at the data present when it got there, rather than
following the writer. That is a deliberate narrowing, and it is measured:
a file gaining its last record 0.6s in yields five of its six frames here,
where the unbounded retry of ``6c3d1b0d9`` yielded all six. Unbounded
retrying is the defect :issue:`620` reports, so *some* stopping rule had
to be chosen, and a timed grace period would only make the cut-off
intermittent rather than absent.
where an unbounded retry yields all six. Unbounded retrying is the defect
:issue:`620` reports, so *some* stopping rule had to be chosen, and a
timed grace period would only make the cut-off intermittent rather than
absent.
Following a growing file wants a deliberate policy of its own; see the
note in :file:`docs/source/changelog/1.5.0.rst`.

Expand Down
4 changes: 2 additions & 2 deletions pcapkit/foundation/reassembly/ip.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ def reassembly(self, info: 'Packet[_AT]') -> 'None':

# initialise buffer with BUFID; ``RCVBT`` holds one entry per 8-octet
# block of the data buffer, its partial last block included -- 8191
# covered octets 0 to 65527 only, so a fragment reaching octet 65528,
# e.g. at the largest Fragment Offset, indexed past it (#1565)
# would cover octets 0 to 65527 only, so a fragment reaching octet 65528,
# e.g. at the largest Fragment Offset, would index past it (#1565)
if BUFID not in self._buffer:
self._buffer[BUFID] = Buffer(
TDL=-1, # Total Data Length
Expand Down
4 changes: 2 additions & 2 deletions pcapkit/foundation/reassembly/ipv4.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ class IPv4(IP):
#: up to the 4.25-minute TTL ceiling, not a 15-second deadline. It is ruled
#: out here: the recommendation is superseded, and TTL is not in
#: :class:`~pcapkit.foundation.reassembly.data.ip.Packet` at all, so the
#: fragment model would have to grow a field to express a scheme the current
#: requirement asks implementations not to use.
#: fragment model would have to grow a field to express a scheme RFC 1122
#: asks implementations not to use.
#:
#: 60 seconds is the low end of RFC 1122's range, and it makes IPv4 agree
#: with the 60 seconds :rfc:`8200#section-4.5` mandates for IPv6 -- so one
Expand Down
4 changes: 2 additions & 2 deletions pcapkit/foundation/reassembly/reassembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
from pcapkit.utilities.logging import get_logger

# NB: declared above the ``TYPE_CHECKING`` block, not below it, so that
# ``CallbackFn`` can name ``_DT`` outright. As a quoted forward reference it was
# resolvable only from this module's namespace, and every module that spells
# ``CallbackFn`` can name ``_DT`` outright. As a quoted forward reference it would
# resolve only from this module's namespace, and every module that spells
# ``CallbackFn`` in an annotation -- ``pcapkit.foundation.registry.foundation``
# does -- has to evaluate the alias in its own.
# packet
Expand Down
2 changes: 1 addition & 1 deletion pcapkit/foundation/reassembly/tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ def submit(self, buf: 'Buffer', *, bufid: 'BufferID', # type: ignore[override]
# if this buffer is complete -- or if it is not, and ``strict``
# asked for one contiguous payload rather than the received runs
#
# NOTE: ``strict=False`` deliberately keeps reporting the whole
# NOTE: ``strict=False`` deliberately reports the whole
# payload buffer with its holes zero-filled, which is what
# :func:`~pcapkit.interface.misc.follow_tcp_stream` wants of a stream
# it is reconstructing best-effort. ``completed`` says so, rather than
Expand Down
2 changes: 1 addition & 1 deletion pcapkit/foundation/registry/foundation.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def register_dumper(format: 'str', module: 'ModuleDescriptor[Dumper] | Type[Dump

The function will register the given dumper class to the
:data:`pcapkit.foundation.traceflow.traceflow.TraceFlow.__output__` and
:data:`pcapkit.foundation.extraction.Extractor.__output__` registry.
:data:`pcapkit.foundation.extraction.Extractor.__output__` registries.

Arguments:
format: format name
Expand Down
15 changes: 8 additions & 7 deletions pcapkit/foundation/traceflow/tcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class TCP(TraceFlowBase[BufferID, Buffer[_AT], Index, Packet[_AT]], Generic[_AT]

It is **off by default** because buffering every traced payload is a cost
tracing does not otherwise pay, and tracing's per-packet cost is something
this package has deliberately driven down. Nothing is reassembled, parsed
this package deliberately keeps low. Nothing is reassembled, parsed
or retained unless it is asked for.

"""
Expand Down Expand Up @@ -255,8 +255,8 @@ def trace(self, packet: 'Packet[_AT]', *, output: 'bool' = False) -> 'Dumper | s
# A SYN arriving on a flow whose teardown has already been observed is a
# *new* connection reusing the endpoints, and the only signal that proves
# the previous one can receive nothing further. It is what finalises a
# bidirectional flow mid-capture; everything else is flushed by
# :meth:`submit` at the end of the capture.
# bidirectional flow mid-capture; everything else is finalised by
# :meth:`finish` at the end of the capture.
#
# The state test matters. A SYN alone does not mean "new connection" --
# the peer's SYN-ACK carries the flag too, and it belongs to the flow the
Expand Down Expand Up @@ -465,10 +465,11 @@ def _finalise(self, bufid: 'BufferID') -> 'Index':
Returns:
The flow's :term:`index <trace.tcp.index>` entry.

Called once per flow, from the one place that can prove a flow is over --
a new connection superseding it, or :meth:`submit` at the end of the
capture. Registering the flow here rather than at teardown is what keeps
the acknowledgement that completes a close inside the flow it belongs to.
Called once per flow, from where a flow can be proved over -- a new
connection superseding it, or :meth:`finish` at the end of the capture --
or, tracing unidirectionally, on that direction's FIN. Registering a
bidirectional flow here rather than at teardown is what keeps the
acknowledgement that completes a close inside the flow it belongs to.

"""
buf = self._buffer.pop(bufid)
Expand Down
4 changes: 2 additions & 2 deletions pcapkit/foundation/traceflow/traceflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
logger = get_logger(__name__)

# NB: declared above the ``TYPE_CHECKING`` block, not below it, so that
# ``CallbackFn`` can name ``_IT`` outright. As a quoted forward reference it was
# resolvable only from this module's namespace, and every module that spells
# ``CallbackFn`` can name ``_IT`` outright. As a quoted forward reference it would
# resolve only from this module's namespace, and every module that spells
# ``CallbackFn`` in an annotation -- ``pcapkit.foundation.registry.foundation``
# does -- has to evaluate the alias in its own.
_DT = TypeVar('_DT')
Expand Down
2 changes: 1 addition & 1 deletion pcapkit/interface/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def follow_tcp_stream(fin: 'Optional[str]' = None, verbose: 'bool' = False,
as one stream, which is the default -- a stream then holds the
frames and the reassembled payload of *both* directions, which is
what "following a TCP stream" means elsewhere. :data:`False`
restores one stream per direction.
gives one stream per direction.
trace_analyse: whether each traced flow reassembles its application
layer, so that :attr:`Index.packet <pcapkit.foundation.traceflow.data.tcp.Index.packet>` can be read off
:attr:`Extractor.trace <pcapkit.foundation.extraction.Extractor.trace>`.
Expand Down
11 changes: 6 additions & 5 deletions pcapkit/toolkit/dpkt.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class RecordTimestamp:
resolution and its original length would be lost between the reader and
:func:`packet2frame`. The engine's readers yield a :class:`Timestamp` or a
:class:`DecimalTimestamp` instead, which *is* the value `DPKT`_ yields --
so a stored frame's timestamp is exactly what it was before -- and also
so a stored frame's timestamp is unchanged by it -- and also
carries what would otherwise be lost. Reassembly and flow tracing are handed a plain
:obj:`float` of it (:issue:`1501`): of its exact value, since `DPKT`_'s
own for a microsecond PCAP rounds twice (:issue:`1668`; see
Expand Down Expand Up @@ -303,8 +303,9 @@ def packet2frame(packet: 'Packet', timestamp: 'float | Decimal', *,
ts_sec = int(epoch)
ts_usec = int((epoch - ts_sec) * RESOLUTION[resolution > RESOLUTION[False]])

# the mapping is exactly the one reported before #1507, plain value types
# included, so that the dict-capable trace formats write the same bytes
# the mapping carries plain value types rather than the timestamp subclasses,
# so that the dict-capable trace formats write the same bytes as for a plain
# timestamp (#1507)
if isinstance(timestamp, float):
timestamp = float(timestamp)
elif isinstance(timestamp, decimal.Decimal):
Expand Down Expand Up @@ -725,8 +726,8 @@ def _tcp_flags(tcp: 'TCP') -> 'tuple[bool, bool, bool]':
Each flag is masked out of :attr:`dpkt.tcp.TCP.flags` by its ``TH_*``
value, so it is read from the flags octet alone. `DPKT`_ 1.9.8 makes
that field nine bits wide, its top bit the NS bit (:rfc:`3540`): read by
its position among the field's binary digits, every flag was one bit low
with NS set, a SYN reading as a FIN (:issue:`1618`).
its position among the field's binary digits, every flag would be one bit
low with NS set, a SYN reading as a FIN (:issue:`1618`).

"""
from dpkt.tcp import TH_FIN, TH_RST, TH_SYN # isort:skip
Expand Down
6 changes: 3 additions & 3 deletions pcapkit/toolkit/pyshark.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@

#: PyShark's text for a boolean field -> its value. tshark 4.x spells one ``'True'``/``'False'``
#: (measured for ``tcp.flags_syn``, ``tcp.flags_fin`` and ``tcp.flags_reset`` with PyShark 0.6
#: on tshark 4.6.9); ``'1'``/``'0'`` is the spelling this module first parsed (:issue:`1514`).
#: on tshark 4.6.9); ``'1'``/``'0'`` is accepted as well (:issue:`1514`).
_BOOLEAN_FIELD = {'1': True, '0': False, 'True': True, 'False': False} # type: dict[str, bool]


Expand Down Expand Up @@ -518,8 +518,8 @@ def _has_addresses(ip: 'Any') -> 'bool':
Note:
tshark reports no ``ip.dst`` behind an LSRR or SSRR option whose route
data is no whole number of addresses ("Suboption would go past end of
option"), measured with tshark 4.6.9. Reading it raised a bare
:exc:`AttributeError` out of :func:`tcp_traceflow`, which ended the
option"), measured with tshark 4.6.9. Reading it unchecked raises a bare
:exc:`AttributeError` out of :func:`tcp_traceflow`, which would end the
extraction (:issue:`1671`).

"""
Expand Down
3 changes: 2 additions & 1 deletion pcapkit/utilities/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
# ``_common`` binds a ``NoneType`` of its own only on a ``NameError``, so there it
# binds none, and the ``from ._common import *`` in aenum's ``__init__`` fails on
# the name ``__all__`` lists: ``AttributeError: module 'aenum._common' has no
# attribute 'NoneType'``. That left pcapkit unimportable on PyPy 8.0 (#1958).
# attribute 'NoneType'``. Unhandled, that leaves pcapkit unimportable on PyPy 8.0
# (#1958).
# ``aenum._common`` itself ran to its end and stays in :data:`sys.modules`, so
# binding the name there and importing aenum again completes it, leaving
# :mod:`builtins` as PyPy has it. This module runs before any of pcapkit's that
Expand Down
2 changes: 1 addition & 1 deletion pcapkit/utilities/datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
# December 31, 1969, UTC, gives ``0.5``, not ``-0.5`` (#2134, measured on
# GraalPy 25.4.4). ``TimestampNode`` takes ``ChronoUnit.SECONDS.between`` of the
# epoch and the instant, which truncates (graalpython, DateTimeBuiltins.java, at
# graal-25.4.4; no upstream issue is filed yet). CPython and PyPy compute
# graal-25.4.4, with no upstream issue filed). CPython and PyPy compute
# ``(dt - epoch).total_seconds()`` for an aware datetime, which is right, so
# there :func:`totimestamp` is the stdlib call itself.
_TIMESTAMP_TRUNCATES = sys.implementation.name == 'graalpy'
Expand Down
18 changes: 9 additions & 9 deletions pcapkit/utilities/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

.. module:: pcapkit.utilities.exceptions

:mod:`pcapkit.utilities.exceptions` refined built-in exceptions.
Make it possible to show only user error stack information [*]_,
when exception raised on user's operation.
:mod:`pcapkit.utilities.exceptions` holds refined built-in exceptions,
which make it possible to show only user error stack information [*]_
when an exception is raised on user's operation.

.. [*] See |tbtrim|_ project for Pythonic implementation.

Expand Down Expand Up @@ -388,7 +388,7 @@ def _excepthook(etype: 'Type[BaseException]', value: 'BaseException',
# A generic, external marker -- "some pcapkit instance's hook is active" -- for
# a caller that only has :func:`sys.excepthook` and no reference to a particular
# loaded copy of this module. Diagnostic only: :func:`_install_excepthook`'s own
# guard below does *not* use this, and must not go back to doing so. The marker
# guard below does *not* use this, and must not. The marker
# is a plain :obj:`True`, identical on every reloaded copy of this function, so
# it cannot tell "my own instance's hook" from "some *other* instance's" --
# which is exactly the distinction the guard needs and a shared value cannot
Expand Down Expand Up @@ -748,9 +748,9 @@ class StreamEOFError(BaseError, EOFError):
of a schema's read was derived by measuring what is actually left in the
stream -- rather than declared by the caller -- and that measurement came
back zero. This is the frame reader's "no more packets" signal, so it
subclasses :exc:`EOFError` rather than replacing it: existing ``except
(EOFError, StopIteration)`` handlers keep working unchanged, and a caller
that wants to be more specific can catch this instead.
subclasses :exc:`EOFError` rather than replacing it: an ``except
(EOFError, StopIteration)`` handler catches it, and a caller that wants to
be more specific can catch this instead.

A *declared* zero length -- a nested schema legitimately sized to have
nothing to read -- is a different situation and does not raise this.
Expand Down Expand Up @@ -805,8 +805,8 @@ class EnumKeyError(BaseError, KeyError):
the in-library call sites catch :meth:`~pcapkit.corekit.enum.EnumLookup.get`'s
name miss as :exc:`KeyError` -- :class:`~pcapkit.const.http.method.Method`'s
``get`` catches it in order to build an unregistered member, so for that one
a failed name lookup is part of a successful call -- and every one of them
keeps catching.
a failed name lookup is part of a successful call -- so every one of them
catches this as well.

Note:
Distinct from :exc:`~pcapkit.utilities.exceptions.MissingKeyError`,
Expand Down
2 changes: 1 addition & 1 deletion pcapkit/utilities/warnings.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

.. module:: pcapkit.utilities.warnings

:mod:`pcapkit.utilities.warnings` refined built-in warnings.
:mod:`pcapkit.utilities.warnings` holds refined built-in warnings.

Every warning :mod:`pcapkit` reports goes through :func:`warn`, which reports it
**exactly once on each channel**:
Expand Down
Loading