Skip to content

Commit

Permalink
Do not treat arguments that start with '--' as string. (#99)
Browse files Browse the repository at this point in the history
* Do not treat arguments that start with '--' as strings / values.
  • Loading branch information
greenmoon55 authored and dbieber committed Dec 4, 2017
1 parent aff56bb commit fa57593
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 54 deletions.
110 changes: 60 additions & 50 deletions fire/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,8 @@ def _MakeParseFn(fn):

def _ParseFn(args):
"""Parses the list of `args` into (varargs, kwargs), remaining_args."""
kwargs, remaining_args = _ParseKeywordArgs(args, all_args, fn_spec.varkw)
kwargs, remaining_kwargs, remaining_args = \
_ParseKeywordArgs(args, all_args, fn_spec.varkw)

# Note: _ParseArgs modifies kwargs.
parsed_args, kwargs, remaining_args, capacity = _ParseArgs(
Expand Down Expand Up @@ -594,6 +595,7 @@ def _ParseFn(args):
varargs[index] = _ParseValue(value, None, None, metadata)

varargs = parsed_args + varargs
remaining_args += remaining_kwargs

consumed_args = args[:len(args) - len(remaining_args)]
return (varargs, kwargs), consumed_args, remaining_args, capacity
Expand Down Expand Up @@ -681,64 +683,72 @@ def _ParseKeywordArgs(args, fn_args, fn_keywords):
fn_keywords: The argument name for **kwargs, or None if **kwargs not used
Returns:
kwargs: A dictionary mapping keywords to values.
remaining_kwargs: A list of the unused kwargs from the original args.
remaining_args: A list of the unused arguments from the original args.
"""
kwargs = {}
if args:
remaining_args = []
skip_argument = False

for index, argument in enumerate(args):
if skip_argument:
skip_argument = False
continue

arg_consumed = False
if argument.startswith('--'):
# This is a named argument; get its value from this arg or the next.
got_argument = False

keyword = argument[2:]
contains_equals = '=' in keyword
is_bool_syntax = (
not contains_equals and
(index + 1 == len(args) or args[index + 1].startswith('--')))
if contains_equals:
keyword, value = keyword.split('=', 1)
got_argument = True
elif is_bool_syntax:
# Since there's no next arg or the next arg is a Flag, we consider
# this flag to be a boolean.
got_argument = True
if keyword in fn_args:
value = 'True'
elif keyword.startswith('no'):
keyword = keyword[2:]
value = 'False'
else:
value = 'True'
remaining_kwargs = []
remaining_args = []

if not args:
return kwargs, remaining_kwargs, remaining_args

skip_argument = False

for index, argument in enumerate(args):
if skip_argument:
skip_argument = False
continue

arg_consumed = False
if argument.startswith('--'):
# This is a named argument; get its value from this arg or the next.
got_argument = False

keyword = argument[2:]
contains_equals = '=' in keyword
is_bool_syntax = (
not contains_equals and
(index + 1 == len(args) or args[index + 1].startswith('--')))
if contains_equals:
keyword, value = keyword.split('=', 1)
got_argument = True
elif is_bool_syntax:
# Since there's no next arg or the next arg is a Flag, we consider
# this flag to be a boolean.
got_argument = True
if keyword in fn_args:
value = 'True'
elif keyword.startswith('no'):
keyword = keyword[2:]
value = 'False'
else:
if index + 1 < len(args):
value = args[index + 1]
got_argument = True
value = 'True'
else:
if index + 1 < len(args):
value = args[index + 1]
got_argument = True

keyword = keyword.replace('-', '_')
keyword = keyword.replace('-', '_')

# In order for us to consume the argument as a keyword arg, we either:
# Need to be explicitly expecting the keyword, or we need to be
# accepting **kwargs.
if got_argument and (keyword in fn_args or fn_keywords):
# In order for us to consume the argument as a keyword arg, we either:
# Need to be explicitly expecting the keyword, or we need to be
# accepting **kwargs.
if got_argument:
skip_argument = not contains_equals and not is_bool_syntax
arg_consumed = True
if keyword in fn_args or fn_keywords:
kwargs[keyword] = value
skip_argument = not contains_equals and not is_bool_syntax
arg_consumed = True
else:
remaining_kwargs.append(argument)
if skip_argument:
remaining_kwargs.append(args[index + 1])

if not arg_consumed:
# The argument was not consumed, so it is still a remaining argument.
remaining_args.append(argument)
else:
remaining_args = args
if not arg_consumed:
# The argument was not consumed, so it is still a remaining argument.
remaining_args.append(argument)

return kwargs, remaining_args
return kwargs, remaining_kwargs, remaining_args


def _ParseValue(value, index, arg, metadata):
Expand Down
13 changes: 9 additions & 4 deletions fire/fire_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -368,10 +368,15 @@ def testBoolParsingLessExpectedCases(self):
fire.Fire(tc.MixedDefaults,
command=['identity', 'True', '10']), (True, 10))

# Note: Does not return ('--test', '0').
self.assertEqual(fire.Fire(tc.MixedDefaults,
command=['identity', '--alpha', '--test']),
(True, '--test'))
# Note: Does not return (True, '--test') or ('--test', 0).
with self.assertRaisesFireExit(2):
fire.Fire(tc.MixedDefaults, command=['identity', '--alpha', '--test'])

self.assertEqual(
fire.Fire(
tc.MixedDefaults,
command=['identity', '--alpha', 'True', '"--test"']),
(True, '--test'))
# To get ('--test', '0'), use one of the following:
self.assertEqual(fire.Fire(tc.MixedDefaults,
command=['identity', '--alpha=--test']),
Expand Down

0 comments on commit fa57593

Please sign in to comment.