From 63b5ef7d30e5f7a79d7eee5ecd0d72b3d15ae6a6 Mon Sep 17 00:00:00 2001
From: Mads Bisgaard <126242332+bisgaard-itis@users.noreply.github.com>
Date: Tue, 13 Jun 2023 10:04:07 +0200
Subject: [PATCH] Use forked openapi generator repo (#4343)
---
scripts/openapi-generator.bash | 87 ++-
services/api-server/Makefile | 16 +-
.../python_templates/api_client.mustache | 663 ------------------
.../python_templates/configuration.mustache | 469 -------------
4 files changed, 52 insertions(+), 1183 deletions(-)
delete mode 100644 services/api-server/openapi/python_templates/api_client.mustache
delete mode 100644 services/api-server/openapi/python_templates/configuration.mustache
diff --git a/scripts/openapi-generator.bash b/scripts/openapi-generator.bash
index 6fe5ee761f9..896f9e4dbdc 100755
--- a/scripts/openapi-generator.bash
+++ b/scripts/openapi-generator.bash
@@ -1,7 +1,5 @@
#!/bin/bash
-# Script for calling OpenAPI Generato (generate clients, servers, and documentation from OpenAPI 2.0/3.x documents) or
-# fetch the associated templates for Python client generation. Which function is called is determined by the 'RUN_FCN' environment variable.
-# Setting 'RUN_FCN'="OPENAPI_GENERATOR_CLI" calls the generator and setting 'RUN_FCN'="FETCH_TEMPLATES" fetches the python client templates
+# Script for calling OpenAPI Generator (generate clients, servers, and documentation from OpenAPI 2.0/3.x documents).
# OpenAPI Generator: generate clients, servers, and documentation from OpenAPI 2.0/3.x documents
#
@@ -24,52 +22,69 @@
# https://hub.docker.com/r/openapitools/openapi-generator-cli
#
-# fetch_openapi_generator_templates
-# usage: fetch_openapi_generator_templates
-
OPENAPI_GENERATOR_VERSION=v4.2.3
-openapi_generator_cli(){
+
+fetch_openapi_generator_templates(){
+ CURDIR=$(pwd)
+ TMPDIR=$1
+ cd ${TMPDIR}
+
+ echo "Cloning openapi-generator into ${TMPDIR} to get templates..."
+ git clone git@github.com:ITISFoundation/openapi-generator.git
+ cd openapi-generator
+ git checkout openapi-generator-${OPENAPI_GENERATOR_VERSION}
+ git status
+ git pull
+ echo "Done fetching templates..."
+
+ cd ${CURDIR}
+}
+
+
+openapi_generator_cli_generate(){
+ TMPDIR=$(mktemp -d)
USERID=$(stat --format=%u "$PWD")
GROUPID=$(stat --format=%g "$PWD")
+ HOST_TEMPL_DIR=${TMPDIR}/openapi-generator/modules/openapi-generator/src/main/resources/python
+ CONTAINER_TEMPL_DIR=/tmp/openapi_templates
- # to mount a directory (e.g. to find custom templates, define the DOCKER_MOUNT environment variable)
- docker_mount=""
- if [ -v DOCKER_MOUNT ]; then
- docker_mount="-v ${DOCKER_MOUNT}"
+ fetch_openapi_generator_templates "${TMPDIR}"
+ if [ ! -d "${HOST_TEMPL_DIR}" ]; then
+ echo "Templates could not be correctly fetched from Github"
+ exit 1
fi
+ (
+ exec docker run --rm \
+ -v ${HOST_TEMPL_DIR}:${CONTAINER_TEMPL_DIR} \
+ --user "$USERID:$GROUPID" \
+ --volume "$PWD:/local" \
+ openapitools/openapi-generator-cli:${OPENAPI_GENERATOR_VERSION} "$@" \
+ --template-dir=${CONTAINER_TEMPL_DIR}
+ )
+
+ rm -fr "${TMPDIR}"
+}
+
+openapi_generator_cli(){
+ USERID=$(stat --format=%u "$PWD")
+ GROUPID=$(stat --format=%g "$PWD")
+
exec docker run --rm \
- ${docker_mount} \
--user "$USERID:$GROUPID" \
--volume "$PWD:/local" \
openapitools/openapi-generator-cli:${OPENAPI_GENERATOR_VERSION} "$@"
}
-fetch_openapi_generator_templates(){
- TEMPLATE_DIR=$1
- TMPDIR=$(mktemp -d)
-
- echo "Fetching openapi generator templates from github..."
- wget -O ${TMPDIR}/openapi_zip.zip "https://github.com/OpenAPITools/openapi-generator/archive/refs/tags/${OPENAPI_GENERATOR_VERSION}.zip"
- unzip -q ${TMPDIR}/openapi_zip.zip -d ${TMPDIR}
-
- echo "Overwriting templates in this repo..."
- rm -r ${TEMPLATE_DIR}
- mkdir ${TEMPLATE_DIR}
- cd ${TMPDIR}
- openapi_dir=$(ls . | grep openapi-generator)
- cd ${openapi_dir}
- cp -r ./modules/openapi-generator/src/main/resources/python/* ${TEMPLATE_DIR}
-
- rm -r ${TMPDIR}
- echo "Done!"
-}
+generate=false
+if [[ $1 == "generate" ]]; then
+ echo "Found generate input. Will fetch templates from git@github.com:ITISFoundation/openapi-generator.git"
+ generate=true
+fi
-if [[ "${RUN_FCN}" == "OPENAPI_GENERATOR_CLI" ]]; then
- openapi_generator_cli "$@"
-elif [[ "${RUN_FCN}" == "FETCH_TEMPLATES" ]]; then
- fetch_openapi_generator_templates "$@"
+if ${generate}; then
+ openapi_generator_cli_generate "$@"
else
- echo "The environment variable 'RUN_FCN' must be defined when calling this bash script"
+ openapi_generator_cli "$@"
fi
diff --git a/services/api-server/Makefile b/services/api-server/Makefile
index 9e802c37e7c..e0fa9fbe994 100644
--- a/services/api-server/Makefile
+++ b/services/api-server/Makefile
@@ -83,8 +83,6 @@ run-fake-devel: # starts a fake server in a dev-container
# BUILD ###########################################################################
-OPENAPI_GENERATOR_VERSION := v4.2.3
-
define create_and_validate_openapi
# generating openapi specs file under $< (NOTE: Skips DEV FEATURES since this OAS is the 'offically released'!)
@source .env; \
@@ -95,7 +93,6 @@ define create_and_validate_openapi
@set -o allexport; \
source .env; \
cd $(CURDIR); \
- export RUN_FCN=OPENAPI_GENERATOR_CLI; \
$(SCRIPTS_DIR)/openapi-generator.bash validate --input-spec /local/$@
endef
@@ -154,8 +151,6 @@ python-client: client openapi.json ## runs python client generator
# generates
@source .env; \
cd $(CURDIR); \
- export RUN_FCN=OPENAPI_GENERATOR_CLI; \
- export DOCKER_MOUNT=$(REPO_BASE_DIR)/services/api-server/openapi/python_templates:$(CONTAINER_TEMPL_DIR); \
$(SCRIPTS_DIR)/openapi-generator.bash generate \
--generator-name=$(GENERATOR_NAME) \
--git-user-id=$(GIT_USER_ID) \
@@ -165,19 +160,10 @@ python-client: client openapi.json ## runs python client generator
--output=/local/client \
--additional-properties=$(subst $(space),$(comma),$(strip $(ADDITIONAL_PROPS))) \
--package-name=osparc \
- --release-note="Updated to $(APP_VERSION)" \
- --template-dir=$(CONTAINER_TEMPL_DIR)
-
+ --release-note="Updated to $(APP_VERSION)"
generator-help: ## help on client-api generator
# generate help
@$(SCRIPTS_DIR)/openapi-generator-cli.bash help generate
# generator config help
@$(SCRIPTS_DIR)/openapi-generator-cli.bash config-help -g $(GENERATOR_NAME)
-
-
-fetch-openapi-templates: ## fetches open api generator templates and overwrites the ones in $(CURDIR)/openapi/python-templates
- @cd $(CURDIR); \
- export RUN_FCN=FETCH_TEMPLATES; \
- export DOCKER_MOUNT=$(REPO_BASE_DIR)/services/api-server/openapi/python_templates:$(CONTAINER_TEMPL_DIR); \
- $(SCRIPTS_DIR)/openapi-generator.bash $(CURDIR)/openapi/python_templates
diff --git a/services/api-server/openapi/python_templates/api_client.mustache b/services/api-server/openapi/python_templates/api_client.mustache
deleted file mode 100644
index 16922b86e27..00000000000
--- a/services/api-server/openapi/python_templates/api_client.mustache
+++ /dev/null
@@ -1,663 +0,0 @@
-# coding: utf-8
-{{>partial_header}}
-from __future__ import absolute_import
-
-import atexit
-import datetime
-from dateutil.parser import parse
-import json
-import mimetypes
-from multiprocessing.pool import ThreadPool
-import os
-import re
-import tempfile
-
-# python 2 and python 3 compatibility library
-import six
-from six.moves.urllib.parse import quote
-{{#tornado}}
-import tornado.gen
-{{/tornado}}
-
-from {{packageName}}.configuration import Configuration
-import {{modelPackage}}
-from {{packageName}} import rest
-from {{packageName}}.exceptions import ApiValueError
-from contextlib import suppress
-
-class ApiClient(object):
- """Generic API client for OpenAPI client library builds.
-
- OpenAPI generic API client. This client handles the client-
- server communication, and is invariant across implementations. Specifics of
- the methods and models for each application are generated from the OpenAPI
- templates.
-
- NOTE: This class is auto generated by OpenAPI Generator.
- Ref: https://openapi-generator.tech
- Do not edit the class manually.
-
- :param configuration: .Configuration object for this client
- :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.
- :param cookie: a cookie to include in the header when making calls
- to the API
- :param pool_threads: The number of threads to use for async requests
- to the API. More threads means more concurrent API requests.
- """
-
- PRIMITIVE_TYPES = (float, bool, bytes, six.text_type) + six.integer_types
- NATIVE_TYPES_MAPPING = {
- 'int': int,
- 'long': int if six.PY3 else long, # noqa: F821
- 'float': float,
- 'str': str,
- 'bool': bool,
- 'date': datetime.date,
- 'datetime': datetime.datetime,
- 'object': object,
- }
- _pool = None
-
- def __init__(self, configuration=None, header_name=None, header_value=None,
- cookie=None, pool_threads=1):
- if configuration is None:
- configuration = Configuration()
- self.configuration = configuration
- self.pool_threads = pool_threads
-
- self.rest_client = rest.RESTClientObject(configuration)
- self.default_headers = {}
- if header_name is not None:
- self.default_headers[header_name] = header_value
- self.cookie = cookie
- # Set default User-Agent.
- self.user_agent = '{{#httpUserAgent}}{{{.}}}{{/httpUserAgent}}{{^httpUserAgent}}OpenAPI-Generator/{{{packageVersion}}}/python{{/httpUserAgent}}'
- self.client_side_validation = configuration.client_side_validation
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_value, traceback):
- self.close()
-
- def close(self):
- if self._pool:
- self._pool.close()
- self._pool.join()
- self._pool = None
- if hasattr(atexit, 'unregister'):
- atexit.unregister(self.close)
-
- @property
- def pool(self):
- """Create thread pool on first request
- avoids instantiating unused threadpool for blocking clients.
- """
- if self._pool is None:
- atexit.register(self.close)
- self._pool = ThreadPool(self.pool_threads)
- return self._pool
-
- @property
- def user_agent(self):
- """User agent for this API client"""
- return self.default_headers['User-Agent']
-
- @user_agent.setter
- def user_agent(self, value):
- self.default_headers['User-Agent'] = value
-
- def set_default_header(self, header_name, header_value):
- self.default_headers[header_name] = header_value
-
- {{#tornado}}
- @tornado.gen.coroutine
- {{/tornado}}
- {{#asyncio}}async {{/asyncio}}def __call_api(
- self, resource_path, method, path_params=None,
- query_params=None, header_params=None, body=None, post_params=None,
- files=None, response_type=None, auth_settings=None,
- _return_http_data_only=None, collection_formats=None,
- _preload_content=True, _request_timeout=None, _host=None):
-
- config = self.configuration
-
- # header parameters
- header_params = header_params or {}
- header_params.update(self.default_headers)
- if self.cookie:
- header_params['Cookie'] = self.cookie
- if header_params:
- header_params = self.sanitize_for_serialization(header_params)
- header_params = dict(self.parameters_to_tuples(header_params,
- collection_formats))
-
- # path parameters
- if path_params:
- path_params = self.sanitize_for_serialization(path_params)
- path_params = self.parameters_to_tuples(path_params,
- collection_formats)
- for k, v in path_params:
- # specified safe chars, encode everything
- resource_path = resource_path.replace(
- '{%s}' % k,
- quote(str(v), safe=config.safe_chars_for_path_param)
- )
-
- # query parameters
- if query_params:
- query_params = self.sanitize_for_serialization(query_params)
- query_params = self.parameters_to_tuples(query_params,
- collection_formats)
-
- # post parameters
- if post_params or files:
- post_params = post_params if post_params else []
- post_params = self.sanitize_for_serialization(post_params)
- post_params = self.parameters_to_tuples(post_params,
- collection_formats)
- post_params.extend(self.files_parameters(files))
-
- # auth setting
- self.update_params_for_auth(header_params, query_params, auth_settings)
-
- # body
- if body:
- body = self.sanitize_for_serialization(body)
-
- # request url
- if _host is None:
- url = self.configuration.host + resource_path
- else:
- # use server/host defined in path or operation instead
- url = _host + resource_path
-
- # perform request and return response
- response_data = {{#asyncio}}await {{/asyncio}}{{#tornado}}yield {{/tornado}}self.request(
- method, url, query_params=query_params, headers=header_params,
- post_params=post_params, body=body,
- _preload_content=_preload_content,
- _request_timeout=_request_timeout)
-
- self.last_response = response_data
-
- return_data = response_data
- if _preload_content:
- # deserialize response data
- if response_type:
- return_data = self.deserialize(response_data, response_type)
- else:
- return_data = None
-
-{{^tornado}}
- if _return_http_data_only:
- return (return_data)
- else:
- return (return_data, response_data.status,
- response_data.getheaders())
-{{/tornado}}
-{{#tornado}}
- if _return_http_data_only:
- raise tornado.gen.Return(return_data)
- else:
- raise tornado.gen.Return((return_data, response_data.status,
- response_data.getheaders()))
-{{/tornado}}
-
- def sanitize_for_serialization(self, obj):
- """Builds a JSON POST object.
-
- If obj is None, return None.
- If obj is str, int, long, float, bool, return directly.
- If obj is datetime.datetime, datetime.date
- convert to string in iso8601 format.
- If obj is list, sanitize each element in the list.
- If obj is dict, return the dict.
- If obj is OpenAPI model, return the properties dict.
-
- :param obj: The data to serialize.
- :return: The serialized form of data.
- """
- if obj is None:
- return None
- elif isinstance(obj, self.PRIMITIVE_TYPES):
- return obj
- elif isinstance(obj, list):
- return [self.sanitize_for_serialization(sub_obj)
- for sub_obj in obj]
- elif isinstance(obj, tuple):
- return tuple(self.sanitize_for_serialization(sub_obj)
- for sub_obj in obj)
- elif isinstance(obj, (datetime.datetime, datetime.date)):
- return obj.isoformat()
-
- if isinstance(obj, dict):
- obj_dict = obj
- else:
- # Convert model obj to dict except
- # attributes `openapi_types`, `attribute_map`
- # and attributes which value is not None.
- # Convert attribute name to json key in
- # model definition for request.
- obj_dict = {obj.attribute_map[attr]: getattr(obj, attr)
- for attr, _ in six.iteritems(obj.openapi_types)
- if getattr(obj, attr) is not None}
-
- return {key: self.sanitize_for_serialization(val)
- for key, val in six.iteritems(obj_dict)}
-
- def deserialize(self, response, response_type):
- """Deserializes response into an object.
-
- :param response: RESTResponse object to be deserialized.
- :param response_type: class literal for
- deserialized object, or string of class name.
-
- :return: deserialized object.
- """
- # handle file downloading
- # save response body into a tmp file and return the instance
- if response_type == "file":
- return self.__deserialize_file(response)
-
- # fetch data from response object
- try:
- data = json.loads(response.data)
- except ValueError:
- data = response.data
-
- return self.__deserialize(data, response_type)
-
- def __deserialize(self, data, klass):
- """Deserializes dict, list, str into an object.
-
- :param data: dict, list or str.
- :param klass: class literal, or string of class name.
-
- :return: object.
- """
- if data is None:
- return None
-
- if type(klass) == str:
- if klass.startswith('list['):
- sub_kls = re.match(r'list\[(.*)\]', klass).group(1)
- return [self.__deserialize(sub_data, sub_kls)
- for sub_data in data]
-
- if klass.startswith('dict('):
- sub_kls = re.match(r'dict\(([^,]*), (.*)\)', klass).group(2)
- return {k: self.__deserialize(v, sub_kls)
- for k, v in six.iteritems(data)}
-
- # convert str to class
- if klass in self.NATIVE_TYPES_MAPPING:
- klass = self.NATIVE_TYPES_MAPPING[klass]
- elif klass.startswith("AnyOf"):
- for tmp_klass in [{{modelPackage}}.file.File, float, int, bool, str]:
- with suppress(Exception):
- return self.__deserialize(data, tmp_klass)
- raise ValueError(f"Cannot deserialize {data}")
- else:
- klass = getattr({{modelPackage}}, klass)
-
- if klass in self.PRIMITIVE_TYPES:
- return self.__deserialize_primitive(data, klass)
- elif klass == object:
- return self.__deserialize_object(data)
- elif klass == datetime.date:
- return self.__deserialize_date(data)
- elif klass == datetime.datetime:
- return self.__deserialize_datetime(data)
- else:
- return self.__deserialize_model(data, klass)
-
- def call_api(self, resource_path, method,
- path_params=None, query_params=None, header_params=None,
- body=None, post_params=None, files=None,
- response_type=None, auth_settings=None, async_req=None,
- _return_http_data_only=None, collection_formats=None,
- _preload_content=True, _request_timeout=None, _host=None):
- """Makes the HTTP request (synchronous) and returns deserialized data.
-
- To make an async_req request, set the async_req parameter.
-
- :param resource_path: Path to method endpoint.
- :param method: Method to call.
- :param path_params: Path parameters in the url.
- :param query_params: Query parameters in the url.
- :param header_params: Header parameters to be
- placed in the request header.
- :param body: Request body.
- :param post_params dict: Request post form parameters,
- for `application/x-www-form-urlencoded`, `multipart/form-data`.
- :param auth_settings list: Auth Settings names for the request.
- :param response: Response data type.
- :param files dict: key -> filename, value -> filepath,
- for `multipart/form-data`.
- :param async_req bool: execute request asynchronously
- :param _return_http_data_only: response data without head status code
- and headers
- :param collection_formats: dict of collection formats for path, query,
- header, and post parameters.
- :param _preload_content: if False, the urllib3.HTTPResponse object will
- be returned without reading/decoding response
- data. Default is True.
- :param _request_timeout: timeout setting for this request. If one
- number provided, it will be total request
- timeout. It can also be a pair (tuple) of
- (connection, read) timeouts.
- :return:
- If async_req parameter is True,
- the request will be called asynchronously.
- The method will return the request thread.
- If parameter async_req is False or missing,
- then the method will return the response directly.
- """
- if not async_req:
- return self.__call_api(resource_path, method,
- path_params, query_params, header_params,
- body, post_params, files,
- response_type, auth_settings,
- _return_http_data_only, collection_formats,
- _preload_content, _request_timeout, _host)
-
- return self.pool.apply_async(self.__call_api, (resource_path,
- method, path_params,
- query_params,
- header_params, body,
- post_params, files,
- response_type,
- auth_settings,
- _return_http_data_only,
- collection_formats,
- _preload_content,
- _request_timeout,
- _host))
-
- def request(self, method, url, query_params=None, headers=None,
- post_params=None, body=None, _preload_content=True,
- _request_timeout=None):
- """Makes the HTTP request using RESTClient."""
- if method == "GET":
- return self.rest_client.GET(url,
- query_params=query_params,
- _preload_content=_preload_content,
- _request_timeout=_request_timeout,
- headers=headers)
- elif method == "HEAD":
- return self.rest_client.HEAD(url,
- query_params=query_params,
- _preload_content=_preload_content,
- _request_timeout=_request_timeout,
- headers=headers)
- elif method == "OPTIONS":
- return self.rest_client.OPTIONS(url,
- query_params=query_params,
- headers=headers,
- _preload_content=_preload_content,
- _request_timeout=_request_timeout)
- elif method == "POST":
- return self.rest_client.POST(url,
- query_params=query_params,
- headers=headers,
- post_params=post_params,
- _preload_content=_preload_content,
- _request_timeout=_request_timeout,
- body=body)
- elif method == "PUT":
- return self.rest_client.PUT(url,
- query_params=query_params,
- headers=headers,
- post_params=post_params,
- _preload_content=_preload_content,
- _request_timeout=_request_timeout,
- body=body)
- elif method == "PATCH":
- return self.rest_client.PATCH(url,
- query_params=query_params,
- headers=headers,
- post_params=post_params,
- _preload_content=_preload_content,
- _request_timeout=_request_timeout,
- body=body)
- elif method == "DELETE":
- return self.rest_client.DELETE(url,
- query_params=query_params,
- headers=headers,
- _preload_content=_preload_content,
- _request_timeout=_request_timeout,
- body=body)
- else:
- raise ApiValueError(
- "http method must be `GET`, `HEAD`, `OPTIONS`,"
- " `POST`, `PATCH`, `PUT` or `DELETE`."
- )
-
- def parameters_to_tuples(self, params, collection_formats):
- """Get parameters as list of tuples, formatting collections.
-
- :param params: Parameters as dict or list of two-tuples
- :param dict collection_formats: Parameter collection formats
- :return: Parameters as list of tuples, collections formatted
- """
- new_params = []
- if collection_formats is None:
- collection_formats = {}
- for k, v in six.iteritems(params) if isinstance(params, dict) else params: # noqa: E501
- if k in collection_formats:
- collection_format = collection_formats[k]
- if collection_format == 'multi':
- new_params.extend((k, value) for value in v)
- else:
- if collection_format == 'ssv':
- delimiter = ' '
- elif collection_format == 'tsv':
- delimiter = '\t'
- elif collection_format == 'pipes':
- delimiter = '|'
- else: # csv is the default
- delimiter = ','
- new_params.append(
- (k, delimiter.join(str(value) for value in v)))
- else:
- new_params.append((k, v))
- return new_params
-
- def files_parameters(self, files=None):
- """Builds form parameters.
-
- :param files: File parameters.
- :return: Form parameters with files.
- """
- params = []
-
- if files:
- for k, v in six.iteritems(files):
- if not v:
- continue
- file_names = v if type(v) is list else [v]
- for n in file_names:
- with open(n, 'rb') as f:
- filename = os.path.basename(f.name)
- filedata = f.read()
- mimetype = (mimetypes.guess_type(filename)[0] or
- 'application/octet-stream')
- params.append(
- tuple([k, tuple([filename, filedata, mimetype])]))
-
- return params
-
- def select_header_accept(self, accepts):
- """Returns `Accept` based on an array of accepts provided.
-
- :param accepts: List of headers.
- :return: Accept (e.g. application/json).
- """
- if not accepts:
- return
-
- accepts = [x.lower() for x in accepts]
-
- if 'application/json' in accepts:
- return 'application/json'
- else:
- return ', '.join(accepts)
-
- def select_header_content_type(self, content_types):
- """Returns `Content-Type` based on an array of content_types provided.
-
- :param content_types: List of content-types.
- :return: Content-Type (e.g. application/json).
- """
- if not content_types:
- return 'application/json'
-
- content_types = [x.lower() for x in content_types]
-
- if 'application/json' in content_types or '*/*' in content_types:
- return 'application/json'
- else:
- return content_types[0]
-
- def update_params_for_auth(self, headers, querys, auth_settings):
- """Updates header and query params based on authentication setting.
-
- :param headers: Header parameters dict to be updated.
- :param querys: Query parameters tuple list to be updated.
- :param auth_settings: Authentication setting identifiers list.
- """
- if not auth_settings:
- return
-
- for auth in auth_settings:
- auth_setting = self.configuration.auth_settings().get(auth)
- if auth_setting:
- if auth_setting['in'] == 'cookie':
- headers['Cookie'] = auth_setting['value']
- elif auth_setting['in'] == 'header':
- headers[auth_setting['key']] = auth_setting['value']
- elif auth_setting['in'] == 'query':
- querys.append((auth_setting['key'], auth_setting['value']))
- else:
- raise ApiValueError(
- 'Authentication token must be in `query` or `header`'
- )
-
- def __deserialize_file(self, response):
- """Deserializes body to file
-
- Saves response body into a file in a temporary folder,
- using the filename from the `Content-Disposition` header if provided.
-
- :param response: RESTResponse.
- :return: file path.
- """
- fd, path = tempfile.mkstemp(dir=self.configuration.temp_folder_path)
- os.close(fd)
- os.remove(path)
-
- content_disposition = response.getheader("Content-Disposition")
- if content_disposition:
- filename = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?',
- content_disposition).group(1)
- path = os.path.join(os.path.dirname(path), filename)
-
- try:
- with open(path, "w") as f:
- f.write(response.data)
- except TypeError:
- with open(path, "wb") as f:
- f.write(response.data)
-
- return path
-
- def __deserialize_primitive(self, data, klass):
- """Deserializes string to primitive type.
-
- :param data: str.
- :param klass: class literal.
-
- :return: int, long, float, str, bool.
- """
- try:
- return klass(data)
- except UnicodeEncodeError:
- return six.text_type(data)
- except TypeError:
- return data
-
- def __deserialize_object(self, value):
- """Return an original value.
-
- :return: object.
- """
- return value
-
- def __deserialize_date(self, string):
- """Deserializes string to date.
-
- :param string: str.
- :return: date.
- """
- try:
- return parse(string).date()
- except ImportError:
- return string
- except ValueError:
- raise rest.ApiException(
- status=0,
- reason="Failed to parse `{0}` as date object".format(string)
- )
-
- def __deserialize_datetime(self, string):
- """Deserializes string to datetime.
-
- The string should be in iso8601 datetime format.
-
- :param string: str.
- :return: datetime.
- """
- try:
- return parse(string)
- except ImportError:
- return string
- except ValueError:
- raise rest.ApiException(
- status=0,
- reason=(
- "Failed to parse `{0}` as datetime object"
- .format(string)
- )
- )
-
- def __deserialize_model(self, data, klass):
- """Deserializes list or dict to model.
-
- :param data: dict, list.
- :param klass: class literal.
- :return: model object.
- """
-
- if not klass.openapi_types and not hasattr(klass,
- 'get_real_child_model'):
- return data
-
- kwargs = {}
- if (data is not None and
- klass.openapi_types is not None and
- isinstance(data, (list, dict))):
- for attr, attr_type in six.iteritems(klass.openapi_types):
- if klass.attribute_map[attr] in data:
- value = data[klass.attribute_map[attr]]
- kwargs[attr] = self.__deserialize(value, attr_type)
-
- instance = klass(**kwargs)
-
- if hasattr(instance, 'get_real_child_model'):
- klass_name = instance.get_real_child_model(data)
- if klass_name:
- instance = self.__deserialize(data, klass_name)
- return instance
diff --git a/services/api-server/openapi/python_templates/configuration.mustache b/services/api-server/openapi/python_templates/configuration.mustache
deleted file mode 100644
index e6664130a55..00000000000
--- a/services/api-server/openapi/python_templates/configuration.mustache
+++ /dev/null
@@ -1,469 +0,0 @@
-# coding: utf-8
-
-{{>partial_header}}
-
-from __future__ import absolute_import
-
-import logging
-{{^asyncio}}
-import multiprocessing
-{{/asyncio}}
-import sys
-import urllib3
-
-import six
-from six.moves import http_client as httplib
-
-
-class Configuration(object):
- """NOTE: This class is auto generated by OpenAPI Generator
-
- Ref: https://openapi-generator.tech
- Do not edit the class manually.
-
- :param host: Base url
- :param api_key: Dict to store API key(s).
- Each entry in the dict specifies an API key.
- The dict key is the name of the security scheme in the OAS specification.
- The dict value is the API key secret.
- :param api_key_prefix: Dict to store API prefix (e.g. Bearer)
- The dict key is the name of the security scheme in the OAS specification.
- The dict value is an API key prefix when generating the auth data.
- :param username: Username for HTTP basic authentication
- :param password: Password for HTTP basic authentication
- :param signing_info: Configuration parameters for HTTP signature.
- Must be an instance of {{{packageName}}}.signing.HttpSigningConfiguration
-
- :Example:
-
- Given the following security scheme in the OpenAPI specification:
- components:
- securitySchemes:
- cookieAuth: # name for the security scheme
- type: apiKey
- in: cookie
- name: JSESSIONID # cookie name
-
- You can programmatically set the cookie:
- conf = {{{packageName}}}.Configuration(
- api_key={'cookieAuth': 'abc123'}
- api_key_prefix={'cookieAuth': 'JSESSIONID'}
- )
- The following cookie will be added to the HTTP request:
- Cookie: JSESSIONID abc123
-
- Configure API client with HTTP basic authentication:
- conf = {{{packageName}}}.Configuration(
- username='the-user',
- password='the-password',
- )
-
- Configure API client with HTTP signature authentication. Use the 'hs2019' signature scheme,
- sign the HTTP requests with the RSA-SSA-PSS signature algorithm, and set the expiration time
- of the signature to 5 minutes after the signature has been created.
- Note you can use the constants defined in the {{{packageName}}}.signing module, and you can
- also specify arbitrary HTTP headers to be included in the HTTP signature, except for the
- 'Authorization' header, which is used to carry the signature.
-
- One may be tempted to sign all headers by default, but in practice it rarely works.
- This is beccause explicit proxies, transparent proxies, TLS termination endpoints or
- load balancers may add/modify/remove headers. Include the HTTP headers that you know
- are not going to be modified in transit.
-
- conf = {{{packageName}}}.Configuration(
- signing_info = {{{packageName}}}.signing.HttpSigningConfiguration(
- key_id = 'my-key-id',
- private_key_path = 'rsa.pem',
- signing_scheme = signing.SCHEME_HS2019,
- signing_algorithm = signing.ALGORITHM_RSASSA_PSS,
- signed_headers = [signing.HEADER_REQUEST_TARGET,
- signing.HEADER_CREATED,
- signing.HEADER_EXPIRES,
- signing.HEADER_HOST,
- signing.HEADER_DATE,
- signing.HEADER_DIGEST,
- 'Content-Type',
- 'Content-Length',
- 'User-Agent'
- ],
- signature_max_validity = datetime.timedelta(minutes=5)
- )
- )
- """
-
- def __init__(self, host="https://api.osparc.io",
- api_key=None, api_key_prefix=None,
- username=None, password=None,
- signing_info=None):
- """Constructor
- """
- self.host = host
- """Default Base url
- """
- self.temp_folder_path = None
- """Temp file folder for downloading files
- """
- # Authentication Settings
- self.api_key = {}
- if api_key:
- self.api_key = api_key
- """dict to store API key(s)
- """
- self.api_key_prefix = {}
- if api_key_prefix:
- self.api_key_prefix = api_key_prefix
- """dict to store API prefix (e.g. Bearer)
- """
- self.refresh_api_key_hook = None
- """function hook to refresh API key if expired
- """
- self.username = username
- """Username for HTTP basic authentication
- """
- self.password = password
- """Password for HTTP basic authentication
- """
- if signing_info is not None:
- signing_info.host = host
- self.signing_info = signing_info
- """The HTTP signing configuration
- """
-{{#hasOAuthMethods}}
- self.access_token = ""
- """access token for OAuth/Bearer
- """
-{{/hasOAuthMethods}}
-{{^hasOAuthMethods}}
-{{#hasBearerMethods}}
- self.access_token = ""
- """access token for OAuth/Bearer
- """
-{{/hasBearerMethods}}
-{{/hasOAuthMethods}}
- self.logger = {}
- """Logging Settings
- """
- self.logger["package_logger"] = logging.getLogger("{{packageName}}")
- self.logger["urllib3_logger"] = logging.getLogger("urllib3")
- self.logger_format = '%(asctime)s %(levelname)s %(message)s'
- """Log format
- """
- self.logger_stream_handler = None
- """Log stream handler
- """
- self.logger_file_handler = None
- """Log file handler
- """
- self.logger_file = None
- """Debug file location
- """
- self.debug = False
- """Debug switch
- """
-
- self.verify_ssl = True
- """SSL/TLS verification
- Set this to false to skip verifying SSL certificate when calling API
- from https server.
- """
- self.ssl_ca_cert = None
- """Set this to customize the certificate file to verify the peer.
- """
- self.cert_file = None
- """client certificate file
- """
- self.key_file = None
- """client key file
- """
- self.assert_hostname = None
- """Set this to True/False to enable/disable SSL hostname verification.
- """
-
- {{#asyncio}}
- self.connection_pool_maxsize = 100
- """This value is passed to the aiohttp to limit simultaneous connections.
- Default values is 100, None means no-limit.
- """
- {{/asyncio}}
- {{^asyncio}}
- self.connection_pool_maxsize = multiprocessing.cpu_count() * 5
- """urllib3 connection pool's maximum number of connections saved
- per pool. urllib3 uses 1 connection as default value, but this is
- not the best value when you are making a lot of possibly parallel
- requests to the same host, which is often the case here.
- cpu_count * 5 is used as default value to increase performance.
- """
- {{/asyncio}}
-
- self.proxy = None
- """Proxy URL
- """
- self.proxy_headers = None
- """Proxy headers
- """
- self.safe_chars_for_path_param = ''
- """Safe chars for path_param
- """
- self.retries = None
- """Adding retries to override urllib3 default value 3
- """
- # Disable client side validation
- self.client_side_validation = True
-
- @property
- def logger_file(self):
- """The logger file.
-
- If the logger_file is None, then add stream handler and remove file
- handler. Otherwise, add file handler and remove stream handler.
-
- :param value: The logger_file path.
- :type: str
- """
- return self.__logger_file
-
- @logger_file.setter
- def logger_file(self, value):
- """The logger file.
-
- If the logger_file is None, then add stream handler and remove file
- handler. Otherwise, add file handler and remove stream handler.
-
- :param value: The logger_file path.
- :type: str
- """
- self.__logger_file = value
- if self.__logger_file:
- # If set logging file,
- # then add file handler and remove stream handler.
- self.logger_file_handler = logging.FileHandler(self.__logger_file)
- self.logger_file_handler.setFormatter(self.logger_formatter)
- for _, logger in six.iteritems(self.logger):
- logger.addHandler(self.logger_file_handler)
-
- @property
- def debug(self):
- """Debug status
-
- :param value: The debug status, True or False.
- :type: bool
- """
- return self.__debug
-
- @debug.setter
- def debug(self, value):
- """Debug status
-
- :param value: The debug status, True or False.
- :type: bool
- """
- self.__debug = value
- if self.__debug:
- # if debug status is True, turn on debug logging
- for _, logger in six.iteritems(self.logger):
- logger.setLevel(logging.DEBUG)
- # turn on httplib debug
- httplib.HTTPConnection.debuglevel = 1
- else:
- # if debug status is False, turn off debug logging,
- # setting log level to default `logging.WARNING`
- for _, logger in six.iteritems(self.logger):
- logger.setLevel(logging.WARNING)
- # turn off httplib debug
- httplib.HTTPConnection.debuglevel = 0
-
- @property
- def logger_format(self):
- """The logger format.
-
- The logger_formatter will be updated when sets logger_format.
-
- :param value: The format string.
- :type: str
- """
- return self.__logger_format
-
- @logger_format.setter
- def logger_format(self, value):
- """The logger format.
-
- The logger_formatter will be updated when sets logger_format.
-
- :param value: The format string.
- :type: str
- """
- self.__logger_format = value
- self.logger_formatter = logging.Formatter(self.__logger_format)
-
- def get_api_key_with_prefix(self, identifier):
- """Gets API key (with prefix if set).
-
- :param identifier: The identifier of apiKey.
- :return: The token for api key authentication.
- """
- if self.refresh_api_key_hook is not None:
- self.refresh_api_key_hook(self)
- key = self.api_key.get(identifier)
- if key:
- prefix = self.api_key_prefix.get(identifier)
- if prefix:
- return "%s %s" % (prefix, key)
- else:
- return key
-
- def get_basic_auth_token(self):
- """Gets HTTP basic authentication header (string).
-
- :return: The token for basic HTTP authentication.
- """
- username = ""
- if self.username is not None:
- username = self.username
- password = ""
- if self.password is not None:
- password = self.password
- return urllib3.util.make_headers(
- basic_auth=username + ':' + password
- ).get('authorization')
-
- def auth_settings(self):
- """Gets Auth Settings dict for api client.
-
- :return: The Auth Settings information dict.
- """
- auth = {}
-{{#authMethods}}
-{{#isApiKey}}
- if '{{keyParamName}}' in self.api_key:
- auth['{{name}}'] = {
- 'type': 'api_key',
- 'in': {{#isKeyInCookie}}'cookie'{{/isKeyInCookie}}{{#isKeyInHeader}}'header'{{/isKeyInHeader}}{{#isKeyInQuery}}'query'{{/isKeyInQuery}},
- 'key': '{{keyParamName}}',
- 'value': self.get_api_key_with_prefix('{{keyParamName}}')
- }
-{{/isApiKey}}
-{{#isBasic}}
- {{#isBasicBasic}}
- if self.username is not None and self.password is not None:
- auth['{{name}}'] = {
- 'type': 'basic',
- 'in': 'header',
- 'key': 'Authorization',
- 'value': self.get_basic_auth_token()
- }
- {{/isBasicBasic}}
- {{#isBasicBearer}}
- if self.access_token is not None:
- auth['{{name}}'] = {
- 'type': 'bearer',
- 'in': 'header',
- {{#bearerFormat}}
- 'format': '{{{.}}}',
- {{/bearerFormat}}
- 'key': 'Authorization',
- 'value': 'Bearer ' + self.access_token
- }
- {{/isBasicBearer}}
- {{#isHttpSignature}}
- if self.signing_info is not None:
- auth['{{name}}'] = {
- 'type': 'http-signature',
- 'in': 'header',
- 'key': 'Authorization',
- 'value': None # Signature headers are calculated for every HTTP request
- }
- {{/isHttpSignature}}
-{{/isBasic}}
-{{#isOAuth}}
- if self.access_token is not None:
- auth['{{name}}'] = {
- 'type': 'oauth2',
- 'in': 'header',
- 'key': 'Authorization',
- 'value': 'Bearer ' + self.access_token
- }
-{{/isOAuth}}
-{{/authMethods}}
- return auth
-
- def to_debug_report(self):
- """Gets the essential information for debugging.
-
- :return: The report for debugging.
- """
- return "Python SDK Debug Report:\n"\
- "OS: {env}\n"\
- "Python Version: {pyversion}\n"\
- "Version of the API: {{version}}\n"\
- "SDK Package Version: {{packageVersion}}".\
- format(env=sys.platform, pyversion=sys.version)
-
- def get_host_settings(self):
- """Gets an array of host settings
-
- :return: An array of host settings
- """
- return [
- {{#servers}}
- {
- 'url': "{{{url}}}",
- 'description': "{{{description}}}{{^description}}No description provided{{/description}}",
- {{#variables}}
- {{#-first}}
- 'variables': {
- {{/-first}}
- '{{{name}}}': {
- 'description': "{{{description}}}{{^description}}No description provided{{/description}}",
- 'default_value': "{{{defaultValue}}}",
- {{#enumValues}}
- {{#-first}}
- 'enum_values': [
- {{/-first}}
- "{{{.}}}"{{^-last}},{{/-last}}
- {{#-last}}
- ]
- {{/-last}}
- {{/enumValues}}
- }{{^-last}},{{/-last}}
- {{#-last}}
- }
- {{/-last}}
- {{/variables}}
- }{{^-last}},{{/-last}}
- {{/servers}}
- ]
-
- def get_host_from_settings(self, index, variables=None):
- """Gets host URL based on the index and variables
- :param index: array index of the host settings
- :param variables: hash of variable and the corresponding value
- :return: URL based on host settings
- """
- variables = {} if variables is None else variables
- servers = self.get_host_settings()
-
- try:
- server = servers[index]
- except IndexError:
- raise ValueError(
- "Invalid index {0} when selecting the host settings. "
- "Must be less than {1}".format(index, len(servers)))
-
- url = server['url']
-
- # go through variables and replace placeholders
- for variable_name, variable in server['variables'].items():
- used_value = variables.get(
- variable_name, variable['default_value'])
-
- if 'enum_values' in variable \
- and used_value not in variable['enum_values']:
- raise ValueError(
- "The variable `{0}` in the host URL has invalid value "
- "{1}. Must be {2}.".format(
- variable_name, variables[variable_name],
- variable['enum_values']))
-
- url = url.replace("{" + variable_name + "}", used_value)
-
- return url