diff --git a/codegen/generate_schema.py b/codegen/generate_schema.py index c5513fcf..ad77f87b 100644 --- a/codegen/generate_schema.py +++ b/codegen/generate_schema.py @@ -172,7 +172,7 @@ def format_dataclass_field( field_type, default, optional, custom_type ) elif tag is not None and ignorable: - field_kwargs["default"] = "None" + field_kwargs["default"] = _format_default_for_tagged(field_type) if not field_kwargs: return "" @@ -183,6 +183,49 @@ def format_dataclass_field( return f" = field({formatted_kwargs})" +def _format_default_for_tagged( + field_type: Primitive | PrimitiveArrayType | EntityType | CommonStructType, +) -> str: + match field_type: + case Primitive.int8: + result = "i8(0)" + case Primitive.int16: + result = "i16(0)" + case Primitive.int32: + result = "i32(0)" + case Primitive.int64: + result = "i64(0)" + case Primitive.uint16: + result = "u16(0)" + case Primitive.uint32: + result = "u32(0)" + case Primitive.uint64: + result = "u64(0)" + case Primitive.float64: + result = "f64(0.0)" + case Primitive.bool_: + result = "false" + case Primitive.error_code: + result = "ErrorCode.none" + case ( + Primitive.string + | Primitive.bytes_ + | Primitive.records + | Primitive.uuid + | Primitive.datetime_i64 + | Primitive.timedelta_i32 + | Primitive.timedelta_i64 + ): + result = "None" + case _ if isinstance( + field_type, PrimitiveArrayType | EntityType | CommonStructType + ): + result = "None" + case no_match: + assert_never(no_match) + return result + + @dataclass(frozen=True, slots=True, kw_only=True, order=True) class CustomTypeDef: name: str diff --git a/codegen/generate_tests.py b/codegen/generate_tests.py index 37732767..9029867a 100644 --- a/codegen/generate_tests.py +++ b/codegen/generate_tests.py @@ -120,7 +120,6 @@ def main() -> None: "ProduceRequest", # Records "FetchResponse", # Records "FetchSnapshotResponse", # Records - "CreateTopicsResponse", # Should not output tagged field if its value equals to default "FetchRequest", # Should not output tagged field if its value equals to default (presumably) "ConsumerGroupHeartbeatResponse", # Nullable `assignment` field }: diff --git a/codegen/parser.py b/codegen/parser.py index 8e6746c5..194cf4b6 100644 --- a/codegen/parser.py +++ b/codegen/parser.py @@ -272,6 +272,19 @@ class PrimitiveField(_BaseField): default: str | int | float | bool | None def is_nullable(self, version: int) -> bool: + # Primitive types are never optional + if self.type in { + Primitive.int8, + Primitive.int16, + Primitive.int32, + Primitive.int64, + Primitive.uint16, + Primitive.uint32, + Primitive.uint64, + Primitive.float64, + }: + return False + return ( ( # Tagged fields that are ignorable and don't have a default are optional. diff --git a/src/kio/schema/create_topics/v5/response.py b/src/kio/schema/create_topics/v5/response.py index 1cf05f7c..9b731481 100644 --- a/src/kio/schema/create_topics/v5/response.py +++ b/src/kio/schema/create_topics/v5/response.py @@ -48,8 +48,8 @@ class CreatableTopicResult: """The error code, or 0 if there was no error.""" error_message: str | None = field(metadata={"kafka_type": "string"}) """The error message, or null if there was no error.""" - topic_config_error_code: i16 | None = field( - metadata={"kafka_type": "int16", "tag": 0}, default=None + topic_config_error_code: i16 = field( + metadata={"kafka_type": "int16", "tag": 0}, default=i16(0) ) """Optional topic config error returned if configs are not returned in the response.""" num_partitions: i32 = field(metadata={"kafka_type": "int32"}, default=i32(-1)) diff --git a/src/kio/schema/create_topics/v6/response.py b/src/kio/schema/create_topics/v6/response.py index 21e5b6f2..4741b91a 100644 --- a/src/kio/schema/create_topics/v6/response.py +++ b/src/kio/schema/create_topics/v6/response.py @@ -48,8 +48,8 @@ class CreatableTopicResult: """The error code, or 0 if there was no error.""" error_message: str | None = field(metadata={"kafka_type": "string"}) """The error message, or null if there was no error.""" - topic_config_error_code: i16 | None = field( - metadata={"kafka_type": "int16", "tag": 0}, default=None + topic_config_error_code: i16 = field( + metadata={"kafka_type": "int16", "tag": 0}, default=i16(0) ) """Optional topic config error returned if configs are not returned in the response.""" num_partitions: i32 = field(metadata={"kafka_type": "int32"}, default=i32(-1)) diff --git a/src/kio/schema/create_topics/v7/response.py b/src/kio/schema/create_topics/v7/response.py index 4ea89b54..4589165a 100644 --- a/src/kio/schema/create_topics/v7/response.py +++ b/src/kio/schema/create_topics/v7/response.py @@ -51,8 +51,8 @@ class CreatableTopicResult: """The error code, or 0 if there was no error.""" error_message: str | None = field(metadata={"kafka_type": "string"}) """The error message, or null if there was no error.""" - topic_config_error_code: i16 | None = field( - metadata={"kafka_type": "int16", "tag": 0}, default=None + topic_config_error_code: i16 = field( + metadata={"kafka_type": "int16", "tag": 0}, default=i16(0) ) """Optional topic config error returned if configs are not returned in the response.""" num_partitions: i32 = field(metadata={"kafka_type": "int32"}, default=i32(-1)) diff --git a/tests/generated/test_create_topics_v0_response.py b/tests/generated/test_create_topics_v0_response.py index 9eedba9b..40da0023 100644 --- a/tests/generated/test_create_topics_v0_response.py +++ b/tests/generated/test_create_topics_v0_response.py @@ -11,6 +11,7 @@ from kio.schema.create_topics.v0.response import CreateTopicsResponse from kio.serial import entity_reader from kio.serial import entity_writer +from tests.conftest import JavaTester from tests.conftest import setup_buffer read_creatable_topic_result: Final = entity_reader(CreatableTopicResult) @@ -41,3 +42,11 @@ def test_create_topics_response_roundtrip(instance: CreateTopicsResponse) -> Non buffer.seek(0) result = read_create_topics_response(buffer) assert instance == result + + +@pytest.mark.java +@given(instance=from_type(CreateTopicsResponse)) +def test_create_topics_response_java( + instance: CreateTopicsResponse, java_tester: JavaTester +) -> None: + java_tester.test(instance) diff --git a/tests/generated/test_create_topics_v1_response.py b/tests/generated/test_create_topics_v1_response.py index e0c00fc6..7c4cc9b2 100644 --- a/tests/generated/test_create_topics_v1_response.py +++ b/tests/generated/test_create_topics_v1_response.py @@ -11,6 +11,7 @@ from kio.schema.create_topics.v1.response import CreateTopicsResponse from kio.serial import entity_reader from kio.serial import entity_writer +from tests.conftest import JavaTester from tests.conftest import setup_buffer read_creatable_topic_result: Final = entity_reader(CreatableTopicResult) @@ -41,3 +42,11 @@ def test_create_topics_response_roundtrip(instance: CreateTopicsResponse) -> Non buffer.seek(0) result = read_create_topics_response(buffer) assert instance == result + + +@pytest.mark.java +@given(instance=from_type(CreateTopicsResponse)) +def test_create_topics_response_java( + instance: CreateTopicsResponse, java_tester: JavaTester +) -> None: + java_tester.test(instance) diff --git a/tests/generated/test_create_topics_v2_response.py b/tests/generated/test_create_topics_v2_response.py index 9dacf500..eeba77c4 100644 --- a/tests/generated/test_create_topics_v2_response.py +++ b/tests/generated/test_create_topics_v2_response.py @@ -11,6 +11,7 @@ from kio.schema.create_topics.v2.response import CreateTopicsResponse from kio.serial import entity_reader from kio.serial import entity_writer +from tests.conftest import JavaTester from tests.conftest import setup_buffer read_creatable_topic_result: Final = entity_reader(CreatableTopicResult) @@ -41,3 +42,11 @@ def test_create_topics_response_roundtrip(instance: CreateTopicsResponse) -> Non buffer.seek(0) result = read_create_topics_response(buffer) assert instance == result + + +@pytest.mark.java +@given(instance=from_type(CreateTopicsResponse)) +def test_create_topics_response_java( + instance: CreateTopicsResponse, java_tester: JavaTester +) -> None: + java_tester.test(instance) diff --git a/tests/generated/test_create_topics_v3_response.py b/tests/generated/test_create_topics_v3_response.py index e93e479e..538dc456 100644 --- a/tests/generated/test_create_topics_v3_response.py +++ b/tests/generated/test_create_topics_v3_response.py @@ -11,6 +11,7 @@ from kio.schema.create_topics.v3.response import CreateTopicsResponse from kio.serial import entity_reader from kio.serial import entity_writer +from tests.conftest import JavaTester from tests.conftest import setup_buffer read_creatable_topic_result: Final = entity_reader(CreatableTopicResult) @@ -41,3 +42,11 @@ def test_create_topics_response_roundtrip(instance: CreateTopicsResponse) -> Non buffer.seek(0) result = read_create_topics_response(buffer) assert instance == result + + +@pytest.mark.java +@given(instance=from_type(CreateTopicsResponse)) +def test_create_topics_response_java( + instance: CreateTopicsResponse, java_tester: JavaTester +) -> None: + java_tester.test(instance) diff --git a/tests/generated/test_create_topics_v4_response.py b/tests/generated/test_create_topics_v4_response.py index a5ff5180..31bbf05f 100644 --- a/tests/generated/test_create_topics_v4_response.py +++ b/tests/generated/test_create_topics_v4_response.py @@ -11,6 +11,7 @@ from kio.schema.create_topics.v4.response import CreateTopicsResponse from kio.serial import entity_reader from kio.serial import entity_writer +from tests.conftest import JavaTester from tests.conftest import setup_buffer read_creatable_topic_result: Final = entity_reader(CreatableTopicResult) @@ -41,3 +42,11 @@ def test_create_topics_response_roundtrip(instance: CreateTopicsResponse) -> Non buffer.seek(0) result = read_create_topics_response(buffer) assert instance == result + + +@pytest.mark.java +@given(instance=from_type(CreateTopicsResponse)) +def test_create_topics_response_java( + instance: CreateTopicsResponse, java_tester: JavaTester +) -> None: + java_tester.test(instance) diff --git a/tests/generated/test_create_topics_v5_response.py b/tests/generated/test_create_topics_v5_response.py index 729f2a78..25ee88a4 100644 --- a/tests/generated/test_create_topics_v5_response.py +++ b/tests/generated/test_create_topics_v5_response.py @@ -12,6 +12,7 @@ from kio.schema.create_topics.v5.response import CreateTopicsResponse from kio.serial import entity_reader from kio.serial import entity_writer +from tests.conftest import JavaTester from tests.conftest import setup_buffer read_creatable_topic_configs: Final = entity_reader(CreatableTopicConfigs) @@ -57,3 +58,11 @@ def test_create_topics_response_roundtrip(instance: CreateTopicsResponse) -> Non buffer.seek(0) result = read_create_topics_response(buffer) assert instance == result + + +@pytest.mark.java +@given(instance=from_type(CreateTopicsResponse)) +def test_create_topics_response_java( + instance: CreateTopicsResponse, java_tester: JavaTester +) -> None: + java_tester.test(instance) diff --git a/tests/generated/test_create_topics_v6_response.py b/tests/generated/test_create_topics_v6_response.py index 5f9fe363..ffa80ecf 100644 --- a/tests/generated/test_create_topics_v6_response.py +++ b/tests/generated/test_create_topics_v6_response.py @@ -12,6 +12,7 @@ from kio.schema.create_topics.v6.response import CreateTopicsResponse from kio.serial import entity_reader from kio.serial import entity_writer +from tests.conftest import JavaTester from tests.conftest import setup_buffer read_creatable_topic_configs: Final = entity_reader(CreatableTopicConfigs) @@ -57,3 +58,11 @@ def test_create_topics_response_roundtrip(instance: CreateTopicsResponse) -> Non buffer.seek(0) result = read_create_topics_response(buffer) assert instance == result + + +@pytest.mark.java +@given(instance=from_type(CreateTopicsResponse)) +def test_create_topics_response_java( + instance: CreateTopicsResponse, java_tester: JavaTester +) -> None: + java_tester.test(instance) diff --git a/tests/generated/test_create_topics_v7_response.py b/tests/generated/test_create_topics_v7_response.py index e161d600..5a9a06cf 100644 --- a/tests/generated/test_create_topics_v7_response.py +++ b/tests/generated/test_create_topics_v7_response.py @@ -12,6 +12,7 @@ from kio.schema.create_topics.v7.response import CreateTopicsResponse from kio.serial import entity_reader from kio.serial import entity_writer +from tests.conftest import JavaTester from tests.conftest import setup_buffer read_creatable_topic_configs: Final = entity_reader(CreatableTopicConfigs) @@ -57,3 +58,11 @@ def test_create_topics_response_roundtrip(instance: CreateTopicsResponse) -> Non buffer.seek(0) result = read_create_topics_response(buffer) assert instance == result + + +@pytest.mark.java +@given(instance=from_type(CreateTopicsResponse)) +def test_create_topics_response_java( + instance: CreateTopicsResponse, java_tester: JavaTester +) -> None: + java_tester.test(instance)