Skip to content

Commit 77b523b

Browse files
committed
adding option
1 parent 41185f0 commit 77b523b

2 files changed

Lines changed: 9 additions & 2 deletions

File tree

src/py_avro_schema/_schemas.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,12 @@ class Option(enum.Flag):
131131
#: See https://docs.pydantic.dev/dev/api/fields/#pydantic.fields.Field
132132
USE_FIELD_ALIAS = enum.auto()
133133

134+
#: TypedDict marked with ``total=False`` are valid structures when a field is missing. When of the field is also
135+
# optional, we need to have a way to distinguish between a `None` and a non-set field. With this option, the type
136+
# of each field is extended with `string`. This way, clients can add markers (e.g., `__td_missing__`) to discern
137+
# the two cases.
138+
MARK_NON_TOTAL_TYPED_DICTS = enum.auto()
139+
134140

135141
JSON_OPTIONS = [opt for opt in Option if opt.name and opt.name.startswith("JSON_")]
136142

@@ -1261,7 +1267,7 @@ def _record_field(self, py_field: tuple[str, Type]) -> RecordField:
12611267
"""Return an Avro record field object for a given TypedDict field"""
12621268
aliases, actual_type = get_field_aliases_and_actual_type(py_field[1])
12631269

1264-
if not self.is_total:
1270+
if Option.MARK_NON_TOTAL_TYPED_DICTS in self.options and not self.is_total:
12651271
# If a TypedDict is marked as total=None, it does not need to contain all the field. However, we need to
12661272
# be able to distinguish between the fields that are missing from the ones that are present but set to None.
12671273
# To do that, we extend the original type with str. We will later add a special string

tests/test_typed_dict.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from enum import StrEnum
22
from typing import Annotated, TypedDict
33

4+
import py_avro_schema as pas
45
from py_avro_schema._alias import Alias, register_type_alias
56
from py_avro_schema._testing import assert_schema
67

@@ -109,4 +110,4 @@ class PyType(TypedDict, total=False):
109110
{"name": "opt", "type": [{"namedString": "Opt", "type": "string"}, "null"]},
110111
],
111112
}
112-
assert_schema(PyType, expected)
113+
assert_schema(PyType, expected, options=pas.Option.MARK_NON_TOTAL_TYPED_DICTS)

0 commit comments

Comments
 (0)