forked from loafle/openapi-generator-original
Merge pull request #797 from geekerzp/develop_2.0_python_auth
[Python] Add authentication support (API key, HTTP basic)
This commit is contained in:
@@ -27,15 +27,16 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
super();
|
||||
|
||||
eggPackage = module + "-python";
|
||||
invokerPackage = eggPackage + "/" + module;
|
||||
|
||||
invokerPackage = eggPackage + File.separatorChar + module;
|
||||
|
||||
outputFolder = "generated-code/python";
|
||||
outputFolder = "generated-code" + File.separatorChar + "python";
|
||||
modelTemplateFiles.put("model.mustache", ".py");
|
||||
apiTemplateFiles.put("api.mustache", ".py");
|
||||
templateDir = "python";
|
||||
|
||||
apiPackage = invokerPackage + ".apis";
|
||||
modelPackage = invokerPackage + ".models";
|
||||
apiPackage = invokerPackage + File.separatorChar + "apis";
|
||||
modelPackage = invokerPackage + File.separatorChar + "models";
|
||||
|
||||
languageSpecificPrimitives.clear();
|
||||
languageSpecificPrimitives.add("int");
|
||||
@@ -68,13 +69,12 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
|
||||
supportingFiles.add(new SupportingFile("README.mustache", eggPackage, "README.md"));
|
||||
supportingFiles.add(new SupportingFile("setup.mustache", eggPackage, "setup.py"));
|
||||
supportingFiles.add(new SupportingFile("swagger.mustache", invokerPackage, "swagger.py"));
|
||||
supportingFiles.add(new SupportingFile("api_client.mustache", invokerPackage, "api_client.py"));
|
||||
supportingFiles.add(new SupportingFile("rest.mustache", invokerPackage, "rest.py"));
|
||||
supportingFiles.add(new SupportingFile("util.mustache", invokerPackage, "util.py"));
|
||||
supportingFiles.add(new SupportingFile("config.mustache", invokerPackage, "config.py"));
|
||||
supportingFiles.add(new SupportingFile("configuration.mustache", invokerPackage, "configuration.py"));
|
||||
supportingFiles.add(new SupportingFile("__init__package.mustache", invokerPackage, "__init__.py"));
|
||||
supportingFiles.add(new SupportingFile("__init__model.mustache", modelPackage.replace('.', File.separatorChar), "__init__.py"));
|
||||
supportingFiles.add(new SupportingFile("__init__api.mustache", apiPackage.replace('.', File.separatorChar), "__init__.py"));
|
||||
supportingFiles.add(new SupportingFile("__init__model.mustache", modelPackage, "__init__.py"));
|
||||
supportingFiles.add(new SupportingFile("__init__api.mustache", apiPackage, "__init__.py"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,11 +84,11 @@ public class PythonClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
|
||||
@Override
|
||||
public String apiFileFolder() {
|
||||
return outputFolder + "/" + apiPackage().replace('.', File.separatorChar);
|
||||
return outputFolder + File.separatorChar + apiPackage().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
public String modelFileFolder() {
|
||||
return outputFolder + "/" + modelPackage().replace('.', File.separatorChar);
|
||||
return outputFolder + File.separatorChar + modelPackage().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,4 +7,4 @@ from __future__ import absolute_import
|
||||
{{#apiInfo}}{{#apis}}from .apis.{{classVarName}} import {{classname}}
|
||||
{{/apis}}{{/apiInfo}}
|
||||
# import ApiClient
|
||||
from .swagger import ApiClient
|
||||
from .api_client import ApiClient
|
||||
|
||||
@@ -27,9 +27,8 @@ import os
|
||||
# python 2 and python 3 compatibility library
|
||||
from six import iteritems
|
||||
|
||||
from ..util import remove_none
|
||||
|
||||
from .. import config
|
||||
from .. import configuration
|
||||
from ..api_client import ApiClient
|
||||
|
||||
{{#operations}}
|
||||
class {{classname}}(object):
|
||||
@@ -38,7 +37,10 @@ class {{classname}}(object):
|
||||
if api_client:
|
||||
self.api_client = api_client
|
||||
else:
|
||||
self.api_client = config.api_client
|
||||
if not configuration.api_client:
|
||||
configuration.api_client = ApiClient('{{basePath}}')
|
||||
self.api_client = configuration.api_client
|
||||
|
||||
{{#operation}}
|
||||
def {{nickname}}(self, {{#allParams}}{{#required}}{{paramName}}, {{/required}}{{/allParams}}**kwargs):
|
||||
"""
|
||||
@@ -66,13 +68,32 @@ class {{classname}}(object):
|
||||
resource_path = '{{path}}'.replace('{format}', 'json')
|
||||
method = '{{httpMethod}}'
|
||||
|
||||
path_params = remove_none(dict({{#pathParams}}{{baseName}}=params.get('{{paramName}}'){{#hasMore}}, {{/hasMore}}{{/pathParams}}))
|
||||
query_params = remove_none(dict({{#queryParams}}{{baseName}}=params.get('{{paramName}}'){{#hasMore}}, {{/hasMore}}{{/queryParams}}))
|
||||
header_params = remove_none(dict({{#headerParams}}{{baseName}}=params.get('{{paramName}}'){{#hasMore}}, {{/hasMore}}{{/headerParams}}))
|
||||
form_params = remove_none(dict({{#formParams}}{{^isFile}}{{baseName}}=params.get('{{paramName}}'){{#hasMore}}, {{/hasMore}}{{/isFile}}{{/formParams}}))
|
||||
files = remove_none(dict({{#formParams}}{{#isFile}}{{baseName}}=params.get('{{paramName}}'){{#hasMore}}, {{/hasMore}}{{/isFile}}{{/formParams}}))
|
||||
body_params = {{#bodyParam}}params.get('{{paramName}}'){{/bodyParam}}{{^bodyParam}}None{{/bodyParam}}
|
||||
|
||||
path_params = {}
|
||||
{{#pathParams}}
|
||||
if '{{paramName}}' in params:
|
||||
path_params['{{baseName}}'] = params['{{paramName}}']
|
||||
{{/pathParams}}
|
||||
query_params = {}
|
||||
{{#queryParams}}
|
||||
if '{{paramName}}' in params:
|
||||
query_params['{{baseName}}'] = params['{{paramName}}']
|
||||
{{/queryParams}}
|
||||
header_params = {}
|
||||
{{#headerParams}}
|
||||
if '{{paramName}}' in params:
|
||||
header_params['{{baseName}}'] = params['{{paramName}}']
|
||||
{{/headerParams}}
|
||||
form_params = {}
|
||||
files = {}
|
||||
{{#formParams}}
|
||||
if '{{paramName}}' in params:
|
||||
{{#notFile}}form_params['{{baseName}}'] = params['{{paramName}}']{{/notFile}}{{#isFile}}files['{{baseName}}'] = params['{{paramName}}']{{/isFile}}
|
||||
{{/formParams}}
|
||||
body_params = None
|
||||
{{#bodyParam}}
|
||||
if '{{paramName}}' in params:
|
||||
body_params = params['{{paramName}}']
|
||||
{{/bodyParam}}
|
||||
# HTTP header `Accept`
|
||||
header_params['Accept'] = self.api_client.select_header_accept([{{#produces}}'{{mediaType}}'{{#hasMore}}, {{/hasMore}}{{/produces}}])
|
||||
if not header_params['Accept']:
|
||||
@@ -81,9 +102,12 @@ class {{classname}}(object):
|
||||
# HTTP header `Content-Type`
|
||||
header_params['Content-Type'] = self.api_client.select_header_content_type([{{#consumes}}'{{mediaType}}'{{#hasMore}}, {{/hasMore}}{{/consumes}}])
|
||||
|
||||
# Authentication setting
|
||||
auth_settings = [{{#authMethods}}'{{name}}'{{#hasMore}}, {{/hasMore}}{{/authMethods}}]
|
||||
|
||||
response = self.api_client.call_api(resource_path, method, path_params, query_params, header_params,
|
||||
body=body_params, post_params=form_params, files=files,
|
||||
response={{#returnType}}'{{returnType}}'{{/returnType}}{{^returnType}}None{{/returnType}})
|
||||
response={{#returnType}}'{{returnType}}'{{/returnType}}{{^returnType}}None{{/returnType}}, auth_settings=auth_settings)
|
||||
{{#returnType}}
|
||||
return response
|
||||
{{/returnType}}{{/operation}}
|
||||
|
||||
@@ -28,6 +28,7 @@ except ImportError:
|
||||
# for python2
|
||||
from urllib import quote
|
||||
|
||||
from . import configuration
|
||||
|
||||
class ApiClient(object):
|
||||
"""
|
||||
@@ -37,7 +38,7 @@ class ApiClient(object):
|
||||
:param header_name: a header to pass when making calls to the API
|
||||
:param header_value: a header value to pass when making calls to the API
|
||||
"""
|
||||
def __init__(self, host=None, header_name=None, header_value=None):
|
||||
def __init__(self, host=configuration.host, header_name=None, header_value=None):
|
||||
self.default_headers = {}
|
||||
if header_name is not None:
|
||||
self.default_headers[header_name] = header_value
|
||||
@@ -58,15 +59,15 @@ class ApiClient(object):
|
||||
self.default_headers[header_name] = header_value
|
||||
|
||||
def call_api(self, resource_path, method, path_params=None, query_params=None, header_params=None,
|
||||
body=None, post_params=None, files=None, response=None):
|
||||
body=None, post_params=None, files=None, response=None, auth_settings=None):
|
||||
|
||||
# headers parameters
|
||||
headers = self.default_headers.copy()
|
||||
headers.update(header_params)
|
||||
header_params = header_params or {}
|
||||
header_params.update(self.default_headers)
|
||||
if self.cookie:
|
||||
headers['Cookie'] = self.cookie
|
||||
if headers:
|
||||
headers = self.sanitize_for_serialization(headers)
|
||||
header_params['Cookie'] = self.cookie
|
||||
if header_params:
|
||||
header_params = self.sanitize_for_serialization(header_params)
|
||||
|
||||
# path parameters
|
||||
if path_params:
|
||||
@@ -85,6 +86,9 @@ class ApiClient(object):
|
||||
post_params = self.prepare_post_parameters(post_params, files)
|
||||
post_params = self.sanitize_for_serialization(post_params)
|
||||
|
||||
# auth setting
|
||||
self.update_params_for_auth(header_params, query_params, auth_settings)
|
||||
|
||||
# body
|
||||
if body:
|
||||
body = self.sanitize_for_serialization(body)
|
||||
@@ -93,7 +97,7 @@ class ApiClient(object):
|
||||
url = self.host + resource_path
|
||||
|
||||
# perform request and return response
|
||||
response_data = self.request(method, url, query_params=query_params, headers=headers,
|
||||
response_data = self.request(method, url, query_params=query_params, headers=header_params,
|
||||
post_params=post_params, body=body)
|
||||
|
||||
# deserialize response data
|
||||
@@ -244,11 +248,12 @@ class ApiClient(object):
|
||||
|
||||
if files:
|
||||
for k, v in iteritems(files):
|
||||
with open(v, 'rb') as f:
|
||||
filename = os.path.basename(f.name)
|
||||
filedata = f.read()
|
||||
mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
|
||||
params[k] = tuple([filename, filedata, mimetype])
|
||||
if v:
|
||||
with open(v, 'rb') as f:
|
||||
filename = os.path.basename(f.name)
|
||||
filedata = f.read()
|
||||
mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
|
||||
params[k] = tuple([filename, filedata, mimetype])
|
||||
|
||||
return params
|
||||
|
||||
@@ -279,3 +284,20 @@ class ApiClient(object):
|
||||
return 'application/json'
|
||||
else:
|
||||
return content_types[0]
|
||||
|
||||
def update_params_for_auth(self, headers, querys, auth_settings):
|
||||
"""
|
||||
Update header and query params based on authentication setting
|
||||
"""
|
||||
if not auth_settings:
|
||||
return
|
||||
|
||||
for auth in auth_settings:
|
||||
auth_setting = configuration.auth_settings().get(auth)
|
||||
if auth_setting:
|
||||
if auth_setting['in'] == 'header':
|
||||
headers[auth_setting['key']] = auth_setting['value']
|
||||
elif auth_setting['in'] == 'query':
|
||||
querys[auth_setting['key']] = auth_setting['value']
|
||||
else:
|
||||
raise ValueError('Authentication token must be in `query` or `header`')
|
||||
@@ -1,8 +0,0 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from .swagger import ApiClient
|
||||
|
||||
# Configuration variables
|
||||
|
||||
api_client = ApiClient("{{basePath}}")
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
from __future__ import absolute_import
|
||||
import base64
|
||||
import urllib3
|
||||
|
||||
def get_api_key_with_prefix(key):
|
||||
global api_key
|
||||
global api_key_prefix
|
||||
|
||||
if api_key.get(key) and api_key_prefix.get(key):
|
||||
return api_key_prefix[key] + ' ' + api_key[key]
|
||||
elif api_key.get(key):
|
||||
return api_key[key]
|
||||
|
||||
def get_basic_auth_token():
|
||||
global username
|
||||
global password
|
||||
|
||||
return urllib3.util.make_headers(basic_auth=username + ':' + password).get('authorization')
|
||||
|
||||
def auth_settings():
|
||||
return { {{#authMethods}}{{#isApiKey}}
|
||||
'{{name}}': {
|
||||
'type': 'api_key',
|
||||
'in': {{#isKeyInHeader}}'header'{{/isKeyInHeader}}{{#isKeyInQuery}}'query'{{/isKeyInQuery}},
|
||||
'key': '{{keyParamName}}',
|
||||
'value': get_api_key_with_prefix('{{keyParamName}}')
|
||||
},
|
||||
{{/isApiKey}}{{#isBasic}}
|
||||
'{{name}}': {
|
||||
'type': 'basic',
|
||||
'in': 'header',
|
||||
'key': 'Authorization',
|
||||
'value': get_basic_auth_token()
|
||||
},
|
||||
{{/isBasic}}{{/authMethods}}
|
||||
}
|
||||
|
||||
# Default Base url
|
||||
host = "{{basePath}}"
|
||||
|
||||
# Default api client
|
||||
api_client = None
|
||||
|
||||
# Authentication settings
|
||||
|
||||
api_key = {}
|
||||
api_key_prefix = {}
|
||||
username = ''
|
||||
password = ''
|
||||
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
# coding: utf-8
|
||||
|
||||
"""
|
||||
Credit: this file (rest.py) is modified based on rest.py in Dropbox Python SDK:
|
||||
https://www.dropbox.com/developers/core/sdks/python
|
||||
"""
|
||||
|
||||
import sys
|
||||
import io
|
||||
import json
|
||||
@@ -120,7 +126,7 @@ class RESTClientObject(object):
|
||||
r = RESTResponse(r)
|
||||
|
||||
if r.status not in range(200, 206):
|
||||
raise ErrorResponse(r)
|
||||
raise ApiException(r)
|
||||
|
||||
return self.process_response(r)
|
||||
|
||||
@@ -157,7 +163,7 @@ class RESTClientObject(object):
|
||||
return self.request("PATCH", url, headers=headers, post_params=post_params, body=body)
|
||||
|
||||
|
||||
class ErrorResponse(Exception):
|
||||
class ApiException(Exception):
|
||||
"""
|
||||
Non-2xx HTTP response
|
||||
"""
|
||||
@@ -184,7 +190,10 @@ class ErrorResponse(Exception):
|
||||
"""
|
||||
Custom error response messages
|
||||
"""
|
||||
return "({0})\nReason: {1}\nHeader: {2}\nBody: {3}\n".\
|
||||
return "({0})\n"\
|
||||
"Reason: {1}\n"\
|
||||
"HTTP response headers: {2}\n"\
|
||||
"HTTP response body: {3}\n".\
|
||||
format(self.status, self.reason, self.headers, self.body)
|
||||
|
||||
class RESTClient(object):
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
from six import iteritems
|
||||
|
||||
def remove_none(obj):
|
||||
if isinstance(obj, (list, tuple, set)):
|
||||
return type(obj)(remove_none(x) for x in obj if x is not None)
|
||||
elif isinstance(obj, dict):
|
||||
return type(obj)((remove_none(k), remove_none(v))
|
||||
for k, v in iteritems(obj) if k is not None and v is not None)
|
||||
else:
|
||||
return obj
|
||||
|
||||
|
||||
def inspect_vars(obj):
|
||||
if not hasattr(obj, '__dict__'):
|
||||
return obj
|
||||
else:
|
||||
return {k: inspect_vars(getattr(obj, k)) for k in dir(obj)}
|
||||
Reference in New Issue
Block a user