Package: envparse
envparse========``envparse`` is a simple utility to parse environment variables.If you use Heroku and/or subscribe to the tenets of the`12 Factor App <http://www.12factor.net/>`_you'll be using a lot of environment variable-based configuration in your app.``os.environ`` is a great choice to start off with but over time you'll findyourself duplicating quite a bit of code around handling raw environmentvariables.``envparse`` aims to eliminate this duplicated, often inconsistent parsingcode and instead provide a single, easy-to-use wrapper.Ideas, and code portions, have been taken from `django-environ<https://github.com/joke2k/django-environ>`_ project but made frameworkagnostic.Installing----------Through PyPI::$ pip install envparseManually::$ pip install git+https://github.com/rconradharris/envparse.gitOR$ git clone https://github.com/rconradharris/envparse && cd envparse$ python setup.py installUsage-----In your settings or configuration module, first either import the standardparser or one with a schema::# Standardfrom envparse import env# Schemafrom envparse import Envenv = Env(BOOLEAN_VAR=bool, LIST_VAR=dict(type=list, subtype=int))``env`` can then be called in two ways:* Type explicit: ``env('ENV_VAR_NAME', type=TYPE, ...)``* Type implicit (for Python builtin types only): ``env.TYPE('ENV_VAR_NAME', ...)``If type is not specified, explicitly or implicitly, then the defaulttype is ``str``.Casting to a specified type::# Environment variable: MAIL_ENABLED=1mail_enabled = env('MAIL_ENABLED', type=bool)# OR mail_enabled = env.bool('MAIL_ENABLED')assert mail_enabled is TrueCasting nested types::# Environment variable: FOO=1,2,3foo = env('FOO'), subtype=int)# OR: foo = env('FOO', type=list, subtype=int)# Note that there is no way to implicitly call subtypes.assert foo == [1, 2, 3]Specifying defaults::# Environment variable MAX_ROWS has not been definedmax_rows = env.int('MAX_ROWS', default=100)assert max_rows == 100Proxying values, useful in Heroku for wiring up the environment variables theyprovide to the ones that your app actually uses::# Environment variables: MAILGUN_SMTP_LOGIN=foo,# SMTP_LOGIN='{{MAILGUN_SMTP_LOGIN}}'smtp_login = env('SMTP_LOGIN')assert smtp_login == 'foo'Now if you switch to using Mandrill as an email provider, instead of having tomodify your app, you can simply make a configuration change::SMTP_LOGIN='{{MANDRILL_UESRNAME}}'There are also a few convenience methods:* ``env.json``: parses JSON and returns a dict.* ``env.url``: parses a url and returns a ``urlparse.ParseResult`` object.Type specific notes:* list: the expected environment variable format is ``FOO=1,2,3`` and maycontain spaces between the commas as well as preceding or trailing whitespace.* dict: the expected environment variable format is ``FOO='key1=val1,key2=val2``. Spaces are also allowed.* json: a regular JSON string such as ``FOO='{"foo": "bar"}'`` is expected.Schemas~~~~~~~Define a schema so you can only need to provide the type, subtype, and defaultsonce::# Environment variables: MAIL_ENABLED=0, LIST_INT='1,2,3'# Bind schema to Env object to get schema-based lookupsenv = Env(MAIL_ENABLED=bool, SMTP_LOGIN=dict(type=str, default='foo'),LIST_INT=dict(type=list, subtype=int))assert env('MAIL_ENABLED') is Falseassert env('SMTP_LOGIN') == 'foo' # Not defined so uses defaultassert env('LIST_INT') == [1, 2, 3]The ``Env`` constructor takes values in the form of either: ``VAR_NAME=type``or ``VAR_NAME=dict`` where ``dict`` is a dictionary with either one or more ofthe following keys specified: ``type``, ``subtype``, ``default``.Pre- and Postprocessors~~~~~~~~~~~~~~~~~~~~~~~Preprocessors are callables that are run on the environment variable stringbefore any type casting takes place::# Environment variables: FOO=bar# Preprocessor to change variable to uppercaseto_upper = lambda v: v.upper()foo = env('FOO', preprocessor=to_upper)assert foo == 'BAR'Postprocessors are callables that are run after the type casting takes place.An example of one might be returning a datastructure expected by a framework::# Environment variable: REDIS_URL='redis://:redispass@127.0.0.1:6379/0'def django_redis(url):return {'BACKEND': 'django_redis.cache.RedisCache','LOCATION': '{}:{}:{}'.format(url.hostname, url.port, url.path.strip('/')),'OPTIONS': {'PASSWORD': url.password}}redis_config = env('REDIS_URL', postprocessor=django_redis)assert redis_config == {'BACKEND': 'django_redis.cache.RedisCache','LOCATION': '127.0.0.1:6379:0', 'OPTIONS': {'PASSWORD': 'redispass'}}Environment File~~~~~~~~~~~~~~~~Read from a .env file (line delimited KEY=VALUE)::# This recurses up the directory tree until a file called '.env' is found.env.read_env()# Manually specifying a pathenv.read_env('/config/.myenv')# Values can be read as normalenv.int('FOO')Tests-----.. image:: https://secure.travis-ci.org/rconradharris/envparse.png?branch=masterTo run the tests install tox::pip install toxThen run them with::make test