Commits

Antoine Millet committed 0766d13

Added the plugins tricks in documentation

Comments (0)

Files changed (4)

    :maxdepth: 2
 
    schema/index
+   tipsandtricks/index
 
 Indices and tables
 ==================

docs/tipsandtricks/index.rst

+Tips 'n Tricks
+==============
+
+.. toctree::
+   :maxdepth: 2
+
+   plugins

docs/tipsandtricks/plugins.py

+import sys
+from pprint import pprint
+
+from dotconf import Dotconf
+from dotconf.schema import ValidationError
+from dotconf.parser import ParsingError
+from dotconf.schema.containers import Section, Value, many
+from dotconf.schema.types import Boolean, Integer, String
+
+#
+# Our Dotconf schemas:
+#
+
+class GenericPluginSchema(Section):
+
+    # This value is common to all plugins:
+    common_value = Value(Integer())
+
+    # Enable the allow_unknown meta in order to keep unknown values
+    # on the first validation:
+    _meta = {'allow_unknown': True,
+             'repeat': many,
+             'args': Value(String())}
+
+
+class MainConfigurationSchema(Section):
+
+    global_value = Value(Integer())
+    plugin = GenericPluginSchema()
+
+
+#
+# Our plugins:
+#
+
+class BasePlugin(object):
+
+    name = None
+    schema = None
+
+    def __init__(self, config):
+        self.config = config
+
+    def print_config(self):
+        print '%s: ' % self.__class__.__name__
+        pprint(self.config.to_dict())
+
+
+class BeautifulSchema(GenericPluginSchema):
+
+    beautiful_value = Value(String())
+
+    # The allow_unknown meta is disable to forbid bad config:
+    _meta = {'allow_unknown': False}
+
+
+class BeautifulPlugin(BasePlugin):
+
+    name = 'beautiful'
+    schema = BeautifulSchema()
+
+
+class UglySchema(GenericPluginSchema):
+
+    ugly_value = Value(Boolean())
+    _meta = {'allow_unknown': False}
+
+
+class UglyPlugin(BasePlugin):
+
+    name = 'ugly'
+    schema = UglySchema()
+
+
+
+#
+# Our test config
+#
+
+TEST_CONFIG = '''
+global_value = 42
+
+plugin 'beautiful' {
+    common_value = 123
+    beautiful_value = "I'm so beautiful"
+}
+
+plugin 'ugly' {
+    common_value = 456
+    ugly_value = no
+}
+'''
+
+#
+# This is where the magic happen:
+#
+
+if __name__ == '__main__':
+    my_plugins = (BeautifulPlugin, UglyPlugin)
+    enabled_plugins = []
+
+    # Parse the global configuration:
+    config = Dotconf(TEST_CONFIG, schema=MainConfigurationSchema())
+    try:
+        pconfig = config.parse()
+    except (ValidationError, ParsingError) as err:
+        if err.position is not None:
+            print str(err.position)
+        print err
+        sys.exit(1)
+    else:
+        print 'Main configuration:'
+        pprint(pconfig.to_dict())
+
+    # Enable each used plugins:
+    for plugin_conf in pconfig.subsections('plugin'):
+        # Search the plugin:
+        for plugin in my_plugins:
+            if plugin.name == plugin_conf.args:
+                break
+        else:
+            print 'Unknown plugin %r, exiting.' % plugin_conf.args
+            sys.exit(1)
+        # Check plugin configuration:
+        try:
+            validated_conf = plugin.schema.validate(plugin_conf)
+        except ValidationError as err:
+            print 'Bad plugin configuration:'
+            if err.position is not None:
+                print str(err.position)
+            print err
+            sys.exit(1)
+        else:
+            # Instanciate the plugin object:
+            enabled_plugins.append(plugin(validated_conf))
+
+    # Print each enabled plugin config:
+    for plugin in enabled_plugins:
+        print '\n' + '~' * 80 + '\n'
+        plugin.print_config()
+

docs/tipsandtricks/plugins.rst

+Validate plugins configuration
+==============================
+
+If your application use a plugin system, and you want to validate a
+configuration which can be different for each plugin, this trick is for you.
+
+
+The idea is pretty simple, do a two-step validation: the first one will
+validate all the common configuration, and the second step validate
+each plugin's configuration. To avoid ValidationError in the first step, you
+use the ``allow_unknown`` feature of Sections.
+
+Here is a full example:
+
+.. literalinclude:: plugins.py
+
+And the output::
+
+    Main configuration:
+    {'global_value': 42,
+     'plugin': [{'beautiful_value': "I'm so beautiful", 'common_value': 123},
+                {'common_value': 456, 'ugly_value': False}]}
+
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    BeautifulPlugin: 
+    {'beautiful_value': "I'm so beautiful", 'common_value': 123}
+
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    UglyPlugin: 
+    {'common_value': 456, 'ugly_value': False}
+