Metadata-Version: 1.0
Name: configable
Version: 0.1.10
Summary: Don't repeat yourself. Configure everything.
Home-page: https://github.com/bauerca/configable
Author: Carl A. Bauer
Author-email: carl.a.bauer@gmail.com
License: MIT
Description: Installation
        ------------
        
        ::
        
            pip install configable
        
        Example
        -------
        
        .. code:: python
        
            from configable import Configable, setting
        
            class Car(Configable):
                fuel_efficiency = setting(
                    required=true,
                    kind=float
                )
        
                units = setting(
                    default='metric',
                    choices=[
                        'metric',
                        'english'
                    ]
                )
        
                def mpg(self):
                    eff = self.fuel_efficiency
                    return eff if self.units == 'english' else 2.35214583 * eff
        
            car = Car({
                'fuel_efficiency': 30,
                'units': 'metric'
            })
        
            print car.mpg()
        
        Tutorial
        --------
        
        Configable
        ~~~~~~~~~~
        
        Create configable classes by subclassing Configable and adding
        `settings <https://github.com/bauerca/configable/python#setting>`__.
        Here's a very simple example. For introductory purposes, the settings
        are specified without options; this means they are optional, and their
        values are taken as is from whatever configuration object instantiates
        the class.
        
        .. code:: python
        
            class Animal(Configable):
                species = setting()
                sound = setting()
                def speak(self):
                    print self.sound
        
        A Configable expects a single argument in its constructor: a
        *configuration object*. A *config object* is just a plain old python
        dictionary, probably loaded from a JSON/YAML/etc config file. It should
        contain properties that correspond to the
        `settings <https://github.com/bauerca/configable/python#setting>`__
        defined on the Configable it is instantiating.
        
        .. code:: python
        
            cheetah = Animal({
                'species': 'acinonyx jubatus',
                'sound': 'rawr'
            })
        
        Inheritance
        ~~~~~~~~~~~
        
        When we subclass a subclass of Configable, we are doing some sort of
        specialization of the parent class. This usually means there is a value
        for a setting (or settings) defined on the parent class that implies the
        specialization. Such special values are specified using the ``SUBTYPE``
        property. For example,
        
        .. code:: python
        
            class Cheetah(Animal):
                SUBTYPE = {'species': 'acinonyx jubatus'}
                def speak(self):
                    print 'rawr' # hard-coded sound
        
        ``SUBTYPE`` should be a dictionary with keys/values that correspond to
        settings defined on the parent class. The purpose of the ``SUBTYPE``
        property is to identify matching configuration objects (passed into the
        parent class constructor) as instances of a special subtype of the
        parent class. In other words, we're injecting an inheritance scheme into
        the inheritanceless hash table data structure.
        
        It's way simpler by example; specifying the ``SUBTYPE`` property allows
        this craziness:
        
        .. code:: python
        
            cheetah = Animal({
                'species': 'acinonyx jubatus'
            })
        
            print isinstance(cheetah, Cheetah) // True!
            cheetah.speak() // 'rawr'
        
        The Animal constructor was used to make a Cheetah instance.
        
        ``SUBTYPE`` can also be specified as a staticmethod to handle more
        general conditions:
        
        .. code:: python
        
            class Cheetah(Animal):
                @staticmethod
                def SUBTYPE(config):
                    return config.get('species') == 'acinonyx jubatus'
        
                def speak(self):
                    print 'rawr' # hard-coded sound
        
        In this case, the ``SUBTYPE`` function should return True if its class
        should be instantiated instead of the parent class for this
        configuration object.
        
        Now you can have collections of animals in your config file:
        
        .. code:: json
        
            {
                "cheetah": {
                    "species": "acinonyx jubatus"
                },
                "grizzly": {
                    "species": "ursus arctos",
                    "sound": "roar!"
                }
            }
        
        and the correct subclass will be instantiated for each. Speaking of
        which...
        
        ConfigableMap
        ~~~~~~~~~~~~~
        
        A ConfigableMap is simply a mapping between strings and Configables. The
        class is dead simple; have a look at the source if you want to see
        what's goin down. Or, take it all in with this juicy example:
        
        .. code:: python
        
            from configable import Configable, ConfigableMap, setting
        
            class Dog(Configable):
                breed = setting()
        
            class Dogs(ConfigableMap):
                TYPE = Dog
        
            dogs = Dogs({
                'gracie': {'breed': 'golden'},
                'spot': {'breed': 'terrier'}
            })
        
            print isinstance(dogs.gracie, Dog) // True!
        
        Make sure you assign a ``Type`` property to a Configable class in the
        ConfigableMap prototype! You get all the benefits of subclass
        instantiation
        
        ConfigableArray
        ~~~~~~~~~~~~~~~
        
        Given
        `ConfigableMap <https://github.com/bauerca/configable/python#configablemap>`__,
        you should be satisfied with an example,
        
        .. code:: python
        
            from configable import Configable, ConfigableArray, setting
        
            class Dog(Configable):
                breed = setting()
        
            class Dogs(ConfigableArray):
                TYPE = Dog
        
            dogs = Dogs([
                {'breed': 'golden'},
                {'breed': 'terrier'}
            ])
        
            print isinstance(dogs[0], Dog) // True!
        
        setting
        ~~~~~~~
        
        Call this and assign the result to a property on your Configable
        subclass (see numerous examples above). Generically (where shown option
        values are the defaults),
        
        .. code:: python
        
            class Type(Configable):
                setting_name = setting(
                    required=False, # Boolean
                    default=None,   # Instance of expected type (see 'kind' below)
                    choices=None,   # List of type expected in config obj
                    kind=None       # Callable
                )
        
        Additionally, you can use ``setting`` as a decorator.
        
        .. code:: python
        
            class Type(Configable):
                @setting(
                    required=False, # Boolean
                    default=None,   # Instance of expected type (see 'kind' below)
                    choices=None,   # List of type expected in config obj
                    kind=None       # Callable
                )
                def setting_name(self, value):
                    # Do something with value
        
        The decorated function will be called immediately before the value is
        set on the instance (after
        `kind <https://github.com/bauerca/configable/python#kind-callable>`__ is
        called). You should *not* try to access other settings from inside this
        function as they may not have been loaded yet. If you need to call the
        parent class decorated function, you must use the following syntax,
        
        .. code:: python
        
            class Parent(Configable):
                @setting()
                def name(self, value):
                    self.capname = value.upper()
        
            class Child(Parent):
                @setting()
                def name(self, value):
                    Parent.name(self, value) # MUST USE THIS SYNTAX
                    print self.capname
        
        The following are short explanations of the setting options.
        
        ``required {bool}``
        ^^^^^^^^^^^^^^^^^^^
        
        If set to true, instantiation of the containing Configable subclass will
        fail horribly if the setting is undefined on the configuration object.
        
        ``default {*}``
        ^^^^^^^^^^^^^^^
        
        Pretty self-explanatory. You probably want
        `required <https://github.com/bauerca/configable/python#required>`__ to
        be ``false`` if you are supplying a default setting value. The default
        value should be a *raw* value, i.e. of a type expected in the
        configuration object (fundamental, like int, str, dict, list, etc). The
        default, if taken, will be run through all the following setting checks
        and ops.
        
        ``choices {iterable<*>}``
        ^^^^^^^^^^^^^^^^^^^^^^^^^
        
        If your settings values are restricted to a small set, list them here.
        Configable instantiation will fail if the *raw* value is not in this
        set.
        
        ``kind {callable}``
        ^^^^^^^^^^^^^^^^^^^
        
        The raw value from the configuration object is run through this
        function; therefore, it should accept a single value and return the
        transformed value or throw an error. This is often set as a class,
        especially when you want nested Configables.
        
Keywords: configuration
Platform: UNKNOWN
