Skip to content

Commit 88a99c0

Browse files
committed
fix(wpiutil): reserve generated annotations field
1 parent 07f98c8 commit 88a99c0

2 files changed

Lines changed: 54 additions & 0 deletions

File tree

subprojects/robotpy-wpiutil/tests/test_struct_schema.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,59 @@ def test_generated_metadata_reservation_does_not_change_other_identifiers():
402402
assert wpistruct.get_type_name(generated) == "WPIStruct"
403403

404404

405+
def test_generated_annotations_field_aliases_are_safe_and_deterministic():
406+
fullwidth_annotations = "__annotations__"
407+
schema = (
408+
f"uint8 __annotations__; uint16 {fullwidth_annotations}; "
409+
"uint32 __annotations___"
410+
)
411+
generated = make_wpistruct_from_schema("AnnotationsFields", schema, nested={})
412+
aliases = ["__annotations___", "__annotations___2", "__annotations___3"]
413+
414+
assert [field.name for field in dataclasses.fields(generated)] == aliases
415+
assert list(inspect.signature(generated).parameters) == aliases
416+
positional = generated(1, 0x0302, 0x07060504)
417+
keyword_value = generated(
418+
**{
419+
"__annotations___": 1,
420+
"__annotations___2": 0x0302,
421+
"__annotations___3": 0x07060504,
422+
}
423+
)
424+
encoded = b"\x01\x02\x03\x04\x05\x06\x07"
425+
426+
assert positional == keyword_value
427+
assert dataclasses.asdict(positional) == {
428+
"__annotations___": 1,
429+
"__annotations___2": 0x0302,
430+
"__annotations___3": 0x07060504,
431+
}
432+
assert wpistruct.pack(positional) == encoded
433+
assert wpistruct.unpack(generated, encoded) == positional
434+
assert wpistruct.get_type_name(generated) == "AnnotationsFields"
435+
assert wpistruct.get_schema(generated) == schema
436+
437+
layout = generated.__wpistruct_descriptor__
438+
assert layout.type_name == "AnnotationsFields"
439+
assert layout.schema == schema
440+
assert [(field.schema_name, field.python_name) for field in layout.fields] == [
441+
("__annotations__", "__annotations___"),
442+
(fullwidth_annotations, "__annotations___2"),
443+
("__annotations___", "__annotations___3"),
444+
]
445+
446+
447+
def test_generated_annotations_reservation_is_field_only():
448+
generated = make_wpistruct_from_schema(
449+
"__annotations__", "enum {VALUE=1} uint8 mode", nested={}
450+
)
451+
mode_type = generated.__dataclass_fields__["mode"].type
452+
453+
assert generated.__name__ == "__annotations__"
454+
assert mode_type.__name__ == "__annotations__Mode"
455+
assert wpistruct.get_type_name(generated) == "__annotations__"
456+
457+
405458
def test_generated_serializer_metadata_names_are_sanitized():
406459
generated = make_wpistruct_from_schema(
407460
"MetadataFields",

subprojects/robotpy-wpiutil/wpiutil/wpistruct/_schema.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def __init__(self, type_name: str):
4444

4545
_GENERATED_ATTRIBUTE_NAMES = {
4646
"WPIStruct",
47+
"__annotations__",
4748
"__wpistruct_descriptor__",
4849
}
4950

0 commit comments

Comments
 (0)