10000 Merge pull request #142 from marksmayo/develop · codders/flask-api@28cc484 · GitHub
[go: up one dir, main page]

Skip to content

Commit 28cc484

Browse files
authored
Merge pull request flask-api#142 from marksmayo/develop
python 3 updates, black/isort tidyups
2 parents 921f856 + 85326df commit 28cc484

25 files changed

+576
-485
lines changed

example.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
from flask import request, url_for
2-
from flask.ext.api import FlaskAPI, status, exceptions
2+
from flask.ext.api import FlaskAPI, exceptions, status
33

44
app = FlaskAPI(__name__)
55

66

77
notes = {
8-
0: 'do the shopping',
9-
1: 'build the codez',
10-
2: 'paint the door',
8+
0: "do the shopping",
9+
1: "build the codez",
10+
2: "paint the door",
1111
}
1212

13+
1314
def note_repr(key):
1415
return {
15-
'url': request.host_url.rstrip('/') + url_for('notes_detail', key=key),
16-
'text': notes[key]
16+
"url": request.host_url.rstrip("/") + url_for("notes_detail", key=key),
17+
"text": notes[key],
1718
}
1819

1920

20-
@app.route("/", methods=['GET', 'POST'])
21+
@app.route("/", methods=["GET", "POST"])
2122
def notes_list():
2223
"""
2324
List or create notes.
2425
"""
25-
if request.method == 'POST':
26-
note = str(request.data.get('text', ''))
26+
if request.method == "POST":
27+
note = str(request.data.get("text", ""))
2728
idx = max(notes.keys()) + 1
2829
notes[idx] = note
2930
return note_repr(idx), status.HTTP_201_CREATED
@@ -32,19 +33,19 @@ def notes_list():
3233
return [note_repr(idx) for idx in sorted(notes.keys())]
3334

3435

35-
@app.route("/<int:key>/", methods=['GET', 'PUT', 'DELETE'])
36+
@app.route("/<int:key>/", methods=["GET", "PUT", "DELETE"])
3637
def notes_detail(key):
3738
"""
3839
Retrieve, update or delete note instances.
3940
"""
40-
if request.method == 'PUT':
41-
note = str(request.data.get('text', ''))
41+
if request.method == "PUT":
42+
note = str(request.data.get("text", ""))
4243
notes[key] = note
4344
return note_repr(key)
4445

45-
elif request.method == 'DELETE':
46+
elif request.method == "DELETE":
4647
notes.pop(key, None)
47-
return '', status.HTTP_204_NO_CONTENT
48+
return "", status.HTTP_204_NO_CONTENT
4849

4950
# request.method == 'GET'
5051
if key not in notes:

flask_api/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
from flask_api.app import FlaskAPI
22

3-
__version__ = '3.0.post1'
3+
__version__ = "3.0.post1"

flask_api/app.py

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,23 @@
1-
from flask import request, Flask, Blueprint
1+
import re
2+
import sys
3+
from itertools import chain
4+
5+
from flask import Blueprint, Flask, request
6+
from werkzeug.exceptions import HTTPException
7+
8+
from flask_api.compat import is_flask_legacy
29
from flask_api.exceptions import APIException
310
from flask_api.request import APIRequest
411
from flask_api.response import APIResponse
512
from flask_api.settings import APISettings
613
from flask_api.status import HTTP_204_NO_CONTENT
7-
from itertools import chain
8-
from werkzeug.exceptions import HTTPException
9-
import re
10-
import sys
11-
from flask_api.compat import is_flask_legacy
12-
1314

1415
api_resources = Blueprint(
15-
'flask-api', __name__,
16-
url_prefix='/flask-api',
17-
template_folder='templates', static_folder='static'
16+
"flask-api",
17+
__name__,
18+
url_prefix="/flask-api",
19+
template_folder="templates",
20+
static_folder="static",
1821
)
1922

2023

@@ -30,7 +33,7 @@ def __init__(self, *args, **kwargs):
3033
super().__init__(*args, **kwargs)
3134
self.api_settings = APISettings(self.config)
3235
self.register_blueprint(api_resources)
33-
self.jinja_env.filters['urlize_quoted_links'] = urlize_quoted_links
36+
self.jinja_env.filters["urlize_quoted_links"] = urlize_quoted_links
3437

3538
def preprocess_request(self):
3639
request.parser_classes = self.api_settings.DEFAULT_PARSERS
@@ -47,10 +50,10 @@ def make_response(self, rv):
4750
rv, status_or_headers, headers = rv + (None,) * (3 - len(rv))
4851

4952
if rv is None and status_or_headers == HTTP_204_NO_CONTENT:
50-
rv = ''
53+
rv = ""
5154

5255
if rv is None and status_or_headers:
53-
raise ValueError('View function did not return a response')
56+
raise ValueError("View function did not return a response")
5457

5558
if isinstance(status_or_headers, (dict, list)):
5659
headers, status_or_headers = status_or_headers, None
@@ -96,15 +99,16 @@ def handle_user_exception(self, e):
9699
if isinstance(e, typecheck):
97100
return handler(e)
98101
else:
99-
for typecheck, handler in chain(dict(blueprint_handlers).items(),
100-
dict(app_handlers).items()):
102+
for typecheck, handler in chain(
103+
dict(blueprint_handlers).items(), dict(app_handlers).items()
104+
):
101105
if isinstance(e, typecheck):
102106
return handler(e)
103107

104108
raise e
105109

106110
def handle_api_exception(self, exc):
107-
content = {'message': exc.detail}
111+
content = {"message": exc.detail}
108112
status = exc.status_code
109113
return self.response_class(content, status=status)
110114

@@ -117,13 +121,15 @@ def create_url_adapter(self, request):
117121
"""
118122
if request is not None:
119123
environ = request.environ.copy()
120-
environ['REQUEST_METHOD'] = request.method
121-
return self.url_map.bind_to_environ(environ,
122-
server_name=self.config['SERVER_NAME'])
124+
environ["REQUEST_METHOD"] = request.method
125+
return self.url_map.bind_to_environ(
126+
environ, server_name=self.config["SERVER_NAME"]
127+
)
123128
# We need at the very least the server name to be set for this
124129
# to work.
125-
if self.config['SERVER_NAME'] is not None:
130+
if self.config["SERVER_NAME"] is not None:
126131
return self.url_map.bind(
127-
self.config['SERVER_NAME'],
128-
script_name=self.config['APPLICATION_ROOT'] or '/',
129-
url_scheme=self.config['PREFERRED_URL_SCHEME'])
132+
self.config["SERVER_NAME"],
133+
script_name=self.config["APPLICATION_ROOT"] or "/",
134+
url_scheme=self.config["PREFERRED_URL_SCHEME"],
135+
)

flask_api/compat.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# -*- coding: utf-8 -*-
2-
from __future__ import unicode_literals, absolute_import
2+
from __future__ import absolute_import, unicode_literals
3+
34
from flask import __version__ as flask_version
45

56
# Markdown is optional
@@ -17,7 +18,6 @@ def apply_markdown(text):
1718
md = markdown.Markdown(extensions=extensions)
1819
return md.convert(text)
1920

20-
2121
except ImportError: # pragma: no cover - markdown installed for tests
2222
apply_markdown = None
2323

flask_api/decorators.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from functools import wraps
2+
23
from flask import request
34

45

@@ -11,7 +12,9 @@ def decorated_function(*args, **kwargs):
1112
else:
1213
request.parser_classes = parsers
1314
return func(*args, **kwargs)
15+
1416
return decorated_function
17+
1518
return decorator
1619

1720

@@ -24,5 +27,7 @@ def decorated_function(*args, **kwargs):
2427
else:
2528
request.renderer_classes = renderers
2629
return func(*args, **kwargs)
30+
2731
return decorated_function
32+
2833
return decorator

flask_api/exceptions.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from __future__ import unicode_literals
2+
23
from flask_api import status
34

45

56
class APIException(Exception):
67
status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
7-
detail = ''
8+
detail = ""
89

910
def __init__(self, detail=None):
1011
if detail is not None:
@@ -16,27 +17,28 @@ def __str__(self):
1617

1718
class ParseError(APIException):
1819
status_code = status.HTTP_400_BAD_REQUEST
19-
detail = 'Malformed request.'
20+
detail = "Malformed request."
2021

2122

2223
class AuthenticationFailed(APIException):
2324
status_code = status.HTTP_401_UNAUTHORIZED
24-
detail = 'Incorrect authentication credentials.'
25+
detail = "Incorrect authentication credentials."
2526

2627

2728
class NotAuthenticated(APIException):
2829
status_code = status.HTTP_401_UNAUTHORIZED
29-
detail = 'Authentication credentials were not provided.'
30+
detail = "Authentication credentials were not provided."
3031

3132

3233
class PermissionDenied(APIException):
3334
status_code = status.HTTP_403_FORBIDDEN
34-
detail = 'You do not have permission to perform this action.'
35+
detail = "You do not have permission to perform this action."
3536

3637

3738
class NotFound(APIException):
3839
status_code = status.HTTP_404_NOT_FOUND
39-
detail = 'This resource does not exist.'
40+
detail = "This resource does not exist."
41+
4042

4143
# class MethodNotAllowed(APIException):
4244
# status_code = status.HTTP_405_METHOD_NOT_ALLOWED
@@ -48,17 +50,18 @@ class NotFound(APIException):
4850

4951
class NotAcceptable(APIException):
5052
status_code = status.HTTP_406_NOT_ACCEPTABLE
51-
detail = 'Could not satisfy the request Accept header.'
53+
detail = "Could not satisfy the request Accept header."
5254

5355

5456
class UnsupportedMediaType(APIException):
5557
status_code = status.HTTP_415_UNSUPPORTED_MEDIA_TYPE
56-
detail = 'Unsupported media type in the request Content-Type header.'
58+
detail = "Unsupported media type in the request Content-Type header."
5759

5860

5961
class Throttled(APIException):
6062
status_code = status.HTTP_429_TOO_MANY_REQUESTS
61-
detail = 'Request was throttled.'
63+
detail = "Request was throttled."
64+
6265

6366
# def __init__(self, wait=None, detail=None):
6467
# if wait is None:

flask_api/mediatypes.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
from __future__ import unicode_literals
33

44

5-
class MediaType(object):
5+
class MediaType:
66
def __init__(self, media_type):
77
self.main_type, self.sub_type, self.params = self._parse(media_type)
88

99
@property
1010
def full_type(self):
11-
return self.main_type + '/' + self.sub_type
11+
return self.main_type + "/" + self.sub_type
1212

1313
@property
1414
def precedence(self):
@@ -20,11 +20,11 @@ def precedence(self):
2020
1. 'type/*'
2121
0. '*/*'
2222
"""
23-
if self.main_type == '*':
23+
if self.main_type == "*":
2424
return 0
25-
elif self.sub_type == '*':
25+
elif self.sub_type == "*":
2626
return 1
27-
elif not self.params or list(self.params.keys()) == ['q']:
27+
elif not self.params or list(self.params.keys()) == ["q"]:
2828
return 2
2929
return 3
3030

@@ -39,13 +39,21 @@ def satisfies(self, other):
3939
'*/*' >= 'text/plain'
4040
"""
4141
for key in self.params.keys():
42-
if key != 'q' and other.params.get(key, None) != self.params.get(key, None):
42+
if key != "q" and other.params.get(key, None) != self.params.get(key, None):
4343
return False
4444

45-
if self.sub_type != '*' and other.sub_type != '*' and other.sub_type != self.sub_type:
45+
if (
46+
self.sub_type != "*"
47+
and other.sub_type != "*"
48+
and other.sub_type != self.sub_type
49+
):
4650
return False
4751

48-
if self.main_type != '*' and other.main_type != '*' and other.main_type != self.main_type:
52+
if (
53+
self.main_type != "*"
54+
and other.main_type != "*"
55+
and other.main_type != self.main_type
56+
):
4957
return False
5058

5159
return True
@@ -55,15 +63,15 @@ def _parse(self, media_type):
5563
Parse a media type string, like "application/json; indent=4" into a
5664
three-tuple, like: ('application', 'json', {'indent': 4})
5765
"""
58-
full_type, sep, param_string = media_type.partition(';')
66+
full_type, sep, param_string = media_type.partition(";")
5967
params = {}
60-
for token in param_string.strip().split(','):
61-
key, sep, value = [s.strip() for s in token.partition('=')]
68+
for token in param_string.strip().split(","):
69+
key, sep, value = [s.strip() for s in token.partition("=")]
6270
if value.startswith('"') and value.endswith('"'):
6371
value = value[1:-1]
6472
if key:
6573
params[key] = value
66-
main_type, sep, sub_type = [s.strip() for s in full_type.partition('/')]
74+
main_type, sep, sub_type = [s.strip() for s in full_type.partition("/")]
6775
return (main_type, sub_type, params)
6876

6977
def __repr__(self):
@@ -75,21 +83,18 @@ def __str__(self):
7583
Note that this ensures the params are sorted.
7684
"""
7785
if self.params:
78-
params_str = ', '.join([
79-
'%s="%s"' % (key, val)
80-
for key, val in sorted(self.params.items())
81-
])
82-
return self.full_type + '; ' + params_str
86+
params_str = ", ".join(
87+
['%s="%s"' % (key, val) for key, val in sorted(self.params.items())]
88+
)
89+
return self.full_type + "; " + params_str
8390
return self.full_type
8491

8592
def __hash__(self):
8693
return hash(str(self))
8794

8895
def __eq__(self, other):
8996
# Compare two MediaType instances, ignoring parameter ordering.
90-
return (
91-
self.full_type == other.full_type and self.params == other.params
92-
)
97+
return self.full_type == other.full_type and self.params == other.params
9398

9499

95100
def parse_accept_header(accept):
@@ -105,7 +110,7 @@ def parse_accept_header(accept):
105110
]
106111
"""
107112
ret = [set(), set(), set(), set()]
108-
for token in accept.split(','):
113+
for token in accept.split(","):
109114
media_type = MediaType(token.strip())
110115
ret[3 - media_type.precedence].add(media_type)
111116
return [media_types for media_types in ret if media_types]

0 commit comments

Comments
 (0)
0