Skip to content

Commit 327cc21

Browse files
committed
添加单元测试 添加静态目录
1 parent 8aef901 commit 327cc21

File tree

6 files changed

+326
-125
lines changed

6 files changed

+326
-125
lines changed

api.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ definitions:
7070
type: string
7171
User:
7272
properties:
73+
id:
74+
type: string
7375
nickname:
7476
type: string
7577
avatar:
Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,32 @@
11
# -*- coding: utf-8 -*-
22
from __future__ import absolute_import, print_function
33

4-
from six import with_metaclass
5-
import six
6-
import falcon
4+
import inspect
75

8-
from ..validators import request_validate, response_filter
6+
from sanic.views import HTTPMethodView
97

10-
import inspect
8+
from ..validators import request_validate, response_filter
119

1210
before_decorators = [request_validate]
1311
after_decorators = [response_filter]
1412

15-
16-
if six.PY3:
17-
ismethod = inspect.isfunction
18-
else:
19-
ismethod = inspect.ismethod
13+
methods = ['get', 'put', 'post', 'delete']
2014

2115

2216
def add_before_decorators(model_class):
23-
for name, m in inspect.getmembers(model_class, ismethod):
24-
if name in ['on_get', 'on_post', 'on_put', 'on_delete']:
25-
setattr(model_class, name, falcon.before(*before_decorators)(m))
17+
for name, m in inspect.getmembers(model_class, inspect.isfunction):
18+
if name in methods:
19+
for dec in before_decorators:
20+
m = dec(m)
21+
setattr(model_class, name, m)
2622

2723

2824
def add_after_decorators(model_class):
29-
for name, m in inspect.getmembers(model_class, ismethod):
30-
if name in ['on_get', 'on_post', 'on_put', 'on_delete']:
31-
setattr(model_class, name, falcon.after(*after_decorators)(m))
25+
for name, m in inspect.getmembers(model_class, inspect.isfunction):
26+
if name in methods:
27+
for dec in after_decorators:
28+
m = dec(m)
29+
setattr(model_class, name, m)
3230

3331

3432
class APIMetaclass(type):
@@ -40,6 +38,8 @@ class APIMetaclass(type):
4038
add_before_decorators(cls)
4139
add_after_decorators(cls)
4240

43-
class Resource(with_metaclass(APIMetaclass, object)):
4441

45-
pass
42+
class Resource(HTTPMethodView, metaclass=APIMetaclass):
43+
44+
45+
pass
Lines changed: 110 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,57 @@
11
# -*- coding: utf-8 -*-
22

3-
{% include '_do_not_change.tpl' %}
3+
###
4+
### DO NOT CHANGE THIS FILE
5+
###
6+
### The code is auto generated, your change will be overwritten by
7+
### code generating.
8+
###
49
from __future__ import absolute_import, print_function
510

11+
import re
612
import json
713
from datetime import date
814
from functools import wraps
915

1016
import six
11-
import falcon
17+
from sanic import response
18+
from sanic.exceptions import ServerError
19+
from sanic.response import HTTPResponse
1220

1321
from werkzeug.datastructures import MultiDict, Headers
22+
from sanic.request import RequestParameters
1423
from jsonschema import Draft4Validator
1524

1625
from .schemas import (
1726
validators, filters, scopes, security, base_path, normalize)
1827

1928

20-
if six.PY3:
21-
def _remove_characters(text, deletechars):
22-
return text.translate({ord(x): None for x in deletechars})
23-
else:
24-
def _remove_characters(text, deletechars):
25-
return text.translate(None, deletechars)
29+
def unpack(value):
30+
"""Return a three tuple of data, code, and headers"""
31+
if not isinstance(value, tuple):
32+
return value, 200, {}
33+
34+
try:
35+
data, code, headers = value
36+
return data, code, headers
37+
except ValueError:
38+
pass
39+
40+
try:
41+
data, code = value
42+
return data, code, {}
43+
except ValueError:
44+
pass
45+
46+
return value, 200, {}
47+
48+
49+
def _remove_characters(text, deletechars):
50+
return text.translate({ord(x): None for x in deletechars})
2651

2752

2853
def _path_to_endpoint(path):
29-
endpoint = path.strip('/').replace('/', '_').replace('-', '_')
54+
endpoint = '_'.join(filter(None, re.sub(r'(/|<|>|-)', r'_', path).split('_')))
3055
_base_path = base_path.strip('/').replace('/', '_').replace('-', '_')
3156
if endpoint.startswith(_base_path):
3257
endpoint = endpoint[len(_base_path)+1:]
@@ -41,7 +66,7 @@ class JSONEncoder(json.JSONEncoder):
4166
return json.JSONEncoder.default(self, o)
4267

4368

44-
class FalconValidatorAdaptor(object):
69+
class SanicValidatorAdaptor(object):
4570

4671
def __init__(self, schema):
4772
self.validator = Draft4Validator(schema)
@@ -55,10 +80,10 @@ class FalconValidatorAdaptor(object):
5580
def type_convert(self, obj):
5681
if obj is None:
5782
return None
58-
if isinstance(obj, (dict, list)) and not isinstance(obj, MultiDict):
83+
if isinstance(obj, (dict, list)) and not isinstance(obj, RequestParameters):
5984
return obj
6085
if isinstance(obj, Headers):
61-
obj = MultiDict(six.iteritems(obj))
86+
obj = MultiDict(obj.items())
6287
result = dict()
6388

6489
convert_funs = {
@@ -73,7 +98,7 @@ class FalconValidatorAdaptor(object):
7398
func = convert_funs.get(type_, lambda v: v[0])
7499
return [func([i]) for i in v]
75100

76-
for k, values in obj.lists():
101+
for k, values in obj.items():
77102
prop = self.validator.schema['properties'].get(k, {})
78103
type_ = prop.get('type')
79104
fun = convert_funs.get(type_, lambda v: v[0])
@@ -86,83 +111,82 @@ class FalconValidatorAdaptor(object):
86111

87112
def validate(self, value):
88113
value = self.type_convert(value)
89-
errors = {e.path[0]: e.message for e in self.validator.iter_errors(value)}
114+
errors = list(e.message for e in self.validator.iter_errors(value))
90115
return normalize(self.validator.schema, value)[0], errors
91116

92117

93-
def request_validate(req, resp, resource, params):
94-
95-
endpoint = _path_to_endpoint(req.uri_template)
96-
# scope
97-
if (endpoint, req.method) in scopes and not set(
98-
scopes[(endpoint, req.method)]).issubset(set(security.scopes)):
99-
falcon.HTTPUnauthorized('403403403')
100-
# data
101-
method = req.method
102-
if method == 'HEAD':
103-
method = 'GET'
104-
locations = validators.get((endpoint, method), {})
105-
context = {}
106-
for location, schema in six.iteritems(locations):
107-
value = getattr(req, location, MultiDict())
108-
if location == 'headers':
109-
value = {k.capitalize(): v for k, v in value.items()}
110-
elif location == 'json':
111-
body = req.stream.read()
112-
113-
try:
114-
value = json.loads(body.decode('utf-8'))
115-
except (ValueError, UnicodeDecodeError):
116-
raise falcon.HTTPError(falcon.HTTP_753,
117-
'Malformed JSON',
118-
'Could not decode the request body. The '
119-
'JSON was incorrect or not encoded as '
120-
'UTF-8.')
121-
if value is None:
122-
value = MultiDict()
123-
validator = FalconValidatorAdaptor(schema)
124-
result, errors = validator.validate(value)
125-
if errors:
126-
raise falcon.HTTPUnprocessableEntity('Unprocessable Entity', description=errors)
127-
context[location] = result
128-
req.context = context
129-
118+
def request_validate(view):
119+
120+
@wraps(view)
121+
def wrapper(*args, **kwargs):
122+
request = args[1]
123+
endpoint = _path_to_endpoint(request.uri_template)
124+
# scope
125+
if (endpoint, request.method) in scopes and not set(
126+
scopes[(endpoint, request.method)]).issubset(set(security.scopes)):
127+
raise ServerError('403', status_code=403)
128+
# data
129+
method = request.method
130+
if method == 'HEAD':
131+
method = 'GET'
132+
locations = validators.get((endpoint, method), {})
133+
for location, schema in locations.items():
134+
value = getattr(request, location, MultiDict())
135+
if value is None:
136+
value = MultiDict()
137+
validator = SanicValidatorAdaptor(schema)
138+
result, errors = validator.validate(value)
139+
if errors:
140+
raise ServerError('Unprocessable Entity', status_code=422)
141+
request[location] = result
142+
return view(*args, **kwargs)
143+
144+
return wrapper
145+
146+
147+
def response_filter(view):
148+
149+
@wraps(view)
150+
def wrapper(*args, **kwargs):
151+
request = args[1]
152+
resp = view(*args, **kwargs)
153+
154+
if isinstance(resp, HTTPResponse):
155+
return resp
156+
157+
endpoint = _path_to_endpoint(request.uri_template)
158+
method = request.method
159+
if method == 'HEAD':
160+
method = 'GET'
161+
filter = filters.get((endpoint, method), None)
162+
if not filter:
163+
return resp
164+
165+
headers = None
166+
status = None
167+
if isinstance(resp, tuple):
168+
resp, status, headers = unpack(resp)
169+
170+
if len(filter) == 1:
171+
status = list(filter.keys())[0]
130172

131-
def response_filter(req, resp, resource):
173+
schemas = filter.get(status)
174+
if not schemas:
175+
# return resp, status, headers
176+
raise ServerError('`%d` is not a defined status code.' % status, 500)
132177

133-
endpoint = _path_to_endpoint(req.uri_template)
134-
method = req.method
135-
if method == 'HEAD':
136-
method = 'GET'
137-
filter = filters.get((endpoint, method), None)
138-
if not filter:
139-
return resp
178+
resp, errors = normalize(schemas['schema'], resp)
179+
if schemas['headers']:
180+
headers, header_errors = normalize(
181+
{'properties': schemas['headers']}, headers)
182+
errors.extend(header_errors)
183+
if errors:
184+
raise ServerError('Expectation Failed', 500)
140185

141-
headers = None
142-
status = None
186+
return response.json(
187+
resp,
188+
status=status,
189+
headers=headers,
190+
)
143191

144-
if len(filter) == 1:
145-
if six.PY3:
146-
status = list(filter.keys())[0]
147-
else:
148-
status = filter.keys()[0]
149-
150-
schemas = filter.get(status)
151-
if not schemas:
152-
# return resp, status, headers
153-
raise falcon.HTTPInternalServerError(
154-
'Not defined',
155-
description='`%d` is not a defined status code.' % status)
156-
157-
_resp, errors = normalize(schemas['schema'], req.context['result'])
158-
if schemas['headers']:
159-
headers, header_errors = normalize(
160-
{'properties': schemas['headers']}, headers)
161-
errors.extend(header_errors)
162-
if errors:
163-
raise falcon.HTTPInternalServerError(title='Expectation Failed',
164-
description=errors)
165-
166-
if 'result' not in req.context:
167-
return
168-
resp.body = json.dumps(_resp)
192+
return wrapper

swagger_py_codegen/templates/sanic/app.tpl

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,28 @@ import {{ blueprint }}
88

99
def create_app():
1010
app = Sanic(__name__)
11-
app.register_blueprint(
12-
{{ blueprint }}.bp,
13-
url_prefix='{{ base_path }}')
11+
app.static('/static', './static')
12+
app.blueprint({{ blueprint }}.bp)
1413
return app
1514

1615

1716
app = create_app()
1817

18+
@app.exception(NotFound)
19+
def not_found(request, exception):
20+
return json({'error_code': 'not_found',
21+
'message': exception.args[0]},
22+
status=exception.status_code,
23+
)
24+
25+
26+
@app.exception(InvalidUsage)
27+
def method_not_allow(request, exception):
28+
return json({'error_code': 'method_not_allow',
29+
'message': exception.args[0]},
30+
status=exception.status_code,
31+
)
32+
1933

2034
if __name__ == '__main__':
2135
app.run(host="0.0.0.0", port=8000)

0 commit comments

Comments
 (0)