Skip to content

Commit 203e58b

Browse files
committed
cleanup/comments
1 parent 500f363 commit 203e58b

File tree

1 file changed

+24
-10
lines changed
  • openapi_python_client/parser/properties

1 file changed

+24
-10
lines changed

openapi_python_client/parser/properties/union.py

+24-10
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,27 @@ def build(
5353

5454
type_list_data = []
5555
if isinstance(data.type, list) and not (data.anyOf or data.oneOf):
56+
# The schema specifies "type:" with a list of allowable types. If there is *not* also an "anyOf"
57+
# or "oneOf", then we should treat that as a shorthand for a oneOf where each variant is just
58+
# a single "type:". For example:
59+
# {"type": ["string", "int"]} becomes
60+
# {"oneOf": [{"type": "string"}, {"type": "int"}]}
61+
# However, if there *is* also an "anyOf" or "oneOf" list, then the information from "type:" is
62+
# redundant since every allowable variant type is already fully described in the list.
5663
for _type in data.type:
5764
type_list_data.append(data.model_copy(update={"type": _type, "default": None}))
65+
# Here we're copying properties from the top-level union schema that might apply to one
66+
# of the type variants, like "format" for a string. But we don't copy "default" because
67+
# default values will be handled at the top level by the UnionProperty.
5868

5969
def process_items(
60-
preserve_name_for_item: Schema | Reference | None = None,
70+
use_original_name_for: oai.Schema | oai.Reference | None = None,
6171
) -> tuple[list[PropertyProtocol] | PropertyError, Schemas]:
6272
props: list[PropertyProtocol] = []
6373
new_schemas = schemas
64-
items_with_classes: list[Schema | Reference] = []
74+
schemas_with_classes: list[oai.Schema | oai.Reference] = []
6575
for i, sub_prop_data in enumerate(chain(data.anyOf, data.oneOf, type_list_data)):
66-
sub_prop_name = name if sub_prop_data is preserve_name_for_item else f"{name}_type_{i}"
76+
sub_prop_name = name if sub_prop_data is use_original_name_for else f"{name}_type_{i}"
6777
sub_prop, new_schemas = property_from_data(
6878
name=sub_prop_name,
6979
required=True,
@@ -75,15 +85,19 @@ def process_items(
7585
if isinstance(sub_prop, PropertyError):
7686
return PropertyError(detail=f"Invalid property in union {name}", data=sub_prop_data), new_schemas
7787
if isinstance(sub_prop, HasNamedClass):
78-
items_with_classes.append(sub_prop_data)
88+
schemas_with_classes.append(sub_prop_data)
7989
props.append(sub_prop)
8090

81-
if (not preserve_name_for_item) and (len(items_with_classes) == 1):
82-
# After our first pass, if it turns out that there was exactly one enum or model in the list,
83-
# then we'll do a second pass where we use the original name for that item instead of a
84-
# "xyz_type_n" synthetic name. Enum and model are the only types that would get their own
85-
# Python class.
86-
return process_items(items_with_classes[0])
91+
if (not use_original_name_for) and len(schemas_with_classes) == 1:
92+
# An example of this scenario is a oneOf where one of the variants is an inline enum or
93+
# model, and the other is a simple value like null. If the name of the union property is
94+
# "foo" then it's desirable for the enum or model class to be named "Foo", not "FooType1".
95+
# So, we'll do a second pass where we tell ourselves to use the original property name
96+
# for that item instead of "{name}_type_{i}".
97+
# This only makes a functional difference if the variant was an inline schema, because
98+
# we wouldn't be generating a class otherwise, but even if it wasn't inline this will
99+
# save on pointlessly long variable names inside from_dict/to_dict.
100+
return process_items(use_original_name_for=schemas_with_classes[0])
87101

88102
return props, new_schemas
89103

0 commit comments

Comments
 (0)