Common Utilities

pcapkit.dumpkit.common holds the utilities shared by pcapkit.dumpkit, chiefly customised hooks for dictdumper.dumper.Dumper classes.

pcapkit.dumpkit.common.make_dumper(output)[source]

Create a customised Dumper class.

Parameters:

output (Type[dictdumper.dumper.Dumper]) – Output class to customise.

Return type:

Type[dictdumper.dumper.Dumper]

Returns:

Customised Dumper subclass of output.

Changed in version 1.5.0: Several dumped shapes change. A nameless flag value renders its value as the name, Flags::0 [0] rather than Flags::None [0] (#648). An OrderedMultiDict dumps as a list of one-key mappings in wire order, not grouped by key (#1263). An IPv4Network or IPv6Network dumps as its string, a timezone as its offset in seconds, and NULL and NO_VALUE as '<NULL>' and '<NO_VALUE>' (#1258). In plist output, None is kept (#1257), and a string carrying a character XML forbids is written as <data> (#1262).

class pcapkit.dumpkit.common.Dumper(fname, **kwargs)[source]

Bases: DumperBase

Base Dumper object.

This class is a customised Dumper for the pcapkit.dumpkit implementation, which is generally customised for opt-in registration to the Extractor and TraceFlow output dumper registries.

Example

Registration is opt-in. Pass keyword argument fmt at class definition to register the dumper under that output format:

class MyDumper(Dumper, fmt='my_format', ext='.mine'):
    ...

Omit it and the subclass is not registered:

class MyMixin(Dumper):  # not registered
    ...

Such a class can still be registered later, on demand. Note this hook writes every output registry, so the equivalent manual call is the module-level one that does the same, not any one class’ own method:

from pcapkit.foundation.registry.foundation import register_dumper

register_dumper('my_mixin', MyMixin, ext='.mine')

Changed in version 1.5.0: Registration is opt-in, under the fmt class keyword; 1.4.x registered every subclass, under its kind when the keyword was omitted (#514).

classmethod __init_subclass__(fmt=None, ext=None, *args, **kwargs)[source]

Initialise subclass.

This method is used to register the subclass to the Extractor and TraceFlow output dumper registries.

Parameters:
  • fmt (str | None) – Output format to register the subclass under, lowercased. None (the default) skips registration entirely.

  • ext (str | None) – Output file extension; None infers it from fmt. Only meaningful alongside fmt.

  • *args (Any) – Arbitrary positional arguments.

  • **kwargs (Any) – Arbitrary keyword arguments.

Raises:

UnsupportedCall – If ext is given without fmt, or if any unrecognised class keyword is given.

Return type:

None

Registration is opt-in: the subclass is registered if and only if fmt is given. This is what lets a subclass decline registration rather than having to inherit DumperBase to avoid it, and it matches EnumSchema.__init_subclass__, which guards on its own code keyword the same way.

Note

Inferring fmt from the subclass’ kind property would need an instance, hence a tempfile.NamedTemporaryFile() created while the class statement is still executing. Guarding on fmt avoids that: a class definition does not touch the filesystem.

Internal Definitions

pcapkit.dumpkit.common.render_enum(o)[source]

Render an enumeration member as Type::name [value].

This is the spelling every dumped enumeration carries in the json, tree, text, txt, plist and xml output of both Extractor and TraceFlow, so it lives in one function rather than being spelled out at each place make_dumper()’s hook needs it.

Parameters:

o (Enum | aenum.Enum) – Enumeration member to render.

Return type:

str

Returns:

The member’s Type::name [value] rendering.

Note

A Flag value composed entirely of undeclared bits has no name at all – name is None, not a string – so interpolating it unguarded would put the literal four characters None into the name half and render Flags (0) as 'Flags::None [0]' (GitHub issue #648).

That is worth a guard rather than a shrug. 'None' is a plausible member name, so a consumer splitting the rendering on :: cannot tell it from a member genuinely so named – and NONE is a declared name elsewhere in the library. And the defect is not confined to zero: Flags(1), Flags(8) and Flags(65536) are every bit as nameless, so a guard written against value == 0 would fix one case and leave the rest.

The fallback is the value’s own decimal spelling, which is what the enumeration libraries themselves already use for an undeclared residue: Flags(2057).name is 'ACK|9', naming the declared bit and giving the leftovers as one number. A wholly-undeclared value is that same rendering with no declared bit to precede it, so Flags(9) becomes 'Flags::9 [9]' and Flags(0) becomes 'Flags::0 [0]'. It also cannot be mistaken for a member name, since a Python identifier may not begin with a digit.

This is not an aenum quirk. A stdlib enum.IntFlag built from the same members answers name is None identically on CPython 3.14.7, so the guard belongs here rather than in a choice of enumeration library.

class pcapkit.dumpkit.common.DumperBase(fname, **kwargs)[source]

Bases: dictdumper.dumper.Dumper

Base Dumper object.

Note

This class is for internal use only. For customisation, please use Dumper instead.