From c725c201a741a56fa2e3026d1b870cfb7eab76f4 Mon Sep 17 00:00:00 2001 From: marcsello Date: Mon, 13 Apr 2020 21:14:06 +0200 Subject: [PATCH] Initial commit --- .gitignore | 8 +++++ Dockerfile | 10 ++++++ model_service/app.py | 40 +++++++++++++++++++++++ model_service/model/__init__.py | 2 ++ model_service/model/db.py | 5 +++ model_service/schemas/__init__.py | 2 ++ model_service/tests/__init__.py | 1 + model_service/utils/__init__.py | 3 ++ model_service/utils/error_handlers.py | 18 ++++++++++ model_service/utils/require_decorators.py | 16 +++++++++ model_service/views/__init__.py | 2 ++ model_service/views/model_view.py | 27 +++++++++++++++ requirements-dev.txt | 1 + requirements.txt | 11 +++++++ 14 files changed, 146 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 model_service/app.py create mode 100644 model_service/model/__init__.py create mode 100644 model_service/model/db.py create mode 100644 model_service/schemas/__init__.py create mode 100644 model_service/tests/__init__.py create mode 100644 model_service/utils/__init__.py create mode 100644 model_service/utils/error_handlers.py create mode 100644 model_service/utils/require_decorators.py create mode 100644 model_service/views/__init__.py create mode 100644 model_service/views/model_view.py create mode 100644 requirements-dev.txt create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53fd5d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.swp +venv +*.pyc +__pycache__/* +__pycache__ +*.wpr +*.log +.idea diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b2dd1c4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3 + +ADD model_service requirements.txt /model_service/ +WORKDIR /model_service/ + +RUN pip3 install -r requirements.txt && pip3 install gunicorn + +EXPOSE 8000 +CMD ["gunicorn", "-b", "0.0.0.0:8000", "app:app"] + diff --git a/model_service/app.py b/model_service/app.py new file mode 100644 index 0000000..d53e41f --- /dev/null +++ b/model_service/app.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +import os +from flask import Flask +from werkzeug.middleware.proxy_fix import ProxyFix + +# import stuff +from model import db + +from utils import register_all_error_handlers + +# import views +from views import ModelView + +# create flask app +app = Flask(__name__) +app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1) +# configure flask app +app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URI', "sqlite://") # Default to memory db + +# important stuff +app.secret_key = os.environ.get('SECRET_KEY', os.urandom(12)) +# disable this for better performance +app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + +# initialize stuff +db.init_app(app) + +with app.app_context(): + db.create_all() + +# register error handlers +register_all_error_handlers(app) + +# register views +for view in [ModelView]: + view.register(app, trailing_slash=False) + +# start debuggig if needed +if __name__ == "__main__": + app.run(debug=True) diff --git a/model_service/model/__init__.py b/model_service/model/__init__.py new file mode 100644 index 0000000..a1ba3ea --- /dev/null +++ b/model_service/model/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 +from .db import db diff --git a/model_service/model/db.py b/model_service/model/db.py new file mode 100644 index 0000000..52b24e8 --- /dev/null +++ b/model_service/model/db.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 +from flask_sqlalchemy import SQLAlchemy + +db = SQLAlchemy() + diff --git a/model_service/schemas/__init__.py b/model_service/schemas/__init__.py new file mode 100644 index 0000000..63f77b6 --- /dev/null +++ b/model_service/schemas/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 + diff --git a/model_service/tests/__init__.py b/model_service/tests/__init__.py new file mode 100644 index 0000000..21b405d --- /dev/null +++ b/model_service/tests/__init__.py @@ -0,0 +1 @@ +import os diff --git a/model_service/utils/__init__.py b/model_service/utils/__init__.py new file mode 100644 index 0000000..6c6531e --- /dev/null +++ b/model_service/utils/__init__.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python3 +from .require_decorators import json_required +from .error_handlers import register_all_error_handlers diff --git a/model_service/utils/error_handlers.py b/model_service/utils/error_handlers.py new file mode 100644 index 0000000..959f8ae --- /dev/null +++ b/model_service/utils/error_handlers.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + + +def get_standard_error_handler(code: int): + def error_handler(err): + return {"msg": str(err)}, code + + return error_handler + + +# function to register all handlers + + +def register_all_error_handlers(app): + error_codes_to_override = [404, 403, 401, 405, 400, 409, 422] + + for code in error_codes_to_override: + app.register_error_handler(code, get_standard_error_handler(code)) diff --git a/model_service/utils/require_decorators.py b/model_service/utils/require_decorators.py new file mode 100644 index 0000000..ba5b9ab --- /dev/null +++ b/model_service/utils/require_decorators.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +from flask import request, current_app, abort + +from functools import wraps + + +def json_required(f): + @wraps(f) + def call(*args, **kwargs): + + if request.is_json: + return f(*args, **kwargs) + else: + abort(400, "JSON required") + + return call diff --git a/model_service/views/__init__.py b/model_service/views/__init__.py new file mode 100644 index 0000000..dd055a1 --- /dev/null +++ b/model_service/views/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 +from .model_view import ModelView diff --git a/model_service/views/model_view.py b/model_service/views/model_view.py new file mode 100644 index 0000000..7628171 --- /dev/null +++ b/model_service/views/model_view.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +from flask import request, jsonify +from flask_classful import FlaskView, route +from model import db +from utils import json_required + +import requests.exceptions + + +class ModelView(FlaskView): + + def post(self): + return jsonify({}) + + def get(self, _id: str): + return jsonify({"id": _id}) + + @route('<_id>/details') + def get_details(self, _id: str): + return jsonify({"id": _id}) + + def delete(self, _id: str): + return jsonify({"id": _id}) + + @route('$default', methods=['PUT']) + def put_default(self): + return jsonify({}) diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..e079f8a --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1 @@ +pytest diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9de5b90 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,11 @@ +requests +blinker +Flask +marshmallow +Flask-Classful +Flask-SQLAlchemy +SQLAlchemy-Utils +SQLAlchemy +marshmallow-sqlalchemy +psycopg2-binary +