Beispiel #1
0
    def test_option_value_compare(self):
        # OptionValue are tuple and equivalence should compare as tuples.
        val = PositiveOptionValue(('foo',))

        self.assertEqual(val[0], 'foo')
        self.assertEqual(val, PositiveOptionValue(('foo',)))
        self.assertNotEqual(val, PositiveOptionValue(('foo', 'bar')))

        # Can compare a tuple to an OptionValue.
        self.assertEqual(val, ('foo',))
        self.assertNotEqual(val, ('foo', 'bar'))

        # Different OptionValue types are never equal.
        self.assertNotEqual(val, OptionValue(('foo',)))

        # For usability reasons, we raise TypeError when attempting to compare
        # against a non-tuple.
        with self.assertRaisesRegexp(TypeError, 'cannot compare a'):
            val == 'foo'

        # But we allow empty option values to compare otherwise we can't
        # easily compare value-less types like PositiveOptionValue and
        # NegativeOptionValue.
        empty_positive = PositiveOptionValue()
        empty_negative = NegativeOptionValue()
        self.assertEqual(empty_positive, ())
        self.assertEqual(empty_positive, PositiveOptionValue())
        self.assertEqual(empty_negative, ())
        self.assertEqual(empty_negative, NegativeOptionValue())
        self.assertNotEqual(empty_positive, 'foo')
        self.assertNotEqual(empty_positive, ('foo',))
        self.assertNotEqual(empty_negative, 'foo')
        self.assertNotEqual(empty_negative, ('foo',))
Beispiel #2
0
 def test_defaults(self):
     config = self.get_config()
     self.maxDiff = None
     self.assertEquals(
         {
             'CHOICES':
             NegativeOptionValue(),
             'DEFAULTED':
             PositiveOptionValue(('not-simple', )),
             'IS_GCC':
             NegativeOptionValue(),
             'REMAINDER': (PositiveOptionValue(), NegativeOptionValue(),
                           NegativeOptionValue(), NegativeOptionValue()),
             'SIMPLE':
             NegativeOptionValue(),
             'VALUES':
             NegativeOptionValue(),
             'VALUES2':
             NegativeOptionValue(),
             'VALUES3':
             NegativeOptionValue(),
             'WITH_ENV':
             NegativeOptionValue(),
             'IMPLIED':
             NegativeOptionValue(),
             'IMPLIED_ENV':
             NegativeOptionValue(),
             'IMPLIED_VALUES':
             NegativeOptionValue(),
         }, config)
Beispiel #3
0
    def test_option_choices(self):
        with self.assertRaises(InvalidOptionError) as e:
            Option('--option', nargs=3, choices=('a', 'b'))
        self.assertEquals(e.exception.message,
                          'Not enough `choices` for `nargs`')

        with self.assertRaises(InvalidOptionError) as e:
            Option('--without-option', nargs=1, choices=('a', 'b'))
        self.assertEquals(e.exception.message,
                          'A `default` must be given along with `choices`')

        with self.assertRaises(InvalidOptionError) as e:
            Option('--without-option', nargs='+', choices=('a', 'b'))
        self.assertEquals(e.exception.message,
                          'A `default` must be given along with `choices`')

        with self.assertRaises(InvalidOptionError) as e:
            Option('--without-option', default='c', choices=('a', 'b'))
        self.assertEquals(e.exception.message,
                          "The `default` value must be one of 'a', 'b'")

        with self.assertRaises(InvalidOptionError) as e:
            Option('--without-option',
                   default=(
                       'a',
                       'c',
                   ),
                   choices=('a', 'b'))
        self.assertEquals(e.exception.message,
                          "The `default` value must be one of 'a', 'b'")

        with self.assertRaises(InvalidOptionError) as e:
            Option('--without-option', default=('c', ), choices=('a', 'b'))
        self.assertEquals(e.exception.message,
                          "The `default` value must be one of 'a', 'b'")

        option = Option('--with-option', nargs='+', choices=('a', 'b'))
        with self.assertRaises(InvalidOptionError) as e:
            option.get_value('--with-option=c')
        self.assertEquals(e.exception.message, "'c' is not one of 'a', 'b'")

        value = option.get_value('--with-option=b,a')
        self.assertTrue(value)
        self.assertEquals(PositiveOptionValue(('b', 'a')), value)

        option = Option('--without-option',
                        nargs='*',
                        default='a',
                        choices=('a', 'b'))
        with self.assertRaises(InvalidOptionError) as e:
            option.get_value('--with-option=c')
        self.assertEquals(e.exception.message, "'c' is not one of 'a', 'b'")

        value = option.get_value('--with-option=b,a')
        self.assertTrue(value)
        self.assertEquals(PositiveOptionValue(('b', 'a')), value)

        # Test nargs inference from choices
        option = Option('--with-option', choices=('a', 'b'))
        self.assertEqual(option.nargs, 1)
Beispiel #4
0
    def test_imply_option_values(self):
        def get_config(*args):
            return self.get_config(*args,
                                   configure='imply_option/values.configure')

        help, config = get_config(['--help'])
        self.assertEquals(config, {})

        config = get_config([])
        self.assertEquals(config, {})

        config = get_config(['--enable-foo=a'])
        self.assertIn('BAR', config)
        self.assertEquals(config['BAR'], PositiveOptionValue(('a', )))

        config = get_config(['--enable-foo=a,b'])
        self.assertIn('BAR', config)
        self.assertEquals(config['BAR'], PositiveOptionValue(('a', 'b')))

        with self.assertRaises(InvalidOptionError) as e:
            get_config(['--enable-foo=a,b', '--disable-bar'])

        self.assertEquals(
            e.exception.message,
            "'--enable-bar=a,b' implied by '--enable-foo' conflicts with "
            "'--disable-bar' from the command-line")
Beispiel #5
0
    def test_depends_or(self):
        with self.moz_configure('''
            option('--foo', nargs=1, help='foo')
            @depends('--foo')
            def foo(value):
                return value or None

            option('--bar', nargs=1, help='bar')
            @depends('--bar')
            def bar(value):
                return value

            set_config('FOOBAR', foo | bar)
        '''):
            config = self.get_config()
            self.assertEqual(config, {
                'FOOBAR': NegativeOptionValue(),
            })

            config = self.get_config(['--foo=foo'])
            self.assertEqual(config, {
                'FOOBAR': PositiveOptionValue(('foo', )),
            })

            config = self.get_config(['--bar=bar'])
            self.assertEqual(config, {
                'FOOBAR': PositiveOptionValue(('bar', )),
            })

            config = self.get_config(['--foo=foo', '--bar=bar'])
            self.assertEqual(config, {
                'FOOBAR': PositiveOptionValue(('foo', )),
            })
Beispiel #6
0
    def _value_for_option(self, option):
        implied = {}
        for implied_option in self._implied_options[:]:
            if implied_option.name not in (option.name, option.env):
                continue
            self._implied_options.remove(implied_option)

            if (implied_option.when and
                not self._value_for(implied_option.when)):
                continue

            value = self._resolve(implied_option.value,
                                  need_help_dependency=False)

            if value is not None:
                if isinstance(value, OptionValue):
                    pass
                elif value is True:
                    value = PositiveOptionValue()
                elif value is False or value == ():
                    value = NegativeOptionValue()
                elif isinstance(value, types.StringTypes):
                    value = PositiveOptionValue((value,))
                elif isinstance(value, tuple):
                    value = PositiveOptionValue(value)
                else:
                    raise TypeError("Unexpected type: '%s'"
                                    % type(value).__name__)

                opt = value.format(implied_option.option)
                self._helper.add(opt, 'implied')
                implied[opt] = implied_option

        try:
            value, option_string = self._helper.handle(option)
        except ConflictingOptionError as e:
            reason = implied[e.arg].reason
            if isinstance(reason, Option):
                reason = self._raw_options.get(reason) or reason.option
                reason = reason.split('=', 1)[0]
            raise InvalidOptionError(
                "'%s' implied by '%s' conflicts with '%s' from the %s"
                % (e.arg, reason, e.old_arg, e.old_origin))

        if option_string:
            self._raw_options[option] = option_string

        when = self._conditions.get(option)
        if (when and not self._value_for(when, need_help_dependency=True) and
            value is not None and value.origin != 'default'):
            if value.origin == 'environment':
                # The value we return doesn't really matter, because of the
                # requirement for @depends to have the same when.
                return None
            raise InvalidOptionError(
                '%s is not available in this configuration'
                % option_string.split('=', 1)[0])

        return value
Beispiel #7
0
    def test_returned_default(self):
        config = self.get_config(['--enable-simple'])
        self.assertIn('DEFAULTED', config)
        self.assertEquals(PositiveOptionValue(('simple', )),
                          config['DEFAULTED'])

        config = self.get_config(['--disable-simple'])
        self.assertIn('DEFAULTED', config)
        self.assertEquals(PositiveOptionValue(('not-simple', )),
                          config['DEFAULTED'])
Beispiel #8
0
    def _value_for_option(self, option):
        implied = {}
        for implied_option in self._implied_options[:]:
            if implied_option.name not in (option.name, option.env):
                continue
            self._implied_options.remove(implied_option)

            if (implied_option.when
                    and not self._value_for(implied_option.when)):
                continue

            value = self._resolve(implied_option.value,
                                  need_help_dependency=False)

            if value is not None:
                if isinstance(value, OptionValue):
                    pass
                elif value is True:
                    value = PositiveOptionValue()
                elif value is False or value == ():
                    value = NegativeOptionValue()
                elif isinstance(value, types.StringTypes):
                    value = PositiveOptionValue((value, ))
                elif isinstance(value, tuple):
                    value = PositiveOptionValue(value)
                else:
                    raise TypeError("Unexpected type: '%s'" %
                                    type(value).__name__)

                opt = value.format(implied_option.option)
                self._helper.add(opt, 'implied')
                implied[opt] = implied_option

        try:
            value, option_string = self._helper.handle(option)
        except ConflictingOptionError as e:
            reason = implied[e.arg].reason
            if isinstance(reason, Option):
                reason = self._raw_options.get(reason) or reason.option
                reason = reason.split('=', 1)[0]
            raise InvalidOptionError(
                "'%s' implied by '%s' conflicts with '%s' from the %s" %
                (e.arg, reason, e.old_arg, e.old_origin))

        if option_string:
            self._raw_options[option] = option_string

        when = self._conditions.get(option)
        if (when and not self._value_for(when, need_help_dependency=True)
                and value is not None and value.origin != 'default'):
            if value.origin == 'environment':
                # The value we return doesn't really matter, because of the
                # requirement for @depends to have the same when.
                return None
            raise InvalidOptionError(
                '%s is not available in this configuration' %
                option_string.split('=', 1)[0])

        return value
Beispiel #9
0
    def test_option_value_enable(self,
                                 enable='enable',
                                 disable='disable',
                                 nargs=0,
                                 default=None):
        option = self.test_option_value('%s-option' % enable,
                                        nargs=nargs,
                                        default=default)

        value = option.get_value('--%s-option' % disable, 'option')
        self.assertEquals(value, NegativeOptionValue())
        self.assertEquals(value.origin, 'option')

        option = self.test_option_value('%s-option' % disable,
                                        nargs=nargs,
                                        default=default)

        if nargs in (0, '?', '*'):
            value = option.get_value('--%s-option' % enable, 'option')
            self.assertEquals(value, PositiveOptionValue())
            self.assertEquals(value.origin, 'option')
        else:
            with self.assertRaises(InvalidOptionError) as e:
                option.get_value('--%s-option' % enable, 'option')
            if nargs == 1:
                self.assertEquals(e.exception.message,
                                  '--%s-option takes 1 value' % enable)
            elif nargs == '+':
                self.assertEquals(
                    e.exception.message,
                    '--%s-option takes 1 or more values' % enable)
            else:
                self.assertEquals(e.exception.message,
                                  '--%s-option takes 2 values' % enable)
Beispiel #10
0
    def test_option_value_enable(
        self, enable="enable", disable="disable", nargs=0, default=None
    ):
        option = self.test_option_value(
            "%s-option" % enable, nargs=nargs, default=default
        )

        value = option.get_value("--%s-option" % disable, "option")
        self.assertEquals(value, NegativeOptionValue())
        self.assertEquals(value.origin, "option")

        option = self.test_option_value(
            "%s-option" % disable, nargs=nargs, default=default
        )

        if nargs in (0, "?", "*"):
            value = option.get_value("--%s-option" % enable, "option")
            self.assertEquals(value, PositiveOptionValue())
            self.assertEquals(value.origin, "option")
        else:
            with self.assertRaises(InvalidOptionError) as e:
                option.get_value("--%s-option" % enable, "option")
            if nargs == 1:
                self.assertEquals(
                    str(e.exception), "--%s-option takes 1 value" % enable
                )
            elif nargs == "+":
                self.assertEquals(
                    str(e.exception), "--%s-option takes 1 or more values" % enable
                )
            else:
                self.assertEquals(
                    str(e.exception), "--%s-option takes 2 values" % enable
                )
Beispiel #11
0
    def test_with_env(self):
        for config in (
                self.get_config(),
                self.get_config(['--disable-with-env']),
                self.get_config(['--enable-with-env', '--disable-with-env']),
                self.get_config(env={'MOZ_WITH_ENV': ''}),
                # Options win over environment
                self.get_config(['--disable-with-env'],
                                env={'MOZ_WITH_ENV': '1'}),
        ):
            self.assertIn('WITH_ENV', config)
            self.assertEquals(NegativeOptionValue(), config['WITH_ENV'])

        for config in (
                self.get_config(['--enable-with-env']),
                self.get_config(['--disable-with-env', '--enable-with-env']),
                self.get_config(env={'MOZ_WITH_ENV': '1'}),
                self.get_config(['--enable-with-env'],
                                env={'MOZ_WITH_ENV': ''}),
        ):
            self.assertIn('WITH_ENV', config)
            self.assertEquals(PositiveOptionValue(), config['WITH_ENV'])

        with self.assertRaises(InvalidOptionError):
            self.get_config(['--enable-with-env=value'])

        with self.assertRaises(InvalidOptionError):
            self.get_config(env={'MOZ_WITH_ENV': 'value'})
Beispiel #12
0
    def test_depends_getattr(self):
        with self.moz_configure('''
            @imports(_from='mozbuild.util', _import='ReadOnlyNamespace')
            def namespace(**kwargs):
                return ReadOnlyNamespace(**kwargs)

            option('--foo', nargs=1, help='foo')
            @depends('--foo')
            def foo(value):
                return value

            option('--bar', nargs=1, help='bar')
            @depends('--bar')
            def bar(value):
                return value or None

            @depends(foo, bar)
            def foobar(foo, bar):
                return namespace(foo=foo, bar=bar)

            set_config('FOO', foobar.foo)
            set_config('BAR', foobar.bar)
            set_config('BAZ', foobar.baz)
        '''):
            config = self.get_config()
            self.assertEqual(config, {
                'FOO': NegativeOptionValue(),
            })

            config = self.get_config(['--foo=foo'])
            self.assertEqual(config, {
                'FOO': PositiveOptionValue(('foo', )),
            })

            config = self.get_config(['--bar=bar'])
            self.assertEqual(
                config, {
                    'FOO': NegativeOptionValue(),
                    'BAR': PositiveOptionValue(('bar', )),
                })

            config = self.get_config(['--foo=foo', '--bar=bar'])
            self.assertEqual(
                config, {
                    'FOO': PositiveOptionValue(('foo', )),
                    'BAR': PositiveOptionValue(('bar', )),
                })
Beispiel #13
0
    def test_depends_binary_ops(self):
        with self.moz_configure('''
            option('--foo', nargs=1, help='foo')
            @depends('--foo')
            def foo(value):
                return value or 0

            option('--bar', nargs=1, help='bar')
            @depends('--bar')
            def bar(value):
                return value or ''

            option('--baz', nargs=1, help='baz')
            @depends('--baz')
            def baz(value):
                return value

            set_config('FOOorBAR', foo | bar)
            set_config('FOOorBARorBAZ', foo | bar | baz)
            set_config('FOOandBAR', foo & bar)
            set_config('FOOandBARandBAZ', foo & bar & baz)
        '''):
            for foo_opt, foo_value in (('', 0), ('--foo=foo',
                                                 PositiveOptionValue(
                                                     ('foo', )))):
                for bar_opt, bar_value in (('', ''), ('--bar=bar',
                                                      PositiveOptionValue(
                                                          ('bar', )))):
                    for baz_opt, baz_value in (('', NegativeOptionValue()),
                                               ('--baz=baz',
                                                PositiveOptionValue(
                                                    ('baz', )))):
                        config = self.get_config(
                            [x for x in (foo_opt, bar_opt, baz_opt) if x])
                        self.assertEqual(
                            config, {
                                'FOOorBAR':
                                foo_value or bar_value,
                                'FOOorBARorBAZ':
                                foo_value or bar_value or baz_value,
                                'FOOandBAR':
                                foo_value and bar_value,
                                'FOOandBARandBAZ':
                                foo_value and bar_value and baz_value,
                            })
Beispiel #14
0
    def test_returned_choices(self):
        for val in ('a', 'b', 'c'):
            config = self.get_config(
                ['--enable-values=alpha', '--returned-choices=%s' % val])
            self.assertIn('CHOICES', config)
            self.assertEquals(PositiveOptionValue((val,)), config['CHOICES'])

        for val in ('0', '1', '2'):
            config = self.get_config(
                ['--enable-values=numeric', '--returned-choices=%s' % val])
            self.assertIn('CHOICES', config)
            self.assertEquals(PositiveOptionValue((val,)), config['CHOICES'])

        with self.assertRaises(InvalidOptionError):
            self.get_config(['--enable-values=numeric',
                             '--returned-choices=a'])

        with self.assertRaises(InvalidOptionError):
            self.get_config(['--enable-values=alpha', '--returned-choices=0'])
Beispiel #15
0
    def test_included(self):
        config = self.get_config(env={'CC': 'gcc'})
        self.assertIn('IS_GCC', config)
        self.assertEquals(config['IS_GCC'], True)

        config = self.get_config(
            ['--enable-include=extra.configure', '--extra'])
        self.assertIn('EXTRA', config)
        self.assertEquals(PositiveOptionValue(), config['EXTRA'])

        with self.assertRaises(InvalidOptionError):
            self.get_config(['--extra'])
Beispiel #16
0
    def test_option_choices(self):
        with self.assertRaises(InvalidOptionError):
            Option('--option', nargs=3, choices=('a', 'b'))

        with self.assertRaises(InvalidOptionError):
            Option('--without-option', nargs=1, choices=('a', 'b'))

        with self.assertRaises(InvalidOptionError):
            Option('--without-option', nargs='+', choices=('a', 'b'))

        with self.assertRaises(InvalidOptionError):
            Option('--without-option', default='c', choices=('a', 'b'))

        with self.assertRaises(InvalidOptionError):
            Option('--without-option', default=('a', 'c',), choices=('a', 'b'))

        with self.assertRaises(InvalidOptionError):
            Option('--without-option', default=('c',), choices=('a', 'b'))

        option = Option('--with-option', nargs='+', choices=('a', 'b'))
        with self.assertRaises(InvalidOptionError):
            option.get_value('--with-option=c')

        value = option.get_value('--with-option=b,a')
        self.assertTrue(value)
        self.assertEquals(PositiveOptionValue(('b', 'a')), value)

        option = Option('--without-option', nargs='*', default='a',
                        choices=('a', 'b'))
        with self.assertRaises(InvalidOptionError):
            option.get_value('--with-option=c')

        value = option.get_value('--with-option=b,a')
        self.assertTrue(value)
        self.assertEquals(PositiveOptionValue(('b', 'a')), value)

        # Test nargs inference from choices
        option = Option('--with-option', choices=('a', 'b'))
        self.assertEqual(option.nargs, 1)
Beispiel #17
0
    def test_values(self, name='VALUES'):
        for config in (
                self.get_config(),
                self.get_config(['--disable-values']),
                self.get_config(['--enable-values', '--disable-values']),
        ):
            self.assertIn(name, config)
            self.assertEquals(NegativeOptionValue(), config[name])

        for config in (
                self.get_config(['--enable-values']),
                self.get_config(['--disable-values', '--enable-values']),
        ):
            self.assertIn(name, config)
            self.assertEquals(PositiveOptionValue(), config[name])

        config = self.get_config(['--enable-values=foo'])
        self.assertIn(name, config)
        self.assertEquals(PositiveOptionValue(('foo', )), config[name])

        config = self.get_config(['--enable-values=foo,bar'])
        self.assertIn(name, config)
        self.assertTrue(config[name])
        self.assertEquals(PositiveOptionValue(('foo', 'bar')), config[name])
Beispiel #18
0
    def test_implied_options(self):
        config = self.get_config(['--enable-values'])
        self.assertIn('IMPLIED', config)
        self.assertIn('IMPLIED_VALUES', config)
        self.assertIn('IMPLIED_ENV', config)
        self.assertEquals(PositiveOptionValue(), config['IMPLIED'])
        self.assertEquals(PositiveOptionValue(), config['IMPLIED_VALUES'])
        self.assertEquals(PositiveOptionValue(), config['IMPLIED_ENV'])

        config = self.get_config(['--enable-values=a'])
        self.assertIn('IMPLIED', config)
        self.assertIn('IMPLIED_VALUES', config)
        self.assertIn('IMPLIED_ENV', config)
        self.assertEquals(PositiveOptionValue(), config['IMPLIED'])
        self.assertEquals(PositiveOptionValue(('a', )),
                          config['IMPLIED_VALUES'])
        self.assertEquals(PositiveOptionValue(('a', )), config['IMPLIED_ENV'])

        config = self.get_config(['--enable-values=a,b'])
        self.assertIn('IMPLIED', config)
        self.assertIn('IMPLIED_VALUES', config)
        self.assertIn('IMPLIED_ENV', config)
        self.assertEquals(PositiveOptionValue(), config['IMPLIED'])
        self.assertEquals(PositiveOptionValue(('a', 'b')),
                          config['IMPLIED_VALUES'])
        self.assertEquals(PositiveOptionValue(('a', 'b')),
                          config['IMPLIED_ENV'])

        config = self.get_config(['--disable-values'])
        self.assertIn('IMPLIED', config)
        self.assertIn('IMPLIED_VALUES', config)
        self.assertIn('IMPLIED_ENV', config)
        self.assertEquals(NegativeOptionValue(), config['IMPLIED'])
        self.assertEquals(NegativeOptionValue(), config['IMPLIED_VALUES'])
        self.assertEquals(NegativeOptionValue(), config['IMPLIED_ENV'])

        # --enable-values implies --enable-implied, which conflicts with
        # --disable-implied
        with self.assertRaises(InvalidOptionError):
            self.get_config(['--enable-values', '--disable-implied'])
Beispiel #19
0
    def test_imply_option_when(self):
        with self.moz_configure('''
            option('--with-foo', help='foo')
            imply_option('--with-qux', True, when='--with-foo')
            option('--with-qux', help='qux')
            set_config('QUX', depends('--with-qux')(lambda x: x))
        '''):
            config = self.get_config()
            self.assertEquals(config, {
                'QUX': NegativeOptionValue(),
            })

            config = self.get_config(['--with-foo'])
            self.assertEquals(config, {
                'QUX': PositiveOptionValue(),
            })
Beispiel #20
0
    def _value_for_option(self, option):
        implied = {}
        for implied_option in self._implied_options[:]:
            if implied_option.name not in (option.name, option.env):
                continue
            self._implied_options.remove(implied_option)

            value = self._resolve(implied_option.value,
                                  need_help_dependency=False)

            if value is not None:
                if isinstance(value, OptionValue):
                    pass
                elif value is True:
                    value = PositiveOptionValue()
                elif value is False or value == ():
                    value = NegativeOptionValue()
                elif isinstance(value, types.StringTypes):
                    value = PositiveOptionValue((value,))
                elif isinstance(value, tuple):
                    value = PositiveOptionValue(value)
                else:
                    raise TypeError("Unexpected type: '%s'"
                                    % type(value).__name__)

                opt = value.format(implied_option.option)
                self._helper.add(opt, 'implied')
                implied[opt] = implied_option

        try:
            value, option_string = self._helper.handle(option)
        except ConflictingOptionError as e:
            reason = implied[e.arg].reason
            if isinstance(reason, Option):
                reason = self._raw_options.get(reason) or reason.option
                reason = reason.split('=', 1)[0]
            raise InvalidOptionError(
                "'%s' implied by '%s' conflicts with '%s' from the %s"
                % (e.arg, reason, e.old_arg, e.old_origin))

        if option_string:
            self._raw_options[option] = option_string

        return value
Beispiel #21
0
    def test_basic(self):
        helper = CommandLineHelper({}, ['cmd', '--foo', '--bar'])

        self.assertEquals(['--foo', '--bar'], list(helper))

        helper.add('--enable-qux')

        self.assertEquals(['--foo', '--bar', '--enable-qux'], list(helper))

        value, option = helper.handle(Option('--bar'))
        self.assertEquals(['--foo', '--enable-qux'], list(helper))
        self.assertEquals(PositiveOptionValue(), value)
        self.assertEquals('--bar', option)

        value, option = helper.handle(Option('--baz'))
        self.assertEquals(['--foo', '--enable-qux'], list(helper))
        self.assertEquals(NegativeOptionValue(), value)
        self.assertEquals(None, option)
Beispiel #22
0
    def test_option_value_enable(self, enable='enable', disable='disable',
                                 nargs=0, default=None):
        option = self.test_option_value('%s-option' % enable, nargs=nargs,
                                        default=default)

        value = option.get_value('--%s-option' % disable, 'option')
        self.assertEquals(value, NegativeOptionValue())
        self.assertEquals(value.origin, 'option')

        option = self.test_option_value('%s-option' % disable, nargs=nargs,
                                        default=default)

        if nargs in (0, '?', '*'):
            value = option.get_value('--%s-option' % enable, 'option')
            self.assertEquals(value, PositiveOptionValue())
            self.assertEquals(value.origin, 'option')
        else:
            with self.assertRaises(InvalidOptionError):
                option.get_value('--%s-option' % enable, 'option')
Beispiel #23
0
    def test_basic(self):
        helper = CommandLineHelper({}, ["cmd", "--foo", "--bar"])

        self.assertEquals(["--foo", "--bar"], list(helper))

        helper.add("--enable-qux")

        self.assertEquals(["--foo", "--bar", "--enable-qux"], list(helper))

        value, option = helper.handle(Option("--bar"))
        self.assertEquals(["--foo", "--enable-qux"], list(helper))
        self.assertEquals(PositiveOptionValue(), value)
        self.assertEquals("--bar", option)

        value, option = helper.handle(Option("--baz"))
        self.assertEquals(["--foo", "--enable-qux"], list(helper))
        self.assertEquals(NegativeOptionValue(), value)
        self.assertEquals(None, option)

        with self.assertRaises(AssertionError):
            CommandLineHelper({}, ["--foo", "--bar"])
Beispiel #24
0
    def test_possible_origins(self):
        with self.assertRaises(InvalidOptionError):
            Option('--foo', possible_origins='command-line')

        helper = CommandLineHelper({'BAZ': '1'}, ['cmd', '--foo', '--bar'])
        foo = Option('--foo',
                     possible_origins=('command-line',))
        value, option = helper.handle(foo)
        self.assertEquals(PositiveOptionValue(), value)
        self.assertEquals('command-line', value.origin)
        self.assertEquals('--foo', option)

        bar = Option('--bar',
                     possible_origins=('mozconfig',))
        with self.assertRaisesRegexp(InvalidOptionError,
            "--bar can not be set by command-line. Values are accepted from: mozconfig"):
            helper.handle(bar)

        baz = Option(env='BAZ',
                     possible_origins=('implied',))
        with self.assertRaisesRegexp(InvalidOptionError,
            "BAZ=1 can not be set by environment. Values are accepted from: implied"):
            helper.handle(baz)
Beispiel #25
0
    def test_imply_option_simple(self):
        def get_config(*args):
            return self.get_config(*args,
                                   configure='imply_option/simple.configure')

        config, out = self.get_result(
            ['--help'], configure='imply_option/simple.configure')
        self.assertEquals(config, {})

        config = get_config([])
        self.assertEquals(config, {})

        config = get_config(['--enable-foo'])
        self.assertIn('BAR', config)
        self.assertEquals(config['BAR'], PositiveOptionValue())

        with self.assertRaises(InvalidOptionError) as e:
            get_config(['--enable-foo', '--disable-bar'])

        self.assertEquals(
            e.exception.message,
            "'--enable-bar' implied by '--enable-foo' conflicts with "
            "'--disable-bar' from the command-line")
Beispiel #26
0
    def test_simple(self):
        for config in (
                self.get_config(),
                self.get_config(['--disable-simple']),
                # Last option wins.
                self.get_config(['--enable-simple', '--disable-simple']),
        ):
            self.assertNotIn('ENABLED_SIMPLE', config)
            self.assertIn('SIMPLE', config)
            self.assertEquals(NegativeOptionValue(), config['SIMPLE'])

        for config in (
                self.get_config(['--enable-simple']),
                self.get_config(['--disable-simple', '--enable-simple']),
        ):
            self.assertIn('ENABLED_SIMPLE', config)
            self.assertIn('SIMPLE', config)
            self.assertEquals(PositiveOptionValue(), config['SIMPLE'])
            self.assertIs(config['SIMPLE'], config['ENABLED_SIMPLE'])

        # --enable-simple doesn't take values.
        with self.assertRaises(InvalidOptionError):
            self.get_config(['--enable-simple=value'])
Beispiel #27
0
    def test_possible_origins(self):
        with self.assertRaises(InvalidOptionError):
            Option("--foo", possible_origins="command-line")

        helper = CommandLineHelper({"BAZ": "1"}, ["cmd", "--foo", "--bar"])
        foo = Option("--foo", possible_origins=("command-line",))
        value, option = helper.handle(foo)
        self.assertEquals(PositiveOptionValue(), value)
        self.assertEquals("command-line", value.origin)
        self.assertEquals("--foo", option)

        bar = Option("--bar", possible_origins=("mozconfig",))
        with self.assertRaisesRegexp(
            InvalidOptionError,
            "--bar can not be set by command-line. Values are accepted from: mozconfig",
        ):
            helper.handle(bar)

        baz = Option(env="BAZ", possible_origins=("implied",))
        with self.assertRaisesRegexp(
            InvalidOptionError,
            "BAZ=1 can not be set by environment. Values are accepted from: implied",
        ):
            helper.handle(baz)
Beispiel #28
0
    def test_option_when(self):
        with self.moz_configure('''
            option('--with-foo', help='foo', when=True)
            option('--with-bar', help='bar', when=False)
            option('--with-qux', env="QUX", help='qux', when='--with-foo')

            set_config('FOO', depends('--with-foo', when=True)(lambda x: x))
            set_config('BAR', depends('--with-bar', when=False)(lambda x: x))
            set_config('QUX', depends('--with-qux', when='--with-foo')(lambda x: x))
        '''):
            config = self.get_config()
            self.assertEquals(config, {
                'FOO': NegativeOptionValue(),
            })

            config = self.get_config(['--with-foo'])
            self.assertEquals(config, {
                'FOO': PositiveOptionValue(),
                'QUX': NegativeOptionValue(),
            })

            config = self.get_config(['--with-foo', '--with-qux'])
            self.assertEquals(config, {
                'FOO': PositiveOptionValue(),
                'QUX': PositiveOptionValue(),
            })

            with self.assertRaises(InvalidOptionError) as e:
                self.get_config(['--with-bar'])

            self.assertEquals(
                e.exception.message,
                '--with-bar is not available in this configuration')

            with self.assertRaises(InvalidOptionError) as e:
                self.get_config(['--with-qux'])

            self.assertEquals(
                e.exception.message,
                '--with-qux is not available in this configuration')

            with self.assertRaises(InvalidOptionError) as e:
                self.get_config(['QUX=1'])

            self.assertEquals(e.exception.message,
                              'QUX is not available in this configuration')

            config = self.get_config(env={'QUX': '1'})
            self.assertEquals(config, {
                'FOO': NegativeOptionValue(),
            })

            help, config = self.get_config(['--help'])
            self.assertEquals(
                help,
                textwrap.dedent('''\
                Usage: configure [options]

                Options: [defaults in brackets after descriptions]
                  --help                    print this message
                  --with-foo                foo

                Environment variables:
            '''))

            help, config = self.get_config(['--help', '--with-foo'])
            self.assertEquals(
                help,
                textwrap.dedent('''\
                Usage: configure [options]

                Options: [defaults in brackets after descriptions]
                  --help                    print this message
                  --with-foo                foo
                  --with-qux                qux

                Environment variables:
            '''))

        with self.moz_configure('''
            option('--with-foo', help='foo', when=True)
            set_config('FOO', depends('--with-foo')(lambda x: x))
        '''):
            with self.assertRaises(ConfigureError) as e:
                self.get_config()

            self.assertEquals(
                e.exception.message,
                '@depends function needs the same `when` as '
                'options it depends on')

        with self.moz_configure('''
            @depends(when=True)
            def always():
                return True
            @depends(when=True)
            def always2():
                return True
            option('--with-foo', help='foo', when=always)
            set_config('FOO', depends('--with-foo', when=always2)(lambda x: x))
        '''):
            with self.assertRaises(ConfigureError) as e:
                self.get_config()

            self.assertEquals(
                e.exception.message,
                '@depends function needs the same `when` as '
                'options it depends on')

        with self.moz_configure('''
            @depends(when=True)
            def always():
                return True
            @depends(when=True)
            def always2():
                return True
            with only_when(always2):
                option('--with-foo', help='foo', when=always)
                # include() triggers resolution of its dependencies, and their
                # side effects.
                include(depends('--with-foo', when=always)(lambda x: x))
                # The sandbox should figure that the `when` here is
                # appropriate. Bad behavior in CombinedDependsFunction.__eq__
                # made this fail in the past.
                set_config('FOO', depends('--with-foo', when=always)(lambda x: x))
        '''):
            self.get_config()

        with self.moz_configure('''
            option('--with-foo', help='foo')
            option('--without-bar', help='bar', when='--with-foo')
            option('--with-qux', help='qux', when='--with-bar')
            set_config('QUX', True, when='--with-qux')
        '''):
            # These are valid:
            self.get_config(['--with-foo'])
            self.get_config(['--with-foo', '--with-bar'])
            self.get_config(['--with-foo', '--without-bar'])
            self.get_config(['--with-foo', '--with-bar', '--with-qux'])
            self.get_config(['--with-foo', '--with-bar', '--without-qux'])
            with self.assertRaises(InvalidOptionError) as e:
                self.get_config(['--with-bar'])
            with self.assertRaises(InvalidOptionError) as e:
                self.get_config(['--without-bar'])
            with self.assertRaises(InvalidOptionError) as e:
                self.get_config(['--with-qux'])
            with self.assertRaises(InvalidOptionError) as e:
                self.get_config(['--without-qux'])
            with self.assertRaises(InvalidOptionError) as e:
                self.get_config(['--with-foo', '--without-bar', '--with-qux'])
            with self.assertRaises(InvalidOptionError) as e:
                self.get_config(
                    ['--with-foo', '--without-bar', '--without-qux'])
Beispiel #29
0
    def test_option_value_format(self):
        val = PositiveOptionValue()
        self.assertEquals('--with-value', val.format('--with-value'))
        self.assertEquals('--with-value', val.format('--without-value'))
        self.assertEquals('--enable-value', val.format('--enable-value'))
        self.assertEquals('--enable-value', val.format('--disable-value'))
        self.assertEquals('--value', val.format('--value'))
        self.assertEquals('VALUE=1', val.format('VALUE'))

        val = PositiveOptionValue(('a',))
        self.assertEquals('--with-value=a', val.format('--with-value'))
        self.assertEquals('--with-value=a', val.format('--without-value'))
        self.assertEquals('--enable-value=a', val.format('--enable-value'))
        self.assertEquals('--enable-value=a', val.format('--disable-value'))
        self.assertEquals('--value=a', val.format('--value'))
        self.assertEquals('VALUE=a', val.format('VALUE'))

        val = PositiveOptionValue(('a', 'b'))
        self.assertEquals('--with-value=a,b', val.format('--with-value'))
        self.assertEquals('--with-value=a,b', val.format('--without-value'))
        self.assertEquals('--enable-value=a,b', val.format('--enable-value'))
        self.assertEquals('--enable-value=a,b', val.format('--disable-value'))
        self.assertEquals('--value=a,b', val.format('--value'))
        self.assertEquals('VALUE=a,b', val.format('VALUE'))

        val = NegativeOptionValue()
        self.assertEquals('--without-value', val.format('--with-value'))
        self.assertEquals('--without-value', val.format('--without-value'))
        self.assertEquals('--disable-value', val.format('--enable-value'))
        self.assertEquals('--disable-value', val.format('--disable-value'))
        self.assertEquals('', val.format('--value'))
        self.assertEquals('VALUE=', val.format('VALUE'))
Beispiel #30
0
    def test_extra_args(self):
        foo = Option('--with-foo', env='FOO', nargs='*')
        helper = CommandLineHelper({}, ['cmd'])
        helper.add('FOO=a,b,c', 'other-origin')
        value, option = helper.handle(foo)
        self.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value)
        self.assertEquals('other-origin', value.origin)
        self.assertEquals('FOO=a,b,c', option)

        helper = CommandLineHelper({}, ['cmd'])
        helper.add('FOO=a,b,c', 'other-origin')
        helper.add('--with-foo=a,b,c', 'other-origin')
        value, option = helper.handle(foo)
        self.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value)
        self.assertEquals('other-origin', value.origin)
        self.assertEquals('--with-foo=a,b,c', option)

        # Adding conflicting options is not allowed.
        helper = CommandLineHelper({}, ['cmd'])
        helper.add('FOO=a,b,c', 'other-origin')
        with self.assertRaises(ConflictingOptionError) as cm:
            helper.add('FOO=', 'other-origin')
        self.assertEqual('FOO=', cm.exception.arg)
        self.assertEqual('other-origin', cm.exception.origin)
        self.assertEqual('FOO=a,b,c', cm.exception.old_arg)
        self.assertEqual('other-origin', cm.exception.old_origin)
        with self.assertRaises(ConflictingOptionError) as cm:
            helper.add('FOO=a,b', 'other-origin')
        self.assertEqual('FOO=a,b', cm.exception.arg)
        self.assertEqual('other-origin', cm.exception.origin)
        self.assertEqual('FOO=a,b,c', cm.exception.old_arg)
        self.assertEqual('other-origin', cm.exception.old_origin)
        # But adding the same is allowed.
        helper.add('FOO=a,b,c', 'other-origin')
        value, option = helper.handle(foo)
        self.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value)
        self.assertEquals('other-origin', value.origin)
        self.assertEquals('FOO=a,b,c', option)

        # The same rule as above applies when using the option form vs. the
        # variable form. But we can't detect it when .add is called.
        helper = CommandLineHelper({}, ['cmd'])
        helper.add('FOO=a,b,c', 'other-origin')
        helper.add('--without-foo', 'other-origin')
        with self.assertRaises(ConflictingOptionError) as cm:
            helper.handle(foo)
        self.assertEqual('--without-foo', cm.exception.arg)
        self.assertEqual('other-origin', cm.exception.origin)
        self.assertEqual('FOO=a,b,c', cm.exception.old_arg)
        self.assertEqual('other-origin', cm.exception.old_origin)
        helper = CommandLineHelper({}, ['cmd'])
        helper.add('FOO=a,b,c', 'other-origin')
        helper.add('--with-foo=a,b', 'other-origin')
        with self.assertRaises(ConflictingOptionError) as cm:
            helper.handle(foo)
        self.assertEqual('--with-foo=a,b', cm.exception.arg)
        self.assertEqual('other-origin', cm.exception.origin)
        self.assertEqual('FOO=a,b,c', cm.exception.old_arg)
        self.assertEqual('other-origin', cm.exception.old_origin)
        helper = CommandLineHelper({}, ['cmd'])
        helper.add('FOO=a,b,c', 'other-origin')
        helper.add('--with-foo=a,b,c', 'other-origin')
        value, option = helper.handle(foo)
        self.assertEquals(PositiveOptionValue(('a', 'b', 'c')), value)
        self.assertEquals('other-origin', value.origin)
        self.assertEquals('--with-foo=a,b,c', option)

        # Conflicts are also not allowed against what is in the
        # environment/on the command line.
        helper = CommandLineHelper({}, ['cmd', '--with-foo=a,b'])
        helper.add('FOO=a,b,c', 'other-origin')
        with self.assertRaises(ConflictingOptionError) as cm:
            helper.handle(foo)
        self.assertEqual('FOO=a,b,c', cm.exception.arg)
        self.assertEqual('other-origin', cm.exception.origin)
        self.assertEqual('--with-foo=a,b', cm.exception.old_arg)
        self.assertEqual('command-line', cm.exception.old_origin)

        helper = CommandLineHelper({}, ['cmd', '--with-foo=a,b'])
        helper.add('--without-foo', 'other-origin')
        with self.assertRaises(ConflictingOptionError) as cm:
            helper.handle(foo)
        self.assertEqual('--without-foo', cm.exception.arg)
        self.assertEqual('other-origin', cm.exception.origin)
        self.assertEqual('--with-foo=a,b', cm.exception.old_arg)
        self.assertEqual('command-line', cm.exception.old_origin)
Beispiel #31
0
    def imply_option_impl(self, option, value, reason=None):
        '''Implementation of imply_option().
        Injects additional options as if they had been passed on the command
        line. The `option` argument is a string as in option()'s `name` or
        `env`. The option must be declared after `imply_option` references it.
        The `value` argument indicates the value to pass to the option.
        It can be:
        - True. In this case `imply_option` injects the positive option
          (--enable-foo/--with-foo).
              imply_option('--enable-foo', True)
              imply_option('--disable-foo', True)
          are both equivalent to `--enable-foo` on the command line.

        - False. In this case `imply_option` injects the negative option
          (--disable-foo/--without-foo).
              imply_option('--enable-foo', False)
              imply_option('--disable-foo', False)
          are both equivalent to `--disable-foo` on the command line.

        - None. In this case `imply_option` does nothing.
              imply_option('--enable-foo', None)
              imply_option('--disable-foo', None)
          are both equivalent to not passing any flag on the command line.

        - a string or a tuple. In this case `imply_option` injects the positive
          option with the given value(s).
              imply_option('--enable-foo', 'a')
              imply_option('--disable-foo', 'a')
          are both equivalent to `--enable-foo=a` on the command line.
              imply_option('--enable-foo', ('a', 'b'))
              imply_option('--disable-foo', ('a', 'b'))
          are both equivalent to `--enable-foo=a,b` on the command line.

        Because imply_option('--disable-foo', ...) can be misleading, it is
        recommended to use the positive form ('--enable' or '--with') for
        `option`.

        The `value` argument can also be (and usually is) a reference to a
        @depends function, in which case the result of that function will be
        used as per the descripted mapping above.

        The `reason` argument indicates what caused the option to be implied.
        It is necessary when it cannot be inferred from the `value`.
        '''
        # Don't do anything when --help was on the command line
        if self._help:
            return
        if not reason and isinstance(value, DummyFunction):
            deps = self._depends[value][1]
            possible_reasons = [d for d in deps if d != self._help_option]
            if len(possible_reasons) == 1:
                if isinstance(possible_reasons[0], Option):
                    reason = (self._raw_options.get(possible_reasons[0])
                              or possible_reasons[0].option)

        if not reason or not isinstance(value, DummyFunction):
            raise ConfigureError(
                "Cannot infer what implies '%s'. Please add a `reason` to "
                "the `imply_option` call." % option)

        value = self._resolve(value, need_help_dependency=False)
        if value is not None:
            if isinstance(value, OptionValue):
                pass
            elif value is True:
                value = PositiveOptionValue()
            elif value is False or value == ():
                value = NegativeOptionValue()
            elif isinstance(value, types.StringTypes):
                value = PositiveOptionValue((value, ))
            elif isinstance(value, tuple):
                value = PositiveOptionValue(value)
            else:
                raise TypeError("Unexpected type: '%s'" % type(value))

            option = value.format(option)
            self._helper.add(option, 'implied')
            self._implied_options[option] = inspect.stack()[1], reason
Beispiel #32
0
    def test_only_when(self):
        moz_configure = '''
            option('--enable-when', help='when')
            @depends('--enable-when', '--help')
            def when(value, _):
                return bool(value)

            with only_when(when):
                option('--foo', nargs='*', help='foo')
                @depends('--foo')
                def foo(value):
                    return value

                set_config('FOO', foo)
                set_define('FOO', foo)

            # It is possible to depend on a function defined in a only_when
            # block. It then resolves to `None`.
            set_config('BAR', depends(foo)(lambda x: x))
            set_define('BAR', depends(foo)(lambda x: x))
        '''

        with self.moz_configure(moz_configure):
            config = self.get_config()
            self.assertEqual(config, {
                'DEFINES': {},
            })

            config = self.get_config(['--enable-when'])
            self.assertEqual(
                config, {
                    'BAR': NegativeOptionValue(),
                    'FOO': NegativeOptionValue(),
                    'DEFINES': {
                        'BAR': NegativeOptionValue(),
                        'FOO': NegativeOptionValue(),
                    },
                })

            config = self.get_config(['--enable-when', '--foo=bar'])
            self.assertEqual(
                config, {
                    'BAR': PositiveOptionValue(['bar']),
                    'FOO': PositiveOptionValue(['bar']),
                    'DEFINES': {
                        'BAR': PositiveOptionValue(['bar']),
                        'FOO': PositiveOptionValue(['bar']),
                    },
                })

            # The --foo option doesn't exist when --enable-when is not given.
            with self.assertRaises(InvalidOptionError) as e:
                self.get_config(['--foo'])

            self.assertEquals(e.exception.message,
                              '--foo is not available in this configuration')

        # Cannot depend on an option defined in a only_when block, because we
        # don't know what OptionValue would make sense.
        with self.moz_configure(moz_configure + '''
            set_config('QUX', depends('--foo')(lambda x: x))
        '''):
            with self.assertRaises(ConfigureError) as e:
                self.get_config()

            self.assertEquals(
                e.exception.message,
                '@depends function needs the same `when` as '
                'options it depends on')

        with self.moz_configure(moz_configure + '''
            set_config('QUX', depends('--foo', when=when)(lambda x: x))
        '''):
            self.get_config(['--enable-when'])

        # Using imply_option for an option defined in a only_when block fails
        # similarly if the imply_option happens outside the block.
        with self.moz_configure('''
            imply_option('--foo', True)
        ''' + moz_configure):
            with self.assertRaises(InvalidOptionError) as e:
                self.get_config()

            self.assertEquals(e.exception.message,
                              '--foo is not available in this configuration')

        # And similarly doesn't fail when the condition is true.
        with self.moz_configure('''
            imply_option('--foo', True)
        ''' + moz_configure):
            self.get_config(['--enable-when'])
Beispiel #33
0
    def imply_option_impl(self, option, value, reason=None):
        '''Implementation of imply_option().
        Injects additional options as if they had been passed on the command
        line. The `option` argument is a string as in option()'s `name` or
        `env`. The option must be declared after `imply_option` references it.
        The `value` argument indicates the value to pass to the option.
        It can be:
        - True. In this case `imply_option` injects the positive option
          (--enable-foo/--with-foo).
              imply_option('--enable-foo', True)
              imply_option('--disable-foo', True)
          are both equivalent to `--enable-foo` on the command line.

        - False. In this case `imply_option` injects the negative option
          (--disable-foo/--without-foo).
              imply_option('--enable-foo', False)
              imply_option('--disable-foo', False)
          are both equivalent to `--disable-foo` on the command line.

        - None. In this case `imply_option` does nothing.
              imply_option('--enable-foo', None)
              imply_option('--disable-foo', None)
          are both equivalent to not passing any flag on the command line.

        - a string or a tuple. In this case `imply_option` injects the positive
          option with the given value(s).
              imply_option('--enable-foo', 'a')
              imply_option('--disable-foo', 'a')
          are both equivalent to `--enable-foo=a` on the command line.
              imply_option('--enable-foo', ('a', 'b'))
              imply_option('--disable-foo', ('a', 'b'))
          are both equivalent to `--enable-foo=a,b` on the command line.

        Because imply_option('--disable-foo', ...) can be misleading, it is
        recommended to use the positive form ('--enable' or '--with') for
        `option`.

        The `value` argument can also be (and usually is) a reference to a
        @depends function, in which case the result of that function will be
        used as per the descripted mapping above.

        The `reason` argument indicates what caused the option to be implied.
        It is necessary when it cannot be inferred from the `value`.
        '''
        # Don't do anything when --help was on the command line
        if self._help:
            return
        if not reason and isinstance(value, DummyFunction):
            deps = self._depends[value][1]
            possible_reasons = [d for d in deps if d != self._help_option]
            if len(possible_reasons) == 1:
                if isinstance(possible_reasons[0], Option):
                    reason = (self._raw_options.get(possible_reasons[0]) or
                              possible_reasons[0].option)

        if not reason or not isinstance(value, DummyFunction):
            raise ConfigureError(
                "Cannot infer what implies '%s'. Please add a `reason` to "
                "the `imply_option` call."
                % option)

        value = self._resolve(value, need_help_dependency=False)
        if value is not None:
            if isinstance(value, OptionValue):
                pass
            elif value is True:
                value = PositiveOptionValue()
            elif value is False or value == ():
                value = NegativeOptionValue()
            elif isinstance(value, types.StringTypes):
                value = PositiveOptionValue((value,))
            elif isinstance(value, tuple):
                value = PositiveOptionValue(value)
            else:
                raise TypeError("Unexpected type: '%s'" % type(value))

            option = value.format(option)
            self._helper.add(option, 'implied')
            self._implied_options[option] = inspect.stack()[1], reason