vc2_conformance.fixeddict
: Fixed-key dictionaries¶
The vc2_conformance.fixeddict
module provides the
fixeddict()
function for creating new dict
subclasses
which permit only certain keys to be used. These new types may be used like
ordinary Python dictionaries but add three main features:
Explicitness – The VC-2 pseudocode creates and uses many dictionaries (called ‘maps’ in the specification) in place of struct-like objects.
fixeddicts
provide a way to give these clear names.Avoidance of typos – Misspelt key names will result in a
FixedDictKeyError
.Better pretty printing – See more below…
Tutorial¶
Using fixeddict()
, dictionary-like types with well defined fields can
be described like so:
>>> from vc2_conformance.fixeddict import fixeddict
>>> FrameSize = fixeddict(
... "FrameSize",
... "custom_dimensions_flag",
... "frame_width",
... "frame_height",
... )
This produces a ‘dict’ subclass called FrameSize
with all of the usual
dictionary behaviour but which only allows the specified keys to be used:
>>> f = FrameSize()
>>> f["custom_dimensions_flag"] = True
>>> f["frame_width"] = 1920
>>> f["frame_height"] = 1080
>>> f["frame_width"]
1920
>>> f["not_in_fixeddict"] = 123
Traceback (most recent call last):
...
FixedDictKeyError: 'not_in_fixeddict'
To improve readability when producing string representations of VC-2 data structures, the generated dictionary types have a ‘pretty’ string representation.
>>> print(f)
FrameSize:
custom_dimensions_flag: True
frame_width: 1920
frame_height: 1080
To further improve the readability of this output, custom string formatting
functions may be provided for each entry in the dictionary. To define these,
Entry
instances must be used in place of key name strings like
so:
>>> from vc2_conformance.string_formatters import Hex
>>> from vc2_data_tables import ParseCodes # An IntEnum
>>> ParseInfo = fixeddict(
... "ParseInfo",
... Entry("parse_info_prefix", formatter=Hex(8)),
... Entry("parse_code", enum=ParseCodes, formatter=Hex(2)),
... Entry("next_parse_offset"),
... Entry("previous_parse_offset"),
>>> pi = ParseInfo(
... parse_info_prefix=0x42424344,
... parse_code=0x10,
... next_parse_offset=0,
... previous_parse_offset=0,
... )
>>> str(pi)
ParseInfo:
parse_info_prefix: 0x42424344
parse_code: end_of_sequence (0x10)
next_parse_offset: 0
previous_parse_offset: 0
See the vc2_conformance.string_formatters
module for a set of useful
string formatting functions.
Finally, documentation can optionally be added in the form of help
and
help_type
arguments which will combined into the generated type’s
docstring:
>>> ParseInfo = fixeddict(
... "ParseInfo",
... Entry("parse_info_prefix", formatter=Hex(8), help_type="int", help="Always 0x42424344"),
... Entry("parse_code", enum=ParseCodes, formatter=Hex(2), help_type="int"),
... Entry("next_parse_offset", help_type="int"),
... Entry("previous_parse_offset", help_type="int"),
... help="A deserialised parse info block.",
... )
>>> print(ParseInfo.__doc__)
A deserialised parse info block.
Parameters
==========
parse_info_prefix : int
Always 0x42424344
parse_code : int
next_parse_offset : int
previous_parse_offset : int
API¶
-
fixeddict
(name, *entries, **kwargs)¶ Create a fixed-entry dictionary.
A fixed-entry dictionary is a
dict
subclass which permits only a preset list of key names.The first argument is the name of the created class, the remaining arguments may be strings or
Entry
instances describing the allowed entries in the dictionary.Example usage:
>>> ExampleDict = fixeddict( ... "ExampleDict", ... "attr", ... Entry("attr_with_default"), ... )
Instances of the dictionary can be created like an ordinary dictionary:
>>> d = ExampleDict(attr=10, attr_with_default=20) >>> d["attr"] 10 >>> d["attr_with_default"] 20
The string format of generated dictionaries includes certain pretty-printing behaviour (see
Entry
) and will also omit any entries whose name is prefixed with an underscore (_
).The class itself will have a static (and read-only) attribute
entry_objs
which is a :py;class:collections.OrderedDict mapping from entry name toEntry
object in the dictionary.The keyword-only argument, ‘module’ may be provided which overrides the
__module__
value of the returned fixeddict type. (By default the module name is inferred using runtime stack inspection, if possible). This must be set correctly for this type to be picklable.The keyword-only argument ‘help’ may be used to set the docstring of the returned class. This will automatically be appended with the list of entries allowed (and their help strings).
-
class
Entry
(name, **kwargs)¶ Defines advanced properties of of an entry in a
fixeddict()
dictionary.All constructor arguments, except name, are keyword-only.
- Parameters
- namestr
The name of this entry in the dictionary.
- formatterfunction(value) -> string
A function which takes a value and returns a string representation to use when printing this value as a string. Defaults to ‘str’.
- friendly_formatterfunction(value) -> string
If provided, when converting this value to a string, this function will be used to generate a ‘friendly’ name for this value. This will be followed by the actual value in brackets. If this function returns None, only the actual value will be shown (without brackets).
- enum
Enum
A convenience interface which is equivalent to the following
formatter
argument:def enum_formatter(value): try: return str(MyEnum(value).value) except ValueError: return str(value)
And the following
friendly_formatter
argument:def friendly_enum_formatter(value): try: return MyEnum(value).name except ValueError: return None
If
formatter
orfriendly_formatter
are provided in addition toenum
, they will override the functions implicitly defined byenum
.- helpstr
Optional documentation string.
- help_typestr
Optional string describing the type of the entry.