From 75f82f93a33613e6e789f6a4f83092fafc244e00 Mon Sep 17 00:00:00 2001 From: SerenaFeng Date: Thu, 12 May 2016 11:25:06 +0800 Subject: [PATCH] support list property in tornado_swagger_ui list property will be declared in format '@ptype property4: C{list} of L{PropertySubclass}' JIRA: FUNCTEST-248 Change-Id: I3ee31389f1eab39cc9f621cbab006f0a8764c8ca Signed-off-by: SerenaFeng --- .../tornado_swagger_ui/README.md | 52 ++++++++++++++-- .../tornado_swagger_ui/example/basic.py | 16 ++--- .../tornado_swagger_ui/tornado_swagger/swagger.py | 71 ++++++++++++++++++---- 3 files changed, 116 insertions(+), 23 deletions(-) diff --git a/utils/test/result_collection_api/tornado_swagger_ui/README.md b/utils/test/result_collection_api/tornado_swagger_ui/README.md index 1ae383461..707eec0a7 100644 --- a/utils/test/result_collection_api/tornado_swagger_ui/README.md +++ b/utils/test/result_collection_api/tornado_swagger_ui/README.md @@ -28,9 +28,9 @@ class ItemNoParamHandler(GenericApiHandler): @swagger.operation(nickname='create') def post(self): """ - @param body: create test results for a pod. + @param body: create test results for a item. @type body: L{Item} - @return 200: pod is created. + @return 200: item is created. @raise 400: invalid input """ @@ -49,9 +49,9 @@ class ItemNoParamHandler(GenericApiHandler): def make_app(): return swagger.Application([ - (r"/pods", ItemNoParamHandler), - (r"/pods/([^/]+)", ItemHandler), - (r"/projects/([^/]+)/cases/([^/]+)", ItemOptionParamHandler), + (r"/items", ItemNoParamHandler), + (r"/items/([^/]+)", ItemHandler), + (r"/items/([^/]+)/cases/([^/]+)", ItemOptionParamHandler), ]) # You define models like this: @@ -157,6 +157,48 @@ class Item: ] } } + +# if you want to declare an list property, you can do it like this: +class Item: + """ + @ptype property3: L{PropertySubclass} + @ptype property4: C{list} of L{PropertySubclass} + """ + def __init__(self, property1, property2, property3, property4=None): + self.property1 = property1 + self.property2 = property2 + self.property3 = property3 + self.property4 = property4 + +# Swagger json: + "models": { + "Item": { + "description": "A description...", + "id": "Item", + "required": [ + "property1", + ], + "properties": [ + "property1": { + "type": "string" + }, + "property2": { + "type": "string" + }, + "property3": { + "type": "PropertySubclass" + "default": null + }, + "property4": { + "default": null, + "items": { + "type": "PropertySubclass"}, + "type": "array" + } + } + ] + } + } ``` # Running and testing diff --git a/utils/test/result_collection_api/tornado_swagger_ui/example/basic.py b/utils/test/result_collection_api/tornado_swagger_ui/example/basic.py index ded99d55d..20ad9cba1 100644 --- a/utils/test/result_collection_api/tornado_swagger_ui/example/basic.py +++ b/utils/test/result_collection_api/tornado_swagger_ui/example/basic.py @@ -28,11 +28,13 @@ class Item: In this case we would have property1, name as required parameters and property3 as optional parameter. @property property3: Item description @ptype property3: L{PropertySubclass} + @ptype property4: C{list} of L{PropertySubclass} """ - def __init__(self, property1, property2=None, property3=None): + def __init__(self, property1, property2=None, property3=None, property4=None): self.property1 = property1 self.property2 = property2 self.property3 = property3 + self.property4 = property4 items = {} @@ -71,9 +73,9 @@ class ItemNoParamHandler(GenericApiHandler): @swagger.operation(nickname='create') def post(self): """ - @param body: create test results for a pod. + @param body: create a item. @type body: L{Item} - @return 200: pod is created. + @return 200: item is created. @raise 400: invalid input """ property1 = self.json_args.get('property1') @@ -99,9 +101,9 @@ class ItemHandler(GenericApiHandler): def get(self, arg): """ @rtype: L{Item} - @description: get pod's test results + @description: get information of a item @notes: - get a pod test results, + get a item, This will be added to the Implementation Notes.It lets you put very long text in your api. """ @@ -110,9 +112,9 @@ class ItemHandler(GenericApiHandler): @swagger.operation(nickname='delete') def delete(self, arg): """ - @description: delete pod by pod_id + @description: delete a item @notes: - delete test results of a pod + delete a item in items This will be added to the Implementation Notes.It lets you put very long text in your api. """ diff --git a/utils/test/result_collection_api/tornado_swagger_ui/tornado_swagger/swagger.py b/utils/test/result_collection_api/tornado_swagger_ui/tornado_swagger/swagger.py index 2d688a80a..0939b0d68 100644 --- a/utils/test/result_collection_api/tornado_swagger_ui/tornado_swagger/swagger.py +++ b/utils/test/result_collection_api/tornado_swagger_ui/tornado_swagger/swagger.py @@ -4,6 +4,7 @@ import inspect from functools import wraps import epydoc.markup +from HTMLParser import HTMLParser import tornado.web from settings import default_settings, models from handlers import swagger_handlers @@ -11,6 +12,30 @@ from handlers import swagger_handlers __author__ = 'serena' +class EpytextParser(HTMLParser): + a_text = False + + def __init__(self, tag): + HTMLParser.__init__(self) + self.tag = tag + self.data = None + + def handle_starttag(self, tag, attr): + if tag == self.tag: + self.a_text = True + + def handle_endtag(self, tag): + if tag == self.tag: + self.a_text = False + + def handle_data(self, data): + if self.a_text: + self.data = data + + def get_data(self): + return self.data + + class DocParser(object): def __init__(self): self.notes = None @@ -31,7 +56,7 @@ class DocParser(object): for field in fields: tag = field.tag() arg = field.arg() - body = field.body().to_plaintext(None).strip() + body = field.body() self._get_parser(tag)(arg=arg, body=body) return doc @@ -51,7 +76,7 @@ class DocParser(object): def _parse_param(self, **kwargs): arg = kwargs.get('arg', None) - body = kwargs.get('body', None) + body = self._get_body(**kwargs) self.params.setdefault(arg, {}).update({ 'name': arg, 'description': body, @@ -65,14 +90,14 @@ class DocParser(object): def _parse_type(self, **kwargs): arg = kwargs.get('arg', None) - body = kwargs.get('body', None) + body = self._get_body(**kwargs) self.params.setdefault(arg, {}).update({ 'name': arg, 'dataType': body }) def _parse_rtype(self, **kwargs): - body = kwargs.get('body', None) + body = self._get_body(**kwargs) self.responseClass = body def _parse_property(self, **kwargs): @@ -83,25 +108,32 @@ class DocParser(object): def _parse_ptype(self, **kwargs): arg = kwargs.get('arg', None) - body = kwargs.get('body', None) - self.properties.setdefault(arg, {}).update({ - 'type': body - }) + code = self._parse_epytext_para('code', **kwargs) + link = self._parse_epytext_para('link', **kwargs) + if code is None: + self.properties.setdefault(arg, {}).update({ + 'type': link + }) + elif code == 'list': + self.properties.setdefault(arg, {}).update({ + 'type': 'array', + 'items': {'type': link} + }) def _parse_return(self, **kwargs): arg = kwargs.get('arg', None) - body = kwargs.get('body', None) + body = self._get_body(**kwargs) self.responseMessages.append({ 'code': arg, 'message': body }) def _parse_notes(self, **kwargs): - body = kwargs.get('body', '') + body = self._get_body(**kwargs) self.notes = self._sanitize_doc(body) def _parse_description(self, **kwargs): - body = kwargs.get('body', '') + body = self._get_body(**kwargs) self.summary = self._sanitize_doc(body) def _not_supported(self, **kwargs): @@ -111,6 +143,23 @@ class DocParser(object): def _sanitize_doc(comment): return comment.replace('\n', '
') if comment else comment + @staticmethod + def _get_body(**kwargs): + body = kwargs.get('body', None) + return body.to_plaintext(None).strip() if body else body + + @staticmethod + def _parse_epytext_para(tag, **kwargs): + def _parse_epytext(tag, body): + epytextParser = EpytextParser(tag) + epytextParser.feed(str(body)) + data = epytextParser.get_data() + epytextParser.close() + return data + + body = kwargs.get('body', None) + return _parse_epytext(tag, body) if body else body + class model(DocParser): def __init__(self, cls=None, *args, **kwargs): -- 2.16.6