Skip to content

Commit

Permalink
Fix CreateTopicsResponse generation (#99)
Browse files Browse the repository at this point in the history
The key is in handling optionality and defaults of primitive types
correctly.
  • Loading branch information
ivanyu authored Nov 20, 2023
1 parent 50442a1 commit 0e2ad8d
Show file tree
Hide file tree
Showing 14 changed files with 135 additions and 8 deletions.
45 changes: 44 additions & 1 deletion codegen/generate_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 ""
Expand All @@ -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
Expand Down
1 change: 0 additions & 1 deletion codegen/generate_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
}:
Expand Down
13 changes: 13 additions & 0 deletions codegen/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions src/kio/schema/create_topics/v5/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
4 changes: 2 additions & 2 deletions src/kio/schema/create_topics/v6/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
4 changes: 2 additions & 2 deletions src/kio/schema/create_topics/v7/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
9 changes: 9 additions & 0 deletions tests/generated/test_create_topics_v0_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
9 changes: 9 additions & 0 deletions tests/generated/test_create_topics_v1_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
9 changes: 9 additions & 0 deletions tests/generated/test_create_topics_v2_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
9 changes: 9 additions & 0 deletions tests/generated/test_create_topics_v3_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
9 changes: 9 additions & 0 deletions tests/generated/test_create_topics_v4_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
9 changes: 9 additions & 0 deletions tests/generated/test_create_topics_v5_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
9 changes: 9 additions & 0 deletions tests/generated/test_create_topics_v6_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
9 changes: 9 additions & 0 deletions tests/generated/test_create_topics_v7_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)

0 comments on commit 0e2ad8d

Please sign in to comment.