Skip to content

Commit 9b5234c

Browse files
Pooglesziirish
authored andcommitted
Partial: Remove encodings and future imports.
1 parent 38f44a6 commit 9b5234c

38 files changed

+964
-101
lines changed

flask_restplus/__about__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
__version__ = '0.13.1.dev'
2+
__description__ = 'Fully featured framework for fast, easy and documented API development with Flask'

flask_restplus/_http.py

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
"""
2+
This file is backported from Python 3.5 http built-in module.
3+
"""
4+
5+
from enum import IntEnum
6+
7+
8+
class HTTPStatus(IntEnum):
9+
"""HTTP status codes and reason phrases
10+
11+
Status codes from the following RFCs are all observed:
12+
13+
* RFC 7231: Hypertext Transfer Protocol (HTTP/1.1), obsoletes 2616
14+
* RFC 6585: Additional HTTP Status Codes
15+
* RFC 3229: Delta encoding in HTTP
16+
* RFC 4918: HTTP Extensions for WebDAV, obsoletes 2518
17+
* RFC 5842: Binding Extensions to WebDAV
18+
* RFC 7238: Permanent Redirect
19+
* RFC 2295: Transparent Content Negotiation in HTTP
20+
* RFC 2774: An HTTP Extension Framework
21+
"""
22+
def __new__(cls, value, phrase, description=''):
23+
obj = int.__new__(cls, value)
24+
obj._value_ = value
25+
26+
obj.phrase = phrase
27+
obj.description = description
28+
return obj
29+
30+
def __str__(self):
31+
return str(self.value)
32+
33+
# informational
34+
CONTINUE = 100, 'Continue', 'Request received, please continue'
35+
SWITCHING_PROTOCOLS = (101, 'Switching Protocols',
36+
'Switching to new protocol; obey Upgrade header')
37+
PROCESSING = 102, 'Processing'
38+
39+
# success
40+
OK = 200, 'OK', 'Request fulfilled, document follows'
41+
CREATED = 201, 'Created', 'Document created, URL follows'
42+
ACCEPTED = (202, 'Accepted',
43+
'Request accepted, processing continues off-line')
44+
NON_AUTHORITATIVE_INFORMATION = (203,
45+
'Non-Authoritative Information', 'Request fulfilled from cache')
46+
NO_CONTENT = 204, 'No Content', 'Request fulfilled, nothing follows'
47+
RESET_CONTENT = 205, 'Reset Content', 'Clear input form for further input'
48+
PARTIAL_CONTENT = 206, 'Partial Content', 'Partial content follows'
49+
MULTI_STATUS = 207, 'Multi-Status'
50+
ALREADY_REPORTED = 208, 'Already Reported'
51+
IM_USED = 226, 'IM Used'
52+
53+
# redirection
54+
MULTIPLE_CHOICES = (300, 'Multiple Choices',
55+
'Object has several resources -- see URI list')
56+
MOVED_PERMANENTLY = (301, 'Moved Permanently',
57+
'Object moved permanently -- see URI list')
58+
FOUND = 302, 'Found', 'Object moved temporarily -- see URI list'
59+
SEE_OTHER = 303, 'See Other', 'Object moved -- see Method and URL list'
60+
NOT_MODIFIED = (304, 'Not Modified',
61+
'Document has not changed since given time')
62+
USE_PROXY = (305, 'Use Proxy',
63+
'You must use proxy specified in Location to access this resource')
64+
TEMPORARY_REDIRECT = (307, 'Temporary Redirect',
65+
'Object moved temporarily -- see URI list')
66+
PERMANENT_REDIRECT = (308, 'Permanent Redirect',
67+
'Object moved temporarily -- see URI list')
68+
69+
# client error
70+
BAD_REQUEST = (400, 'Bad Request',
71+
'Bad request syntax or unsupported method')
72+
UNAUTHORIZED = (401, 'Unauthorized',
73+
'No permission -- see authorization schemes')
74+
PAYMENT_REQUIRED = (402, 'Payment Required',
75+
'No payment -- see charging schemes')
76+
FORBIDDEN = (403, 'Forbidden',
77+
'Request forbidden -- authorization will not help')
78+
NOT_FOUND = (404, 'Not Found',
79+
'Nothing matches the given URI')
80+
METHOD_NOT_ALLOWED = (405, 'Method Not Allowed',
81+
'Specified method is invalid for this resource')
82+
NOT_ACCEPTABLE = (406, 'Not Acceptable',
83+
'URI not available in preferred format')
84+
PROXY_AUTHENTICATION_REQUIRED = (407,
85+
'Proxy Authentication Required',
86+
'You must authenticate with this proxy before proceeding')
87+
REQUEST_TIMEOUT = (408, 'Request Timeout',
88+
'Request timed out; try again later')
89+
CONFLICT = 409, 'Conflict', 'Request conflict'
90+
GONE = (410, 'Gone',
91+
'URI no longer exists and has been permanently removed')
92+
LENGTH_REQUIRED = (411, 'Length Required',
93+
'Client must specify Content-Length')
94+
PRECONDITION_FAILED = (412, 'Precondition Failed',
95+
'Precondition in headers is false')
96+
REQUEST_ENTITY_TOO_LARGE = (413, 'Request Entity Too Large',
97+
'Entity is too large')
98+
REQUEST_URI_TOO_LONG = (414, 'Request-URI Too Long',
99+
'URI is too long')
100+
UNSUPPORTED_MEDIA_TYPE = (415, 'Unsupported Media Type',
101+
'Entity body in unsupported format')
102+
REQUESTED_RANGE_NOT_SATISFIABLE = (416,
103+
'Requested Range Not Satisfiable',
104+
'Cannot satisfy request range')
105+
EXPECTATION_FAILED = (417, 'Expectation Failed',
106+
'Expect condition could not be satisfied')
107+
UNPROCESSABLE_ENTITY = 422, 'Unprocessable Entity'
108+
LOCKED = 423, 'Locked'
109+
FAILED_DEPENDENCY = 424, 'Failed Dependency'
110+
UPGRADE_REQUIRED = 426, 'Upgrade Required'
111+
PRECONDITION_REQUIRED = (428, 'Precondition Required',
112+
'The origin server requires the request to be conditional')
113+
TOO_MANY_REQUESTS = (429, 'Too Many Requests',
114+
'The user has sent too many requests in '
115+
'a given amount of time ("rate limiting")')
116+
REQUEST_HEADER_FIELDS_TOO_LARGE = (431,
117+
'Request Header Fields Too Large',
118+
'The server is unwilling to process the request because its header '
119+
'fields are too large')
120+
121+
# server errors
122+
INTERNAL_SERVER_ERROR = (500, 'Internal Server Error',
123+
'Server got itself in trouble')
124+
NOT_IMPLEMENTED = (501, 'Not Implemented',
125+
'Server does not support this operation')
126+
BAD_GATEWAY = (502, 'Bad Gateway',
127+
'Invalid responses from another server/proxy')
128+
SERVICE_UNAVAILABLE = (503, 'Service Unavailable',
129+
'The server cannot process the request due to a high load')
130+
GATEWAY_TIMEOUT = (504, 'Gateway Timeout',
131+
'The gateway server did not receive a timely response')
132+
HTTP_VERSION_NOT_SUPPORTED = (505, 'HTTP Version Not Supported',
133+
'Cannot fulfill request')
134+
VARIANT_ALSO_NEGOTIATES = 506, 'Variant Also Negotiates'
135+
INSUFFICIENT_STORAGE = 507, 'Insufficient Storage'
136+
LOOP_DETECTED = 508, 'Loop Detected'
137+
NOT_EXTENDED = 510, 'Not Extended'
138+
NETWORK_AUTHENTICATION_REQUIRED = (511,
139+
'Network Authentication Required',
140+
'The client needs to authenticate to gain network access')

flask_restplus/postman.py

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
from time import time
2+
from uuid import uuid5, NAMESPACE_URL
3+
4+
from six import iteritems
5+
from six.moves.urllib.parse import urlencode
6+
7+
8+
def clean(data):
9+
'''Remove all keys where value is None'''
10+
return dict((k, v) for k, v in iteritems(data) if v is not None)
11+
12+
13+
DEFAULT_VARS = {
14+
'string': '',
15+
'integer': 0,
16+
'number': 0,
17+
}
18+
19+
20+
class Request(object):
21+
'''Wraps a Swagger operation into a Postman Request'''
22+
def __init__(self, collection, path, params, method, operation):
23+
self.collection = collection
24+
self.path = path
25+
self.params = params
26+
self.method = method.upper()
27+
self.operation = operation
28+
29+
@property
30+
def id(self):
31+
seed = str(' '.join((self.method, self.url)))
32+
return str(uuid5(self.collection.uuid, seed))
33+
34+
@property
35+
def url(self):
36+
return self.collection.api.base_url.rstrip('/') + self.path
37+
38+
@property
39+
def headers(self):
40+
headers = {}
41+
# Handle content-type
42+
if self.method != 'GET':
43+
consumes = self.collection.api.__schema__.get('consumes', [])
44+
consumes = self.operation.get('consumes', consumes)
45+
if len(consumes):
46+
headers['Content-Type'] = consumes[-1]
47+
48+
# Add all parameters headers
49+
for param in self.operation.get('parameters', []):
50+
if param['in'] == 'header':
51+
headers[param['name']] = param.get('default', '')
52+
53+
# Add security headers if needed (global then local)
54+
for security in self.collection.api.__schema__.get('security', []):
55+
for key, header in iteritems(self.collection.apikeys):
56+
if key in security:
57+
headers[header] = ''
58+
for security in self.operation.get('security', []):
59+
for key, header in iteritems(self.collection.apikeys):
60+
if key in security:
61+
headers[header] = ''
62+
63+
lines = [':'.join(line) for line in iteritems(headers)]
64+
return '\n'.join(lines)
65+
66+
@property
67+
def folder(self):
68+
if 'tags' not in self.operation or len(self.operation['tags']) == 0:
69+
return
70+
tag = self.operation['tags'][0]
71+
for folder in self.collection.folders:
72+
if folder.tag == tag:
73+
return folder.id
74+
75+
def as_dict(self, urlvars=False):
76+
url, variables = self.process_url(urlvars)
77+
return clean({
78+
'id': self.id,
79+
'method': self.method,
80+
'name': self.operation['operationId'],
81+
'description': self.operation.get('summary'),
82+
'url': url,
83+
'headers': self.headers,
84+
'collectionId': self.collection.id,
85+
'folder': self.folder,
86+
'pathVariables': variables,
87+
'time': int(time()),
88+
})
89+
90+
def process_url(self, urlvars=False):
91+
url = self.url
92+
path_vars = {}
93+
url_vars = {}
94+
params = dict((p['name'], p) for p in self.params)
95+
params.update(dict((p['name'], p) for p in self.operation.get('parameters', [])))
96+
if not params:
97+
return url, None
98+
for name, param in iteritems(params):
99+
if param['in'] == 'path':
100+
url = url.replace('{%s}' % name, ':%s' % name)
101+
path_vars[name] = DEFAULT_VARS.get(param['type'], '')
102+
elif param['in'] == 'query' and urlvars:
103+
default = DEFAULT_VARS.get(param['type'], '')
104+
url_vars[name] = param.get('default', default)
105+
if url_vars:
106+
url = '?'.join((url, urlencode(url_vars)))
107+
return url, path_vars
108+
109+
110+
class Folder(object):
111+
def __init__(self, collection, tag):
112+
self.collection = collection
113+
self.tag = tag['name']
114+
self.description = tag['description']
115+
116+
@property
117+
def id(self):
118+
return str(uuid5(self.collection.uuid, str(self.tag)))
119+
120+
@property
121+
def order(self):
122+
return [
123+
r.id for r in self.collection.requests
124+
if r.folder == self.id
125+
]
126+
127+
def as_dict(self):
128+
return clean({
129+
'id': self.id,
130+
'name': self.tag,
131+
'description': self.description,
132+
'order': self.order,
133+
'collectionId': self.collection.id
134+
})
135+
136+
137+
class PostmanCollectionV1(object):
138+
'''Postman Collection (V1 format) serializer'''
139+
def __init__(self, api, swagger=False):
140+
self.api = api
141+
self.swagger = swagger
142+
143+
@property
144+
def uuid(self):
145+
return uuid5(NAMESPACE_URL, self.api.base_url)
146+
147+
@property
148+
def id(self):
149+
return str(self.uuid)
150+
151+
@property
152+
def requests(self):
153+
if self.swagger:
154+
# First request is Swagger specifications
155+
yield Request(self, '/swagger.json', {}, 'get', {
156+
'operationId': 'Swagger specifications',
157+
'summary': 'The API Swagger specifications as JSON',
158+
})
159+
# Then iter over API paths and methods
160+
for path, operations in iteritems(self.api.__schema__['paths']):
161+
path_params = operations.get('parameters', [])
162+
163+
for method, operation in iteritems(operations):
164+
if method != 'parameters':
165+
yield Request(self, path, path_params, method, operation)
166+
167+
@property
168+
def folders(self):
169+
for tag in self.api.__schema__['tags']:
170+
yield Folder(self, tag)
171+
172+
@property
173+
def apikeys(self):
174+
return dict(
175+
(name, secdef['name'])
176+
for name, secdef in iteritems(self.api.__schema__.get('securityDefinitions'))
177+
if secdef.get('in') == 'header' and secdef.get('type') == 'apiKey'
178+
)
179+
180+
def as_dict(self, urlvars=False):
181+
return clean({
182+
'id': self.id,
183+
'name': ' '.join((self.api.title, self.api.version)),
184+
'description': self.api.description,
185+
'order': [r.id for r in self.requests if not r.folder],
186+
'requests': [r.as_dict(urlvars=urlvars) for r in self.requests],
187+
'folders': [f.as_dict() for f in self.folders],
188+
'timestamp': int(time()),
189+
})

0 commit comments

Comments
 (0)