Skip to content

Commit eaf75f3

Browse files
committed
First commit
1 parent f68a732 commit eaf75f3

20 files changed

+542
-0
lines changed

.coveragerc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[run]
2+
include=
3+
*project/*
4+
omit =
5+
venv/*

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,8 @@ ENV/
9999

100100
# mypy
101101
.mypy_cache/
102+
103+
.idea
104+
105+
pylintReport.txt
106+
db.sqlite3

.travis.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
language: python
2+
sudo: false
3+
cache: false
4+
python:
5+
- '3.6'
6+
install:
7+
- pip install -r requirements-tests.txt
8+
9+
script:
10+
- coverage erase
11+
- coverage run -m unittest
12+
after_success:
13+
- coverage combine
14+
- coveralls
15+
16+
notifications:
17+
email:
18+
- a.vara.1986@gmail.com

Dockerfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
FROM python:3.6.4-alpine3.7
2+
3+
RUN apk add --update curl gcc g++ libffi-dev openssl-dev python3-dev \
4+
&& rm -rf /var/cache/apk/*
5+
RUN ln -s /usr/include/locale.h /usr/include/xlocale.h
6+
7+
ENV PYTHONUNBUFFERED=1 ENVIRONMENT=pre APP_HOME=/microservice/
8+
9+
RUN mkdir $APP_HOME
10+
WORKDIR $APP_HOME
11+
ADD requirement*.txt $APP_HOME
12+
RUN pip install -r requirements-docker.txt
13+
ADD . $APP_HOME
14+
15+
EXPOSE 5000
16+
17+
CMD ["gunicorn", "--worker-class", "eventlet", "--workers", "8", "--log-level", "INFO", "--bind", "0.0.0.0:5000", "manage:app"]

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,23 @@
11
# microservices-scaffold
22
Barebones Python Microservices
3+
4+
[![Build Status](https://travis-ci.org/python-microservices/microservices-scaffold.svg?branch=master)](https://travis-ci.org/python-microservices/microservices-scaffold)
5+
[![Build Status](https://coveralls.io/repos/github/python-microservices/microservices-scaffold/Badge.svg?branch=master)](https://coveralls.io/repos/github/python-microservices/microservices-scaffold)
6+
[![Build Status](https://requires.io/github/python-microservices/microservices-scaffold/requirements.svg?branch=master)](https://requires.io/github/python-microservices/microservices-scaffold/requirements/?branch=master)
7+
8+
9+
10+
# Docker
11+
12+
Create and push the image
13+
14+
docker build -t template -f Dockerfile .
15+
16+
Test the image:
17+
18+
docker run -d -p 5000:5000 template
19+
20+
21+
Push to Kubernetes:
22+
23+
kubectl create -f service.yaml

manage.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# encoding: utf-8
2+
from flask_script import Manager
3+
4+
from project import create_app
5+
6+
app, db = create_app()
7+
8+
manager = Manager(app)
9+
10+
11+
@manager.command
12+
def create_db():
13+
"""Creates the db tables."""
14+
db.create_all()
15+
16+
17+
@manager.command
18+
def drop_db():
19+
"""Drops the db tables."""
20+
db.drop_all()
21+
22+
23+
if __name__ == '__main__':
24+
manager.run()

project/__init__.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# encoding: utf-8
2+
3+
import os
4+
5+
from flasgger import Swagger
6+
from flask import Flask
7+
8+
from project.config import CONFIG
9+
10+
__author__ = "Alberto Vara"
11+
__email__ = "a.vara.1986@gmail.com"
12+
__version__ = "0.0.1"
13+
14+
ENVIRONMENT = os.environ.get("ENVIRONMENT", "default")
15+
16+
SWAGGER_CONFIG = {
17+
"headers": [
18+
],
19+
"specs": [
20+
{
21+
"endpoint": 'apispec_1',
22+
"route": '{application_root}/apispec_1.json',
23+
"rule_filter": lambda rule: True, # all in
24+
"model_filter": lambda tag: True, # all in
25+
}
26+
],
27+
"info": {
28+
"title": "API ",
29+
"description": "API para...",
30+
"contact": {
31+
"responsibleOrganization": "ME",
32+
"responsibleDeveloper": "Me",
33+
"email": "me@me.com",
34+
},
35+
"version": "0.0.1"
36+
},
37+
"securityDefinitions": {
38+
"APIKeyHeader": {"type": "apiKey", "name": "Authorization", "in": "header"},
39+
},
40+
"static_url_path": "{application_root}/flasgger_static",
41+
"swagger_ui": True,
42+
"uiversion": 2,
43+
"specs_route": "/apidocs/",
44+
"basePath": "{application_root}"
45+
}
46+
47+
48+
class PrefixMiddleware(object):
49+
50+
def __init__(self, app, prefix=''):
51+
self.app = app
52+
self.prefix = prefix
53+
54+
def __call__(self, environ, start_response):
55+
56+
if environ['PATH_INFO'].startswith(self.prefix):
57+
environ['PATH_INFO'] = environ['PATH_INFO'][len(self.prefix):]
58+
environ['SCRIPT_NAME'] = self.prefix
59+
return self.app(environ, start_response)
60+
else:
61+
start_response('404', [('Content-Type', 'text/plain')])
62+
return ["This url does not belong to the app.".encode()]
63+
64+
65+
def create_app():
66+
from project.models import db
67+
from project.views import views_bp as views_blueprint
68+
environment = os.environ.get("ENVIRONMENT", "default")
69+
70+
app = Flask(__name__)
71+
app.config.from_object(CONFIG[environment])
72+
app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix=app.config["APPLICATION_ROOT"])
73+
74+
db.init_app(app)
75+
76+
SWAGGER_CONFIG["specs"][0]["route"] = SWAGGER_CONFIG["specs"][0]["route"].format(
77+
application_root=app.config["APPLICATION_ROOT"]
78+
)
79+
SWAGGER_CONFIG["static_url_path"] = SWAGGER_CONFIG["static_url_path"].format(
80+
application_root=app.config["APPLICATION_ROOT"]
81+
)
82+
SWAGGER_CONFIG["specs_route"] = SWAGGER_CONFIG["specs_route"].format(
83+
application_root=app.config["APPLICATION_ROOT"]
84+
)
85+
SWAGGER_CONFIG["basePath"] = SWAGGER_CONFIG["basePath"].format(
86+
application_root=app.config["APPLICATION_ROOT"]
87+
)
88+
Swagger(app, config=SWAGGER_CONFIG)
89+
90+
app.register_blueprint(views_blueprint)
91+
with app.test_request_context():
92+
db.create_all()
93+
return app, db

project/config.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# coding=utf-8
2+
import os
3+
4+
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
5+
6+
7+
class Config:
8+
"""Default configuration for all environments"""
9+
10+
DEBUG = False
11+
TESTING = False
12+
APP_NAME = "Template"
13+
APPLICATION_ROOT = "/template"
14+
SQLALCHEMY_TRACK_MODIFICATIONS = True
15+
SECRET_KEY = os.environ.get("SECRET_KEY") or "gjr39dkjn344_!67#"
16+
17+
18+
class TestConfig(Config):
19+
"""Configuration to run tests"""
20+
21+
DEBUG = True
22+
TESTING = True
23+
DATABASE = os.path.join(BASE_DIR, "db_test.sqlite3")
24+
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR, "db_test.sqlite3")
25+
26+
27+
class DevConfig(Config):
28+
"""Configuration to run in local environments"""
29+
30+
DEBUG = True
31+
TESTING = True
32+
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR, "db.sqlite3")
33+
34+
35+
class PreConfig(Config):
36+
"""Configuration to run with docker and kubernetes in Preproduction"""
37+
SQLALCHEMY_TRACK_MODIFICATIONS = False
38+
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR, "db.sqlite3")
39+
40+
41+
class ProdConfig(Config):
42+
"""Configuration to run with docker and kubernetes in Production"""
43+
SQLALCHEMY_TRACK_MODIFICATIONS = False
44+
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR, "prod.db")
45+
46+
47+
CONFIG = {
48+
"test": TestConfig,
49+
"dev": DevConfig,
50+
"pre": PreConfig,
51+
"prod": ProdConfig,
52+
"default": DevConfig
53+
}

project/models/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# encoding: utf-8
2+
from __future__ import absolute_import, print_function, unicode_literals
3+
4+
from flask_sqlalchemy import SQLAlchemy
5+
6+
db = SQLAlchemy()

project/models/models.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# encoding: utf-8
2+
from __future__ import absolute_import, print_function, unicode_literals
3+
4+
import datetime
5+
6+
from sqlalchemy import Column, Integer, String, DateTime
7+
8+
from project.models import db
9+
10+
11+
def dump_datetime(value: datetime) -> list:
12+
"""Deserialize datetime object into string form for JSON processing."""
13+
return [value.strftime("%Y-%m-%d"), value.strftime("%H:%M:%S")]
14+
15+
16+
class Colors(db.Model):
17+
"""Example model"""
18+
__tablename__ = 'colors'
19+
20+
id = Column(Integer, primary_key=True, autoincrement=True)
21+
name = Column(String, nullable=False)
22+
timestamp = Column(DateTime, default=datetime.datetime.now)
23+
24+
@property
25+
def serialize(self) -> dict:
26+
"""Return object data in easily serializeable format"""
27+
return {
28+
'id': self.id,
29+
'timestamp': dump_datetime(self.timestamp),
30+
'name': self.name,
31+
}

0 commit comments

Comments
 (0)