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"])
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'])
def __init__(self, config, environ=os.environ, argv=sys.argv, stdout=sys.stdout, stderr=sys.stderr): dict.__setitem__(self, '__builtins__', self.BUILTINS) self._paths = [] self._templates = set() # Store the real function and its dependencies, behind each # DummyFunction generated from @depends. self._depends = {} self._seen = set() self._options = OrderedDict() # Store the raw values returned by @depends functions self._results = {} # Store values for each Option, as per returned by Option.get_value self._option_values = {} # Store raw option (as per command line or environment) for each Option self._raw_options = {} # Store options added with `imply_option`, and the reason they were # added (which can either have been given to `imply_option`, or # inferred. self._implied_options = {} # Store all results from _prepare_function self._prepared_functions = set() self._helper = CommandLineHelper(environ, argv) assert isinstance(config, dict) self._config, self._stdout, self._stderr = config, stdout, stderr self._help = None self._help_option = self.option_impl('--help', help='print this message') self._seen.add(self._help_option) # self._option_impl('--help') will have set this if --help was on the # command line. if self._option_values[self._help_option]: self._help = HelpFormatter(argv[0]) self._help.add(self._help_option)
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)
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)
def __init__(self, config, environ=os.environ, argv=sys.argv, stdout=sys.stdout, stderr=sys.stderr, logger=None): dict.__setitem__(self, '__builtins__', self.BUILTINS) self._environ = dict(environ) self._paths = [] self._all_paths = set() self._templates = set() # Associate SandboxDependsFunctions to DependsFunctions. self._depends = OrderedDict() self._seen = set() # Store the @imports added to a given function. self._imports = {} self._options = OrderedDict() # Store raw option (as per command line or environment) for each Option self._raw_options = OrderedDict() # Store options added with `imply_option`, and the reason they were # added (which can either have been given to `imply_option`, or # inferred. Their order matters, so use a list. self._implied_options = [] # Store all results from _prepare_function self._prepared_functions = set() # Queue of functions to execute, with their arguments self._execution_queue = [] # Store the `when`s associated to some options. self._conditions = {} # A list of conditions to apply as a default `when` for every *_impl() self._default_conditions = [] self._helper = CommandLineHelper(environ, argv) assert isinstance(config, dict) self._config = config # Tracks how many templates "deep" we are in the stack. self._template_depth = 0 logging.addLevelName(TRACE, 'TRACE') if logger is None: logger = moz_logger = logging.getLogger('moz.configure') logger.setLevel(logging.DEBUG) formatter = logging.Formatter('%(levelname)s: %(message)s') handler = ConfigureOutputHandler(stdout, stderr) handler.setFormatter(formatter) queue_debug = handler.queue_debug logger.addHandler(handler) else: assert isinstance(logger, logging.Logger) moz_logger = None @contextmanager def queue_debug(): yield self._logger = logger # Some callers will manage to log a bytestring with characters in it # that can't be converted to ascii. Make our log methods robust to this # by detecting the encoding that a producer is likely to have used. encoding = getpreferredencoding() def wrapped_log_method(logger, key): method = getattr(logger, key) def wrapped(*args, **kwargs): out_args = [ six.ensure_text(arg, encoding=encoding or 'utf-8') if isinstance(arg, six.binary_type) else arg for arg in args ] return method(*out_args, **kwargs) return wrapped log_namespace = { k: wrapped_log_method(logger, k) for k in ('debug', 'info', 'warning', 'error') } log_namespace['queue_debug'] = queue_debug self.log_impl = ReadOnlyNamespace(**log_namespace) self._help = None self._help_option = self.option_impl( '--help', help='print this message', category=HELP_OPTIONS_CATEGORY) self._seen.add(self._help_option) self._always = DependsFunction(self, lambda: True, []) self._never = DependsFunction(self, lambda: False, []) if self._value_for(self._help_option): self._help = HelpFormatter(argv[0]) self._help.add(self._help_option) elif moz_logger: handler = logging.FileHandler('config.log', mode='w', delay=True, encoding='utf-8') handler.setFormatter(formatter) logger.addHandler(handler)
def __init__(self, config, environ=os.environ, argv=sys.argv, stdout=sys.stdout, stderr=sys.stderr, logger=None): dict.__setitem__(self, '__builtins__', self.BUILTINS) self._paths = [] self._templates = set() # Store the real function and its dependencies, behind each # DependsFunction generated from @depends. self._depends = {} self._seen = set() # Store the @imports added to a given function. self._imports = {} self._options = OrderedDict() # Store the raw values returned by @depends functions self._results = {} # Store values for each Option, as per returned by Option.get_value self._option_values = {} # Store raw option (as per command line or environment) for each Option self._raw_options = {} # Store options added with `imply_option`, and the reason they were # added (which can either have been given to `imply_option`, or # inferred. self._implied_options = {} # Store all results from _prepare_function self._prepared_functions = set() self._helper = CommandLineHelper(environ, argv) assert isinstance(config, dict) self._config = config if logger is None: logger = moz_logger = logging.getLogger('moz.configure') logger.setLevel(logging.DEBUG) formatter = logging.Formatter('%(levelname)s: %(message)s') handler = ConfigureOutputHandler(stdout, stderr) handler.setFormatter(formatter) queue_debug = handler.queue_debug logger.addHandler(handler) else: assert isinstance(logger, logging.Logger) moz_logger = None @contextmanager def queue_debug(): yield log_namespace = { k: getattr(logger, k) for k in ('debug', 'info', 'warning', 'error') } log_namespace['queue_debug'] = queue_debug self.log_impl = ReadOnlyNamespace(**log_namespace) self._help = None self._help_option = self.option_impl('--help', help='print this message') self._seen.add(self._help_option) # self._option_impl('--help') will have set this if --help was on the # command line. if self._option_values[self._help_option]: self._help = HelpFormatter(argv[0]) self._help.add(self._help_option) elif moz_logger: handler = logging.FileHandler('config.log', mode='w', delay=True) handler.setFormatter(formatter) logger.addHandler(handler)
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)
def test_precedence(self): foo = Option('--with-foo', nargs='*') helper = CommandLineHelper({}, ['cmd', '--with-foo=a,b']) value, option = helper.handle(foo) self.assertEquals(PositiveOptionValue(('a', 'b')), value) self.assertEquals('command-line', value.origin) self.assertEquals('--with-foo=a,b', option) helper = CommandLineHelper({}, ['cmd', '--with-foo=a,b', '--without-foo']) value, option = helper.handle(foo) self.assertEquals(NegativeOptionValue(), value) self.assertEquals('command-line', value.origin) self.assertEquals('--without-foo', option) helper = CommandLineHelper({}, ['cmd', '--without-foo', '--with-foo=a,b']) value, option = helper.handle(foo) self.assertEquals(PositiveOptionValue(('a', 'b')), value) self.assertEquals('command-line', value.origin) self.assertEquals('--with-foo=a,b', option) foo = Option('--with-foo', env='FOO', nargs='*') helper = CommandLineHelper({'FOO': ''}, ['cmd', '--with-foo=a,b']) value, option = helper.handle(foo) self.assertEquals(PositiveOptionValue(('a', 'b')), value) self.assertEquals('command-line', value.origin) self.assertEquals('--with-foo=a,b', option) helper = CommandLineHelper({'FOO': 'a,b'}, ['cmd', '--without-foo']) value, option = helper.handle(foo) self.assertEquals(NegativeOptionValue(), value) self.assertEquals('command-line', value.origin) self.assertEquals('--without-foo', option) helper = CommandLineHelper({'FOO': ''}, ['cmd', '--with-bar=a,b']) value, option = helper.handle(foo) self.assertEquals(NegativeOptionValue(), value) self.assertEquals('environment', value.origin) self.assertEquals('FOO=', option) helper = CommandLineHelper({'FOO': 'a,b'}, ['cmd', '--without-bar']) value, option = helper.handle(foo) self.assertEquals(PositiveOptionValue(('a', 'b')), value) self.assertEquals('environment', value.origin) self.assertEquals('FOO=a,b', option) helper = CommandLineHelper({}, ['cmd', '--with-foo=a,b', 'FOO=']) value, option = helper.handle(foo) self.assertEquals(NegativeOptionValue(), value) self.assertEquals('command-line', value.origin) self.assertEquals('FOO=', option) helper = CommandLineHelper({}, ['cmd', '--without-foo', 'FOO=a,b']) value, option = helper.handle(foo) self.assertEquals(PositiveOptionValue(('a', 'b')), value) self.assertEquals('command-line', value.origin) self.assertEquals('FOO=a,b', option) helper = CommandLineHelper({}, ['cmd', 'FOO=', '--with-foo=a,b']) value, option = helper.handle(foo) self.assertEquals(PositiveOptionValue(('a', 'b')), value) self.assertEquals('command-line', value.origin) self.assertEquals('--with-foo=a,b', option) helper = CommandLineHelper({}, ['cmd', 'FOO=a,b', '--without-foo']) value, option = helper.handle(foo) self.assertEquals(NegativeOptionValue(), value) self.assertEquals('command-line', value.origin) self.assertEquals('--without-foo', option)
def __init__(self, config, environ=os.environ, argv=sys.argv, stdout=sys.stdout, stderr=sys.stderr, logger=None): dict.__setitem__(self, '__builtins__', self.BUILTINS) self._paths = [] self._all_paths = set() self._templates = set() # Store the real function and its dependencies, behind each # DependsFunction generated from @depends. self._depends = {} self._seen = set() # Store the @imports added to a given function. self._imports = {} self._options = OrderedDict() # Store raw option (as per command line or environment) for each Option self._raw_options = OrderedDict() # Store options added with `imply_option`, and the reason they were # added (which can either have been given to `imply_option`, or # inferred. Their order matters, so use a list. self._implied_options = [] # Store all results from _prepare_function self._prepared_functions = set() # Queue of functions to execute, with their arguments self._execution_queue = [] self._helper = CommandLineHelper(environ, argv) assert isinstance(config, dict) self._config = config if logger is None: logger = moz_logger = logging.getLogger('moz.configure') logger.setLevel(logging.DEBUG) formatter = logging.Formatter('%(levelname)s: %(message)s') handler = ConfigureOutputHandler(stdout, stderr) handler.setFormatter(formatter) queue_debug = handler.queue_debug logger.addHandler(handler) else: assert isinstance(logger, logging.Logger) moz_logger = None @contextmanager def queue_debug(): yield # Some callers will manage to log a bytestring with characters in it # that can't be converted to ascii. Make our log methods robust to this # by detecting the encoding that a producer is likely to have used. encoding = getpreferredencoding() def wrapped_log_method(logger, key): method = getattr(logger, key) if not encoding: return method def wrapped(*args, **kwargs): out_args = [ arg.decode(encoding) if isinstance(arg, str) else arg for arg in args ] return method(*out_args, **kwargs) return wrapped log_namespace = { k: wrapped_log_method(logger, k) for k in ('debug', 'info', 'warning', 'error') } log_namespace['queue_debug'] = queue_debug self.log_impl = ReadOnlyNamespace(**log_namespace) self._help = None self._help_option = self.option_impl('--help', help='print this message') self._seen.add(self._help_option) if self._value_for(self._help_option): self._help = HelpFormatter(argv[0]) self._help.add(self._help_option) elif moz_logger: handler = logging.FileHandler('config.log', mode='w', delay=True) handler.setFormatter(formatter) logger.addHandler(handler)
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)
def test_precedence(self): foo = Option("--with-foo", nargs="*") helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b"]) value, option = helper.handle(foo) self.assertEquals(PositiveOptionValue(("a", "b")), value) self.assertEquals("command-line", value.origin) self.assertEquals("--with-foo=a,b", option) helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b", "--without-foo"]) value, option = helper.handle(foo) self.assertEquals(NegativeOptionValue(), value) self.assertEquals("command-line", value.origin) self.assertEquals("--without-foo", option) helper = CommandLineHelper({}, ["cmd", "--without-foo", "--with-foo=a,b"]) value, option = helper.handle(foo) self.assertEquals(PositiveOptionValue(("a", "b")), value) self.assertEquals("command-line", value.origin) self.assertEquals("--with-foo=a,b", option) foo = Option("--with-foo", env="FOO", nargs="*") helper = CommandLineHelper({"FOO": ""}, ["cmd", "--with-foo=a,b"]) value, option = helper.handle(foo) self.assertEquals(PositiveOptionValue(("a", "b")), value) self.assertEquals("command-line", value.origin) self.assertEquals("--with-foo=a,b", option) helper = CommandLineHelper({"FOO": "a,b"}, ["cmd", "--without-foo"]) value, option = helper.handle(foo) self.assertEquals(NegativeOptionValue(), value) self.assertEquals("command-line", value.origin) self.assertEquals("--without-foo", option) helper = CommandLineHelper({"FOO": ""}, ["cmd", "--with-bar=a,b"]) value, option = helper.handle(foo) self.assertEquals(NegativeOptionValue(), value) self.assertEquals("environment", value.origin) self.assertEquals("FOO=", option) helper = CommandLineHelper({"FOO": "a,b"}, ["cmd", "--without-bar"]) value, option = helper.handle(foo) self.assertEquals(PositiveOptionValue(("a", "b")), value) self.assertEquals("environment", value.origin) self.assertEquals("FOO=a,b", option) helper = CommandLineHelper({}, ["cmd", "--with-foo=a,b", "FOO="]) value, option = helper.handle(foo) self.assertEquals(NegativeOptionValue(), value) self.assertEquals("command-line", value.origin) self.assertEquals("FOO=", option) helper = CommandLineHelper({}, ["cmd", "--without-foo", "FOO=a,b"]) value, option = helper.handle(foo) self.assertEquals(PositiveOptionValue(("a", "b")), value) self.assertEquals("command-line", value.origin) self.assertEquals("FOO=a,b", option) helper = CommandLineHelper({}, ["cmd", "FOO=", "--with-foo=a,b"]) value, option = helper.handle(foo) self.assertEquals(PositiveOptionValue(("a", "b")), value) self.assertEquals("command-line", value.origin) self.assertEquals("--with-foo=a,b", option) helper = CommandLineHelper({}, ["cmd", "FOO=a,b", "--without-foo"]) value, option = helper.handle(foo) self.assertEquals(NegativeOptionValue(), value) self.assertEquals("command-line", value.origin) self.assertEquals("--without-foo", option)