From a984a7c311ecfec869172559a26d2086b5b5fa83 Mon Sep 17 00:00:00 2001 From: brettlangdon Date: Sun, 7 Aug 2016 18:22:24 -0400 Subject: [PATCH] initial commit --- README.md | 2 -- README.rst | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++ flask_env.py | 44 +++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 2 deletions(-) delete mode 100644 README.md create mode 100644 README.rst create mode 100644 flask_env.py diff --git a/README.md b/README.md deleted file mode 100644 index 13710a0..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# flask-env -Easily set Flask settings from environment variables diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..5bed1a0 --- /dev/null +++ b/README.rst @@ -0,0 +1,85 @@ +flask-env +========= + +Easily set Flask settings from environment variables. + +The reason for using :code:`flask-env` is to be able to follow the `12-factor app `_ suggestions for configuring your application. + +With :code:`flask-env` you can define your default configuration options in code and very easily override via environment variables. + + +Installation +~~~~~~~~~~~~ + +.. code:: bash + + pip install flask_env + + +Usage +~~~~~ + +With :code:`flask-env` you will define your configuration as an object and load it into your Flask application via `app.config.from_object `_ method. + +To use in Python 2: + +.. code:: python + + from flask import Flask + from flask_env import MetaFlaskEnv + + + class Configuration(object): + __metaclass__ = MetaFlaskEnv + + DEBUG = False + PORT = 5000 + + + app = Flask(__name__) + app.config.from_object(Configuration) + + +To use in Python 3: + +.. code:: python + + from flask import Flask + from flask_env import MetaFlaskEnv + + + class Configuration(metaclass=MetaFlaskEnv): + DEBUG = False + PORT = 5000 + + + app = Flask(__name__) + app.config.from_object(Configuration) + + +Configuration +~~~~~~~~~~~~~ + +:code:`flask-env` offers two configuration options to determine how/which environment variables are loaded. + +ENV_PREFIX + Only consider environment variables that start with this prefix. + The prefix will be removed from the environment variable name when setting in the configuration. + (default: :code:`''`, example: :code:`ENV_PREFIX = 'MYAPP_'`) + +AS_JSON + Whether or not to try and parse each configuration value as JSON. + This will ensure that when setting variables as integers/null/booleans that they properly get parsed in their applicable Python types. + (default: :code:`True`, example: :code:`AS_JSON = False`) + + +Setting configuration values: + +.. code:: python + + from flask_env import MetaFlaskEnv + + + class Configuration(metaclass=MetaFlaskEnv): + ENV_PREFIX = 'MYAPP_' + AS_JSON = False diff --git a/flask_env.py b/flask_env.py new file mode 100644 index 0000000..5f88f90 --- /dev/null +++ b/flask_env.py @@ -0,0 +1,44 @@ +import json +import os +import sys + + +# DEV: In `python3` we raise `JSONDecodeError` instead of `ValueError` on a bad parse +json_decode_error = ValueError +if sys.version_info.major == 3: + json_decode_error = json.decoder.JSONDecodeError + + +class MetaFlaskEnv(type): + def __init__(cls, name, bases, dict): + """ + MetaFlaskEnv class initializer. + + This function will get called when a new class which utilizes this metaclass is defined, + as opposed to when it is initialized. + """ + super(MetaFlaskEnv, cls).__init__(name, bases, dict) + + # Get our internal settings + prefix = dict.get('ENV_PREFIX', '') + as_json = dict.get('AS_JSON', True) + + # Override default configuration from environment variables + for key, value in os.environ.items(): + # Only include environment keys that start with our prefix (if we have one) + if not key.startswith(prefix): + continue + + # Strip the prefix from the environment variable name + key = key[len(prefix):] + + # Attempt to parse values as JSON if requested (default behavior) + # DEV: This will ensure that doing `PREFIX_PORT=8000` will result in `int(8000)` and not `str(8000)` + if as_json: + try: + value = json.loads(value) + except json_decode_error: + pass + + # Update our config with the value from `os.environ` + setattr(cls, key, value)