Skip to content

Commit b6d9d0a

Browse files
committed
fix type hinting problems
1 parent 8c4ef97 commit b6d9d0a

File tree

2 files changed

+17
-13
lines changed

2 files changed

+17
-13
lines changed

openapi_python_client/parser/properties/merge_properties.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from collections.abc import Callable
2-
from typing import Any
2+
from typing import Any, Dict, TypeVar, Union, cast
33

44
from attr import evolve
55

@@ -11,6 +11,10 @@
1111
from openapi_python_client.parser.properties.protocol import PropertyProtocol
1212
from openapi_python_client.parser.properties.string import StringProperty
1313

14+
# Note that in this file we have to use PropertyProtocol instead of the union type Property,
15+
# to avoid circular imports.
16+
PropertyT = TypeVar("PropertyT", bound=PropertyProtocol)
17+
1418

1519
def merge_properties(prop1: PropertyProtocol, prop2: PropertyProtocol) -> PropertyProtocol:
1620
"""Attempt to create a new property that incorporates the behavior of both.
@@ -56,11 +60,11 @@ def _merge_same_type(prop1: PropertyProtocol, prop2: PropertyProtocol) -> Proper
5660
return prop1
5761

5862
if isinstance(prop1, StringProperty):
59-
return _merge_string(prop1, prop2)
63+
return _merge_string(prop1, cast(StringProperty, prop2))
6064

6165
if isinstance(prop1, ListProperty):
6266
# There's no clear way to represent the intersection of two different list types. Fail in this case.
63-
if prop1.inner_property != prop2.inner_property:
67+
if prop1.inner_property != cast(ListProperty, prop2).inner_property:
6468
raise ValueError("can't redefine a list property with a different element type")
6569

6670
# For all other property types, there aren't any special attributes that affect validation, so just
@@ -71,12 +75,12 @@ def _merge_same_type(prop1: PropertyProtocol, prop2: PropertyProtocol) -> Proper
7175
def _merge_string(prop1: StringProperty, prop2: StringProperty) -> StringProperty:
7276
# If max_length was specified for both, the smallest value takes precedence. If only one of them
7377
# specifies it, _combine_values will pick that one.
74-
max_length: int | None = _combine_values(prop1.max_length, prop2.max_length, lambda a, b: min([a, b]))
78+
max_length: Union[int, None] = _combine_values(prop1.max_length, prop2.max_length, lambda a, b: min([a, b]))
7579

7680
# If pattern was specified for both, we have a problem. OpenAPI has no logical objection to this;
7781
# it would just mean the value must match both of the patterns to be valid. But we have no way to
7882
# represent this in our internal model currently.
79-
pattern: str | None | ValueError = _combine_values(
83+
pattern: Union[str, None, ValueError] = _combine_values(
8084
prop1.pattern, prop2.pattern, lambda a, b: ValueError("specified two different regex patterns")
8185
)
8286
if isinstance(pattern, ValueError):
@@ -89,7 +93,7 @@ def _merge_numeric(prop1: PropertyProtocol, prop2: PropertyProtocol) -> IntPrope
8993
# Here, one of the properties was defined as "int" and the other was just a general number (which
9094
# we call FloatProperty). "Must be integer" is the stricter validation rule, so the result must be
9195
# an IntProperty.
92-
int_prop = prop1 if isinstance(prop1, IntProperty) else prop2
96+
int_prop = prop1 if isinstance(prop1, IntProperty) else cast(IntProperty, prop2)
9397
result = _merge_common_attributes(int_prop, prop1, prop2)
9498
if result.default is not None:
9599
if isinstance(result.default, float) and not result.default.is_integer():
@@ -108,7 +112,7 @@ def _merge_with_enum(prop1: PropertyProtocol, prop2: PropertyProtocol) -> EnumPr
108112
if isinstance(prop1, EnumProperty) and isinstance(prop2, EnumProperty):
109113
# We want the narrowest validation rules that fit both, so use whichever values list is a
110114
# subset of the other.
111-
values: dict[str, ValueType]
115+
values: Dict[str, ValueType]
112116
if _values_are_subset(prop1, prop2):
113117
values = prop1.values
114118
elif _values_are_subset(prop2, prop1):
@@ -118,7 +122,7 @@ def _merge_with_enum(prop1: PropertyProtocol, prop2: PropertyProtocol) -> EnumPr
118122
return _merge_common_attributes(evolve(prop1, values=values), prop2)
119123

120124
# If enum values were specified for just one of the properties, use those.
121-
enum_prop = prop1 if isinstance(prop1, EnumProperty) else prop2
125+
enum_prop = prop1 if isinstance(prop1, EnumProperty) else cast(EnumProperty, prop2)
122126
non_enum_prop = prop2 if isinstance(prop1, EnumProperty) else prop1
123127
if (isinstance(non_enum_prop, IntProperty) and enum_prop.value_type is int) or (
124128
isinstance(non_enum_prop, StringProperty) and enum_prop.value_type is str
@@ -127,7 +131,7 @@ def _merge_with_enum(prop1: PropertyProtocol, prop2: PropertyProtocol) -> EnumPr
127131
raise ValueError("defined with two incompatible types")
128132

129133

130-
def _merge_common_attributes(base: PropertyProtocol, *extend_with: PropertyProtocol) -> PropertyProtocol:
134+
def _merge_common_attributes(base: PropertyT, *extend_with: PropertyProtocol) -> PropertyT:
131135
"""Create a new instance based on base, overriding basic attributes with values from extend_with, in order.
132136
133137
For "default", "description", and "example", a non-None value overrides any value from a previously
@@ -140,7 +144,7 @@ def _merge_common_attributes(base: PropertyProtocol, *extend_with: PropertyProto
140144
current = base
141145
for override in extend_with:
142146
current = evolve(
143-
current,
147+
current, # type: ignore # can't prove that every property type is an attrs class, but it is
144148
required=current.required or override.required,
145149
default=override.default or current.default,
146150
description=override.description or current.description,
@@ -153,7 +157,7 @@ def _values_are_subset(prop1: EnumProperty, prop2: EnumProperty) -> bool:
153157
return set(prop1.values.items()) <= set(prop2.values.items())
154158

155159

156-
def _combine_values(value1: Any, value2: Any, combinator: Callable) -> Any:
160+
def _combine_values(value1: Any, value2: Any, combinator: Callable[[Any, Any], Any]) -> Any:
157161
if value1 == value2:
158162
return value1
159163
if value1 is None:

openapi_python_client/parser/properties/model_property.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
from itertools import chain
4-
from typing import Any, ClassVar, NamedTuple
4+
from typing import Any, ClassVar, NamedTuple, cast
55

66
from attrs import define, evolve
77

@@ -256,7 +256,7 @@ def _add_if_no_conflict(new_prop: Property) -> PropertyError | None:
256256

257257
name_conflict = properties.get(new_prop.name)
258258
try:
259-
merged_prop = merge_properties(name_conflict, new_prop) if name_conflict else new_prop
259+
merged_prop = cast(Property, merge_properties(name_conflict, new_prop)) if name_conflict else new_prop
260260
except ValueError as e:
261261
return PropertyError(
262262
header=f"Found conflicting properties named {new_prop.name} when creating {class_name}",

0 commit comments

Comments
 (0)