2 # -*- coding: utf-8 -*-
5 from functools import wraps
7 from HTMLParser import HTMLParser
9 from settings import default_settings, models
10 from handlers import swagger_handlers
15 class EpytextParser(HTMLParser):
18 def __init__(self, tag):
19 HTMLParser.__init__(self)
23 def handle_starttag(self, tag, attr):
27 def handle_endtag(self, tag):
31 def handle_data(self, data):
39 class DocParser(object):
43 self.responseClass = None
44 self.responseMessages = []
48 def parse_docstring(self, text):
53 doc = epydoc.markup.parse(text, markup='epytext', errors=errors)
54 _, fields = doc.split_fields(errors)
60 self._get_parser(tag)(arg=arg, body=body)
63 def _get_parser(self, tag):
65 'param': self._parse_param,
66 'type': self._parse_type,
67 'rtype': self._parse_rtype,
68 'property': self._parse_property,
69 'ptype': self._parse_ptype,
70 'return': self._parse_return,
71 'raise': self._parse_return,
72 'notes': self._parse_notes,
73 'description': self._parse_description,
75 return parser.get(tag, self._not_supported)
77 def _parse_param(self, **kwargs):
78 arg = kwargs.get('arg', None)
79 body = self._get_body(**kwargs)
80 self.params.setdefault(arg, {}).update({
85 'allowMultiple': False
88 if 'paramType' not in self.params[arg]:
89 self.params[arg]['paramType'] = 'query'
91 def _parse_type(self, **kwargs):
92 arg = kwargs.get('arg', None)
93 body = self._get_body(**kwargs)
94 self.params.setdefault(arg, {}).update({
99 def _parse_rtype(self, **kwargs):
100 body = self._get_body(**kwargs)
101 self.responseClass = body
103 def _parse_property(self, **kwargs):
104 arg = kwargs.get('arg', None)
105 self.properties.setdefault(arg, {}).update({
109 def _parse_ptype(self, **kwargs):
110 arg = kwargs.get('arg', None)
111 code = self._parse_epytext_para('code', **kwargs)
112 link = self._parse_epytext_para('link', **kwargs)
114 self.properties.setdefault(arg, {}).update({
118 self.properties.setdefault(arg, {}).update({
120 'items': {'type': link}
123 def _parse_return(self, **kwargs):
124 arg = kwargs.get('arg', None)
125 body = self._get_body(**kwargs)
126 self.responseMessages.append({
131 def _parse_notes(self, **kwargs):
132 body = self._get_body(**kwargs)
133 self.notes = self._sanitize_doc(body)
135 def _parse_description(self, **kwargs):
136 body = self._get_body(**kwargs)
137 self.summary = self._sanitize_doc(body)
139 def _not_supported(self, **kwargs):
143 def _sanitize_doc(comment):
144 return comment.replace('\n', '<br/>') if comment else comment
147 def _get_body(**kwargs):
148 body = kwargs.get('body', None)
149 return body.to_plaintext(None).strip() if body else body
152 def _parse_epytext_para(tag, **kwargs):
153 def _parse_epytext(tag, body):
154 epytextParser = EpytextParser(tag)
155 epytextParser.feed(str(body))
156 data = epytextParser.get_data()
157 epytextParser.close()
160 body = kwargs.get('body', None)
161 return _parse_epytext(tag, body) if body else body
164 class model(DocParser):
165 def __init__(self, cls=None, *args, **kwargs):
166 super(model, self).__init__()
167 self.id = cls.__name__
172 if '__init__' in dir(cls):
173 self._parse_args(cls.__init__)
174 self.parse_docstring(inspect.getdoc(cls))
177 def _parse_args(self, func):
178 argspec = inspect.getargspec(func)
179 argspec.args.remove("self")
182 defaults = list(zip(argspec.args[-len(argspec.defaults):], argspec.defaults))
183 required_args_count = len(argspec.args) - len(defaults)
184 for arg in argspec.args[:required_args_count]:
185 self.required.append(arg)
186 self.properties.setdefault(arg, {'type': 'string'})
187 for arg, default in defaults:
188 self.properties.setdefault(arg, {'type': 'string', "default": default})
192 class operation(DocParser):
193 def __init__(self, nickname=None, **kwds):
194 super(operation, self).__init__()
195 self.nickname = nickname
200 def __call__(self, *args, **kwds):
202 return self.func(*args, **kwds)
205 self._parse_operation(func)
208 def __wrapper__(*in_args, **in_kwds):
209 return self.func(*in_args, **in_kwds)
211 __wrapper__.rest_api = self
214 def _parse_operation(self, func):
217 self.__name__ = func.__name__
218 self._parse_args(func)
219 self.parse_docstring(inspect.getdoc(self.func))
221 def _parse_args(self, func):
222 argspec = inspect.getargspec(func)
223 argspec.args.remove("self")
227 defaults = argspec.args[-len(argspec.defaults):]
229 for arg in argspec.args:
234 self.params.setdefault(arg, {
236 'required': required,
240 self.func_args = argspec.args
244 default_settings.update(opts)
247 class Application(tornado.web.Application):
248 def __init__(self, handlers=None, default_host="", transforms=None, **settings):
249 super(Application, self).__init__(swagger_handlers() + handlers, default_host, transforms, **settings)