← Back to team overview

configglue team mailing list archive

[Merge] lp:~ricardokirkner/configglue/short-options into lp:configglue

 

Ricardo Kirkner has proposed merging lp:~ricardokirkner/configglue/short-options into lp:configglue.

Requested reviews:
  Canonical ISD hackers (canonical-isd-hackers)
  Configglue developers (configglue)

For more details, see:
https://code.launchpad.net/~ricardokirkner/configglue/short-options/+merge/66411

Overview
========

This branch adds support for specifying short names for options so that they
can be used from the command line.

Details
=======

The Option class and any derived classes now have an extra short_name
attribute that is used to indicate the preferred short name for that option
when specified via the command line.

For example,

class MySchema(Schema):
    foo = IntOption(short_name='f')

will allow that option to be overridden via command line both using

--foo <value>

or

-f <value>
-- 
https://code.launchpad.net/~ricardokirkner/configglue/short-options/+merge/66411
Your team Configglue developers is requested to review the proposed merge of lp:~ricardokirkner/configglue/short-options into lp:configglue.
=== modified file 'configglue/app/tests/test_base.py'
--- configglue/app/tests/test_base.py	2011-06-23 18:55:16 +0000
+++ configglue/app/tests/test_base.py	2011-06-30 04:09:28 +0000
@@ -24,10 +24,12 @@
 def make_app(name=None, schema=None, plugin_manager=None):
     # patch sys.argv so that nose can be run with extra options
     # without conflicting with the schema validation
+    # patch sys.stderr to prevent spurious output
     mock_sys = Mock()
     mock_sys.argv = ['foo.py']
     with patch('configglue.pyschema.glue.sys', mock_sys):
-        app = App(name=name, schema=schema, plugin_manager=plugin_manager)
+        with patch('configglue.app.base.sys.stderr'):
+            app = App(name=name, schema=schema, plugin_manager=plugin_manager)
     return app
 
 

=== modified file 'configglue/pyschema/glue.py'
--- configglue/pyschema/glue.py	2011-06-19 21:24:56 +0000
+++ configglue/pyschema/glue.py	2011-06-30 04:09:28 +0000
@@ -70,7 +70,11 @@
             if not option.fatal:
                 kwargs['default'] = parser.get(section.name, option.name)
             kwargs['action'] = option.action
-            og.add_option('--' + long_name(option), **kwargs)
+            args = ['--' + long_name(option)]
+            if option.short_name:
+                # prepend the option's short name
+                args.insert(0, '-' + option.short_name)
+            og.add_option(*args, **kwargs)
     options, args = op.parse_args(argv)
 
     def set_value(section, option, value):

=== modified file 'configglue/pyschema/schema.py'
--- configglue/pyschema/schema.py	2011-06-22 23:00:16 +0000
+++ configglue/pyschema/schema.py	2011-06-30 04:09:28 +0000
@@ -288,8 +288,9 @@
     require_parser = False
 
     def __init__(self, name='', raw=False, default=NO_DEFAULT, fatal=False,
-                 help='', section=None, action='store'):
+                 help='', section=None, action='store', short_name=''):
         self.name = name
+        self.short_name = short_name
         self.raw = raw
         self.fatal = fatal
         if default is NO_DEFAULT:
@@ -413,9 +414,13 @@
     """
 
     def __init__(self, name='', item=None, raw=False, default=NO_DEFAULT,
-        fatal=False, help='', action='store', remove_duplicates=False):
+        fatal=False, help='', action='store', remove_duplicates=False,
+        short_name=''):
         super(ListOption, self).__init__(name=name, raw=raw,
-            default=default, fatal=fatal, help=help, action=action)
+            default=default, fatal=fatal, help=help, action=action,
+            short_name=short_name)
+        if item is None:
+            item = StringOption()
         self.item = item
         self.require_parser = item.require_parser
         self.raw = item.raw
@@ -459,10 +464,11 @@
     """
 
     def __init__(self, name='', raw=False, default=NO_DEFAULT, fatal=False,
-        null=False, help='', action='store'):
+        null=False, help='', action='store', short_name=''):
         self.null = null
         super(StringOption, self).__init__(name=name, raw=raw,
-            default=default, fatal=fatal, help=help, action=action)
+            default=default, fatal=fatal, help=help, action=action,
+            short_name=short_name)
 
     def _get_default(self):
         return '' if not self.null else None
@@ -501,9 +507,10 @@
     """
 
     def __init__(self, name='', length=0, raw=False, default=NO_DEFAULT,
-        fatal=False, help='', action='store'):
+        fatal=False, help='', action='store', short_name=''):
         super(TupleOption, self).__init__(name=name, raw=raw,
-            default=default, fatal=fatal, help=help, action=action)
+            default=default, fatal=fatal, help=help, action=action,
+            short_name=short_name)
         self.length = length
 
     def _get_default(self):
@@ -551,7 +558,7 @@
 
     def __init__(self, name='', spec=None, strict=False, raw=False,
                  default=NO_DEFAULT, fatal=False, help='', action='store',
-                 item=None):
+                 item=None, short_name=''):
         if spec is None:
             spec = {}
         if item is None:
@@ -560,7 +567,8 @@
         self.strict = strict
         self.item = item
         super(DictOption, self).__init__(name=name, raw=raw,
-            default=default, fatal=fatal, help=help, action=action)
+            default=default, fatal=fatal, help=help, action=action,
+            short_name=short_name)
 
     def _get_default(self):
         default = {}

=== modified file 'configglue/tests/pyschema/test_schema.py'
--- configglue/tests/pyschema/test_schema.py	2011-06-23 17:31:13 +0000
+++ configglue/tests/pyschema/test_schema.py	2011-06-30 04:09:28 +0000
@@ -201,9 +201,15 @@
         self.assertNotEqual(opt1, opt2)
 
     def test_validate(self):
+        """Test Option default validate behaviour."""
         opt = self.cls()
         self.assertRaises(NotImplementedError, opt.validate, 0)
 
+    def test_short_name(self):
+        """Test Option short name."""
+        opt = self.cls(short_name='f')
+        self.assertEqual(opt.short_name, 'f')
+
 
 class TestConfigOption(TestOption):
     cls = ConfigOption
@@ -370,6 +376,11 @@
         self.assertEqual(self.opt.to_string(''), '')
         self.assertEqual(self.opt.to_string('foo'), 'foo')
 
+    def test_short_name(self):
+        """Test StringOption short name."""
+        opt = self.cls(short_name='f')
+        self.assertEqual(opt.short_name, 'f')
+
 
 class TestStringConfigOption(TestStringOption):
     cls = StringConfigOption
@@ -415,6 +426,11 @@
         opt = self.cls()
         self.assertEqual(opt.validate(''), False)
 
+    def test_short_name(self):
+        """Test IntOption short name."""
+        opt = self.cls(short_name='f')
+        self.assertEqual(opt.short_name, 'f')
+
 
 class TestIntConfigOption(TestIntOption):
     cls = IntConfigOption
@@ -465,6 +481,11 @@
         opt = self.cls()
         self.assertEqual(opt.validate(''), False)
 
+    def test_short_name(self):
+        """Test BoolOption short name."""
+        opt = self.cls(short_name='f')
+        self.assertEqual(opt.short_name, 'f')
+
 
 class TestBoolConfigOption(TestBoolOption):
     cls = BoolConfigOption
@@ -564,6 +585,16 @@
         opt = self.cls(item=IntOption())
         self.assertEqual(opt.validate(''), False)
 
+    def test_default_item(self):
+        """Test ListOption default item."""
+        opt = self.cls()
+        self.assertEqual(opt.item, StringOption())
+
+    def test_short_name(self):
+        """Test ListOption short name."""
+        opt = self.cls(short_name='f')
+        self.assertEqual(opt.short_name, 'f')
+
 
 class TestLinesConfigOption(TestListOption):
     cls = LinesConfigOption
@@ -631,6 +662,11 @@
         opt = self.cls(length=2)
         self.assertEqual(opt.validate(0), False)
 
+    def test_short_name(self):
+        """Test TupleOption short name."""
+        opt = self.cls(short_name='f')
+        self.assertEqual(opt.short_name, 'f')
+
 
 class TestTupleConfigOption(TupleOption):
     cls = TupleConfigOption
@@ -833,6 +869,11 @@
         opt = self.cls()
         self.assertEqual(opt.validate(0), False)
 
+    def test_short_name(self):
+        """Test DictOption short name."""
+        opt = self.cls(short_name='f')
+        self.assertEqual(opt.short_name, 'f')
+
 
 class TestDictConfigOption(TestDictOption):
     cls = DictConfigOption

=== modified file 'configglue/tests/pyschema/test_schemaconfig.py'
--- configglue/tests/pyschema/test_schemaconfig.py	2011-06-19 20:14:50 +0000
+++ configglue/tests/pyschema/test_schemaconfig.py	2011-06-30 04:09:28 +0000
@@ -20,6 +20,7 @@
 import os
 import sys
 from StringIO import StringIO
+from optparse import OptionConflictError
 
 from mock import (
     Mock,
@@ -297,6 +298,39 @@
             'fóobâr')
         self.assertEqual(parser.get('__main__', 'foo'), 'fóobâr')
 
+    def test_option_short_name(self):
+        """Test schemaconfigglue support for short option names."""
+        class MySchema(Schema):
+            foo = IntOption(short_name='f')
+
+        parser = SchemaConfigParser(MySchema())
+        op, options, args = schemaconfigglue(
+            parser, argv=['-f', '42'])
+        self.assertEqual(parser.get('__main__', 'foo'), 42)
+
+    def test_option_conflicting_short_name(self):
+        """Test schemaconfigglue with conflicting short option names."""
+        class MySchema(Schema):
+            foo = IntOption(short_name='f')
+            flup = StringOption(short_name='f')
+
+        parser = SchemaConfigParser(MySchema())
+        self.assertRaises(OptionConflictError, schemaconfigglue, parser,
+            argv=['-f', '42'])
+
+    def test_option_specified_twice(self):
+        """Test schemaconfigglue with option name specified twice."""
+        class MySchema(Schema):
+            foo = IntOption(short_name='f')
+
+        parser = SchemaConfigParser(MySchema())
+        op, options, args = schemaconfigglue(
+            parser, argv=['-f', '42', '--foo', '24'])
+        self.assertEqual(parser.get('__main__', 'foo'), 24)
+        op, options, args = schemaconfigglue(
+            parser, argv=['-f', '24', '--foo', '42'])
+        self.assertEqual(parser.get('__main__', 'foo'), 42)
+
 
 class ConfigglueTestCase(unittest.TestCase):
     @patch('configglue.pyschema.glue.SchemaConfigParser')


Follow ups