Skip to content

Commit 57cc70a

Browse files
authored
Merge pull request #169 from p1c2u/feature/operations-more-fields
Operations fields
2 parents 4c4636a + c4d4ed8 commit 57cc70a

File tree

13 files changed

+155
-7
lines changed

13 files changed

+155
-7
lines changed

openapi_core/schema/external_docs/__init__.py

Whitespace-only changes.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"""OpenAPI core external docs factories module"""
2+
from openapi_core.schema.external_docs.models import ExternalDocumentation
3+
4+
5+
class ExternalDocumentationFactory(object):
6+
7+
def __init__(self, dereferencer):
8+
self.dereferencer = dereferencer
9+
10+
def create(self, external_doc_spec):
11+
url = external_doc_spec['url']
12+
description = external_doc_spec.get('description')
13+
14+
return ExternalDocumentation(url, description=description)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""OpenAPI core external docs models module"""
2+
3+
4+
class ExternalDocumentation(object):
5+
"""Represents an OpenAPI External Documentation."""
6+
7+
def __init__(self, url, description=None):
8+
self.url = url
9+
self.description = description

openapi_core/schema/operations/generators.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@
44
from openapi_spec_validator.validators import PathItemValidator
55

66
from openapi_core.compat import lru_cache
7+
from openapi_core.schema.external_docs.factories import (
8+
ExternalDocumentationFactory,
9+
)
710
from openapi_core.schema.operations.models import Operation
811
from openapi_core.schema.parameters.generators import ParametersGenerator
912
from openapi_core.schema.request_bodies.factories import RequestBodyFactory
1013
from openapi_core.schema.responses.generators import ResponsesGenerator
14+
from openapi_core.schema.security.factories import SecurityRequirementFactory
15+
from openapi_core.schema.servers.generators import ServersGenerator
1116

1217

1318
class OperationsGenerator(object):
@@ -32,6 +37,24 @@ def generate(self, path_name, path):
3237
parameters_list)
3338
operation_id = operation_deref.get('operationId')
3439
tags_list = operation_deref.get('tags', [])
40+
summary = operation_deref.get('summary')
41+
description = operation_deref.get('description')
42+
security_requirements_list = operation_deref.get('security', [])
43+
servers_spec = operation_deref.get('servers', [])
44+
45+
servers = self.servers_generator.generate(servers_spec)
46+
47+
security = None
48+
if security_requirements_list:
49+
security = list(map(
50+
self.security_requirement_factory.create,
51+
security_requirements_list))
52+
53+
external_docs = None
54+
if 'externalDocs' in operation_deref:
55+
external_docs_spec = operation_deref.get('externalDocs')
56+
external_docs = self.external_docs_factory.create(
57+
external_docs_spec)
3558

3659
request_body = None
3760
if 'requestBody' in operation_deref:
@@ -43,8 +66,11 @@ def generate(self, path_name, path):
4366
http_method,
4467
Operation(
4568
http_method, path_name, responses, list(parameters),
69+
summary=summary, description=description,
70+
external_docs=external_docs, security=security,
4671
request_body=request_body, deprecated=deprecated,
47-
operation_id=operation_id, tags=list(tags_list)
72+
operation_id=operation_id, tags=list(tags_list),
73+
servers=servers,
4874
),
4975
)
5076

@@ -58,7 +84,22 @@ def responses_generator(self):
5884
def parameters_generator(self):
5985
return ParametersGenerator(self.dereferencer, self.schemas_registry)
6086

87+
@property
88+
@lru_cache()
89+
def external_docs_factory(self):
90+
return ExternalDocumentationFactory(self.dereferencer)
91+
6192
@property
6293
@lru_cache()
6394
def request_body_factory(self):
6495
return RequestBodyFactory(self.dereferencer, self.schemas_registry)
96+
97+
@property
98+
@lru_cache()
99+
def security_requirement_factory(self):
100+
return SecurityRequirementFactory(self.dereferencer)
101+
102+
@property
103+
@lru_cache()
104+
def servers_generator(self):
105+
return ServersGenerator(self.dereferencer)

openapi_core/schema/operations/models.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,22 @@ class Operation(object):
88

99
def __init__(
1010
self, http_method, path_name, responses, parameters,
11-
request_body=None, deprecated=False, operation_id=None, tags=None):
11+
summary=None, description=None, external_docs=None, security=None,
12+
request_body=None, deprecated=False, operation_id=None, tags=None,
13+
servers=None):
1214
self.http_method = http_method
1315
self.path_name = path_name
1416
self.responses = dict(responses)
1517
self.parameters = dict(parameters)
18+
self.summary = summary
19+
self.description = description
20+
self.external_docs = external_docs
21+
self.security = security
1622
self.request_body = request_body
1723
self.deprecated = deprecated
1824
self.operation_id = operation_id
1925
self.tags = tags
26+
self.servers = servers
2027

2128
def __getitem__(self, name):
2229
return self.parameters[name]

openapi_core/schema/security/__init__.py

Whitespace-only changes.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
"""OpenAPI core security factories module"""
2+
from openapi_core.schema.security.models import SecurityRequirement
3+
4+
5+
class SecurityRequirementFactory(object):
6+
7+
def __init__(self, dereferencer):
8+
self.dereferencer = dereferencer
9+
10+
def create(self, security_requirement_spec):
11+
name = next(iter(security_requirement_spec))
12+
scope_names = security_requirement_spec[name]
13+
14+
return SecurityRequirement(name, scope_names=scope_names)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
"""OpenAPI core security models module"""
2+
3+
4+
class SecurityRequirement(object):
5+
"""Represents an OpenAPI Security Requirement."""
6+
7+
def __init__(self, name, scope_names=None):
8+
self.name = name
9+
self.scope_names = scope_names or []

openapi_core/schema/servers/generators.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,16 @@ def __init__(self, dereferencer):
1212

1313
def generate(self, servers_spec):
1414
servers_deref = self.dereferencer.dereference(servers_spec)
15-
if not servers_deref:
16-
yield Server('/')
17-
return
1815
for server_spec in servers_deref:
1916
url = server_spec['url']
2017
variables_spec = server_spec.get('variables', {})
18+
description = server_spec.get('description')
2119

2220
variables = None
2321
if variables_spec:
2422
variables = self.variables_generator.generate(variables_spec)
2523

26-
yield Server(url, variables=variables)
24+
yield Server(url, variables=variables, description=description)
2725

2826
@property
2927
@lru_cache()

openapi_core/schema/servers/models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
class Server(object):
66

7-
def __init__(self, url, variables=None):
7+
def __init__(self, url, variables=None, description=None):
88
self.url = url
99
self.variables = variables and dict(variables) or {}
10+
self.description = description
1011

1112
@property
1213
def default_url(self):

openapi_core/schema/specs/factories.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ def create(self, spec_dict, spec_url=''):
3030
paths = spec_dict_deref.get('paths', {})
3131
components_spec = spec_dict_deref.get('components', {})
3232

33+
if not servers_spec:
34+
servers_spec = [
35+
{'url': '/'},
36+
]
37+
3338
info = self.info_factory.create(info_spec)
3439
servers = self.servers_generator.generate(servers_spec)
3540
paths = self.paths_generator.generate(paths)

tests/integration/data/v3.0/petstore.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,19 @@ paths:
6262
$ref: "#/components/responses/PetsResponse"
6363
post:
6464
summary: Create a pet
65+
description: Creates new pet entry
66+
externalDocs:
67+
url: https://example.com
68+
description: Find more info here
69+
security:
70+
- petstore_auth:
71+
- write:pets
72+
- read:pets
73+
servers:
74+
- url: https://development.gigantic-server.com/v1
75+
description: Development server
76+
- url: https://staging.gigantic-server.com/v1
77+
description: Staging server
6578
operationId: createPets
6679
tags:
6780
- pets

tests/integration/schema/test_spec.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from openapi_core.schema.request_bodies.models import RequestBody
1010
from openapi_core.schema.responses.models import Response
1111
from openapi_core.schema.schemas.models import Schema
12+
from openapi_core.schema.security.models import SecurityRequirement
1213
from openapi_core.schema.servers.models import Server, ServerVariable
1314
from openapi_core.shortcuts import create_spec
1415
from openapi_core.validation.request.validators import RequestValidator
@@ -79,6 +80,42 @@ def test_spec(self, spec, spec_dict):
7980
assert operation.http_method == http_method
8081
assert operation.operation_id is not None
8182
assert operation.tags == operation_spec['tags']
83+
assert operation.summary == operation_spec.get('summary')
84+
assert operation.description == operation_spec.get(
85+
'description')
86+
87+
ext_docs_spec = operation_spec.get('externalDocs')
88+
if ext_docs_spec:
89+
ext_docs = operation.external_docs
90+
assert ext_docs.url == ext_docs_spec['url']
91+
assert ext_docs.description == ext_docs_spec.get(
92+
'description')
93+
94+
security_spec = operation_spec.get('security')
95+
if security_spec:
96+
for idx, sec_req in enumerate(operation.security):
97+
assert type(sec_req) == SecurityRequirement
98+
sec_req_spec = security_spec[idx]
99+
sec_req_nam = next(iter(sec_req_spec))
100+
assert sec_req.name == sec_req_nam
101+
assert sec_req.scope_names == sec_req_spec[sec_req_nam]
102+
103+
servers_spec = operation_spec.get('servers', [])
104+
for idx, server in enumerate(operation.servers):
105+
assert type(server) == Server
106+
107+
server_spec = servers_spec[idx]
108+
assert server.url == server_spec['url']
109+
assert server.default_url == server_spec['url']
110+
assert server.description == server_spec.get('description')
111+
112+
for variable_name, variable in iteritems(server.variables):
113+
assert type(variable) == ServerVariable
114+
assert variable.name == variable_name
115+
116+
variable_spec = server_spec['variables'][variable_name]
117+
assert variable.default == variable_spec['default']
118+
assert variable.enum == variable_spec.get('enum')
82119

83120
responses_spec = operation_spec.get('responses')
84121

0 commit comments

Comments
 (0)