Skip to content
This repository has been archived by the owner on Mar 24, 2024. It is now read-only.

Commit

Permalink
Merge pull request #52 from lendingblock/master
Browse files Browse the repository at this point in the history
Mapping and private spec
  • Loading branch information
lsbardel authored Jul 17, 2018
2 parents 47fc88f + 1ad274b commit 27f93d4
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 9 deletions.
2 changes: 1 addition & 1 deletion openapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Minimal OpenAPI asynchronous server application
"""

__version__ = '0.4.0'
__version__ = '0.4.1'
37 changes: 30 additions & 7 deletions openapi/spec/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ def field2json(self, field):
enum = [e.name for e in field.type]
elif is_subclass(field.type, List):
return self._list2json(field.type)
elif is_subclass(field.type, Dict):
return self._map2json(field.type)
elif is_dataclass(field.type):
return self.get_schema_ref(field.type)
else:
Expand Down Expand Up @@ -136,6 +138,17 @@ def _list2json(self, field_type):
'items': self.field2json(field_type.__args__[0])
}

def _map2json(self, field_type):
args = field_type.__args__
spec = {
'type': 'object'
}
if args:
if len(args) != 2 or args[0] != str:
raise InvalidTypeException(field_type)
spec['additionalProperties'] = self.field2json(args[1])
return spec


class SchemaGroup:

Expand Down Expand Up @@ -176,7 +189,7 @@ def __init__(self, info, default_content_type=None,
def paths(self):
return self.doc['paths']

def build(self, app):
def build(self, app, public=True, private=False):
"""Build the ``doc`` dictionary by adding paths
"""
self.logger = app.logger
Expand All @@ -186,7 +199,7 @@ def build(self, app):
if security:
sk = security
self.doc['info']['security'] = list(sk)
self._build_paths(app)
self._build_paths(app, public, private)
self.schemas = SchemaGroup().parse(self.schemas_to_parse)
s = self.schemas
p = self.parameters
Expand All @@ -204,7 +217,7 @@ def build(self, app):
))
return self

def _build_paths(self, app):
def _build_paths(self, app, public, private):
"""Loop through app paths and add
schemas, parameters and paths objects to the spec
"""
Expand All @@ -214,10 +227,13 @@ def _build_paths(self, app):
route_info = route.get_info()
path = route_info.get('path', route_info.get('formatter', None))
handler = route.handler
if issubclass(handler, ApiPath) and not handler.private:
paths[path] = self._build_path_object(handler, app)
if (issubclass(handler, ApiPath) and
self._include(handler.private, public, private)):
paths[path] = self._build_path_object(
handler, app, public, private
)

def _build_path_object(self, handler, path_obj):
def _build_path_object(self, handler, path_obj, public, private):
path_obj = load_yaml_from_docstring(handler.__doc__) or {}
tags = self._extend_tags(path_obj.pop('tags', None))
if handler.path_schema:
Expand All @@ -236,7 +252,8 @@ def _build_path_object(self, handler, path_obj):
continue

method_doc = load_yaml_from_docstring(method_handler.__doc__) or {}
if method_doc.pop('private', False):
if not self._include(
method_doc.pop('private', False), public, private):
continue
mtags = tags.copy()
mtags.update(self._extend_tags(method_doc.pop('tags', None)))
Expand Down Expand Up @@ -316,6 +333,12 @@ def _extend_tags(self, tags):
names.add(name)
return names

def _include(self, is_private, public, private):
return (
(is_private and private) or
(not is_private and public)
)


async def spec_root(request):
"""Return the OpenApi spec
Expand Down
22 changes: 21 additions & 1 deletion tests/spec/test_schema_parser.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from unittest.mock import patch
from typing import List
from typing import List, Dict
from datetime import datetime
from dataclasses import dataclass, field
from enum import Enum
Expand Down Expand Up @@ -36,6 +36,8 @@ class MyClass:
int_field: int = data_field(format='uint64', description='test')
float_field: float
bool_field: bool
map_field: Dict[str, int]
free_field: Dict
datetime_field: datetime
ref_field: OtherClass = field(metadata={'required': True})
list_ref_field: List[OtherClass]
Expand All @@ -58,6 +60,14 @@ class MyClass:
'format': 'float'
}, 'bool_field': {
'type': 'boolean'
}, 'map_field': {
'type': 'object',
'additionalProperties': {
'type': 'integer',
'format': 'int32'
}
}, 'free_field': {
'type': 'object'
}, 'datetime_field': {
'type': 'string',
'format': 'date-time'
Expand Down Expand Up @@ -156,3 +166,13 @@ class MyClass:
'type': 'integer', 'format': 'int32',
'minimum': 0, 'maximum': 100
}


def test_non_string_keys():
@dataclass
class MyClass:
map_field: Dict[int, str]

parser = SchemaParser()
with pytest.raises(InvalidTypeException):
parser.schema2json(MyClass)

0 comments on commit 27f93d4

Please sign in to comment.