Info Class¶
pcapkit.corekit.infoclass contains the dict-like class
Info, modelled on
dataclasses.dataclass() (PEP 557), and the immutable multi-mapping
classes MultiInfo and
OrderedMultiInfo that a finalised
Info holds its option lists in.
- class pcapkit.corekit.infoclass.Info[VT](dict_=None, **kwargs)[source]¶
Bases:
ReduceAsProtocol2,Mapping[str,VT],Generic[VT]Turn dictionaries into
objectlike instances.Infoobjects are iterable, and support the read-onlydictinterfaceInfoobjects are immutable, thus cannot set or delete attributes after initialisation
Important
Infowill attempt to rename keys with the same names as the class’s builtin methods, and store the mapping information in the__map__and__map_reverse__attributes. However, when accessing such renamed keys, the original key name should always be used, i.e., such renaming is totally transparent to the user.Changed in version 1.3.1.post8: Iterating an instance skips the names listed in
__excluded__.A key whose name is a dunder, such as
__next_type__, is metadata. Iterating an instance,len()andto_dict()leave such a key out unless__included__names it, and carry every other key;__excluded__names the keys thatrepr,strand the dumps ofpcapkit.dumpkitleave out besides. A subclass extends either list with its own names, as for__additional__.Changed in version 1.5.0:
__excluded__names the keys left out ofrepr,strand the dumps only, and__included__the dunder keys that iterating an instance,len()andto_dict()carry (#2003).- Parameters:
dict_ – Source data, read as by
from_dict(), except that no value is rebuilt into theInfosubclass its key’s annotation names.**kwargs – Arbitrary keyword arguments.
- __excluded__: list[str]¶
List of names of keys left out of
repr,strand the dumps ofpcapkit.dumpkit– metadata such as__next_type__, whichto_dict()may still carry, see__included__. Finalisation adds the names in__builtin__, thoughrepr,strand the dumps write a field renamed for clashing with one of them, such as a reassembled datagram’spacket, under its own name (#2733).
- __included__: list[str]¶
List of names of dunder keys that iterating an instance,
len()andto_dict()carry – metadata such as__next_type__, which a rebuild from thedictreads. Every other dunder key is dropped from all three, though indexing still reads it; a key that is no dunder is carried regardless. A subclass extends the list with its own names, as for__excluded__, so a customInfoholding dunder keys of its own must list them here forto_dict()to keep them (#2003).
- __map__: dict[str, str]¶
Mapping of name conflicts with builtin methods (original names to transformed names).
- __map_reverse__: dict[str, str]¶
Mapping of name conflicts with builtin methods (transformed names to original names).
- classmethod __init_subclass__(*args, **kwargs)[source]¶
Refuse to derive from a finalised info class.
final()is a promise to the type checker and nothing more: it records__final__on the class and leaves the interpreter free to subclass it anyway. Every classinfo_final()finalises carries a generated__init__built from the annotations that were visible at that moment, so a subclass added afterwards inherits a constructor that does not know about its own fields – silently, and with the__builtin__and__excluded__sets of its parent. This turns that promise into a rule the interpreter keeps.
- static __new__(cls, *args, **kwargs)[source]¶
Create a new instance.
The class will try to automatically generate
__init__method with the same signature as specified in class variables’ type annotations, which is inspired by PEP 557 (dataclasses).Note
Whether
clsstill needs finalising is read from its own__dict__, never inherited (GitHub issue #1490). Each class is finalised on its first construction, whatever its ancestors’ state, so a subclass of aFinalisedState.BASEorFinalisedState.FINALancestor still gets its own__builtin__,__excluded__and generated__init__, and a@finalclass under aBASEancestor is refused like any other.- Parameters:
*args (
VT) – Arbitrary positional arguments.**kwargs (
VT) – Arbitrary keyword arguments.
- Raises:
InfoError – If
clswas marked withfinal()but never finalised byinfo_final(), i.e. it carries__final__in its own__dict__withoutFinalisedState.FINAL.- Return type:
- classmethod from_dict(dict_=None, **kwargs)[source]¶
Create a new instance.
If
dict_is present and has a.keys()method, then does:for k in dict_: self[k] = dict_[k].If
dict_is present and has no.keys()method, then does:for k, v in dict_: self[k] = v.If
dict_is not present, then does:for k, v in kwargs.items(): self[k] = v.If
dict_is aMultiDict, a key it holds more than once keeps every value, asto_dict()returns them: the first is the value of the key, anditems(multi=True)yields all of them.
A mapping given for a key whose type annotation resolves at runtime to an
Infosubclass (or toOptionalof one) is rebuilt into that class, socls.from_dict(info.to_dict())restores such nested values. A key without such an annotation keeps the mapping as is – seeto_dict().Every
MultiDictorOrderedMultiDictvalue is stored as aMultiInfoorOrderedMultiInforespectively, or as the subclass of either that the key’s annotation names, such asSettings.The rebuild is as unchecked as the rest of this method: a mapping whose keys are not the nested class’s own is accepted and becomes an instance carrying those keys, exactly as a direct call to the nested class’s own
from_dict()would. Validating it here would reject data thatInfo(**kwargs)has always accepted, so the shape of the mapping stays the caller’s responsibility.
- to_dict()[source]¶
-
The
dictis anOrderedMultiDictof the fields, in order – a_OrderedMultiDict, i.e. one whose!=is the negation of its==, so two equal exports compare!=False. A key held more than once – as given by aMultiDicttofrom_dict(), e.g. a repeated IPv6 extension header – keeps every value, in place, foritems(multi=True)andgetlist(), while indexing sees the first. A nestedInfobecomes its ownto_dict(): anOrderedMultiDictfor a field model or anOrderedMultiInfo, and aMultiDictfor aMultiInfo; the values those two hold are not converted.Note
dict(result),{**result}andjson.dumps()see the first value of each key only, and silently drop the rest of a repeated key; read every value withitems(multi=True)orgetlist(). The result compares equal to anotherMultiDictonly, never to a plaindict.Important
We only convert nested
Infoobjects intodictif they are the direct value of theInfoobject’s attribute. Should suchInfoobjects be nested within other data types, such aslist,tuple,set, etc., we leave them intact rather than converting them intodict.Note
from_dict()reverses the flattening only for keys whose type annotation resolves at runtime to anInfosubclass. For any other key – every key of a bareInfo, and annotations naming a type imported only underTYPE_CHECKING– the conversion is one-way, and the nested value comes back as theOrderedMultiInfothatfrom_dict()stores theOrderedMultiDictit was written as in.Changed in version 1.5.0: Returns an
OrderedMultiDictrather than adict, so a key held more than once keeps every value (#1484). It leaves out the dunder keys__included__does not name, carries the keys in__excluded__, and records those as its own__excluded__for the dumpers to leave out (#2003).Changed in version 1.6.0: The
__excluded__it records leaves out a field renamed for clashing with a builtin name, such as a reassembled datagram’spacket, so the dumpers write that field under its own name (#2733).- Return type:
OrderedMultiDict[str,VT]
- @pcapkit.corekit.infoclass.info_final(cls, *, _finalised=True)[source]¶
Finalise info class.
This decorator function is used to generate necessary attributes and methods for the decorated
Infoclass. It can be useful to reduce runtime generation time as well as caching already generated attributes.Notes
The decorator should only be used on the final class. Applying it with
_finalised=Trueseals the class against subclassing, whichInfo.__init_subclass__()enforces, and marks it withfinal()– so@info_finalimplies@finaland there is never a reason to write both. Writing both is harmless in either order, though; what is not is@finalwithout this decorator, whichInfo.__new__()refuses – provided@finalisfinal()(or, on Python 3.11 and up,typing.final()directly). Below 3.11, plaintyping.final()does not set__final__at all (gh-90500), so a class marked with a user’s ownfrom typing import finalon 3.10 is not refused: there is nothing on the class forInfo.__new__()to read.Applying this decorator to the same class a second time only warns: the first application already did the work, so the duplicate is redundant rather than wrong, and the class comes back finalised and usable.
- Parameters:
- Return type:
- Returns:
Finalised info class.
- Warns:
pcapkit.utilities.warnings.InfoWarning– Ifclshas already been finalised by this function, i.e. it carriesFinalisedState.FINALin its own__dict__. The class is returned untouched.
Changed in version 1.5.0:
@finalis enforced at runtime: a class marked with it but never passed through this decorator is refused at first construction (#778).
- class pcapkit.corekit.infoclass.MultiInfo[KT, VT](mapping=None)[source]¶
Bases:
ReduceToItems,_MultiInfo[KT,VT],MultiDict[KT,VT]An immutable
MultiDictthat is anInfo.It holds every value of a key, as a
MultiDictdoes, but refuses every mutation, asInfodoes, withUnsupportedCall(see_MultiInfofor how it is both).A finalised
Infoholds everyMultiDictvalue as one of these, andto_dict()– its own and its holder’s – turns it back into aMultiDict.- Parameters:
mapping (
Mapping[Any,Any] |Iterable[tuple[Any,Any]] |None) – The initial value, as forMultiDict.
Added in version 1.5.0.
- to_dict(flat=None)[source]¶
Return the contents as a plain mapping.
- Parameters:
flat (
bool|None) – If omitted, a plainMultiDictof every value, asInfo.to_dict()writes this object. OtherwiseMultiDict.to_dict’sdict, of the first value of each key ifTrue, or of thelistof them ifFalse.- Return type:
- class pcapkit.corekit.infoclass.OrderedMultiInfo[KT, VT](mapping=None)[source]¶
Bases:
_MultiInfo[KT,VT],OrderedMultiDict[KT,VT]An immutable
OrderedMultiDictthat is anInfo.As
MultiInfo, but keeping the order of every value across keys, as anOrderedMultiDictdoes – i.e. wire order for an option list.A finalised
Infoholds everyOrderedMultiDictvalue as one of these, andto_dict()– its own and its holder’s – turns it back into anOrderedMultiDict.- Parameters:
mapping (
Mapping[Any,Any] |Iterable[tuple[Any,Any]] |None) – The initial value, as forOrderedMultiDict.
Added in version 1.5.0.
- to_dict(flat=None)[source]¶
Return the contents as a plain mapping.
- Parameters:
flat (
bool|None) – If omitted, a plainOrderedMultiDictof every value, in order, asInfo.to_dict()writes this object – the same_OrderedMultiDictit returns. OtherwiseMultiDict.to_dict’sdict, of the first value of each key ifTrue, or of thelistof them ifFalse.- Return type:
Internal Definitions¶
- class pcapkit.corekit.infoclass.InfoMeta(name, bases, attrs, **kwargs)[source]¶
Bases:
ABCMetaMeta class to add dynamic support to
Info.Info.__additional__,Info.__excluded__andInfo.__included__list the field names treated as built-in names, left out ofreprand the dumps, and carried as metadata byInfo.to_dict(), respectively.Note
__new__()appends each base’s names to the subclass’s own:class A(Info): __additional__ = ['a', 'b'] class B(A): __additional__ = ['c', 'd'] class C(B): __additional__ = ['e', 'f'] print(A.__additional__) # ['a', 'b'] print(B.__additional__) # ['c', 'd', 'a', 'b'] print(C.__additional__) # ['e', 'f', 'c', 'd', 'a', 'b']
- static __new__(cls, name, bases, attrs, **kwargs)[source]¶
Create the class, extending its
Info.__additional__,Info.__excluded__andInfo.__included__with every base’s.
- class pcapkit.corekit.infoclass.FinalisedState(*values)[source]¶
Bases:
EnumLookup,IntEnumFinalised state.
Built on
EnumLookupper GitHub issue #877’s ruling that every non-registry enumeration shares that lookup contract; this class defines neithergetnor_missing_of its own.- NONE = 1¶
Not finalised.
- BASE = 2¶
Base class.
- FINAL = 3¶
Finalised. A class reaching this state is also handed to
final(), so a correctly finalised class carries both markers – and they answer two different questions, which is why both are read rather than one standing in for the other.__final__answers “may this be subclassed?”, forInfo.__init_subclass__(); this state answers “hasinfo_final()already generated the attributes?”, forinfo_final()’s own re-entry check. Carrying__final__without this state is the mismatchInfo.__new__()refuses: marked final by hand, never finalised, and so missing the generated__init__that makes the class usable at all.
- class pcapkit.corekit.infoclass._MultiInfo[KT, VT](mapping=None)[source]¶
Bases:
Info[VT],Generic[KT,VT]An
Infothat holds its values as a multi-mapping.The common base of
MultiInfoandOrderedMultiInfo. Each of those also derives from themultidictclass it is named after, afterInfo, so it is anInfo–isinstance()holds, and it inheritsInfo.__new__()’s finalisation,Info.from_dict(),Info.__init_subclass__()andInfo.__additional__/Info.__excluded__– while its values live in the multi-mapping rather than in__dict__.That is the whole carve-out from
Info, and it is confined to this class and its subclasses,MultiInfoandOrderedMultiInfo:__new__()gives the multi-mapping its empty storage, and__update__()adds every pair to it, so that the inheritedInfo.from_dict()builds one;info_final()generates no__init__for such a class (it has no declared fields);__setattr__()admits the multi-mapping’s own bookkeeping, and only while__new__()or__update__()is writing;every mutator of the multi-mapping raises
UnsupportedCall, as assignment to anInfodoes;to_dict()exports the plain multi-mapping, so thatcls.from_dict(info.to_dict()) == info;MultiInfoandOrderedMultiInfobind the mapping protocol back to their multi-mapping class, whichInfoandMappingprecede in the MRO.
A key also reads as an attribute, giving its first value: a
strkey by its name, anEnumkey by its member name. A name the class itself defines, such asitems, is a method and not a key.- static __new__(cls, *args, **kwargs)[source]¶
Create the instance with the empty multi-mapping
__update__()adds to.- Return type:
- __update__(dict_=None, **kwargs)[source]¶
Add every pair to the multi-mapping, so that a repeated key keeps every value.
- __setattr__(name, value)[source]¶
Admit an attribute write only while
__new__()or__update__()is writing.- Parameters:
- Raises:
UnsupportedCall – Outside those writes, as assignment to any
Infodoes.
- class pcapkit.corekit.infoclass._OrderedMultiDict[KT, VT](mapping=None)[source]¶
Bases:
OrderedMultiDict[KT,VT]The
OrderedMultiDictthatInfo.to_dict()returns.It adds one method,
__ne__()(_ne()). Themultidictclasses are Werkzeug’s, kept verbatim, and Werkzeug’sOrderedMultiDictdefines__eq__but no__ne__:!=falls back todict’s, which compares the internal buckets, so two equal exports would compare!=as well as==– and, since__eq__compares the values with!=, two exports holding a nested export would compare unequal (#1484). Its copies, deep copies and pickles stay of this class, as Werkzeug’s build them fromtype(self), and__repr__()writes it as theOrderedMultiDictit is.- __ne__(other)¶
self != other, as the negation ofself == other.The
__ne__that_OrderedMultiDictandOrderedMultiInfoadd to Werkzeug’sOrderedMultiDict. ANotImplementedfrom__eq__is passed on, so that Python asksotherin turn, exactly as it does for==.- Return type:
- __repr__()[source]¶
Write the export as the
OrderedMultiDictit is, with every pair.- Return type:
- pcapkit.corekit.infoclass._ne(self, other)[source]¶
self != other, as the negation ofself == other.The
__ne__that_OrderedMultiDictandOrderedMultiInfoadd to Werkzeug’sOrderedMultiDict. ANotImplementedfrom__eq__is passed on, so that Python asksotherin turn, exactly as it does for==.- Return type:
Type Variables¶
- pcapkit.corekit.infoclass.ST: Type[pcapkit.corekit.infoclass.Info]¶