Skip to main content

Module python

Module python 

Source
Expand description

The Python backend of the shared codec walk.

DDS-XTypes 1.3 §7.4 from the clause, the same as runtime/c, runtime/java, runtime/typescript and the rest do, and none of them calls another. Where two columns disagree on an octet, one has misread the specification — which is the only reason to have a sixth.

§The four decisions this column turns on

An int is unbounded, so a width is never a cast. Every other backend spends part of itself on narrowing: (int) in Java, static_cast in C++, zdNumber/zdBigInt in TypeScript, because a value that arrived wider than its holder is a value already lost. Python has one integer type and it holds every IDL width exactly, so CodecTarget::cast is the identity on every integer and the width lives where it belongs — in the codec’s name, which adapter::python::type_tag builds from the IDL kind and never from the Python spelling. A tag built from the Python type would give octet, unsigned short and unsigned long long one codec.

An assignment is a statement. a = b is not an expression in Python: (a = b) is a SyntaxError. The shared walk builds one through T::perform(T::binary("=", …)) at every assignment site but two, so Python::perform recognises that shape and answers with py::Statement::Set. Nothing else in the tree can hold an =.

A block is an indent. There is no delimiter, so an empty suite is not untidy output — it is a SyntaxError, and there is no program the walk could have meant. The four constructors that take a body (Python::when, Python::count_up, Python::until, Python::routine) pad an empty one with pass here, where they can say which body was empty; the renderer’s own guard is the backstop.

A long double is a Float128 and never a float. A Python float is a binary64 with 53 significand bits and a long double is a binary128 with 113. runtime/python’s Float128 carries the sixteen octets, and this column reaches for it exactly as the TypeScript one reaches for ZdFloat128.

§The one place this file and the materialiser disagree

adapter/python.rs declares a long double member as _Float128 = typing.Annotated[str, _IdlFloat(bits=128)] — the decimal text — and argues for it: a materialised module imports nothing but dataclasses, enum and typing, so a runtime class there would make every generated file depend on a layer the materialiser is not part of. Python::scalar answers Float128.

The runtime settles which of the two a codec may use, and it is not this file’s preference: Writer.write_f128 takes Float128 | float and Reader.read_f128 answers a Float128. Neither takes a str, so a codec built on the materialiser’s spelling would hand a decimal string to a method that has no branch for one.

Nothing enforces the annotation at run time, so the two disagree on paper and not on the wire — primitive-longdouble and sequence-double-and-longdouble are byte-identical in both directions under all ten encoding and byte-order pairs. What it does mean is that a generated module carrying both would not pass a strict type check, and the answer is one of two decisions neither of which is a codec’s to take: the materialiser reaches for the runtime class and gives up its independence from this layer, or the codec converts at the member boundary — for which the shared walk offers no seam, because ScalarWrite::F128 hands the member straight to write_f128 with no cast in between.

§What used to sit beside this file

crates/lang-python/src/emit.rs was a second Python emitter, written against text rather than against a tree, driven by zerodds-idl-python and tools/wireprobe/wireprobe-zerodds-python. It carried its own copy of the walk — which members go out, in what order, under which header — and that copy was the thing this file exists to stop needing: tools/wireprobe/wireprobe-zerodds-python-gen and tools/idlc/src/python_support.rs are built on this file now, the same as the C#, Java, C, C++ and TypeScript columns are built on their own, and crates/lang-python is gone.

Structs§

Python
The Python backend.