From 1009968ea0ca43ef1b1bc421f7694f1f70707948 Mon Sep 17 00:00:00 2001 From: Galen Guyer Date: Sat, 31 Oct 2020 11:58:32 -0400 Subject: Initial commit --- .gitignore | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ .pylintrc | 6 +++ .travis.yml | 12 +++++ Dockerfile | 16 +++++++ LICENCE.txt | 19 ++++++++ README.md | 27 ++++++++++++ config.env.py | 17 +++++++ demo/__init__.py | 20 +++++++++ requirements.txt | 4 ++ wsgi.py | 8 ++++ 10 files changed, 261 insertions(+) create mode 100644 .gitignore create mode 100644 .pylintrc create mode 100644 .travis.yml create mode 100644 Dockerfile create mode 100644 LICENCE.txt create mode 100644 README.md create mode 100644 config.env.py create mode 100644 demo/__init__.py create mode 100644 requirements.txt create mode 100644 wsgi.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68504eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,132 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# 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/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# Don't commit secrets! +config.py diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..3660be0 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,6 @@ +[MASTER] +persistent = yes +load-plugins = pylint_quotes + +[FORMAT] +output-format = colorized diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7e891f8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: python +python: + - "3.8" +services: + - "docker" + +install: + - "pip install -r requirements.txt" +script: + - "pylint demo" + - "docker build -t demo ." + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..194a42a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM python:3.8-alpine +MAINTAINER Galen Guyer + +RUN mkdir /opt/demo + +ADD requirements.txt /opt/demo + +WORKDIR /opt/demo + +RUN pip install -r requirements.txt + +ADD . /opt/demo + +RUN ln -sf /usr/share/zoneinfo/America/New_York /etc/localtime + +CMD ["gunicorn", "demo:APP", "--bind=0.0.0.0:8080", "--access-logfile=-"] diff --git a/LICENCE.txt b/LICENCE.txt new file mode 100644 index 0000000..4457e5d --- /dev/null +++ b/LICENCE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2020 Galen Guyer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7919b4f --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +# Flask wsgi bootstrap/demo + +This demo shows the use of gunicorn with flask. Original credit goes to [Max Meinhold](https://github.com/mxmeinhold/flask-gunicorn-demo). +It includes a basic Dockerfile, a linting demonstration using Pylint, and a Travis CI configuration for running linting. + +This is not an in depth guide in how these tools work, but a basic starting point and reference. + +Make sure to change my name and email if you use this template, especially in the license. + + +## Setup +Locally running this application should be pretty simple. + +1. (optional) Use a virtualenv + * Why use a venv? It isolates your dependencies and helps prevent version conflicts with other projects or system dependencies. + 1. `python3 -m venv venv` will create a venv in a directory named venv + 2. `source ./venv/bin/activate` will activate the venv +2. Install dependencies + * `pip install -r requirements.txt` +3. Run the app + * `gunicorn demo:APP --bind=localhost:5000` +4. Visit localhost:5000 in your web browser. + +## Linting +This demo uses pylint. +Travis CI will automatically run pylint on commits and PRs, but you can also run pylint manually, using `pylint demo`. +The pylint_quotes plugin is loaded by [the pylintrc](./.pylintrc) and will ensure standardised quotation mark formats. diff --git a/config.env.py b/config.env.py new file mode 100644 index 0000000..e996ffa --- /dev/null +++ b/config.env.py @@ -0,0 +1,17 @@ +import secrets +import os + +# Values in this file are loaded into the flask app instance, `demo.APP` in this +# demo. This file sources values from the environment if they exist, otherwise a +# set of defaults are used. This is useful for keeping secrets secret, as well +# as facilitating configuration in a container. Defaults may be overriden either +# by defining the environment variables, or by creating a `config.py` file that +# contains locally set secrets or config values. + + +# Defaults for flask configuration +IP = os.environ.get('IP', '127.0.0.1') +PORT = os.environ.get('PORT', 5000) +SERVER_NAME = os.environ.get('SERVER_NAME', 'localhost:5000') +SECRET_KEY = os.environ.get('SESSION_KEY', default=''.join(secrets.token_hex(16))) + diff --git a/demo/__init__.py b/demo/__init__.py new file mode 100644 index 0000000..86af046 --- /dev/null +++ b/demo/__init__.py @@ -0,0 +1,20 @@ +""" A small flask Hello World """ + +import os +import subprocess + +from flask import Flask, jsonify + +APP = Flask(__name__) + +# Load file based configuration overrides if present +if os.path.exists(os.path.join(os.getcwd(), 'config.py')): + APP.config.from_pyfile(os.path.join(os.getcwd(), 'config.py')) +else: + APP.config.from_pyfile(os.path.join(os.getcwd(), 'config.env.py')) + +APP.secret_key = APP.config['SECRET_KEY'] + +@APP.route('/') +def _index(): + return jsonify(status=200, response="OK") diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..7b7f48f --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +Flask==1.1.2 +gunicorn==20.0.4 +pylint==2.6.0 +pylint-quotes==0.2.1 diff --git a/wsgi.py b/wsgi.py new file mode 100644 index 0000000..a498cb4 --- /dev/null +++ b/wsgi.py @@ -0,0 +1,8 @@ +""" +Primary entry point for the app +""" + +from demo import APP + +if __name__ == "__main__": + APP.run(host=APP.config["IP"], port=int(APP.config["PORT"])) -- cgit v1.2.3