Package: deconstruct
deconstructdeconstructprovides a Pythonic analogue of C'sstruct, primarily for the purpose of interpreting (i.e.deconstructing) contiguous binary data.Internally, deconstruct uses Python'sstruct moduleand can be considered an abstraction of sorts. struct (the module) can be frustrating to use: its format strings appear arcane and furthermore separate the description of the data from its representation, a definite strength of C's struct.In contrast, deconstruct allows structs to be defined and used using a syntax that is Pythonic while maintaining close correspondence to C.UsageWith deconstruct, the struct definition (adapted frominput.h):#include<stdint.h>structinput_event{uint64_ttime[2];int16_ttype;int16_tcode;int32_tvalue;};can be represented as:importdeconstructascclassInputEvent(c.Struct):time:c.uint64[2]type:c.int16code:c.int16value:c.int32This definition can be used to interpret and then access binary data:>>>buffer=b'Some  arbitrary  buffer!'>>>event=InputEvent(buffer)>>>event.code26229>>>event.time(8241904116577431379,2340027244253309282)>>>print(event)structInputEvent[ByteOrder.NATIVE,TypeWidth.STANDARD]{time:uint64=(8241904116577431379,2340027244253309282)type:int16=25120code:int16=26229value:int32=561145190}Of course, in reality the buffer passed in is more likely to come from something more useful, like a file. Notice that fixed-size, n-dimensional arrays can be specified using the syntaxtype[length], a further improvement on Python's struct.Installationdeconstruct is now on PyPI:pipinstalldeconstructAlternatively you can install straight from this repository:pipinstallhttps://github.com/biqqles/deconstruct/archive/master.zipBuilt wheels are also available underReleases, as is a changelog. The latest release is version 0.5.deconstruct has no dependencies but requires Python >= 3.6 as it makes use of the class annotation syntax added in that release (seePEP 526).API listingStruct(buffer: bytes)Subclass this to define your own structs. Subclasses should only declare fields of C types defined in this package.When you instantiate your Struct with abytes-like object, deconstruct creates a format string and uses it to unpack that buffer. In the instance, C types will be replaced with their equivalent Python types for use (e.g.bytesforchar,intforscharandfloatfordouble). All types available for use in struct field definitions and their details are documented in the tablebelow.AttributesNameTypeDescription__byte_order__ByteOrderSet this in your subclass definition to define the byte order used when unpacking the struct. One of:ByteOrder.NATIVE(default value)ByteOrder.BIG_ENDIANByteOrder.LITTLE_ENDIAN__type_width__TypeWidthSet this in your subclass definition to define the type width and padding used for the struct. One of:TypeWidth.NATIVETypeWidth.STANDARD(default value)WhenTypeWidth.NATIVEis set, the struct will use native type widths and alignment. WhenTypeWidth.STANDARDis used, the struct will use Python's struct's "standard" widths1and no padding.Note thatTypeWidth.NATIVEcan only be used withByteOrder.NATIVE. This is a limitation of Python's struct.Class methodsSignatureReturn typeDescriptionnew(*args)StructConstruct a new struct instance with field values specified as positional arguments, passed in order of definition. Note that arguments are not type checked.Class propertiesNameTypeDescriptionformat_stringstrThe struct.py-compatible format string for this structsizeofintThe total size in bytes of the struct. Equivalent to C'ssizeofInstance methodsSignatureReturn typeDescriptionto_bytes()bytesReturns the in-memory ("packed") representation of this struct instance_require()boolOverride this method to specify your own instance validation logic. This method is called each time the struct is initialised; aValueErrorwill be raised if it returns false.You can alsoprintStruct instances for easier debugging and compare them using the==operator.C typesdeconstruct defines the following special types for use in Struct definitions:2deconstruct typeC99 typePython format character"Standard" width (bytes)1Resolves to Python typecharcharc1bytesof length 1scharsigned charb1intucharunsigned charB1intshortshorth2intushortunsigned shortH2intintinti2intuintunsigned intI2intlonglongl4intulongunsigned longL4intlonglonglong longq8intulonglongunsigned long longQ8intboolbool(_Bool)?1boolfloatfloatf4floatdoubledoubled8floatint8int8_tb*1intuint8uint8_tB*1intint16int16_th*2intuint16uint16_tH*2intint32int32_tl*4intuint32uint32_tL*4intint64int64_tq*8intuint64uint64_tQ*8intptrvoid*/intptr_t/uintptr_tPN/A**intsizesize_tnN/A**intssizessize_tNN/A**int* format character with__type_width__ = TypeWidth.STANDARD- platform specific otherwise.** only available with__type_width__ = TypeWidth.NATIVE.ArraysAs mentioned earlier, all the types above support atype[length]syntax to define arrays. Multidimensional arrays work as you would expect, withint[2][2]declaring a 2-D array of typeintand total length 4. When a Struct is used to unpack a buffer, each array will resolve to a tuple (or in the case of a multidimensional array, a nested tuple) of their equivalent Python types, as documented in the table above. The only exception to this ischar, an array of which will be automatically concatenated to a singlebytesobject (if this behaviour is undesirable, usescharorucharinstead).Pointersptruniquely supports an optional notation format using the>operator, allowing you to denote the type it points to. This notation is purely for programmer convenience - it, for example, has no effect on the size of the struct as all pointers are assumed to be of the size ofvoid*(which is guaranteed to be able to hold any pointer).To illustrate this syntax,f: c.ptr > c.doubledenotes a pointer to double (double* f;). Arrays of pointersandpointers to arrays are supported. For example,c.ptr[2] > c.intindicates an array ofint*, whilec.ptr > c.int[2]indicates a pointer to anintarray.You can also useStructsubtypes as the pointed-to type.1.Python's struct has the concept of "standard" type sizes. This is somewhat confusing coming from C as its standards go to some length not to define a standard ABI. However, as this terminology is so fundamental to the documentation of Python's struct it is replicated here for simplicity's sake. These sizes correspond with theminimumsizesimpliedfor C's types.2.Because some of these conflict with Python's primitives, it is not recommended toimport * from deconstructas this will severely pollute your namespace (in fact this is a bad idea in general). I like toimport deconstruct as cas shown above.