@@ -38,6 +38,8 @@ def test_type_hints(self, MyModel, Unset):
38
38
39
39
@with_generated_client_fixture (
40
40
"""
41
+ # Various use cases for oneOf
42
+
41
43
components:
42
44
schemas:
43
45
ThingA:
@@ -152,6 +154,203 @@ def test_type_hints(self, ModelWithUnion, ModelWithRequiredUnion, ModelWithUnion
152
154
)
153
155
154
156
157
+ @with_generated_client_fixture (
158
+ """
159
+ # Various use cases for a oneOf where one of the variants is null, since these are handled
160
+ # a bit differently in the generator
161
+
162
+ components:
163
+ schemas:
164
+ MyEnum:
165
+ type: string
166
+ enum: ["a", "b"]
167
+ MyObject:
168
+ type: object
169
+ properties:
170
+ name:
171
+ type: string
172
+ MyModel:
173
+ properties:
174
+ nullableEnumProp:
175
+ oneOf:
176
+ - {"$ref": "#/components/schemas/MyEnum"}
177
+ - type: "null"
178
+ nullableObjectProp:
179
+ oneOf:
180
+ - {"$ref": "#/components/schemas/MyObject"}
181
+ - type: "null"
182
+ inlineNullableObject:
183
+ # Note, the generated class for this should be called "MyModelInlineNullableObject",
184
+ # since the generator's rule for inline schemas that require their own class is to
185
+ # concatenate the property name to the parent schema name.
186
+ oneOf:
187
+ - type: object
188
+ properties:
189
+ name:
190
+ type: string
191
+ - type: "null"
192
+ """ )
193
+ @with_generated_code_imports (
194
+ ".models.MyEnum" ,
195
+ ".models.MyObject" ,
196
+ ".models.MyModel" ,
197
+ ".models.MyModelInlineNullableObject" ,
198
+ ".types.Unset" ,
199
+ )
200
+ class TestUnionsWithNull :
201
+ def test_nullable_enum_prop (self , MyModel , MyEnum ):
202
+ assert_model_decode_encode (MyModel , {"nullableEnumProp" : "b" }, MyModel (nullable_enum_prop = MyEnum .B ))
203
+ assert_model_decode_encode (MyModel , {"nullableEnumProp" : None }, MyModel (nullable_enum_prop = None ))
204
+
205
+ def test_nullable_object_prop (self , MyModel , MyObject ):
206
+ assert_model_decode_encode ( MyModel , {"nullableObjectProp" : None }, MyModel (nullable_object_prop = None ))
207
+ assert_model_decode_encode ( MyModel , {"nullableObjectProp" : None }, MyModel (nullable_object_prop = None ))
208
+
209
+ def test_nullable_object_prop_with_inline_schema (self , MyModel , MyModelInlineNullableObject ):
210
+ assert_model_decode_encode (
211
+ MyModel ,
212
+ {"inlineNullableObject" : {"name" : "a" }},
213
+ MyModel (inline_nullable_object = MyModelInlineNullableObject (name = "a" )),
214
+ )
215
+ assert_model_decode_encode ( MyModel , {"inlineNullableObject" : None }, MyModel (inline_nullable_object = None ))
216
+
217
+ def test_type_hints (self , MyModel , MyEnum , Unset ):
218
+ assert_model_property_type_hint (MyModel , "nullable_enum_prop" , Union [MyEnum , None , Unset ])
219
+ assert_model_property_type_hint (MyModel , "nullable_object_prop" , Union [ForwardRef ("MyObject" ), None , Unset ])
220
+ assert_model_property_type_hint (
221
+ MyModel ,
222
+ "inline_nullable_object" ,
223
+ Union [ForwardRef ("MyModelInlineNullableObject" ), None , Unset ],
224
+ )
225
+
226
+
227
+ @with_generated_client_fixture (
228
+ """
229
+ # Tests for combining the OpenAPI 3.0 "nullable" attribute with an enum
230
+
231
+ openapi: 3.0.0
232
+
233
+ components:
234
+ schemas:
235
+ MyEnum:
236
+ type: string
237
+ enum: ["a", "b"]
238
+ MyEnumIncludingNull:
239
+ type: string
240
+ nullable: true
241
+ enum: ["a", "b", null]
242
+ MyModel:
243
+ properties:
244
+ nullableEnumProp:
245
+ allOf:
246
+ - {"$ref": "#/components/schemas/MyEnum"}
247
+ nullable: true
248
+ enumIncludingNullProp: {"$ref": "#/components/schemas/MyEnumIncludingNull"}
249
+ """ )
250
+ @with_generated_code_imports (
251
+ ".models.MyEnum" ,
252
+ ".models.MyEnumIncludingNull" ,
253
+ ".models.MyModel" ,
254
+ ".types.Unset" ,
255
+ )
256
+ class TestNullableEnumsInOpenAPI30 :
257
+ def test_nullable_enum_prop (self , MyModel , MyEnum , MyEnumIncludingNull ):
258
+ assert_model_decode_encode (MyModel , {"nullableEnumProp" : "b" }, MyModel (nullable_enum_prop = MyEnum .B ))
259
+ assert_model_decode_encode (MyModel , {"nullableEnumProp" : None }, MyModel (nullable_enum_prop = None ))
260
+ assert_model_decode_encode (
261
+ MyModel ,
262
+ {"enumIncludingNullProp" : "a" },
263
+ MyModel (enum_including_null_prop = MyEnumIncludingNull .A ),
264
+ )
265
+ assert_model_decode_encode ( MyModel , {"enumIncludingNullProp" : None }, MyModel (enum_including_null_prop = None ))
266
+
267
+ def test_type_hints (self , MyModel , MyEnum , MyEnumIncludingNull , Unset ):
268
+ assert_model_property_type_hint (MyModel , "nullable_enum_prop" , Union [MyEnum , None , Unset ])
269
+ assert_model_property_type_hint (MyModel , "enum_including_null_prop" , Union [MyEnumIncludingNull , None , Unset ])
270
+
271
+
272
+ @with_generated_client_fixture (
273
+ """
274
+ # Test use cases where there's a union of types *and* an explicit list of multiple "type:"s
275
+
276
+ components:
277
+ schemas:
278
+ MyStringEnum:
279
+ type: string
280
+ enum: ["a", "b"]
281
+ MyIntEnum:
282
+ type: integer
283
+ enum: [1, 2]
284
+ MyEnumIncludingNull:
285
+ type: ["string", "null"]
286
+ enum: ["a", "b", null]
287
+ MyObject:
288
+ type: object
289
+ properties:
290
+ name:
291
+ type: string
292
+ MyModel:
293
+ properties:
294
+ enumsWithListOfTypesProp:
295
+ type: ["string", "integer"]
296
+ oneOf:
297
+ - {"$ref": "#/components/schemas/MyStringEnum"}
298
+ - {"$ref": "#/components/schemas/MyIntEnum"}
299
+ enumIncludingNullProp: {"$ref": "#/components/schemas/MyEnumIncludingNull"}
300
+ nullableObjectWithListOfTypesProp:
301
+ type: ["string", "object"]
302
+ oneOf:
303
+ - {"$ref": "#/components/schemas/MyObject"}
304
+ - type: "null"
305
+ """ )
306
+ @with_generated_code_imports (
307
+ ".models.MyStringEnum" ,
308
+ ".models.MyIntEnum" ,
309
+ ".models.MyEnumIncludingNull" ,
310
+ ".models.MyObject" ,
311
+ ".models.MyModel" ,
312
+ ".types.Unset" ,
313
+ )
314
+ class TestUnionsWithExplicitListOfTypes :
315
+ # This covers some use cases where combining "oneOf" with "type: [list of types]" (which is fine
316
+ # to do in OpenAPI) used to generate enum/model classes incorrectly.
317
+
318
+ def test_union_of_enums (self , MyModel , MyStringEnum , MyIntEnum ):
319
+ assert_model_decode_encode (
320
+ MyModel ,
321
+ {"enumsWithListOfTypesProp" : "b" },
322
+ MyModel (enums_with_list_of_types_prop = MyStringEnum .B ),
323
+ )
324
+ assert_model_decode_encode (
325
+ MyModel ,
326
+ {"enumsWithListOfTypesProp" : 2 },
327
+ MyModel (enums_with_list_of_types_prop = MyIntEnum .VALUE_2 ),
328
+ )
329
+
330
+ def test_union_of_enum_with_null (self , MyModel , MyEnumIncludingNull ):
331
+ assert_model_decode_encode (
332
+ MyModel ,
333
+ {"enumIncludingNullProp" : "b" },
334
+ MyModel (enum_including_null_prop = MyEnumIncludingNull .B ),
335
+ )
336
+ assert_model_decode_encode (
337
+ MyModel ,
338
+ {"enumIncludingNullProp" : None },
339
+ MyModel (enum_including_null_prop = None ),
340
+ )
341
+
342
+ def test_nullable_object_with_list_of_types (self , MyModel , MyObject ):
343
+ assert_model_decode_encode (
344
+ MyModel ,
345
+ {"nullableObjectWithListOfTypesProp" : {"name" : "a" }},
346
+ MyModel (nullable_object_with_list_of_types_prop = MyObject (name = "a" )),
347
+ )
348
+ assert_model_decode_encode (
349
+ MyModel ,
350
+ {"nullableObjectWithListOfTypesProp" : None },
351
+ MyModel (nullable_object_with_list_of_types_prop = None ),
352
+ )
353
+
155
354
@with_generated_client_fixture (
156
355
"""
157
356
components:
0 commit comments