Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions fire/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -884,12 +884,13 @@ def _ParseKeywordArgs(args, fn_spec):

# Determine the keyword.
keyword = '' # Indicates no valid keyword has been found yet.
if (key in fn_args
or (is_bool_syntax and key.startswith('no') and key[2:] in fn_args)
or fn_keywords):
if key in fn_args or (
is_bool_syntax and key.startswith('no') and key[2:] in fn_args):
keyword = key
elif len(key) == 1:
# This may be a shortcut flag.
# This may be a shortcut flag. Check fn_args before falling back to
# fn_keywords so that short flags like -f expand to the matching
# fn_arg (e.g. 'first_arg') even when **kwargs is present.
matching_fn_args = [arg for arg in fn_args if arg[0] == key]
if len(matching_fn_args) == 1:
keyword = matching_fn_args[0]
Expand All @@ -898,6 +899,10 @@ def _ParseKeywordArgs(args, fn_spec):
f"The argument '{argument}' is ambiguous as it could "
f"refer to any of the following arguments: {matching_fn_args}"
)
elif fn_keywords:
keyword = key
elif fn_keywords:
keyword = key

# Determine the value.
if not keyword:
Expand Down
17 changes: 17 additions & 0 deletions fire/fire_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,23 @@ def testSingleCharFlagParsingExactMatch(self):
fire.Fire(tc.SimilarArgNames,
command=['identity2', '-a', '-alpha']), (True, True))

def testSingleCharFlagParsingWithKwargs(self):
# Short flags should map to their matching fn_arg even when **kwargs is
# present (regression test for github.com/google/python-fire/issues/454).
self.assertEqual(
fire.Fire(tc.fn_with_defaults_and_kwargs,
command=['-f=hello', '-s=world']),
('hello', 'world', {}))
self.assertEqual(
fire.Fire(tc.fn_with_defaults_and_kwargs,
command=['-f', 'hello', '-s', 'world']),
('hello', 'world', {}))
# Unrecognised single-char flags should still be forwarded to **kwargs.
self.assertEqual(
fire.Fire(tc.fn_with_defaults_and_kwargs,
command=['--unknown_key=42']),
('left', 'right', {'unknown_key': 42}))

def testSingleCharFlagParsingCapitalLetter(self):
self.assertEqual(
fire.Fire(tc.CapitalizedArgNames,
Expand Down
5 changes: 5 additions & 0 deletions fire/test_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,11 @@ def fn_with_kwarg_and_defaults(arg1, arg2, opt=True, **kwargs):
return kwargs.get('arg3')


def fn_with_defaults_and_kwargs(first_arg='left', second_arg='right', **kwargs):
"""Function with named defaults plus **kwargs, used to test short flags."""
return (first_arg, second_arg, kwargs)


def fn_with_multiple_defaults(first='first', last='last', late='late'):
"""Function with kwarg and defaults.

Expand Down