zerodds-idl-python 1.0.0-rc.3.1

OMG IDL4 → Python code generator for ZeroDDS (@idl_struct + @dataclass mapping per zerodds-py 1.0).
Documentation
# `zerodds-idl-python`

IDL4 → **Python codegen** for ZeroDDS. Emits `@idl_struct(...)` +
`@dataclass` classes usable directly with `zerodds.IdlTopic(MyClass)`
— the encoder/decoder comes from the `zerodds-py`
runtime, this codegen only delivers the annotated classes.

Part of the [**ZeroDDS**](../../README.md) project. Safety class
**STANDARD** — `forbid(unsafe_code)`, deterministic codegen.

> **Status RC phase**: phase-2 coverage complete — struct (with
> inheritance), enum, bitmask, bitset, union, typedef, exception,
> module nesting, primitives, string, sequence. Not supported
> remain: `valuetype`, `interface`, `fixed`, `map`, `any` — these return
> a clean `IdlPythonError::Unsupported`.

---

## Quick Start

```rust
use zerodds_idl::config::ParserConfig;
use zerodds_idl_python::{PythonGenOptions, generate_python_module};

let ast = zerodds_idl::parse(
    "struct Greeting { long id; string<128> text; };",
    &ParserConfig::default(),
)?;

let py_src =
    generate_python_module(&ast, &PythonGenOptions::default())?;

assert!(py_src.contains("@idl_struct(typename=\"Greeting\")"));
assert!(py_src.contains("@dataclass"));
assert!(py_src.contains("class Greeting:"));
# Ok::<(), Box<dyn std::error::Error>>(())
```

In the CLI, `zerodds-idlc --python -o <dir> <file.idl>` handles the
codegen. Output lands as `<basename>.py` and imports the brands
from `zerodds.idl`.

## Generated code

Input:

```idl
module sensors {
    enum Quality { GOOD, DEGRADED, FAILED };
    struct Reading {
        long sensor_id;
        double value;
        Quality quality;
        sequence<double> history;
    };
};
```

Output (abbreviated):

```python
# SPDX-License-Identifier: Apache-2.0
# Auto-generated by `zerodds-idl-python`. Do not edit by hand.

from dataclasses import dataclass
from enum import IntEnum
from typing import List
from zerodds.idl import idl_struct, Float64, Int32

class sensors_Quality(IntEnum):
    GOOD = 0
    DEGRADED = 1
    FAILED = 2

@idl_struct(typename="sensors::Reading")
@dataclass
class sensors_Reading:
    sensor_id: Int32
    value: Float64
    quality: sensors_Quality
    history: List[Float64]
```

Application usage:

```python
from zerodds import DomainParticipant, IdlTopic
from gen.sensors import sensors_Reading, sensors_Quality

p = DomainParticipant(domain_id=0)
topic = IdlTopic(p, sensors_Reading, "sensors")
writer = topic.create_writer()
writer.write(sensors_Reading(
    sensor_id=1,
    value=42.5,
    quality=sensors_Quality.GOOD,
    history=[40.0, 41.2, 42.5],
))
```

## Construct mapping

| IDL | Python |
| --- | --- |
| `struct` | `@idl_struct(typename=...)` + `@dataclass class` |
| `struct Foo : Base` | `class Foo(Base):` (dataclass inheritance) |
| `enum` | `class X(IntEnum)` |
| `bitmask` | `class X(IntFlag)` with `member = 1 << position` |
| `bitset` | `X: TypeAlias = Int64` + `class X_Bits:` with `_SHIFT`/`_WIDTH`/`_MASK` constants per bitfield |
| `union` | `X = idl_union(typename=..., discriminator=..., cases={...}, default=...)` |
| `typedef T name` | `name: TypeAlias = T` |
| `exception` | `@idl_struct(typename=...)` + `@dataclass class X(Exception):` |
| `module M { ... }` | flat class name `M_Inner` (Python PSM, Annex B) |
| `boolean` | `bool` |
| `octet` | `Octet` (zerodds.idl brand) |
| `short`/`long`/`long long` | `Int16` / `Int32` / `Int64` |
| `unsigned short`/`unsigned long`/`unsigned long long` | `UInt16` / `UInt32` / `UInt64` |
| `int8` / `uint8` | `Int8` / `UInt8` |
| `float` / `double` / `long double` | `Float32` / `Float64` / `LongDouble` |
| `char` / `wchar` | `Char` / `WChar` |
| `string` / `wstring` (bounded or unbounded) | `String` / `WString` |
| `sequence<T>` | `List[T]` |
| `T[N]` (array) | `List[T]` (multi-dim nested) |
| Python reserved word as field name | escaped with a `_` suffix (`class``class_`) |

## Phase 3 (today `IdlPythonError::Unsupported`)

- `valuetype`, `interface`
- `fixed`, `map`, `any`
- union cases with `case ENUM_MEMBER:` (scoped const expression — follow-up iteration)
- union cases with binary const expressions (`case A | B:` etc.)

## Spec mapping

| Spec document | Section |
| --- | --- |
| OMG IDL 4.2 (ISO/IEC 19516) | §7 — construct mapping |
| OMG XTypes 1.3 Annex B (Python PSM) | class naming convention, discriminator layout |
| ZeroDDS `zerodds-py-1.0` (vendor spec) | `@idl_struct` decorator API, type-brand names |

## Features

* `default = []` — std-only.

## Stability

`1.0.0-rc.2`. The CLI and library API are stable; emitted code may still
change in details before 1.0.0-final (brand imports could be consolidated
after a code review).

## Tests

```bash
cargo test -p zerodds-idl-python
```

26 smoke tests (phase 1 + phase 2: typedef, exception, bitmask,
bitset, union, struct inheritance, module nesting for phase-2
constructs) + 1 doc-test.

## See also

- [`zerodds-idl`]../idl/README.md — parser + AST.
- [`zerodds-py`]../py/README.md — Python runtime with `@idl_struct` + `IdlTopic`.
- [`zerodds-idlc`]../../tools/idlc/README.md — CLI with the `--python` flag.
- [`packaging/docker/py-runtime/`]../../packaging/docker/py-runtime/ — sandbox image.