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
18 changes: 18 additions & 0 deletions fire/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,10 @@ def _ParseKeywordArgs(args, fn_spec):
return kwargs, remaining_kwargs, remaining_args

skip_argument = False
positional_capacity = (
None if fn_spec.varargs is not None else len(fn_spec.args))
explicit_positional_kwargs = set()
seen_bare_args = 0

for index, argument in enumerate(args):
if skip_argument:
Expand Down Expand Up @@ -882,6 +886,14 @@ def _ParseKeywordArgs(args, fn_spec):
is_bool_syntax = (not contains_equals and
(index + 1 == len(args) or _IsFlag(args[index + 1])))

if (positional_capacity is not None
and seen_bare_args > positional_capacity):
remaining_kwargs.append(argument)
if not contains_equals and not is_bool_syntax:
remaining_kwargs.append(args[index + 1])
skip_argument = True
continue

# Determine the keyword.
keyword = '' # Indicates no valid keyword has been found yet.
if (key in fn_args
Expand Down Expand Up @@ -929,11 +941,17 @@ def _ParseKeywordArgs(args, fn_spec):
skip_argument = not contains_equals and not is_bool_syntax
if got_argument:
kwargs[keyword] = value
if (keyword in fn_spec.args
and keyword not in explicit_positional_kwargs):
explicit_positional_kwargs.add(keyword)
if positional_capacity is not None:
positional_capacity = max(positional_capacity - 1, 0)
else:
remaining_kwargs.append(argument)
if skip_argument:
remaining_kwargs.append(args[index + 1])
else: # not _IsFlag(argument)
seen_bare_args += 1
remaining_args.append(argument)

return kwargs, remaining_kwargs, remaining_args
Expand Down
20 changes: 20 additions & 0 deletions fire/fire_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

"""Tests for the fire module."""

from dataclasses import dataclass
import os
import sys
from unittest import mock
Expand Down Expand Up @@ -250,6 +251,25 @@ def testFireKeywordArgs(self):
command=['upper', '--alpha', 'A', '--beta', 'B', '-', 'lower']),
'alpha beta')

def testFireKeywordArgsChainedCall(self):
@dataclass
class MyClass:
x: int

def transform(self, **kwargs):
return MyClass(self.x * kwargs.get('multiplier', 2))

def do_something(self, msg):
return f'{msg}: {self.x}'

my_obj = MyClass(3)
self.assertEqual(
fire.Fire(
my_obj,
command=['transform', '--multiplier=3', 'do_something',
'--msg=test']),
'test: 9')

def testFireKeywordArgsWithMissingPositionalArgs(self):
self.assertEqual(
fire.Fire(tc.Kwargs, command=['run', 'Hello', 'World', '--cell', 'is']),
Expand Down