1+ # Copyright 2022 J.P. Morgan Chase & Co.
2+ #
3+ # Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
4+ # the License. You may obtain a copy of the License at
5+ #
6+ # http://www.apache.org/licenses/LICENSE-2.0
7+ #
8+ # Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
9+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
10+ # specific language governing permissions and limitations under the License.
11+
112from enum import StrEnum
2- from typing import Annotated , NotRequired , TypedDict
13+ from typing import Annotated , NotRequired , TypedDict , Union
14+
15+ import pytest
316
17+ import py_avro_schema
418import py_avro_schema as pas
519from py_avro_schema ._alias import Alias , register_type_alias
620from py_avro_schema ._testing import assert_schema
@@ -104,27 +118,35 @@ class PyType(TypedDict, total=False):
104118 valid : ValidEnumSymbol | None
105119
106120 expected = {
107- "type" : "record" ,
108- "name" : "PyType" ,
109121 "fields" : [
110- {"name" : "name" , "type" : "string" },
111- {"name" : "nickname" , "type" : ["string" , "null" ], "default" : "__td_missing__" },
112- {"name" : "age" , "type" : ["string" , "long" , "null" ], "default" : "__td_missing__" },
122+ {"name" : "name" , "type" : {"namedString" : "TDMissingMarker" , "type" : "string" }},
113123 {
114- "name" : "invalid" ,
115- "type" : [{"namedString" : "InvalidEnumSymbol" , "type" : "string" }, "null" ],
116124 "default" : "__td_missing__" ,
125+ "name" : "nickname" ,
126+ "type" : ["null" , {"namedString" : "TDMissingMarker" , "type" : "string" }],
127+ },
128+ {
129+ "default" : "__td_missing__" ,
130+ "name" : "age" ,
131+ "type" : [{"namedString" : "TDMissingMarker" , "type" : "string" }, "long" , "null" ],
132+ },
133+ {
134+ "default" : "__td_missing__" ,
135+ "name" : "invalid" ,
136+ "type" : [{"namedString" : "TDMissingMarker" , "type" : "string" }, "null" ],
117137 },
118138 {
119139 "default" : "__td_missing__" ,
120140 "name" : "valid" ,
121141 "type" : [
122- " string" ,
142+ { "namedString" : "TDMissingMarker" , "type" : " string"} ,
123143 {"default" : "valid_val" , "name" : "ValidEnumSymbol" , "symbols" : ["valid_val" ], "type" : "enum" },
124144 "null" ,
125145 ],
126146 },
127147 ],
148+ "name" : "PyType" ,
149+ "type" : "record" ,
128150 }
129151 assert_schema (PyType , expected , options = pas .Option .MARK_NON_TOTAL_TYPED_DICTS )
130152
@@ -137,14 +159,14 @@ class PyType(TypedDict):
137159 nullable_value : NotRequired [str | None ]
138160
139161 expected = {
140- "type" : "record" ,
141- "name" : "PyType" ,
142162 "fields" : [
143163 {"name" : "name" , "type" : "string" },
144- {"name" : "value" , "type" : " string" },
145- {"name" : "value_int" , "type" : ["long" , " string" ]},
146- {"name" : "nullable_value" , "type" : ["string " , "null" ]},
164+ {"name" : "value" , "type" : { "namedString" : "TDMissingMarker" , "type" : " string"} },
165+ {"name" : "value_int" , "type" : ["long" , { "namedString" : "TDMissingMarker" , "type" : " string"} ]},
166+ {"name" : "nullable_value" , "type" : ["null " , { "namedString" : "TDMissingMarker" , "type" : "string" } ]},
147167 ],
168+ "name" : "PyType" ,
169+ "type" : "record" ,
148170 }
149171
150172 assert_schema (PyType , expected , options = pas .Option .MARK_NON_TOTAL_TYPED_DICTS )
@@ -170,3 +192,15 @@ class PyType(TypedDict):
170192 ],
171193 }
172194 assert_schema (PyType , expected , options = pas .Option .ADD_REFERENCE_ID )
195+
196+
197+ def test_union_typed_dict_error ():
198+ class PyType (TypedDict ):
199+ var : str
200+
201+ class PyType2 (TypedDict ):
202+ var : str
203+
204+ py_type = Union [PyType , PyType2 ]
205+ with pytest .raises (TypeError ):
206+ py_avro_schema ._schemas .schema (py_type )
0 commit comments