configglue team mailing list archive
-
configglue team
-
Mailing list archive
-
Message #00099
[Merge] lp:~ricardokirkner/configglue/refactor-options-option into lp:configglue
Ricardo Kirkner has proposed merging lp:~ricardokirkner/configglue/refactor-options-option into lp:configglue with lp:~ricardokirkner/configglue/refactor-options-tupleoption as a prerequisite.
Requested reviews:
Configglue developers (configglue)
For more details, see:
https://code.launchpad.net/~ricardokirkner/configglue/refactor-options-option/+merge/64442
--
https://code.launchpad.net/~ricardokirkner/configglue/refactor-options-option/+merge/64442
Your team Configglue developers is requested to review the proposed merge of lp:~ricardokirkner/configglue/refactor-options-option into lp:configglue.
=== modified file 'configglue/pyschema/schema.py'
--- configglue/pyschema/schema.py 2011-06-13 18:51:00 +0000
+++ configglue/pyschema/schema.py 2011-06-13 18:51:00 +0000
@@ -24,6 +24,7 @@
'BoolConfigOption',
'BoolOption',
'ConfigOption',
+ 'Option',
'ConfigSection',
'DictConfigOption',
'DictOption',
@@ -46,7 +47,7 @@
def get_config_objects(obj):
objects = []
for name, obj in getmembers(obj):
- if isinstance(obj, (ConfigSection, ConfigOption)):
+ if isinstance(obj, (ConfigSection, Option)):
objects.append((name, obj))
elif type(obj) == type and issubclass(obj, ConfigSection):
instance = obj()
@@ -61,15 +62,15 @@
To define your own configuration schema you should:
1- Inherit from Schema
- 2- Add ConfigOptions and ConfigSections as class attributes.
+ 2- Add Option and ConfigSections as class attributes.
With that your whole configuration schema is defined, and you can now
load configuration files.
- ConfigOptions that don't go in a ConfigSection will belong in the
+ Options that don't go in a ConfigSection will belong in the
'__main__' section of the configuration files.
- One ConfigOption comes already defined in Schema, 'includes' in the
+ One Option comes already defined in Schema, 'includes' in the
'__main__' section, that allows configuration files to include other
configuration files.
@@ -87,7 +88,7 @@
item.name = name
if isinstance(item, ConfigSection):
self._add_section(name, item)
- elif isinstance(item, ConfigOption):
+ elif isinstance(item, Option):
self._add_option(name, item)
# override class attributes with instance attributes to correctly
# handle schema inheritance
@@ -137,7 +138,7 @@
return self._sections.values()
def options(self, section=None):
- """Return all the ConfigOptions within a given section.
+ """Return all the Options within a given section.
If section is omitted, returns all the options in the configuration
file, flattening out any sections.
@@ -153,7 +154,7 @@
elif section.name == '__main__':
class_config_objects = get_config_objects(self.__class__)
options = [getattr(self, att) for att, _ in class_config_objects
- if isinstance(getattr(self, att), ConfigOption)]
+ if isinstance(getattr(self, att), Option)]
else:
options = section.options()
return options
@@ -162,7 +163,7 @@
class ConfigSection(object):
"""A group of options.
- This class is just a bag you can dump ConfigOptions in.
+ This class is just a bag you can dump Options in.
After instantiating the Schema, each ConfigSection will know its own
name.
@@ -187,26 +188,26 @@
return value
def has_option(self, name):
- """Return True if a ConfigOption with the given name is available"""
+ """Return True if a Option with the given name is available"""
opt = getattr(self, name, None)
- return isinstance(opt, ConfigOption)
+ return isinstance(opt, Option)
def option(self, name):
- """Return a ConfigOption by name"""
+ """Return a Option by name"""
opt = getattr(self, name, None)
- assert opt is not None, "Invalid ConfigOption name '%s'" % name
+ assert opt is not None, "Invalid Option name '%s'" % name
return opt
def options(self):
- """Return a list of all available ConfigOptions within this section"""
+ """Return a list of all available Options within this section"""
return [getattr(self, att) for att in vars(self)
- if isinstance(getattr(self, att), ConfigOption)]
-
-
-class ConfigOption(object):
+ if isinstance(getattr(self, att), Option)]
+
+
+class Option(object):
"""Base class for Config Options.
- ConfigOptions are never bound to a particular conguration file, and
+ Options are never bound to a particular conguration file, and
simply describe one particular available option.
They also know how to parse() the content of a config file in to the right
@@ -226,7 +227,7 @@
file. Otherwise, the self.default value will be used if the option is
omitted.
- In runtime, after instantiating the Schema, each ConfigOption will also
+ In runtime, after instantiating the Schema, each Option will also
know its own name and to which section it belongs.
"""
@@ -270,12 +271,12 @@
extra += ' fatal' if self.fatal else ''
section = self.section.name if self.section is not None else None
if section is not None:
- name = " %s.%s" % (section, self.name)
+ name = " {0}.{1}".format(section, self.name)
elif self.name:
- name = " %s" % self.name
+ name = " {0}".format(self.name)
else:
name = ''
- value = "<ConfigOption%s%s>" % (name, extra)
+ value = "<{0}{1}{2}>".format(self.__class__.__name__, name, extra)
return value
def _get_default(self):
@@ -293,8 +294,8 @@
return str(value)
-class BoolOption(ConfigOption):
- """A ConfigOption that is parsed into a bool"""
+class BoolOption(Option):
+ """A Option that is parsed into a bool"""
def _get_default(self):
return False
@@ -319,8 +320,8 @@
return isinstance(value, bool)
-class IntOption(ConfigOption):
- """A ConfigOption that is parsed into an int"""
+class IntOption(Option):
+ """A Option that is parsed into an int"""
def _get_default(self):
return 0
@@ -340,12 +341,12 @@
return isinstance(value, int)
-class ListOption(ConfigOption):
- """A ConfigOption that is parsed into a list of objects
+class ListOption(Option):
+ """A Option that is parsed into a list of objects
All items in the list need to be of the same type. The 'item' constructor
argument determines the type of the list items. item should be another
- child of ConfigOption.
+ child of Option.
self.require_parser will be True if the item provided in turn has
require_parser == True.
@@ -394,8 +395,8 @@
return isinstance(value, list)
-class StringOption(ConfigOption):
- """A ConfigOption that is parsed into a string.
+class StringOption(Option):
+ """A Option that is parsed into a string.
If null==True, a value of 'None' will be parsed in to None instead of
just leaving it as the string 'None'.
@@ -434,8 +435,8 @@
return isinstance(value, basestring)
-class TupleOption(ConfigOption):
- """A ConfigOption that is parsed into a fixed-size tuple of strings.
+class TupleOption(Option):
+ """A Option that is parsed into a fixed-size tuple of strings.
The number of items in the tuple should be specified with the 'length'
constructor argument.
@@ -476,8 +477,8 @@
return isinstance(value, tuple)
-class DictOption(ConfigOption):
- """A ConfigOption that is parsed into a dictionary.
+class DictOption(Option):
+ """A Option that is parsed into a dictionary.
In the configuration file you'll need to specify the name of a section,
and all that section's items will be parsed as a dictionary.
@@ -485,7 +486,7 @@
The available keys for the dict are specified with the 'spec' constructor
argument, that should be in turn a dictionary. spec's keys are the
available keys for the config file, and spec's values should be
- ConfigOptions that will be used to parse the values in the config file.
+ Options that will be used to parse the values in the config file.
"""
@@ -616,3 +617,7 @@
class TupleConfigOption(TupleOption):
__metaclass__ = DeprecatedOption
+
+
+class ConfigOption(Option):
+ __metaclass__ = DeprecatedOption
=== modified file 'doc/howto/custom-schema-options.rst'
--- doc/howto/custom-schema-options.rst 2011-06-13 18:51:00 +0000
+++ doc/howto/custom-schema-options.rst 2011-06-13 18:51:00 +0000
@@ -18,28 +18,28 @@
configglue's built-in option types don't cover every possible data type --
only the common types, such as ``bool`` and ``int``. For more obscure data
types, such as complex numbers or even user-created types you can define your
-own configglue :class:`~configglue.pyschema.schema.ConfigOption` subclasses.
+own configglue :class:`~configglue.pyschema.schema.Option` subclasses.
Writing an option subclass
==========================
-When planning your :class:`~configglue.pyschema.schema.ConfigOption` subclass,
+When planning your :class:`~configglue.pyschema.schema.Option` subclass,
first give some thought to which existing
-:class:`~configglue.pyschema.schema.ConfigOption` class your new option
+:class:`~configglue.pyschema.schema.Option` class your new option
is most similar to. Can you subclass an existing configglue option and save
yourself some work? If not, you should subclass the
-:class:`~configglue.pyschema.schema.ConfigOption` class, from which everything
+:class:`~configglue.pyschema.schema.Option` class, from which everything
is descended.
Initializing your new option is a matter of separating out any arguments that are
specific to your case from the common arguments and passing the latter to the
-:meth:`~configglue.pyschema.schema.ConfigOption.__init__` method of
-:class:`~configglue.pyschema.schema.ConfigOption` (or your parent class).
+:meth:`~configglue.pyschema.schema.Option.__init__` method of
+:class:`~configglue.pyschema.schema.Option` (or your parent class).
In our example, we'll call our option ``UpperCaseDictOption``. (It's a
-good idea to call your :class:`~configglue.pyschema.schema.ConfigOption`
-subclass ``<Something>ConfigOption``, so it's easily identifiable as a
-:class:`~configglue.pyschema.schema.ConfigOption` subclass.) It behaves
+good idea to call your :class:`~configglue.pyschema.schema.Option`
+subclass ``<Something>Option``, so it's easily identifiable as a
+:class:`~configglue.pyschema.schema.Option` subclass.) It behaves
mostly like a :class:`~configglue.pyschema.schema.DictOption`, so we'll
subclass from that::
=== modified file 'doc/index.rst'
--- doc/index.rst 2011-04-21 02:42:18 +0000
+++ doc/index.rst 2011-06-13 18:51:00 +0000
@@ -35,7 +35,7 @@
* **Schemas:**
:doc:`Schema syntax <topics/schemas>` |
- :doc:`ConfigOption types <ref/schemas/options>`
+ :doc:`Option types <ref/schemas/options>`
* **Advanced:**
:doc:`Custom options <howto/custom-schema-options>`
=== modified file 'doc/ref/schemas/options.rst'
--- doc/ref/schemas/options.rst 2011-06-13 18:51:00 +0000
+++ doc/ref/schemas/options.rst 2011-06-13 18:51:00 +0000
@@ -21,7 +21,7 @@
:mod:`configglue.pyschema.schema`, but for convenience they're imported
into :mod:`configglue.pyschema`; the standard convention is to use
``from configglue import pyschema`` and refer to classes as
- ``pyschema.<Foo>ConfigOption``.
+ ``pyschema.<Foo>Option``.
.. _common-schema-option-attributes:
@@ -34,7 +34,7 @@
``name``
--------
-.. attribute:: ConfigOption.name
+.. attribute:: Option.name
The name of the option. This will be automatically set to the name assigned to
the option in the schema definition.
@@ -42,7 +42,7 @@
``raw``
-------
-.. attribute:: ConfigOption.raw
+.. attribute:: Option.raw
If ``True``, variable interpolation will not be carried out for this option.
@@ -51,7 +51,7 @@
``default``
-----------
-.. attribute:: ConfigOption.default
+.. attribute:: Option.default
The default value for this option, if none is provided in the config file.
@@ -60,7 +60,7 @@
``fatal``
---------
-.. attribute:: ConfigOption.fatal
+.. attribute:: Option.fatal
If ``True``, ``SchemaConfigParser.parse_all`` will raise an exception if no
value is provided in the configuration file for this option. Otherwise,
@@ -71,7 +71,7 @@
``help``
--------
-.. attribute:: ConfigOption.help
+.. attribute:: Option.help
The help text describing this option. This text will be used as the
``optparse.OptParser`` help text.
@@ -81,7 +81,7 @@
``section``
-----------
-.. attribute:: ConfigOption.section
+.. attribute:: Option.section
The :class:`~configglue.pyschema.ConfigSection` object where this option was
defined.
@@ -91,7 +91,7 @@
.. ``action``
.. ----------
..
-.. .. attribute:: ConfigOption.action
+.. .. attribute:: Option.action
..
.. lorem ipsum
..
@@ -130,7 +130,7 @@
*Required*.
List elements will be parsed as being of this type. Should be an
- instance of a subclass of :class:`~configglue.pyschema.schema.ConfigOption`.
+ instance of a subclass of :class:`~configglue.pyschema.schema.Option`.
.. attribute:: ListOption.remove_duplicates
@@ -180,7 +180,7 @@
If not ``None``, should be a ``dict`` instance, such that its values
are instances of a subclass of
- :class:`~configglue.pyschema.schema.ConfigOption`.
+ :class:`~configglue.pyschema.schema.Option`.
.. attribute:: DictOption.strict
@@ -195,5 +195,5 @@
Any not explicitly defined attributes will be parsed as being
of this type. This should be an instance of a subclass of
- :class:`~configglue.pyschema.schema.ConfigOption`.
+ :class:`~configglue.pyschema.schema.Option`.
=== modified file 'doc/topics/config-file.rst'
--- doc/topics/config-file.rst 2011-06-13 18:51:00 +0000
+++ doc/topics/config-file.rst 2011-06-13 18:51:00 +0000
@@ -10,7 +10,7 @@
[my_section]
-A ConfigOption is matched by a ConfigParser option, which is defined by a
+A Option is matched by a ConfigParser option, which is defined by a
simple key, value pair, like::
my_option = the value
@@ -35,7 +35,7 @@
A few special considerations have to be kept in mind while working with these
configuration files. As ConfigParser requires a config file to have at least
-one section defined, any top-level ConfigOptions are added to an implicitely
+one section defined, any top-level Option are added to an implicitely
defined section called ``__main__``.
Therefore, if you have a schema like::
=== modified file 'doc/topics/schemas.rst'
--- doc/topics/schemas.rst 2011-06-13 18:51:00 +0000
+++ doc/topics/schemas.rst 2011-06-13 18:51:00 +0000
@@ -15,7 +15,7 @@
* Each attribute of the schema represents either a configuration section
(see :class:`~configglue.pyschema.schema.ConfigSection`) or
- option (see :class:`~configglue.pyschema.schema.ConfigOption`).
+ option (see :class:`~configglue.pyschema.schema.Option`).
Quick example
=============
@@ -58,7 +58,7 @@
------------
Each option in your schema should be an instance of the appropriate
-:class:`~configglue.pyschema.schema.ConfigOption` class.
+:class:`~configglue.pyschema.schema.Option` class.
configglue ships with a couple of built-in option types; you can find the
complete list in the :ref:`schema option reference <schema-option-types>`. You
@@ -79,17 +79,17 @@
<common-schema-option-attributes>`, but here's a quick summary of the most
often-used ones:
- :attr:`~ConfigOption.default`
+ :attr:`~Option.default`
The default value for this option, if none is provided in the config file.
Default is :attr:`configglue.pyschema.schema.NO_DEFAULT`.
- :attr:`~ConfigOption.fatal`
+ :attr:`~Option.fatal`
If ``True``, :func:`SchemaConfigParser.parse_all` will raise an exception if no
value is provided in the configuration file for this option. Otherwise,
:attr:`self.default` will be used.
Default is ``False``.
- :attr:`~ConfigOption.help`
+ :attr:`~Option.help`
The help text describing this option. This text will be used as the
:class:`optparse.OptParser` help text.
Default is ``''``.
@@ -139,7 +139,7 @@
overriding it. In order to achieve this, in your schema subclass, copy the
parent's attribute explicitely, to avoid modifying the parent schema class.
Option attributes (derived from
-:class:`~configglue.pyschema.schema.ConfigOption`) will be overridden, as
+:class:`~configglue.pyschema.schema.Option`) will be overridden, as
expected.
For example::
=== modified file 'tests/pyschema/test_schema.py'
--- tests/pyschema/test_schema.py 2011-06-13 18:51:00 +0000
+++ tests/pyschema/test_schema.py 2011-06-13 18:51:00 +0000
@@ -24,6 +24,7 @@
BoolConfigOption,
BoolOption,
ConfigOption,
+ Option,
ConfigSection,
DictConfigOption,
DictOption,
@@ -153,7 +154,9 @@
self.assertEqual(type(objects[key]), type(value))
-class TestConfigOption(unittest.TestCase):
+class TestOption(unittest.TestCase):
+ cls = Option
+
def test_equal(self):
opt1 = IntOption(name='opt1')
opt2 = IntOption(name='opt2')
@@ -183,10 +186,14 @@
self.assertNotEqual(opt1, opt2)
def test_validate(self):
- opt = ConfigOption()
+ opt = self.cls()
self.assertRaises(NotImplementedError, opt.validate, 0)
+class TestConfigOption(TestOption):
+ cls = ConfigOption
+
+
class TestSchemaInheritance(unittest.TestCase):
def setUp(self):
class SchemaA(Schema):
=== modified file 'tests/pyschema/test_schemaconfig.py'
--- tests/pyschema/test_schemaconfig.py 2011-06-13 18:51:00 +0000
+++ tests/pyschema/test_schemaconfig.py 2011-06-13 18:51:00 +0000
@@ -29,6 +29,7 @@
from configglue.pyschema.parser import SchemaConfigParser
from configglue.pyschema.schema import (
ConfigOption,
+ Option,
ConfigSection,
IntOption,
Schema,
@@ -36,48 +37,54 @@
)
-class TestConfigOption(unittest.TestCase):
+class TestOption(unittest.TestCase):
+ cls = Option
+
def test_repr_name(self):
- opt = ConfigOption()
- expected = "<ConfigOption>"
+ opt = self.cls()
+ expected = "<{0}>".format(self.cls.__name__)
self.assertEqual(repr(opt), expected)
- opt = ConfigOption(name='name')
- expected = "<ConfigOption name>"
+ opt = self.cls(name='name')
+ expected = "<{0} name>".format(self.cls.__name__)
self.assertEqual(repr(opt), expected)
sect = ConfigSection(name='sect')
- opt = ConfigOption(name='name', section=sect)
- expected = "<ConfigOption sect.name>"
+ opt = self.cls(name='name', section=sect)
+ expected = "<{0} sect.name>".format(self.cls.__name__)
self.assertEqual(repr(opt), expected)
def test_repr_extra(self):
- opt = ConfigOption(name='name', raw=True)
- expected = "<ConfigOption name raw>"
- self.assertEqual(repr(opt), expected)
-
- opt = ConfigOption(name='name', fatal=True)
- expected = "<ConfigOption name fatal>"
- self.assertEqual(repr(opt), expected)
-
- opt = ConfigOption(name='name', raw=True, fatal=True)
- expected = "<ConfigOption name raw fatal>"
+ opt = self.cls(name='name', raw=True)
+ expected = "<{0} name raw>".format(self.cls.__name__)
+ self.assertEqual(repr(opt), expected)
+
+ opt = self.cls(name='name', fatal=True)
+ expected = "<{0} name fatal>".format(self.cls.__name__)
+ self.assertEqual(repr(opt), expected)
+
+ opt = self.cls(name='name', raw=True, fatal=True)
+ expected = "<{0} name raw fatal>".format(self.cls.__name__)
self.assertEqual(repr(opt), expected)
def test_parse(self):
- opt = ConfigOption()
+ opt = self.cls()
self.assertRaises(NotImplementedError, opt.parse, '')
def test_equal(self):
- opt1 = ConfigOption()
- opt2 = ConfigOption(name='name', raw=True)
+ opt1 = self.cls()
+ opt2 = self.cls(name='name', raw=True)
- self.assertEqual(opt1, ConfigOption())
- self.assertEqual(opt2, ConfigOption(name='name', raw=True))
+ self.assertEqual(opt1, self.cls())
+ self.assertEqual(opt2, self.cls(name='name', raw=True))
self.assertNotEqual(opt1, opt2)
self.assertNotEqual(opt1, None)
+class TestConfigOption(TestOption):
+ cls = ConfigOption
+
+
class TestConfigSection(unittest.TestCase):
def test_repr_name(self):
sect = ConfigSection()
Follow ups