v0.25.0
perf(utils): cache the per-class serialization plan on the message hot path
ArrowSerializableDataclass._to_row_dict and deserialize_from_batch ran get_type_hints(include_extras=True) and re-derived the transient / required-field / ArrowType(pa.binary()) facts on every RPC message — profiling a downstream integration suite (the VGI DuckDB extension) showed typing introspection (~22%) and isinstance dispatch chains (~33%, including the runtime-checkable _BytesSerializable Protocol check) dominating the Python-side cost per message.
_serialization_plan(cls)resolves type hints once per class and caches a_SerializationPlan(per-field resolved/unwrapped annotation, transient flag, binary-override flag, defaults, required-field list) on the class itself — samecls.__dict__idiom as_ArrowSchemaDescriptor, so subclasses never inherit a parent's cached plan.- Serialize and deserialize consume the plan instead of re-resolving annotations per call.
_convert_value_for_serializationgains an exact-type fast path for plainstr/int/float/bool/bytesvalues (exact checks, soEnummembers — str/int subclasses — still take the full dispatch).
Measured (8-field message, Python 3.13): _serialize 65 → 26 µs (−60%), serialize_to_bytes 78 → 38 µs (−51%), deserialize_from_batch 48 → 27 µs (−43%).
No wire-format or API changes. Verified with the full test suite (3659 passed), strict mypy/ty/ruff/pydoclint, and the VGI DuckDB extension's 285-test integration suite run against this build.