Skip to content

Commit ba92359

Browse files
authored
feat!: implemented full discriminator support (#107)
1 parent 25f4d9c commit ba92359

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

@@ -262,19 +277,6 @@ def _one_of(self, data: dict[str, Any]) -> OneOf:
262277
def create_inner_schemas(schemas: list[dict[str, Any]]) -> list[Schema]:
263278
return [self.create(x) for x in schemas]
264279

265-
def build_discriminator(discriminator_data: dict[str, Any]) -> Discriminator:
266-
discriminator = Discriminator(
267-
property_name=discriminator_data["propertyName"],
268-
)
269-
270-
if "mapping" in discriminator_data:
271-
discriminator.mapping = {
272-
key: self.create(schema)
273-
for key, schema in discriminator_data["mapping"].items()
274-
}
275-
276-
return discriminator
277-
278280
attrs_map = {
279281
"schemas": PropertyMeta(name="oneOf", cast=create_inner_schemas),
280282
"discriminator": PropertyMeta(
@@ -289,7 +291,13 @@ def _any_of(self, data: dict[str, Any]) -> AnyOf:
289291
def create_inner_schemas(schemas: list[dict[str, Any]]) -> list[Schema]:
290292
return [self.create(x) for x in schemas]
291293

292-
attrs_map = {"schemas": PropertyMeta(name="anyOf", cast=create_inner_schemas)}
294+
attrs_map = {
295+
"schemas": PropertyMeta(name="anyOf", cast=create_inner_schemas),
296+
"discriminator": PropertyMeta(
297+
name="discriminator",
298+
cast=build_discriminator,
299+
),
300+
}
293301

294302
if "type" in data:
295303
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
@@ -161,7 +161,7 @@ class Discriminator:
161161
"""Polymorphism discriminator."""
162162

163163
property_name: str
164-
mapping: dict[str, Any] | None = field(default_factory=dict)
164+
mapping: dict[str, str] | None = field(default_factory=dict)
165165

166166

167167
@dataclass
@@ -177,6 +177,7 @@ class AnyOf(Schema):
177177
"""AnyOf composition schema."""
178178

179179
schemas: list[Schema] = field(default_factory=list)
180+
discriminator: Discriminator | None = None
180181

181182

182183
@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
@@ -304,3 +304,13 @@ components:
304304
format: uri
305305
example: 'https://github.com/manchenkoff/openapi3-parser'
306306
description: 'User Avatar URL'
307+
308+
Payload:
309+
oneOf:
310+
- type: string
311+
- type: integer
312+
discriminator:
313+
propertyName: payloadType
314+
mapping:
315+
str: 'SomeTarget'
316+
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)