blob: de766d414c20a201092d847022b65cb24904df6e [file] [log] [blame]
Python Generated Code Guide
===========================
Usage
-----
.. sourcecode:: bash
usage: generate_python_backend.py [-h] [--input INPUT] [--output OUTPUT] [--custom-type-location CUSTOM_TYPE_LOCATION]
options:
-h, --help show this help message and exit
--input INPUT Input PDL-JSON source
--output OUTPUT Output Python file
--custom-type-location CUSTOM_TYPE_LOCATION
Module of declaration of custom types
Example invocation:
.. sourcecode:: bash
cargo run my-protocol.pdl --output-format json | \
./scripts/generate_python_backend.py > my-protocol.py
Language bindings
-----------------
The generator produces a pure python implementation of the parser and serializer
for the selected grammar, using only builtin features of the Python language.
The generated constructs are all type annotated and _should_ pass the type
validation.
All packets inherit either from their parent declaration or at the root
a blanket `Packet` class implementation.
.. sourcecode:: python
@dataclass
class Packet:
payload: Optional[bytes] = field(repr=False, default_factory=bytes, compare=False)
Enum declarations
^^^^^^^^^^^^^^^^^
+---------------------------------------+---------------------------------------------------------------+
| :: | .. sourcecode:: python |
| | |
| enum TestEnum : 8 { | class TestEnum(enum.IntEnum): |
| A = 1, | A = 1 |
| B = 2..3, | B_MIN = 2 |
| C = 4, | B_MAX = 3 |
| OTHER = .., | C = 4 |
| } | |
+---------------------------------------+---------------------------------------------------------------+
.. note::
Python enums are open by construction, default cases in enum declarations are ignored.
Packet declarations
^^^^^^^^^^^^^^^^^^^
+---------------------------------------+---------------------------------------------------------------+
| :: | .. sourcecode:: python |
| | |
| packet TestPacket { | @dataclass |
| a: 8, | packet TestPacket(Packet): |
| b: TestEnum, | a: int = field(kw_only=True, default=0) |
| } | b: TestEnum = field(kw_only=True, default=TestEnum.A) |
| | |
| | @staticmethod |
| | def parse(span: bytes) -> Tuple['TestPacket', bytes]: |
| | pass |
| | |
| | def serialize(self, payload: bytes = None) -> bytes: |
| | pass |
| | |
| | @property |
| | def size(self) -> int: |
| | pass |
+---------------------------------------+---------------------------------------------------------------+
| :: | .. sourcecode:: python |
| | |
| packet TestPacket: ParentPacket { | @dataclass |
| a: 8, | packet TestPacket(ParentPacket): |
| b: TestEnum, | a: int = field(kw_only=True, default=0) |
| } | b: TestEnum = field(kw_only=True, default=TestEnum.A) |
| | |
| | @staticmethod |
| | def parse(span: bytes) -> Tuple['TestPacket', bytes]: |
| | pass |
| | |
| | def serialize(self, payload: bytes = None) -> bytes: |
| | pass |
| | |
| | @property |
| | def size(self) -> int: |
| | pass |
+---------------------------------------+---------------------------------------------------------------+
Field declarations
^^^^^^^^^^^^^^^^^^
Fields without a binding name do not have a concrete representation in the
generated class, but are nonetheless validated during parsing or implicitely
generated during serialization.
+---------------------------------------+---------------------------------------------------------------+
| :: | .. sourcecode:: python |
| | |
| a: 8 | a: int = field(kw_only=True, default=0) |
+---------------------------------------+---------------------------------------------------------------+
| :: | .. sourcecode:: python |
| | |
| a: TestEnum, | a: TestEnum = field(kw_only=True, default=TestEnum.A) |
| b: TestStruct | b: TestStruct = field(kw_only=True, |
| | default_factory=TestStruct) |
+---------------------------------------+---------------------------------------------------------------+
| :: | .. sourcecode:: python |
| | |
| a: 8[], | a: List[int] = field(kw_only=True, default_factory=list) |
| b: 16[128], | b: List[int] = field(kw_only=True, default_factory=list) |
| c: TestEnum[], | c: List[TestEnum] = field(kw_only=True, |
| d: TestStruct[] | default_factory=list) |
| | d: List[TestStruct] = field(kw_only=True, |
| | default_factory=list) |
+---------------------------------------+---------------------------------------------------------------+