From f9d337bdc65934d30437a7b7a4d54c8e57644a35 Mon Sep 17 00:00:00 2001 From: "weihong.xu" Date: Sun, 25 Sep 2022 23:58:08 +0800 Subject: [PATCH] Support SkipParse decorator --- fire/core.py | 27 +++++++++++++++++++++++---- fire/decorators.py | 8 ++++++++ fire/decorators_test.py | 12 ++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/fire/core.py b/fire/core.py index 4546b273..1a79b951 100644 --- a/fire/core.py +++ b/fire/core.py @@ -722,7 +722,18 @@ def _MakeParseFn(fn, metadata): required_kwonly = set(fn_spec.kwonlyargs) - set(fn_spec.kwonlydefaults) def _ParseFn(args): - """Parses the list of `args` into (varargs, kwargs), remaining_args.""" + """Parses the list of `args` into (varargs, kwargs), consumed_args, remaining_args.""" + + skip_parse = metadata.get(decorators.SKIP_PARSE, False) + + if skip_parse: + kwargs = {} + remaining_kwargs = [] + remaining_args = [] + varargs = consumed_args = args[:] + capacity = False + return (varargs, kwargs), consumed_args, remaining_args, capacity + kwargs, remaining_kwargs, remaining_args = _ParseKeywordArgs(args, fn_spec) # Note: _ParseArgs modifies kwargs. @@ -754,8 +765,16 @@ def _ParseFn(args): varargs = parsed_args + varargs remaining_args += remaining_kwargs - consumed_args = args[:len(args) - len(remaining_args)] - return (varargs, kwargs), consumed_args, remaining_args, capacity + sorted_remaining_args = [] + consumed_args = [] + for arg in args: + if arg in remaining_args: + sorted_remaining_args.append(arg) + remaining_args.remove(arg) + else: + consumed_args.append(arg) + + return (varargs, kwargs), consumed_args, sorted_remaining_args, capacity return _ParseFn @@ -989,4 +1008,4 @@ def _ParseValue(value, index, arg, metadata): elif default is not None: parse_fn = default - return parse_fn(value) + return parse_fn(value) \ No newline at end of file diff --git a/fire/decorators.py b/fire/decorators.py index 9e56d6df..37587efb 100644 --- a/fire/decorators.py +++ b/fire/decorators.py @@ -27,6 +27,14 @@ FIRE_METADATA = 'FIRE_METADATA' FIRE_PARSE_FNS = 'FIRE_PARSE_FNS' ACCEPTS_POSITIONAL_ARGS = 'ACCEPTS_POSITIONAL_ARGS' +SKIP_PARSE = 'SKIP_PARSE' + + +def SkipParse(fn): + """Set a flag to tell Fire to pass original args to decorated fn. + """ + _SetMetadata(fn, SKIP_PARSE, True) + return fn def SetParseFn(fn, *arguments): diff --git a/fire/decorators_test.py b/fire/decorators_test.py index cc7d6203..4867687b 100644 --- a/fire/decorators_test.py +++ b/fire/decorators_test.py @@ -90,6 +90,13 @@ def example7(self, arg1, arg2=None, *varargs, **kwargs): # pylint: disable=keyw return arg1, arg2, varargs, kwargs +class SkipParseArgs(object): + + @decorators.SkipParse + def example8(self, *args): + return args + + class FireDecoratorsTest(testutils.BaseTestCase): def testSetParseFnsNamedArgs(self): @@ -169,6 +176,11 @@ def testSetParseFn(self): command=['example7', '1', '--arg2=2', '3', '4', '--kwarg=5']), ('1', '2', ('3', '4'), {'kwarg': '5'})) + def testSkipParse(self): + command = ['example8', 'test', '1', '--arg2=2', '3', '4', '--kwarg=5', '--flag'] + self.assertEqual( + core.Fire(SkipParseArgs, command=command), tuple(command[1:])) + if __name__ == '__main__': testutils.main()