User Defined Exceptions

pcapkit.utilities.exceptions refined built-in exceptions. Make it possible to show only user error stack information [*], when exception raised on user’s operation.

Loud and Quiet Errors

Raising a BaseError is, by default, a loud act: the error is logged once at logging.CRITICAL on the logger logger, and outside development mode an exception hook is installed on sys.excepthook and threading.excepthook, the first time a loud error needs it, so the user sees the exception line rather than a walk through pcapkit’s internals. That hook only shortens the printing of a BaseError itself; every other exception is handed on to whichever hook was previously installed, unchanged.

quiet=True marks an error that pcapkit raises as internal control flow and expects to catch itself – the MissingKeyError behind MultiDict.get is the archetype. 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 repr() are unaffected.

Changed in version 1.5.0: In 1.4.x, quiet=True logged at ERROR instead of CRITICAL rather than not logging, and sys.tracebacklimit was set on both paths. A single MultiDict.get() miss therefore produced an ERROR record – one per frame when parsing unfragmented IPv6 with reassembly enabled – and truncated the tracebacks of unrelated exceptions for the rest of the process. Those records never corresponded to a fault; to observe internal lookup misses, catch the exception rather than read the log (#362).

exception pcapkit.utilities.exceptions.BaseError(*args, quiet=False, **kwargs)[source]

Bases: Exception

Base error class of all kinds.

A loud error – the default – is reported once, at logging.CRITICAL level, on the logger logger. Outside development mode it also installs _excepthook() as sys.excepthook and _threading_excepthook() as 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 pcapkit’s internals.

A quiet error (quiet=True) is one pcapkit raises as internal control flow and expects to catch itself, such as the MissingKeyError behind MultiDict.get. It is therefore silent and free of side effects: nothing is logged, and neither sys.excepthook nor threading.excepthook is touched. It is still a perfectly ordinary exception, carrying its message for whoever catches it.

Important

  • The terseness is deliberately not done by setting sys.tracebacklimit to 0: that is process-global, so one loud error would truncate the tracebacks of every other, unrelated exception for the rest of the process. Each of the two hooks here shortens the printing of a BaseError only, and hands every other exception, unchanged, to whatever hook pcapkit found installed before it first needed its own.

  • Both hooks are installed lazily, from here, rather than at import time, so a program that imports pcapkit but never raises one of its errors never has sys.excepthook or threading.excepthook touched.

  • The two hooks still do not cover every path an exception can take. A traceback a caller formats itself with traceback – rather than letting it reach the top level uncaught – passes through neither. See GitHub issue #719.

  • The stacklevel of the log record is the relative level stacklevel() computes, so the record is attributed to the caller whose operation failed rather than to this module. It must not be negated: logging.Logger.findCaller() reads that as “do not walk out at all” and would blame logging itself for every error.

Changed in version 1.5.0: A quiet error logs nothing, where 1.4.x logged it at ERROR, and no error sets sys.tracebacklimit (#362).

Parameters:
  • quiet – If True, the error is neither logged nor allowed to install the exception hook; it is raised silently, as internal control flow.

  • *args – Arbitrary positional arguments.

  • **kwargs – Arbitrary keyword arguments.

TypeError Category

exception pcapkit.utilities.exceptions.DigitError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be (a) number(s).

exception pcapkit.utilities.exceptions.IntError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be integral.

exception pcapkit.utilities.exceptions.RealError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The function is not defined for real number.

exception pcapkit.utilities.exceptions.ComplexError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The function is not defined for complex instance.

exception pcapkit.utilities.exceptions.BoolError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be bool type.

exception pcapkit.utilities.exceptions.BytesError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be bytes type.

exception pcapkit.utilities.exceptions.StringError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be str type.

exception pcapkit.utilities.exceptions.BytearrayError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be bytearray type.

exception pcapkit.utilities.exceptions.DictError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be dict type.

exception pcapkit.utilities.exceptions.ListError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be list type.

exception pcapkit.utilities.exceptions.TupleError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be tuple type.

exception pcapkit.utilities.exceptions.IterableError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be iterable.

exception pcapkit.utilities.exceptions.IOObjError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be file-like object.

exception pcapkit.utilities.exceptions.ProtocolUnbound(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

Protocol slice unbound.

exception pcapkit.utilities.exceptions.CallableError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be callable.

exception pcapkit.utilities.exceptions.InfoError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be Info instance.

exception pcapkit.utilities.exceptions.IPError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be IP address.

exception pcapkit.utilities.exceptions.EnumError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be enumeration protocol type.

exception pcapkit.utilities.exceptions.ComparisonError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

Rich comparison not supported between instances.

exception pcapkit.utilities.exceptions.RegistryError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be registry type.

exception pcapkit.utilities.exceptions.FieldError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, TypeError

The argument(s) must be field type.

AttributeError Category

exception pcapkit.utilities.exceptions.FormatError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, AttributeError

Unknown format(s).

exception pcapkit.utilities.exceptions.UnsupportedCall(*args, quiet=False, **kwargs)[source]

Bases: BaseError, AttributeError

Unsupported function or property call.

IOError Category

exception pcapkit.utilities.exceptions.FileError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, OSError

[Errno 5] Wrong file format.

FileExistsError Category

exception pcapkit.utilities.exceptions.FileExists(*args, quiet=False, **kwargs)[source]

Bases: BaseError, FileExistsError

[Errno 17] File already exists.

FileNotFoundError Category

exception pcapkit.utilities.exceptions.FileNotFound(*args, quiet=False, **kwargs)[source]

Bases: BaseError, FileNotFoundError

[Errno 2] File not found.

IndexError Category

exception pcapkit.utilities.exceptions.ProtocolNotFound(*args, quiet=False, **kwargs)[source]

Bases: BaseError, IndexError

Protocol not found in ProtoChain.

ValueError Category

exception pcapkit.utilities.exceptions.VersionError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ValueError

Unknown IP version.

exception pcapkit.utilities.exceptions.IndexNotFound(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ValueError

Protocol not in ProtoChain.

exception pcapkit.utilities.exceptions.ProtocolError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ValueError

Invalid protocol format.

exception pcapkit.utilities.exceptions.EndianError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ValueError

Invalid endian (byte order).

exception pcapkit.utilities.exceptions.KeyExists(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ValueError

Key already exists.

exception pcapkit.utilities.exceptions.NoDefaultValue(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ValueError

No default value.

exception pcapkit.utilities.exceptions.EnumValueError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ValueError

No member of an enumeration carries this value.

The value-miss half of the pair whose name-miss half is EnumKeyError; see that one for the stdlib Enum shape both follow, and for why the two halves derive from different builtins.

exception pcapkit.utilities.exceptions.FieldValueError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ValueError

Invalid field value.

exception pcapkit.utilities.exceptions.SchemaError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ValueError

Invalid schema.

exception pcapkit.utilities.exceptions.SeekError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ValueError

Invalid seek position.

exception pcapkit.utilities.exceptions.TruncateError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ValueError

Invalid truncate size.

exception pcapkit.utilities.exceptions.VendorPathNotFound(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ValueError

Crawler module is not inside the vendor package root.

NotImplementedError Category

exception pcapkit.utilities.exceptions.ProtocolNotImplemented(*args, quiet=False, **kwargs)[source]

Bases: BaseError, NotImplementedError

Protocol not implemented.

exception pcapkit.utilities.exceptions.VendorNotImplemented(*args, quiet=False, **kwargs)[source]

Bases: BaseError, NotImplementedError

Vendor not implemented.

struct.error Category

exception pcapkit.utilities.exceptions.StructError(*args, eof=False, **kwargs)[source]

Bases: BaseError, error

Unpack failed.

EOFError Category

exception pcapkit.utilities.exceptions.StreamEOFError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, EOFError

Underlying stream exhausted; no data left to read.

Raised by prepare() when the length 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 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.

A declared zero length – a nested schema legitimately sized to have nothing to read – is a different situation and does not raise this.

Frame and PCAPNG raise it too, quietly, when fewer octets are left than a record header or a block needs.

Note

prepare() always raises this with quiet=True: reaching end of stream is the frame reader’s ordinary way of finding out there is nothing left to parse, not a fault to log – the same convention StructError follows for the same situation via its own eof=True.

KeyError Category

exception pcapkit.utilities.exceptions.MissingKeyError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, KeyError

Key not found.

exception pcapkit.utilities.exceptions.FragmentError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, KeyError

Invalid fragment dict.

exception pcapkit.utilities.exceptions.PacketError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, KeyError

Invalid packet dict.

exception pcapkit.utilities.exceptions.EnumKeyError(*args, quiet=False, **kwargs)[source]

Bases: BaseError, KeyError

No member of an enumeration carries this name.

The name-miss half of the pair whose value-miss half is EnumValueError, and the split between them follows stdlib Enum rather than this package’s own taste: E['nosuch'] raises KeyError and E(999) raises ValueError, so a lookup that misses by name is KeyError-derived and one that misses by value is ValueError-derived. That is a ruling given in review of #877’s phase-2 re-parenting, carried out by GitHub issue #923: raise whichever of the two stdlib Enum would raise in the same circumstances, and raise it from this module rather than as a builtin.

Deriving from KeyError is what makes that ruling cheap to carry out: six in-library call sites catch get()’s name miss as KeyError – 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.

Note

Distinct from MissingKeyError, which is deliberately not reused here: that one reports an absent mapping key, as MultiDict and the pcapkit.toolkit extractors raise it, and conflating the two would leave a caller unable to tell a registry that has no such member from a packet dict that has no such field.

Added in version 1.5.0.

ModuleNotFoundError Category

exception pcapkit.utilities.exceptions.ModuleNotFound(*args, quiet=False, **kwargs)[source]

Bases: BaseError, ModuleNotFoundError

Module not found.

io.UnsupportedOperation Category

exception pcapkit.utilities.exceptions.UnsupportedOperation(*args, quiet=False, **kwargs)[source]

Bases: BaseError, UnsupportedOperation

Unsupported operation.

Error Handling Utilities

pcapkit.utilities.exceptions.stacklevel()[source]

Stack level of the innermost frame outside pcapkit.

The value is a relative level, in the sense both warnings.warn() and the logging module use: level 1 is the frame that called stacklevel(), level 2 its caller, and so on outwards. Handing it to either of them attributes the complaint to the caller who reached into pcapkit, rather than to whichever pcapkit internal happened to notice the problem – which is the whole point of the function, since the internal frames are noise to the user reading the report.

The arithmetic, since it is easy to get backwards. Number the frames outwards from this one, so that a number is the relative level a consumer wants:

level 0             stacklevel() itself
level 1             whoever called stacklevel()
...
level boundary      the outermost frame inside pcapkit
...
level outermost     the interpreter entry point

The frame to name is the first one past the boundary, hence boundary + 1. boundary is measured from the inside out: it depends only on how deep the pcapkit frames run, never on how deep the caller’s own stack is. Numbering from the outside in would grow with the outer stack, so the frame named would drift one further out for every extra frame above the boundary – under pytest, dozens of them.

Both bounds are enforced, as neither consumer copes with a level outside them:

  • Never below 1. 0 and negative values mean “do not walk out at all” to logging.Logger.findCaller(), which then attributes the record to logging itself; warnings.warn() treats them as 1.

  • Never above outermost. That bound is reached when the whole stack is inside pcapkit, e.g. running the package as a script, and walking past the outermost frame makes warnings.warn() fall back to blaming the sys module.

The walk goes through inspect.currentframe() and f_back rather than traceback.extract_stack(): it skips building the FrameSummary objects and the linecache lookups traceback.extract_stack() does for every frame, which is worth avoiding on a function called once per warning. It is also immune to sys.tracebacklimit, which traceback.StackSummary.extract() honours: a limit of 0 would make extract_stack() return an empty list and silently break the attribution of every warning. BaseError does not set that limit (it prints its terse line through an exception hook instead), but user code may.

Important

The level is relative to the caller of stacklevel(). A function that forwards it to warnings.warn() on its caller’s behalf has to add one for its own frame – see pcapkit.utilities.warnings.warn(), which does exactly that.

Return type:

int

Returns:

Number of frames from the caller of stacklevel() outwards to the innermost frame whose path does not contain /pcapkit/.

Footnotes