Auxiliary Functions¶
Decorators¶
pcapkit.utilities.decorators contains several useful
decorators, including seekset(),
beholder() and
prepare().
- @pcapkit.utilities.decorators.seekset(func)[source]¶
Read file from start then set back to original.
Important
This decorator function is designed for decorating class methods.
The decorator will keep the current offset of
self._file, then call the decorated function. Afterwards, it will rewind the offset ofself._fileto the original and returns the return value from the decorated function.Note
The decorated function should have following signature:
func(self: 'pcapkit.protocols.protocol.ProtocolBase', *args: 'typing.Any', **kwargs: 'typing.Any') -> 'typing.Any'
- @pcapkit.utilities.decorators.beholder(func)[source]¶
Behold extraction procedure.
Important
This decorator function is designed for decorating class methods.
This decorator first keep the current offset of
self._file, then try to call the decorated function. Should any exception raised, it will re-parse theself._fileasRawprotocol.Note
The decorated function should have following signature:
func(self: 'pcapkit.protocols.protocol.ProtocolBase', proto: 'int', length: 'typing.Optional[int]', *args: 'typing.Any', **kwargs: 'typing.Any') -> 'pcapkit.protocols.protocol.ProtocolBase'
- Parameters:
func (
Callable[[Concatenate[ProtocolBase,int,int|None,ParamSpec(P, bound=None)]],TypeVar(R_beholder, bound=ProtocolBase)]) – decorated function- Return type:
Callable[[ParamSpec(P, bound=None)],TypeVar(R_beholder, bound=ProtocolBase)]
- @pcapkit.utilities.decorators.prepare(func)[source]¶
Prepare schema packet data before unpacking.
Important
This decorate function is designed for decorating the
Schema.unpackclass method.This decorator will revise the parameter list provided to the original
Schema.unpackmethod and extract necessary information based on the given parameters, then provide the revised version of parameter list to the original method.Note
The decorated function should have following signature:
func(cls: 'typing.Type[pcapkit.protocols.schema.schema.Schema]', data: 'bytes | typing.IO[bytes]', length: 'Optional[int]', packet: 'Optional[dict[str, Any]]') -> 'pcapkit.protocols.schema.schema.Schema'
No further positional or keyword arguments are read from – or forwarded to – the decorated function.
prepare()is applied to exactly one function in this tree,Schema.unpack, whose real signature has never had more than these four parameters, and nothing calls it with more; an earlier revision of this note nonetheless promised implementors a trailing*args, **kwargs, which the wrapper below never populated. A caller relying on that promise got extras silently discarded instead of forwarded – see #454 – so the wrapper now raisesTypeErrorfor a fifth positional argument or an unconsumed keyword, the same as an ordinary call with too many arguments would.- Parameters:
func (
Callable[[Concatenate[Type[TypeVar(R_prepare, bound=Schema)],bytes|IO[bytes],int|None,dict[str,Any] |None,ParamSpec(P, bound=None)]],TypeVar(R_prepare, bound=Schema)]) – decorated function- Return type:
Callable[[ParamSpec(P, bound=None)],TypeVar(R_prepare, bound=Schema)]
Important
All three decorators above are designed for decorating class methods. For more information, please refer to the documentation of each decorator function.
Type Variables¶
- pcapkit.utilities.decorators.R_beholder: pcapkit.protocols.protocol.ProtocolBase¶
- pcapkit.utilities.decorators.R_prepare: pcapkit.protocols.schema.schema.Schema¶
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 theloggingmodule use: level1is the frame that calledstacklevel(), level2its caller, and so on outwards. Handing it to either of them attributes the complaint to the caller who reached intopcapkit, rather than to whicheverpcapkitinternal 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. What makes this a fix rather than a rewrite is thatboundaryis measured from the inside out: it depends only on how deep thepcapkitframes run, never on how deep the caller’s own stack is. Numbering from the outside in, as this function once did, grew with the outer stack, so the frame it named drifted 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.0and negative values mean “do not walk out at all” tologging.Logger.findCaller(), which then attributes the record tologgingitself;warnings.warn()treats them as1.Never above
outermost. That bound is reached when the whole stack is insidepcapkit, e.g. running the package as a script, and walking past the outermost frame makeswarnings.warn()fall back to blaming thesysmodule.
The walk goes through
inspect.currentframe()andf_backrather thantraceback.extract_stack(), which cannot be used here:traceback.StackSummary.extract()honourssys.tracebacklimit, andBaseErrorsets that to0for every loud error outside development mode. One such error therefore madeextract_stack()return an empty list for the rest of the process, which is where the old-1came from – so in ordinary use the first error silently broke the attribution of every warning after it. Walking frames also skips building theFrameSummaryobjects and thelinecachelookups behind them, which is worth having on a function called once per warning.Important
The level is relative to the caller of
stacklevel(). A function that forwards it towarnings.warn()on its caller’s behalf has to add one for its own frame – seepcapkit.utilities.warnings.warn(), which does exactly that.- Return type:
- Returns:
Number of frames from the caller of
stacklevel()outwards to the innermost frame whose path does not contain/pcapkit/.
- pcapkit.utilities.warnings.warn(message, category, stacklevel=None)[source]¶
Wrapper function of
warnings.warn().The warning is reported once on the
loggerlogger, then once throughwarnings.warn(). The logger call does not consultwarnings.filters, so a log-based consumer sees the complaint even when the application has filtered the category out; thewarnings.warn()call is filtered normally, so the application keeps full control of that channel – including turning the warning into an error with-W error.- Parameters:
stacklevel (
int|None) – Warning stack level, relative to the caller of this function –1blames the line that calledwarn(),2its caller, and so on, exactly as the argument of the same name reads onwarnings.warn()itself. Defaults tostacklevel(), i.e. the innermost frame outsidepcapkit.
See also
pcapkit.utilities.warningsfor the emission model in full, and for how to silence either channel.