diff --git a/python-flask-server/.gitignore b/python-flask-server/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..a655050c2631466828b5b8bfc59ae27f9ac02dc5 --- /dev/null +++ b/python-flask-server/.gitignore @@ -0,0 +1,64 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ +venv/ +.python-version + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +#Ipython Notebook +.ipynb_checkpoints diff --git a/python-flask-server/.swagger-codegen-ignore b/python-flask-server/.swagger-codegen-ignore new file mode 100644 index 0000000000000000000000000000000000000000..c5fa491b4c557bf997d5dd21797de782545dc9e5 --- /dev/null +++ b/python-flask-server/.swagger-codegen-ignore @@ -0,0 +1,23 @@ +# Swagger Codegen Ignore +# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen + +# Use this file to prevent files from being overwritten by the generator. +# The patterns follow closely to .gitignore or .dockerignore. + +# As an example, the C# client generator defines ApiClient.cs. +# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line: +#ApiClient.cs + +# You can match any string of characters against a directory, file or extension with a single asterisk (*): +#foo/*/qux +# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux + +# You can recursively match patterns against a directory, file or extension with a double asterisk (**): +#foo/**/qux +# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux + +# You can also negate patterns with an exclamation (!). +# For example, you can ignore all files in a docs folder with the file extension .md: +#docs/*.md +# Then explicitly reverse the ignore rule for a single file: +#!docs/README.md diff --git a/python-flask-server/.travis.yml b/python-flask-server/.travis.yml new file mode 100644 index 0000000000000000000000000000000000000000..dd6c4450aa902ae68479c3d76d45145e18d6052e --- /dev/null +++ b/python-flask-server/.travis.yml @@ -0,0 +1,13 @@ +# ref: https://docs.travis-ci.com/user/languages/python +language: python +python: + - "3.2" + - "3.3" + - "3.4" + - "3.5" + #- "3.5-dev" # 3.5 development branch + #- "nightly" # points to the latest development branch e.g. 3.6-dev +# command to install dependencies +install: "pip install -r requirements.txt" +# command to run tests +script: nosetests diff --git a/python-flask-server/README.md b/python-flask-server/README.md new file mode 100644 index 0000000000000000000000000000000000000000..323aaee2ae6b1e0c241e9cf9e86f83d66c29a04f --- /dev/null +++ b/python-flask-server/README.md @@ -0,0 +1,33 @@ +# Swagger generated server + +## Overview +This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project. By using the +[OpenAPI-Spec](https://github.com/swagger-api/swagger-core/wiki) from a remote server, you can easily generate a server stub. This +is an example of building a swagger-enabled Flask server. + +This example uses the [Connexion](https://github.com/zalando/connexion) library on top of Flask. + +To run the server, please execute the following from the root directory: + +``` +pip3 install -r requirements.txt +python3 -m swagger_server +``` + +and open your browser to here: + +``` +http://localhost:8080/ui/ +``` + +Your Swagger definition lives here: + +``` +http://localhost:8080/swagger.json +``` + +To launch the integration tests, use tox: +``` +sudo pip install tox +tox +``` diff --git a/python-flask-server/git_push.sh b/python-flask-server/git_push.sh new file mode 100644 index 0000000000000000000000000000000000000000..6ca091b49d95e3553ca74febd220e1ff1873eb8a --- /dev/null +++ b/python-flask-server/git_push.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# ref: https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/ +# +# Usage example: /bin/sh ./git_push.sh wing328 swagger-petstore-perl "minor update" + +git_user_id=$1 +git_repo_id=$2 +release_note=$3 + +if [ "$git_user_id" = "" ]; then + git_user_id="" + echo "[INFO] No command line input provided. Set \$git_user_id to $git_user_id" +fi + +if [ "$git_repo_id" = "" ]; then + git_repo_id="" + echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" +fi + +if [ "$release_note" = "" ]; then + release_note="" + echo "[INFO] No command line input provided. Set \$release_note to $release_note" +fi + +# Initialize the local directory as a Git repository +git init + +# Adds the files in the local repository and stages them for commit. +git add . + +# Commits the tracked changes and prepares them to be pushed to a remote repository. +git commit -m "$release_note" + +# Sets the new remote +git_remote=`git remote` +if [ "$git_remote" = "" ]; then # git remote not defined + + if [ "$GIT_TOKEN" = "" ]; then + echo "[INFO] \$GIT_TOKEN (environment variable) is not set. Using the git crediential in your environment." + git remote add origin https://github.com/${git_user_id}/${git_repo_id}.git + else + git remote add origin https://${git_user_id}:${GIT_TOKEN}@github.com/${git_user_id}/${git_repo_id}.git + fi + +fi + +git pull origin master + +# Pushes (Forces) the changes in the local repository up to the remote repository +echo "Git pushing to https://github.com/${git_user_id}/${git_repo_id}.git" +git push origin master 2>&1 | grep -v 'To https' + diff --git a/python-flask-server/requirements.txt b/python-flask-server/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..995dc64d6559ef7a5adec5e2047b827d7819e147 --- /dev/null +++ b/python-flask-server/requirements.txt @@ -0,0 +1,3 @@ +connexion == 1.0.129 +python_dateutil == 2.6.0 +setuptools >= 21.0.0 diff --git a/python-flask-server/setup.py b/python-flask-server/setup.py new file mode 100644 index 0000000000000000000000000000000000000000..1d08c48ed3fc83b61cab84bb758dcf9b7e18131f --- /dev/null +++ b/python-flask-server/setup.py @@ -0,0 +1,33 @@ +# coding: utf-8 + +import sys +from setuptools import setup, find_packages + +NAME = "swagger_server" +VERSION = "1.0.0" + +# To install the library, run the following +# +# python setup.py install +# +# prerequisite: setuptools +# http://pypi.python.org/pypi/setuptools + +REQUIRES = ["connexion"] + +setup( + name=NAME, + version=VERSION, + description="PCMAWeb API Specification", + author_email="", + url="", + keywords=["Swagger", "PCMAWeb API Specification"], + install_requires=REQUIRES, + packages=find_packages(), + package_data={'': ['swagger/swagger.yaml']}, + include_package_data=True, + long_description="""\ + No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) + """ +) + diff --git a/python-flask-server/swagger_server/__init__.py b/python-flask-server/swagger_server/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/python-flask-server/swagger_server/__main__.py b/python-flask-server/swagger_server/__main__.py new file mode 100644 index 0000000000000000000000000000000000000000..d0bb8478eada47bfdd6f591f68b3dbb56e118231 --- /dev/null +++ b/python-flask-server/swagger_server/__main__.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 + +import connexion +from .encoder import JSONEncoder + + +if __name__ == '__main__': + app = connexion.App(__name__, specification_dir='./swagger/') + app.app.json_encoder = JSONEncoder + app.add_api('swagger.yaml', arguments={'title': 'No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)'}) + app.run(port=8080) diff --git a/python-flask-server/swagger_server/controllers/__init__.py b/python-flask-server/swagger_server/controllers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/python-flask-server/swagger_server/controllers/default_controller.py b/python-flask-server/swagger_server/controllers/default_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..9939484a1eaa03789927daecc440ce7276428b1e --- /dev/null +++ b/python-flask-server/swagger_server/controllers/default_controller.py @@ -0,0 +1,82 @@ +import connexion +from swagger_server.models.phenotype import Phenotype +from datetime import date, datetime +from typing import List, Dict +from six import iteritems +from ..util import deserialize_date, deserialize_datetime + + +def phenotypes_get(): + """ + phenotypes_get + Gets the list of available phenotypes + + :rtype: List[Phenotype] + """ + return 'do some magic!' + + +def projects_get(): + """ + projects_get + Gets `Project` characteristics (listed phenotypes). + + :rtype: List[Phenotype] + """ + return 'do some magic!' + + +def projects_post(phenotypeID): + """ + projects_post + Create a new project from a selection of phenotypes + :param phenotypeID: IDs of the phenotypes selected for the project + :type phenotypeID: List[str] + + :rtype: str + """ + return 'do some magic!' + + +def projects_project_id_datazoom_get(projectID, threshold=None, start_pos=None, end_pos=None): + """ + projects_project_id_datazoom_get + Manhattan plot and heatmap data + :param projectID: project ID + :type projectID: str + :param threshold: significance threshold for the SNPs + :type threshold: float + :param start_pos: start position for the SNPs + :type start_pos: float + :param end_pos: end position for the SNPs + :type end_pos: float + + :rtype: str + """ + return 'do some magic!' + + +def projects_project_id_genome_get(projectID, threshold=None): + """ + projects_project_id_genome_get + Retrieve genome panel data for a given project + :param projectID: project ID + :type projectID: str + :param threshold: significance threshold for the SNPs + :type threshold: float + + :rtype: str + """ + return 'do some magic!' + + +def projects_project_idget(projectID): + """ + projects_project_idget + Retrieve a project definition + :param projectID: project ID + :type projectID: str + + :rtype: Phenotype + """ + return 'do some magic!' diff --git a/python-flask-server/swagger_server/encoder.py b/python-flask-server/swagger_server/encoder.py new file mode 100644 index 0000000000000000000000000000000000000000..90988e4d3eaa78f769c3a6ee06877a2fc52bfcb3 --- /dev/null +++ b/python-flask-server/swagger_server/encoder.py @@ -0,0 +1,19 @@ +from connexion.decorators import produces +from six import iteritems +from swagger_server.models.base_model_ import Model + + +class JSONEncoder(produces.JSONEncoder): + include_nulls = False + + def default(self, o): + if isinstance(o, Model): + dikt = {} + for attr, _ in iteritems(o.swagger_types): + value = getattr(o, attr) + if value is None and not self.include_nulls: + continue + attr = o.attribute_map[attr] + dikt[attr] = value + return dikt + return produces.JSONEncoder.default(self, o) \ No newline at end of file diff --git a/python-flask-server/swagger_server/models/__init__.py b/python-flask-server/swagger_server/models/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..1244184bd359fd5d073719b753250d632380909e --- /dev/null +++ b/python-flask-server/swagger_server/models/__init__.py @@ -0,0 +1,5 @@ +# coding: utf-8 + +from __future__ import absolute_import +# import models into model package +from .phenotype import Phenotype diff --git a/python-flask-server/swagger_server/models/base_model_.py b/python-flask-server/swagger_server/models/base_model_.py new file mode 100644 index 0000000000000000000000000000000000000000..5202b30fb63da1879343e51ef9c6ebcf54ce8349 --- /dev/null +++ b/python-flask-server/swagger_server/models/base_model_.py @@ -0,0 +1,75 @@ +from pprint import pformat +from typing import TypeVar, Type +from six import iteritems +from ..util import deserialize_model + +T = TypeVar('T') + + +class Model(object): + # swaggerTypes: The key is attribute name and the value is attribute type. + swagger_types = {} + + # attributeMap: The key is attribute name and the value is json key in definition. + attribute_map = {} + + @classmethod + def from_dict(cls: Type[T], dikt) -> T: + """ + Returns the dict as a model + """ + return deserialize_model(dikt, cls) + + def to_dict(self): + """ + Returns the model properties as a dict + + :rtype: dict + """ + result = {} + + for attr, _ in iteritems(self.swagger_types): + value = getattr(self, attr) + if isinstance(value, list): + result[attr] = list(map( + lambda x: x.to_dict() if hasattr(x, "to_dict") else x, + value + )) + elif hasattr(value, "to_dict"): + result[attr] = value.to_dict() + elif isinstance(value, dict): + result[attr] = dict(map( + lambda item: (item[0], item[1].to_dict()) + if hasattr(item[1], "to_dict") else item, + value.items() + )) + else: + result[attr] = value + + return result + + def to_str(self): + """ + Returns the string representation of the model + + :rtype: str + """ + return pformat(self.to_dict()) + + def __repr__(self): + """ + For `print` and `pprint` + """ + return self.to_str() + + def __eq__(self, other): + """ + Returns true if both objects are equal + """ + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + """ + Returns true if both objects are not equal + """ + return not self == other \ No newline at end of file diff --git a/python-flask-server/swagger_server/models/phenotype.py b/python-flask-server/swagger_server/models/phenotype.py new file mode 100644 index 0000000000000000000000000000000000000000..ab8b18118d8f755e8c9cdc8180ebe8331b250050 --- /dev/null +++ b/python-flask-server/swagger_server/models/phenotype.py @@ -0,0 +1,90 @@ +# coding: utf-8 + +from __future__ import absolute_import +from .base_model_ import Model +from datetime import date, datetime +from typing import List, Dict +from ..util import deserialize_model + + +class Phenotype(Model): + """ + NOTE: This class is auto generated by the swagger code generator program. + Do not edit the class manually. + """ + def __init__(self, id: str=None, label: str=None): + """ + Phenotype - a model defined in Swagger + + :param id: The id of this Phenotype. + :type id: str + :param label: The label of this Phenotype. + :type label: str + """ + self.swagger_types = { + 'id': str, + 'label': str + } + + self.attribute_map = { + 'id': 'id', + 'label': 'label' + } + + self._id = id + self._label = label + + @classmethod + def from_dict(cls, dikt) -> 'Phenotype': + """ + Returns the dict as a model + + :param dikt: A dict. + :type: dict + :return: The Phenotype of this Phenotype. + :rtype: Phenotype + """ + return deserialize_model(dikt, cls) + + @property + def id(self) -> str: + """ + Gets the id of this Phenotype. + + :return: The id of this Phenotype. + :rtype: str + """ + return self._id + + @id.setter + def id(self, id: str): + """ + Sets the id of this Phenotype. + + :param id: The id of this Phenotype. + :type id: str + """ + + self._id = id + + @property + def label(self) -> str: + """ + Gets the label of this Phenotype. + + :return: The label of this Phenotype. + :rtype: str + """ + return self._label + + @label.setter + def label(self, label: str): + """ + Sets the label of this Phenotype. + + :param label: The label of this Phenotype. + :type label: str + """ + + self._label = label + diff --git a/python-flask-server/swagger_server/swagger/swagger.yaml b/python-flask-server/swagger_server/swagger/swagger.yaml new file mode 100644 index 0000000000000000000000000000000000000000..91eb9a0411aa67eb76d267a5d84b3662fcaec032 --- /dev/null +++ b/python-flask-server/swagger_server/swagger/swagger.yaml @@ -0,0 +1,138 @@ +--- +swagger: "2.0" +info: + version: "0.0.0" + title: "PCMAWeb API Specification" +paths: + /phenotypes: + get: + description: "Gets the list of available phenotypes\n" + operationId: "phenotypes_get" + parameters: [] + responses: + 200: + description: "List of the available phenotypes" + schema: + type: "array" + title: "ArrayOfPhenotypes" + items: + $ref: "#/definitions/Phenotype" + x-swagger-router-controller: "swagger_server.controllers.default_controller" + /projects: + get: + description: "Gets `Project` characteristics (listed phenotypes).\n" + operationId: "projects_get" + parameters: [] + responses: + 200: + description: "Retrieved project" + schema: + type: "array" + title: "ArrayOfPhenotypes" + items: + $ref: "#/definitions/Phenotype" + x-swagger-router-controller: "swagger_server.controllers.default_controller" + post: + description: "Create a new project from a selection of phenotypes\n" + operationId: "projects_post" + parameters: + - name: "phenotypeID" + in: "formData" + description: "IDs of the phenotypes selected for the project" + required: true + type: "array" + items: + type: "string" + collectionFormat: "multi" + responses: + 200: + description: "Project created" + schema: + type: "string" + title: "ProjectID" + x-swagger-router-controller: "swagger_server.controllers.default_controller" + /projects/{projectID}: + get: + description: "Retrieve a project definition\n" + operationId: "projects_project_idget" + parameters: + - name: "projectID" + in: "path" + description: "project ID" + required: true + type: "string" + responses: + 200: + description: "Retrieved project" + schema: + $ref: "#/definitions/Phenotype" + x-swagger-router-controller: "swagger_server.controllers.default_controller" + /projects/{projectID}/genome: + get: + description: "Retrieve genome panel data for a given project\n" + operationId: "projects_project_id_genome_get" + produces: + - "text/tab-separated-values; charset=utf-8" + parameters: + - name: "projectID" + in: "path" + description: "project ID" + required: true + type: "string" + - name: "threshold" + in: "query" + description: "significance threshold for the SNPs" + required: false + type: "number" + responses: + 200: + description: "Genome panel data in TSV format, where each column is position:chrid:p-value\n" + schema: + type: "string" + title: "Genome panel data" + x-swagger-router-controller: "swagger_server.controllers.default_controller" + /projects/{projectID}/datazoom: + get: + description: "Manhattan plot and heatmap data\n" + operationId: "projects_project_id_datazoom_get" + produces: + - "text/tab-separated-values; charset=utf-8" + parameters: + - name: "projectID" + in: "path" + description: "project ID" + required: true + type: "string" + - name: "threshold" + in: "query" + description: "significance threshold for the SNPs" + required: false + type: "number" + - name: "start_pos" + in: "query" + description: "start position for the SNPs" + required: false + type: "number" + - name: "end_pos" + in: "query" + description: "end position for the SNPs" + required: false + type: "number" + responses: + 200: + description: "Manhattan plot and heatmap data in TSV format\nEach line is\ + \ a SNP with the first column containing the SNP ID, the second the Chromosome\ + \ ID and the third the position (absolute or relative in the chromosome?),\ + \ the fourth the joint statistic, and the 5th and following columns the\ + \ phenotype-specific statistics.\n" + schema: + type: "string" + title: "Manhattan plot/Heatmap data" + x-swagger-router-controller: "swagger_server.controllers.default_controller" +definitions: + Phenotype: + properties: + id: + type: "string" + label: + type: "string" diff --git a/python-flask-server/swagger_server/test/__init__.py b/python-flask-server/swagger_server/test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..77b10c3a012f7114a239d6816f79036d21f49efa --- /dev/null +++ b/python-flask-server/swagger_server/test/__init__.py @@ -0,0 +1,14 @@ +from flask_testing import TestCase +from ..encoder import JSONEncoder +import connexion +import logging + + +class BaseTestCase(TestCase): + + def create_app(self): + logging.getLogger('connexion.operation').setLevel('ERROR') + app = connexion.App(__name__, specification_dir='../swagger/') + app.app.json_encoder = JSONEncoder + app.add_api('swagger.yaml') + return app.app diff --git a/python-flask-server/swagger_server/test/test_default_controller.py b/python-flask-server/swagger_server/test/test_default_controller.py new file mode 100644 index 0000000000000000000000000000000000000000..0a193be77f837a07972fc5be2f113e816201f7a0 --- /dev/null +++ b/python-flask-server/swagger_server/test/test_default_controller.py @@ -0,0 +1,85 @@ +# coding: utf-8 + +from __future__ import absolute_import + +from swagger_server.models.phenotype import Phenotype +from . import BaseTestCase +from six import BytesIO +from flask import json + + +class TestDefaultController(BaseTestCase): + """ DefaultController integration test stubs """ + + def test_phenotypes_get(self): + """ + Test case for phenotypes_get + + + """ + response = self.client.open('/phenotypes', + method='GET') + self.assert200(response, "Response body is : " + response.data.decode('utf-8')) + + def test_projects_get(self): + """ + Test case for projects_get + + + """ + response = self.client.open('/projects', + method='GET') + self.assert200(response, "Response body is : " + response.data.decode('utf-8')) + + def test_projects_post(self): + """ + Test case for projects_post + + + """ + data = dict(phenotypeID='phenotypeID_example') + response = self.client.open('/projects', + method='POST', + data=data) + self.assert200(response, "Response body is : " + response.data.decode('utf-8')) + + def test_projects_project_id_datazoom_get(self): + """ + Test case for projects_project_id_datazoom_get + + + """ + query_string = [('threshold', 3.4), + ('start_pos', 3.4), + ('end_pos', 3.4)] + response = self.client.open('/projects/{projectID}/datazoom'.format(projectID='projectID_example'), + method='GET', + query_string=query_string) + self.assert200(response, "Response body is : " + response.data.decode('utf-8')) + + def test_projects_project_id_genome_get(self): + """ + Test case for projects_project_id_genome_get + + + """ + query_string = [('threshold', 3.4)] + response = self.client.open('/projects/{projectID}/genome'.format(projectID='projectID_example'), + method='GET', + query_string=query_string) + self.assert200(response, "Response body is : " + response.data.decode('utf-8')) + + def test_projects_project_idget(self): + """ + Test case for projects_project_idget + + + """ + response = self.client.open('/projects/{projectID}'.format(projectID='projectID_example'), + method='GET') + self.assert200(response, "Response body is : " + response.data.decode('utf-8')) + + +if __name__ == '__main__': + import unittest + unittest.main() diff --git a/python-flask-server/swagger_server/util.py b/python-flask-server/swagger_server/util.py new file mode 100644 index 0000000000000000000000000000000000000000..40c72d43ebd26285cc5602aed924ff166ff69354 --- /dev/null +++ b/python-flask-server/swagger_server/util.py @@ -0,0 +1,149 @@ +from typing import GenericMeta +from datetime import datetime, date +from six import integer_types, iteritems + + +def _deserialize(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 klass in integer_types or klass in (float, str, bool): + return _deserialize_primitive(data, klass) + elif klass == object: + return _deserialize_object(data) + elif klass == date: + return deserialize_date(data) + elif klass == datetime: + return deserialize_datetime(data) + elif type(klass) == GenericMeta: + if klass.__extra__ == list: + return _deserialize_list(data, klass.__args__[0]) + if klass.__extra__ == dict: + return _deserialize_dict(data, klass.__args__[1]) + else: + return deserialize_model(data, klass) + + +def _deserialize_primitive(data, klass): + """ + Deserializes to primitive type. + + :param data: data to deserialize. + :param klass: class literal. + + :return: int, long, float, str, bool. + :rtype: int | long | float | str | bool + """ + try: + value = klass(data) + except UnicodeEncodeError: + value = unicode(data) + except TypeError: + value = data + return value + + +def _deserialize_object(value): + """ + Return a original value. + + :return: object. + """ + return value + + +def deserialize_date(string): + """ + Deserializes string to date. + + :param string: str. + :type string: str + :return: date. + :rtype: date + """ + try: + from dateutil.parser import parse + return parse(string).date() + except ImportError: + return string + + +def deserialize_datetime(string): + """ + Deserializes string to datetime. + + The string should be in iso8601 datetime format. + + :param string: str. + :type string: str + :return: datetime. + :rtype: datetime + """ + try: + from dateutil.parser import parse + return parse(string) + except ImportError: + return string + + +def deserialize_model(data, klass): + """ + Deserializes list or dict to model. + + :param data: dict, list. + :type data: dict | list + :param klass: class literal. + :return: model object. + """ + instance = klass() + + if not instance.swagger_types: + return data + + for attr, attr_type in iteritems(instance.swagger_types): + if data is not None \ + and instance.attribute_map[attr] in data \ + and isinstance(data, (list, dict)): + value = data[instance.attribute_map[attr]] + setattr(instance, attr, _deserialize(value, attr_type)) + + return instance + + +def _deserialize_list(data, boxed_type): + """ + Deserializes a list and its elements. + + :param data: list to deserialize. + :type data: list + :param boxed_type: class literal. + + :return: deserialized list. + :rtype: list + """ + return [_deserialize(sub_data, boxed_type) + for sub_data in data] + + + +def _deserialize_dict(data, boxed_type): + """ + Deserializes a dict and its elements. + + :param data: dict to deserialize. + :type data: dict + :param boxed_type: class literal. + + :return: deserialized dict. + :rtype: dict + """ + return {k: _deserialize(v, boxed_type) + for k, v in iteritems(data)} diff --git a/python-flask-server/test-requirements.txt b/python-flask-server/test-requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..7f8d96e6b40e853d658f88fa745ddcf37ff7644c --- /dev/null +++ b/python-flask-server/test-requirements.txt @@ -0,0 +1,6 @@ +flask_testing==0.6.1 +coverage>=4.0.3 +nose>=1.3.7 +pluggy>=0.3.1 +py>=1.4.31 +randomize>=0.13 diff --git a/python-flask-server/tox.ini b/python-flask-server/tox.ini new file mode 100644 index 0000000000000000000000000000000000000000..b696749b3a16ef32084d3516efa7628d128e981e --- /dev/null +++ b/python-flask-server/tox.ini @@ -0,0 +1,10 @@ +[tox] +envlist = py35 + +[testenv] +deps=-r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt + +commands= + nosetests \ + [] \ No newline at end of file