diff --git a/docs/source/pcapkit/const/pcapng.rst b/docs/source/pcapkit/const/pcapng.rst index 8e8c5b62a..3ccea319f 100644 --- a/docs/source/pcapkit/const/pcapng.rst +++ b/docs/source/pcapkit/const/pcapng.rst @@ -61,7 +61,7 @@ Option Types This module contains the constant enumeration for **Option Types**, which is automatically generated from :class:`pcapkit.vendor.pcapng.option_type.OptionType`. -.. versionchanged:: 1.1.0 +.. versionchanged:: 1.1.0.post1 A member converts with :class:`int` to its option code, and compares, orders and hashes as that code. diff --git a/docs/source/pcapkit/foundation/reassembly/ip/ip.rst b/docs/source/pcapkit/foundation/reassembly/ip/ip.rst index 1a72dfa08..943fccd85 100644 --- a/docs/source/pcapkit/foundation/reassembly/ip/ip.rst +++ b/docs/source/pcapkit/foundation/reassembly/ip/ip.rst @@ -14,6 +14,7 @@ origin, using the :rfc:`791` procedure described in :doc:`index`. .. automethod:: reassembly .. automethod:: submit + .. automethod:: _detect_conflicts Data Models ----------- diff --git a/docs/source/pcapkit/utilities/exceptions.rst b/docs/source/pcapkit/utilities/exceptions.rst index f6349c610..d0daeec3c 100644 --- a/docs/source/pcapkit/utilities/exceptions.rst +++ b/docs/source/pcapkit/utilities/exceptions.rst @@ -13,8 +13,8 @@ Loud and Quiet Errors Raising a :class:`~pcapkit.utilities.exceptions.BaseError` is, by default, a **loud** act: the error is logged once at :data:`logging.CRITICAL` on the ``pcapkit`` logger (:data:`~pcapkit.utilities.logging.logger`), and outside development mode -an exception hook is installed on :data:`sys.excepthook` and -:data:`threading.excepthook`, the first time a loud error needs it, so the user +an exception hook is installed on :func:`sys.excepthook` and +:func:`threading.excepthook`, the first time a loud error needs it, so the user sees the exception line rather than a walk through :mod:`pcapkit`'s internals. That hook only shortens the printing of a :class:`~pcapkit.utilities.exceptions.BaseError` itself; every other exception @@ -28,6 +28,12 @@ Such an error emits nothing on any channel and touches no process-global state. It is still an ordinary exception carrying its message, so ``except`` clauses and :func:`repr` are unaffected. +An error is also quiet when it is constructed inside a +:class:`~pcapkit.utilities.exceptions._CaughtByCaller` block naming one of its +classes. That is how :mod:`pcapkit` marks as control flow an error raised by +code it calls but does not own, such as a generated ``_validate_value`` +override, which cannot know to pass ``quiet=True`` itself (:issue:`1845`). + .. versionchanged:: 1.5.0 In 1.4.x, ``quiet=True`` logged at ``ERROR`` instead of ``CRITICAL`` rather @@ -48,6 +54,9 @@ It is still an ordinary exception carrying its message, so ``except`` clauses an :param \*args: Arbitrary positional arguments. :param \*\*kwargs: Arbitrary keyword arguments. +.. autoclass:: pcapkit.utilities.exceptions._CaughtByCaller + :no-members: + :exc:`TypeError` Category ------------------------- diff --git a/pcapkit/__init__.py b/pcapkit/__init__.py index 79a0e499d..c361fcfd8 100644 --- a/pcapkit/__init__.py +++ b/pcapkit/__init__.py @@ -11,7 +11,7 @@ .. _DictDumper: https://dictdumper.jarryshaw.me Unlike popular PCAP file extractors, such as `Scapy`_, -`DPKT`_, `PyShark`_, and etc, :mod:`pcapkit` uses streaming +`DPKT`_ and `PyShark`_, :mod:`pcapkit` uses streaming strategy to read input files. That is to read frame by frame, decrease occupation on memory, as well as enhance efficiency in some way. diff --git a/pcapkit/dumpkit/common.py b/pcapkit/dumpkit/common.py index 7f182fc52..2a7d7e5a7 100644 --- a/pcapkit/dumpkit/common.py +++ b/pcapkit/dumpkit/common.py @@ -107,7 +107,7 @@ class MyMixin(Dumper): # not registered from pcapkit.foundation.registry.foundation import register_dumper - register_dumper('my_mixin', MyMixin, '.mine') + register_dumper('my_mixin', MyMixin, ext='.mine') .. versionchanged:: 1.5.0 diff --git a/pcapkit/dumpkit/pcap.py b/pcapkit/dumpkit/pcap.py index 80157dc19..b7b5c84dc 100644 --- a/pcapkit/dumpkit/pcap.py +++ b/pcapkit/dumpkit/pcap.py @@ -272,7 +272,7 @@ def _make_timestamp(self, frame_info: 'Data_FrameInfo', Notes: ``frame_info`` does not say which resolution its ``ts_usec`` is in. A PCAP frame carries its file's, and one converted from PCAP-NG - carries its interface's (c.f. :func:`~pcapkit.toolkit.pcapng.block2frame`), + carries its interface's (cf. :func:`~pcapkit.toolkit.pcapng.block2frame`), either of which may differ from this file's (:issue:`1500`). ``time_epoch`` settles it: the fraction is in whichever resolution truncates the frame's offset into its second to exactly that value. diff --git a/pcapkit/foundation/engines/pcap_ct.py b/pcapkit/foundation/engines/pcap_ct.py index e822c7af7..f984e7fa5 100644 --- a/pcapkit/foundation/engines/pcap_ct.py +++ b/pcapkit/foundation/engines/pcap_ct.py @@ -128,7 +128,7 @@ class PCAP_CT(EngineBase['RawFrame']): _dlink: 'Enum_LinkType' #: Closed flag, so that the handle is not closed twice. _closed: 'bool' - #: What the :mod:`pcap` import actually found, c.f. :attr:`backend`. + #: What the :mod:`pcap` import actually found, cf. :attr:`backend`. _backend: '_pcap_backend.Probe' ########################################################################## diff --git a/pcapkit/foundation/engines/pcapng.py b/pcapkit/foundation/engines/pcapng.py index 444d78713..17baf34c7 100644 --- a/pcapkit/foundation/engines/pcapng.py +++ b/pcapkit/foundation/engines/pcapng.py @@ -200,7 +200,7 @@ def read_frame(self) -> 'P_PCAPNG': - check if the block is a packet block; - if not, save the block into the internal context storage and repeat; - if yes, save the related information into the internal context storage; - - write the parsed block into output file. + - write the parsed block into output file; - reassemble IP and/or TCP fragments; - trace TCP flows if any; - record frame information if any. diff --git a/pcapkit/foundation/engines/pypcap.py b/pcapkit/foundation/engines/pypcap.py index f5ce059be..d620be29e 100644 --- a/pcapkit/foundation/engines/pypcap.py +++ b/pcapkit/foundation/engines/pypcap.py @@ -100,7 +100,7 @@ class PyPCAP(EngineBase['RawFrame']): _dlink: 'Enum_LinkType' #: Closed flag, so that the handle is not closed twice. _closed: 'bool' - #: What the :mod:`pcap` import actually found, c.f. :attr:`backend`. + #: What the :mod:`pcap` import actually found, cf. :attr:`backend`. _backend: '_pcap_backend.Probe' ########################################################################## diff --git a/pcapkit/foundation/extraction.py b/pcapkit/foundation/extraction.py index 714945406..bc76351e1 100644 --- a/pcapkit/foundation/extraction.py +++ b/pcapkit/foundation/extraction.py @@ -111,7 +111,7 @@ class Extractor(Generic[_P]): For supported engines, please refer to :meth:`~pcapkit.foundation.extraction.Extractor.run`. - .. versionchanged:: 1.2.0 + .. versionchanged:: 1.1.1.post2 ``strict`` is renamed ``reasm_strict``, with no alias, and ``reasm_store`` is inserted after it, so a positional argument from @@ -218,7 +218,7 @@ class Extractor(Generic[_P]): _exptl: 'Protocols' #: Extract til layer. _exlyr: 'Layers' - #: Caller supplied parsing context, c.f. :mod:`pcapkit.corekit.context`. + #: Caller supplied parsing context, cf. :mod:`pcapkit.corekit.context`. _exctx: 'ContextRegistry' #: Extraction engine name. _exnam: 'Engines' @@ -1202,7 +1202,7 @@ def __init__(self, context: caller supplied parsing context for protocols that need information not carried on the wire, keyed by protocol index - ID -- c.f. :mod:`pcapkit.corekit.context`. Accepts a + ID -- cf. :mod:`pcapkit.corekit.context`. Accepts a :class:`~pcapkit.corekit.context.ContextRegistry`, a single :class:`~pcapkit.corekit.context.ProtocolContext`, a mapping, or any iterable of contexts. The channel is honoured by the @@ -1224,7 +1224,7 @@ def __init__(self, engine first, which supports PCAP output. pcapkit.utilities.warnings.EngineWarning: If the requested extraction - engine is not available, c.f. :meth:`run`. + engine is not available, cf. :meth:`run`. pcapkit.utilities.warnings.AttributeWarning: If ``trace_analyse`` is requested while the extraction engine is PyShark. diff --git a/pcapkit/foundation/traceflow/traceflow.py b/pcapkit/foundation/traceflow/traceflow.py index f1f41c38a..190df66a3 100644 --- a/pcapkit/foundation/traceflow/traceflow.py +++ b/pcapkit/foundation/traceflow/traceflow.py @@ -248,7 +248,7 @@ class it names, restores the shipped entry rather than storing RegistryWarning: If a different dumper is already registered for ``format``; it is overwritten. - .. versionremoved:: 1.2.0 + .. versionremoved:: 1.1.1.post2 ``register``, which this replaces with no alias. diff --git a/pcapkit/interface/__init__.py b/pcapkit/interface/__init__.py index 2f2dcda84..1b627d4ed 100644 --- a/pcapkit/interface/__init__.py +++ b/pcapkit/interface/__init__.py @@ -5,8 +5,8 @@ .. module:: pcapkit.interface -:mod:`pcapkit.interface` defines several user-oriented -interfaces, variables, and etc. These interfaces are +:mod:`pcapkit.interface` defines the user-oriented +interfaces and constants. These interfaces are designed to help and simplify the usage of :mod:`pcapkit`. """ diff --git a/pcapkit/interface/core.py b/pcapkit/interface/core.py index f84004ec1..e9d569e7e 100644 --- a/pcapkit/interface/core.py +++ b/pcapkit/interface/core.py @@ -5,7 +5,7 @@ .. module:: pcapkit.interface.core :mod:`pcapkit.interface.core` defines core user-oriented -interfaces, variables, and etc., which wraps around the +interfaces and variables, which wrap around the foundation classes from :mod:`pcapkit.foundation`. """ @@ -144,7 +144,7 @@ def extract(fin: 'Optional[str | IO[bytes]]' = None, fout: 'Optional[str]' = Non context: caller supplied parsing context for protocols that need information not carried on the wire, keyed by protocol index ID -- - c.f. :mod:`pcapkit.corekit.context`. The motivating case is + cf. :mod:`pcapkit.corekit.context`. The motivating case is :class:`~pcapkit.protocols.internet.esp.ESP`, which needs the Security Association to find the trailer and decrypt the payload:: @@ -157,7 +157,7 @@ def extract(fin: 'Optional[str | IO[bytes]]' = None, fout: 'Optional[str]' = Non Returns: An :class:`~pcapkit.foundation.extraction.Extractor` object. - .. versionchanged:: 1.2.0 + .. versionchanged:: 1.1.1.post2 ``strict`` is renamed ``reasm_strict``, with no alias, and ``reasm_store`` is inserted after it, so a positional argument from diff --git a/pcapkit/toolkit/scapy.py b/pcapkit/toolkit/scapy.py index 26622db11..6846261ab 100644 --- a/pcapkit/toolkit/scapy.py +++ b/pcapkit/toolkit/scapy.py @@ -326,7 +326,7 @@ def _tcp_segment(tcp: 'TCP') -> 'tuple[bytes, bytes] | None': Returns: The header, as many octets as the Data Offset counts, and the payload - after it, up to the end of the datagrams that carry the segment, c.f. + after it, up to the end of the datagrams that carry the segment, cf. ``_within_datagrams()``; or :data:`None` if the datagrams hold fewer than the 20 octets of the fixed header, or the Data Offset counts fewer (:rfc:`9293#section-3.1`), as there is then no header to split off. diff --git a/pcapkit/utilities/config.py b/pcapkit/utilities/config.py index de40efdc7..b4d3cbb87 100644 --- a/pcapkit/utilities/config.py +++ b/pcapkit/utilities/config.py @@ -63,7 +63,7 @@ 'true': True, 'false': False, 'on': True, 'off': False} -#: What a recursion-bound limit risks once lifted, c.f. :issue:`1610`. +#: What a recursion-bound limit risks once lifted, cf. :issue:`1610`. _RECURSION_RISK = ("each layer is dissected from inside the parse of the one before it, so a deep " "frame may hit Python's recursion limit and raise RecursionError (#1610)") @@ -195,7 +195,7 @@ def read_flag(name: 'str', default: 'bool' = False) -> 'bool': #: header is a layer, so :data:`FRAME_LAYER_LIMIT` applies as well. #: #: Rebuilding a frame with :meth:`~pcapkit.protocols.protocol.ProtocolBase.from_data` -#: stops where parsing it did, and warns once too (:issue:`1619`), c.f. +#: stops where parsing it did, and warns once too (:issue:`1619`), cf. #: :meth:`Internet._make_payload #: `. #: diff --git a/pcapkit/utilities/exceptions.py b/pcapkit/utilities/exceptions.py index 276fa0743..4e37cca12 100644 --- a/pcapkit/utilities/exceptions.py +++ b/pcapkit/utilities/exceptions.py @@ -223,8 +223,8 @@ class BaseError(Exception): A loud error -- the default -- is reported once, at :data:`logging.CRITICAL` level, on the ``pcapkit`` logger (:data:`~pcapkit.utilities.logging.logger`). Outside development mode it - also installs :func:`_excepthook` as :data:`sys.excepthook` and - :func:`_threading_excepthook` as :data:`threading.excepthook`, the first time + also installs :func:`_excepthook` as :func:`sys.excepthook` and + :func:`_threading_excepthook` as :func:`threading.excepthook`, the first time a loud error needs them, so that error -- and every loud error reaching the top level after it, on the main thread or any other -- prints its one-line exception message rather than a walk through :mod:`pcapkit`'s internals. @@ -234,7 +234,7 @@ class BaseError(Exception): :exc:`~pcapkit.utilities.exceptions.MissingKeyError` behind :meth:`MultiDict.get `. It is therefore silent and free of side effects: nothing is logged, and neither - :data:`sys.excepthook` nor :data:`threading.excepthook` is touched. It is + :func:`sys.excepthook` nor :func:`threading.excepthook` is touched. It is still a perfectly ordinary exception, carrying its message for whoever catches it. @@ -255,8 +255,8 @@ class BaseError(Exception): installed before it first needed its own. * The hooks are installed lazily, from here, rather than at import time, so a program that imports :mod:`pcapkit` but never raises one of - its errors never has :data:`sys.excepthook` or - :data:`threading.excepthook` touched. + its errors never has :func:`sys.excepthook` or + :func:`threading.excepthook` touched. * The hooks still do not cover *every* path an exception can take. A traceback a caller formats itself with :mod:`traceback` -- rather than letting it reach the top level uncaught -- passes through @@ -292,7 +292,7 @@ def __init__(self, *args: 'Any', quiet: 'bool' = False, **kwargs: 'Any') -> 'Non #: Callable[[Type[BaseException], BaseException, Optional[TracebackType]], None]: -#: Whatever :data:`sys.excepthook` was installed immediately before +#: Whatever :func:`sys.excepthook` was installed immediately before #: :func:`_install_excepthook` last replaced it -- :data:`None` until that #: happens. This is what a non-:class:`BaseError` is delegated to from #: :func:`_excepthook`. @@ -302,7 +302,7 @@ def __init__(self, *args: 'Any', quiet: 'bool' = False, **kwargs: 'Any') -> 'Non #: :data:`None` in the very globals the already-installed :func:`_excepthook` #: still reads from on every call (a global lookup, not a value closed over at #: definition time). The old hook -- still installed, since a reload does not -#: retroactively change what :data:`sys.excepthook` points at -- then falls +#: retroactively change what :func:`sys.excepthook` points at -- then falls #: back to :data:`sys.__excepthook__` for a non-:class:`BaseError`, silently #: losing whatever had been captured before the reload (a host application's #: own hook, or ``tbtrim``'s). Measured: a delegate trimmed to one frame before @@ -315,10 +315,10 @@ def __init__(self, *args: 'Any', quiet: 'bool' = False, **kwargs: 'Any') -> 'Non _previous_excepthook = None # type: Optional[Callable[..., None]] #: bool: Set for the duration of :func:`_excepthook`, so a re-entrant call -- the -#: delegate somehow routing back through :data:`sys.excepthook` -- falls back to +#: delegate somehow routing back through :func:`sys.excepthook` -- falls back to #: the interpreter's own hook rather than recursing or printing twice. A single #: shared flag is correct here, unlike the threading analogue below: nothing -#: but the main thread's own unwind ever calls :data:`sys.excepthook`, so there +#: but the main thread's own unwind ever calls :func:`sys.excepthook`, so there #: is no concurrent, unrelated invocation for one flag to be confused with. _excepthook_running = False @@ -367,7 +367,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 :data:`sys.excepthook` and no reference to a particular +# 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 # is a plain :obj:`True`, identical on every reloaded copy of this function, so @@ -378,18 +378,18 @@ def _excepthook(etype: 'Type[BaseException]', value: 'BaseException', #: Callable[[ExceptHookArgs], object]: The thread analogue of -#: ``_previous_excepthook`` -- whatever :data:`threading.excepthook` was +#: ``_previous_excepthook`` -- whatever :func:`threading.excepthook` was #: installed immediately before :func:`_install_excepthook` last replaced it. #: Subject to the same reload caveat documented on ``_previous_excepthook``. #: Typed to return :class:`object` rather than :data:`None`, matching -#: :data:`threading.excepthook` itself in typeshed -- unlike -#: :data:`sys.excepthook`, which is typed as returning :data:`None`. +#: :func:`threading.excepthook` itself in typeshed -- unlike +#: :func:`sys.excepthook`, which is typed as returning :data:`None`. _previous_threading_excepthook = None # type: Optional[Callable[..., object]] #: threading.local: Per-thread re-entrancy guard for #: :func:`_threading_excepthook`, kept separate from ``_excepthook_running`` -#: rather than shared with it. Unlike :data:`sys.excepthook`, which only ever -#: fires once, on the main thread's own unwind, :data:`threading.excepthook` +#: rather than shared with it. Unlike :func:`sys.excepthook`, which only ever +#: fires once, on the main thread's own unwind, :func:`threading.excepthook` #: can genuinely be running in *two different threads at once* -- each with its #: own uncaught exception, entirely unrelated to the other. A single shared #: flag would make one thread's hook see the other's unrelated, concurrent @@ -402,10 +402,10 @@ def _excepthook(etype: 'Type[BaseException]', value: 'BaseException', def _threading_excepthook(args: 'ExceptHookArgs') -> 'None': """Thread analogue of :func:`_excepthook`; same contract, one argument. - :data:`threading.excepthook` is called with a single + :func:`threading.excepthook` is called with a single :class:`threading.ExceptHookArgs`, carrying ``exc_type``, ``exc_value``, ``exc_traceback`` and ``thread`` -- not the three positional parameters - :data:`sys.excepthook` takes. Everything else here mirrors :func:`_excepthook` + :func:`sys.excepthook` takes. Everything else here mirrors :func:`_excepthook` as closely as the default thread hook's own output allows: a loud :class:`BaseError` prints the ``"Exception in thread ...:"`` header the default hook always prints first -- the one piece of that output @@ -419,7 +419,7 @@ def _threading_excepthook(args: 'ExceptHookArgs') -> 'None': hook's own printing at all. This hook is needed because the interpreter's *default* - :data:`threading.excepthook` consults :data:`sys.tracebacklimit`, which + :func:`threading.excepthook` consults :data:`sys.tracebacklimit`, which :class:`BaseError` does not set; without it a loud :class:`BaseError` raised on a worker thread would print a full default traceback. @@ -455,7 +455,7 @@ def _install_excepthook() -> 'None': Called from :class:`BaseError`'s constructor rather than at import time, so that a program that never raises a :mod:`pcapkit` error never has - :data:`sys.excepthook` or :data:`threading.excepthook` touched merely for + :func:`sys.excepthook` or :func:`threading.excepthook` touched merely for having imported the package. Idempotent for *this* module instance, independently for each hook: if a diff --git a/tests/project/test_no_version_directives_in_generated_tables_1884_unit.py b/tests/project/test_no_version_directives_in_generated_tables_1884_unit.py index a73dfe7d9..eac19f92e 100644 --- a/tests/project/test_no_version_directives_in_generated_tables_1884_unit.py +++ b/tests/project/test_no_version_directives_in_generated_tables_1884_unit.py @@ -60,7 +60,7 @@ ('http.rst', 'versionchanged:: 1.5.0', ':issue:`860`'), ('http.rst', 'versionchanged:: 1.5.0', ':issue:`908`'), ('ipv6.rst', 'versionchanged:: 1.5.0', ':issue:`925`'), - ('pcapng.rst', 'versionchanged:: 1.1.0', 'option code'), + ('pcapng.rst', 'versionchanged:: 1.1.0.post1', 'option code'), ('pcapng.rst', 'versionadded:: 1.5.0', ':issue:`886`'), ('reg.rst', 'versionchanged:: 1.1.1', 'port number'), ('reg.rst', 'versionchanged:: 1.5.0', ':issue:`732`'),