Metadata-Version: 2.1
Name: stackable
Version: 0.2
Summary: stackable settings for any Python and Django application
Home-page: UNKNOWN
Author: miraculixx
Author-email: miraculixx@gmx.ch
License: MIT
Description: Stackable Configuration
        =======================
        
        Stackable is a drop-in replacement for Django's settings `settings.py` that is ideally suited for 12factor apps:
        
        * environment-specific configuration settings
        * modular configuration settings
        * object oriented with subclassing
        * configuration settings are stackable 
        * secret data handling (keys, passwords)
        
        Using this approache gives us several benefits from the traditional Django `settings`, 
        in particular the complexity becomes manageable.
        
        How it works
        ------------
        
        StackableSettings uses Python standard classes and multi-inheritance to compose settings. Example:
        
        ```
        # config.py
        EnvSettings_GLOBAL(object):
          # standard apps
          INSTALLED_APPS=(
             ...
          )
          SOME_SETTING='foo'
          
        Config_SomeApp(object):
          APP_CONFIG='baz'
        
        EnvSettings_Local(EnvSettings_GLOBAL):
          # additional settings for local testing
          SOME_SETTING='bar'
          APP_CONFIG='testing'
        
        # load order is in reverse, that is first EnvSettings_GLOBAL,
        # then Config_SomeApp. In other words, Config_SomeApp overrides
        # any variable set by EnvSettings_GLOBAL.
        EnvSettings_production(Config_SomeApp,
                              EnvSettings_GLOBAL):
          SOME_SETTING='prod'
          
        # settings.py
        StackableSettings.load()
        ```   
           
        Running manage.py will load config.py (or a config module) and import the
        settings classes. Settings are loaded by loading a class and all its
        superclasses, applying all capitalized variables from the class to the 
        settings.py's local() scope, which is the same as having capitalized variables 
        in settings.py directly. Note that only CAPITALIZED variables are loaded. 
        
        The settings class to load is given by the DJANGO_CONFIGURATION env variable, 
        and it defaults to EnvSettings_Local. You can find it in the 
        app's ./config module. In ./deploy/common there are several configuration 
        classes that can be used across deployable apps.
        
        In the above example, SOME_SETTING will have the value 'bar' if DJANGO_CONFIGURATION
        is either not set or has the value 'EnvSettings_local'. It will have the value
        'prod' if DJANGO_CONFIGURATION was set to 'EnvSettings_production'.
        
        
        Patches
        =======
        
        The way we load settings is by going through the list of classes in the class 
        specified in $DJANGO_CONFIGURATION. So you have EnvSettings_collect that 
        has a bunch of classes listet in it. What the settings loader does is take all
        the UPPER_CASE_VARIABLES and add it each to list of settings, whereby existing
        settings are overwritten by those loaded later. So if you have 
        
        ```
        class SomeEnv(object):
         FOO_BAZ = ('xyz',)
         
        class MyEnv(SomeEnv)
         FOO_BAZ = ('abc',)
        
        ```
             
        and load MyEnv, you'll end up with FOO_BAZ==tuple('abc'). Something like 
        FOO_BAZ += 'abc' won't work as it would simply replace what was there before. 
        
        That's why we need to use a *patch*:
        
        ```
        class MyEnv(SomeOther)
          _addtl_foo_baz = ('abc',)
          __patches__ = StackableSettings.patch(
              StackableSettings.patch_list('FOO_BAZ', _addtl_foo_baz),
          )
        ```
        
        Which results in FOO_BAZ == tuple('xyz', 'abc'). There are several patch methods,
        see StackableSettings.
        
        
        Secret Key Handling
        ===================
        
        In order to not expose production keys to everyone on the team, StackableSettings 
        implements a simple keychain using environment variables or files. With this approach, 
        the settings classes only contain place holder values, which get replaced 
        at run-time by the real keys and secrets. The keys to be applied are retrieved 
        according to the `DJANGO_CONFIGURATION` env variable so that each environment can
        use different keys.
         
        Keys are either stored in an encrypted environment variable or an encrypted file. 
        A source file by default lives in `~/.stackable/keys.yml` and is organized by
        environment name. They `keys.yml` file looks something like this:
        
        ```
        # yml
        EnvSettings_Local:
           SOME_SETTING: SECRET
           
        EnvSettings_Production:
           SOME_SETTING: OTHER_SECRET
        ...
        ```
        
        To create the encrypted environment variable:
        
        ```
        $ python -m stackable.encryptkeys
        Creating variables for stackable from /home/patrick/.stackable/keys.yml
        Set the environment for stackable as follows:
        ---
        export DJANGO_CONFIGURATION=EnvSettings_Local DJANGO_CONFIGURATION_TEST=EnvSettings_Local ENV_APIKEY_DECRYPT=ce77e82d-b0a2-4007-9380-d7fddd4bd420 EnvSettings_Local_KEYS=VydQzauHmTnqladba+oU16w=
        ```
        
        To enable encrypted keys in your EnvSettings class:
        
        ```
        from stackable.contrib.conf_api import Config_ApiKeys
        
        class EnvSettings_XYZ(Config_ApiKeys, 
                              ...):
            pass
        ```
        
        `Config_ApiKeys` triggers stackable to read encrypted keys from the environment. 
        See its definition for more details on available options.  
        
        TODO
        * implement a Django command for this
        
        
Platform: UNKNOWN
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Description-Content-Type: text/markdown
