10000 Fix the issue where keyword only arguments with default value is inco… · shader/python-fire@b978161 · GitHub
[go: up one dir, main page]

Skip to content

Commit b978161

Browse files
joejoevictordbieber
authored andcommitted
Fix the issue where keyword only arguments with default value is incorrectly marked as required.
PiperOrigin-RevId: 301185283 Change-Id: I0d7e2df1d5411769db6250f819f776c955c788f9
1 parent aa72776 commit b978161

File tree

3 files changed

+47
-9
lines changed

3 files changed

+47
-9
lines changed

fire/helptext.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
from __future__ import division
3434
from __future__ import print_function
3535

36+
import itertools
37+
3638
from fire import completion
3739
from fire import custom_descriptions
3840
from fire import decorators
@@ -167,6 +169,11 @@ def _DescriptionSection(component, info):
167169
return None
168170

169171

172+
def _CreateKeywordOnlyFlagItem(flag, docstring_info, spec):
173+
return _CreateFlagItem(
174+
flag, docstring_info, required=flag not in spec.kwonlydefaults)
175+
176+
170177
def _ArgsAndFlagsSections(info, spec, metadata):
171178
"""The "Args and Flags" sections of the help string."""
172179
args_with_no_defaults = spec.args[:len(spec.args) - len(spec.defaults)]
@@ -199,15 +206,15 @@ def _ArgsAndFlagsSections(info, spec, metadata):
199206
('NOTES', 'You can also use flags syntax for POSITIONAL ARGUMENTS')
200207
)
201208

202-
optional_flag_items = [
209+
positional_flag_items = [
203210
_CreateFlagItem(flag, docstring_info, required=False)
204211
for flag in args_with_defaults
205212
]
206-
required_flag_items = [
207-
_CreateFlagItem(flag, docstring_info, required=True)
213+
kwonly_flag_items = [
214+
_CreateKeywordOnlyFlagItem(flag, docstring_info, spec)
208215
for flag in spec.kwonlyargs
209216
]
210-
flag_items = optional_flag_items + required_flag_items
217+
flag_items = positional_flag_items + kwonly_flag_items
211218

212219
if spec.varkw:
213220
description = _GetArgDescription(spec.varkw, docstring_info)
@@ -382,9 +389,7 @@ def _CreateFlagItem(flag, docstring_info, required=False):
382389
flag: The name of the flag.
383390
docstring_info: A docstrings.DocstringInfo namedtuple with information about
384391
the containing function's docstring.
385-
required: Whether the flag is required. Keyword-only arguments (only in
386-
Python 3) become required flags, whereas normal keyword arguments become
387-
optional flags.
392+
required: Whether the flag is required.
388393
Returns:
389394
A string to be used in constructing the help screen for the function.
390395
"""
@@ -570,13 +575,21 @@ def _GetCallableUsageItems(spec, metadata):
570575
return items
571576

572577

578+
def _KeywordOnlyArguments(spec, required=True):
579+
return (flag for flag in spec.kwonlyargs
580+
if required == (flag in spec.kwonlydefaults))
581+
582+
573583
def _GetCallableAvailabilityLines(spec):
574584
"""The list of availability lines for a callable for use in a usage string."""
575585
args_with_defaults = spec.args[len(spec.args) - len(spec.defaults):]
576586

577587
# TODO(dbieber): Handle args_with_no_defaults if not accepts_positional_args.
578-
optional_flags = [('--' + flag) for flag in args_with_defaults]
579-
required_flags = [('--' + flag) for flag in spec.kwonlyargs]
588+
optional_flags = [('--' + flag) for flag in itertools.chain(
589+
args_with_defaults, _KeywordOnlyArguments(spec, required=False))]
590+
required_flags = [
591+
('--' + flag) for flag in _KeywordOnlyArguments(spec, required=True)
592+
]
580593

581594
# Flags section:
582595
availability_lines = []

fire/helptext_test.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@
2020

2121
import os
2222
import textwrap
23+
import unittest
2324

2425
from fire import formatting
2526
from fire import helptext
2627
from fire import test_components as tc
2728
from fire import testutils
2829
from fire import trace
30+
import six
2931

3032

3133
class HelpTest(testutils.BaseTestCase):
@@ -158,6 +160,26 @@ def testHelpTextNoInit(self):
158160
self.assertIn('NAME\n OldStyleEmpty', help_screen)
159161
self.assertIn('SYNOPSIS\n OldStyleEmpty', help_screen)
160162

163+
@unittest.skipIf(
164+
six.PY2,
165+
'Python 2 does not support single asterisk in function definition')
166+
def testHelpTextKeywordOnlyArgumentsWithDefault(self):
167+
component = tc.py3.KeywordOnly.with_default
168+
output = helptext.HelpText(
169+
component=component, trace=trace.FireTrace(component, 'with_default'))
170+
self.assertIn('NAME\n with_default', output)
171+
self.assertIn('FLAGS\n --x=X', output)
172+
173+
@unittest.skipIf(
174+
six.PY2,
175+
'Python 2 does not support single asterisk in function definition')
176+
def testHelpTextKeywordOnlyArgumentsWithoutDefault(self):
177+
component = tc.py3.KeywordOnly.double
178+
output = helptext.HelpText(
179+
component=component, trace=trace.FireTrace(component, 'double'))
180+
self.assertIn('NAME\n double', output)
181+
self.assertIn('FLAGS\n --count=COUNT (required)', output)
182+
161183
def testHelpScreen(self):
162184
component = tc.ClassWithDocstring()
163185
t = trace.FireTrace(component, name='ClassWithDocstring')

fire/test_components_py3.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ def double(self, *, count):
3232
def triple(self, *, count):
3333
return count * 3
3434

35+
def with_default(self, *, x="x"):
36+
print("x: " + x)
37+
3538

3639
class LruCacheDecoratedMethod(object):
3740

0 commit comments

Comments
 (0)
0