Skip to content

Commit f67ea52

Browse files
committed
feat!: implemented full discriminator support
1 parent 9deae91 commit f67ea52

6 files changed

Lines changed: 78 additions & 37 deletions

File tree

src/openapi_parser/builders/schema.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,21 @@ def merge_all_of_schemas(original_data: dict[str, Any]) -> dict[str, Any]:
111111
return schema_dict
112112

113113

114+
def build_discriminator(value: dict[str, Any]) -> Discriminator:
115+
"""Build a Discriminator object from raw data.
116+
117+
Args:
118+
value: Raw discriminator data
119+
120+
Returns:
121+
Discriminator object
122+
"""
123+
return Discriminator(
124+
property_name=value["propertyName"],
125+
mapping=value.get("mapping", {}),
126+
)
127+
128+
114129
class SchemaFactory:
115130
"""Factory for creating schema objects from raw dicts."""
116131

@@ -256,19 +271,6 @@ def _one_of(self, data: dict[str, Any]) -> OneOf:
256271
def create_inner_schemas(schemas: list[dict[str, Any]]) -> list[Schema]:
257272
return [self.create(x) for x in schemas]
258273

259-
def build_discriminator(discriminator_data: dict[str, Any]) -> Discriminator:
260-
discriminator = Discriminator(
261-
property_name=discriminator_data["propertyName"],
262-
)
263-
264-
if "mapping" in discriminator_data:
265-
discriminator.mapping = {
266-
key: self.create(schema)
267-
for key, schema in discriminator_data["mapping"].items()
268-
}
269-
270-
return discriminator
271-
272274
attrs_map = {
273275
"schemas": PropertyMeta(name="oneOf", cast=create_inner_schemas),
274276
"discriminator": PropertyMeta(
@@ -283,7 +285,13 @@ def _any_of(self, data: dict[str, Any]) -> AnyOf:
283285
def create_inner_schemas(schemas: list[dict[str, Any]]) -> list[Schema]:
284286
return [self.create(x) for x in schemas]
285287

286-
attrs_map = {"schemas": PropertyMeta(name="anyOf", cast=create_inner_schemas)}
288+
attrs_map = {
289+
"schemas": PropertyMeta(name="anyOf", cast=create_inner_schemas),
290+
"discriminator": PropertyMeta(
291+
name="discriminator",
292+
cast=build_discriminator,
293+
),
294+
}
287295

288296
if "type" in data:
289297
return AnyOf(**extract_attrs(data, attrs_map))

src/openapi_parser/specification.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ class Discriminator:
165165
"""Polymorphism discriminator."""
166166

167167
property_name: str
168-
mapping: dict[str, Any] | None = field(default_factory=dict)
168+
mapping: dict[str, str] | None = field(default_factory=dict)
169169

170170

171171
@dataclass
@@ -181,6 +181,7 @@ class AnyOf(Schema):
181181
"""AnyOf composition schema."""
182182

183183
schemas: list[Schema] = field(default_factory=list)
184+
discriminator: Discriminator | None = None
184185

185186

186187
@dataclass

tests/builders/schema/test_anyof.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
AnyOf,
99
Array,
1010
Boolean,
11+
Discriminator,
1112
Integer,
1213
Number,
1314
Object,
@@ -142,6 +143,32 @@
142143
],
143144
),
144145
),
146+
(
147+
{
148+
"anyOf": [
149+
{"type": "string"},
150+
{"type": "integer"},
151+
],
152+
"discriminator": {
153+
"propertyName": "objectType",
154+
"mapping": {
155+
"str": "SomeTarget",
156+
"int": "OtherTarget",
157+
},
158+
},
159+
},
160+
AnyOf(
161+
type=DataType.ANY_OF,
162+
schemas=[
163+
String(type=DataType.STRING),
164+
Integer(type=DataType.INTEGER),
165+
],
166+
discriminator=Discriminator(
167+
property_name="objectType",
168+
mapping={"str": "SomeTarget", "int": "OtherTarget"},
169+
),
170+
),
171+
),
145172
)
146173

147174

tests/builders/schema/test_oneof.py

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -102,17 +102,8 @@
102102
"discriminator": {
103103
"propertyName": "objectType",
104104
"mapping": {
105-
"objectType1": {
106-
"type": "string",
107-
"maxLength": 1,
108-
"minLength": 0,
109-
"pattern": "[0-9]",
110-
"format": "uuid",
111-
},
112-
"objectType2": {
113-
"type": "integer",
114-
"format": "int32",
115-
},
105+
"objectType1": "objectType1",
106+
"objectType2": "objectType2",
116107
},
117108
},
118109
},
@@ -134,17 +125,8 @@
134125
discriminator=Discriminator(
135126
property_name="objectType",
136127
mapping={
137-
"objectType1": String(
138-
type=DataType.STRING,
139-
max_length=1,
140-
min_length=0,
141-
pattern="[0-9]",
142-
format=StringFormat.UUID,
143-
),
144-
"objectType2": Integer(
145-
type=DataType.INTEGER,
146-
format=IntegerFormat.INT32,
147-
),
128+
"objectType1": "objectType1",
129+
"objectType2": "objectType2",
148130
},
149131
),
150132
),

tests/data/swagger.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,3 +302,13 @@ components:
302302
format: uri
303303
example: 'https://github.com/manchenkoff/openapi3-parser'
304304
description: 'User Avatar URL'
305+
306+
Payload:
307+
oneOf:
308+
- type: string
309+
- type: integer
310+
discriminator:
311+
propertyName: payloadType
312+
mapping:
313+
str: 'SomeTarget'
314+
int: 'OtherTarget'

tests/openapi_fixture.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515
Array,
1616
Contact,
1717
Content,
18+
Discriminator,
1819
Encoding,
1920
Info,
2021
Integer,
2122
License,
2223
Link,
2324
Object,
25+
OneOf,
2426
Operation,
2527
Parameter,
2628
Path,
@@ -301,6 +303,17 @@ def create_specification() -> Specification:
301303
),
302304
],
303305
),
306+
"Payload": OneOf(
307+
type=DataType.ONE_OF,
308+
schemas=[
309+
String(type=DataType.STRING),
310+
Integer(type=DataType.INTEGER),
311+
],
312+
discriminator=Discriminator(
313+
property_name="payloadType",
314+
mapping={"str": "SomeTarget", "int": "OtherTarget"},
315+
),
316+
),
304317
}
305318

306319
security: list[dict[str, Any]] = [{"Basic": []}]

0 commit comments

Comments
 (0)