8000 handle NumPy style docstring params containing a colon #189 · shader/python-fire@b1f3f95 · GitHub
[go: up one dir, main page]

Skip to content

Commit b1f3f95

Browse files
vbarbaresicopybara-github
authored andcommitted
handle NumPy style docstring params containing a colon google#189
The problematic case was: name : str name, default: World The second line wasn't treated as a description if it contained a colon and ended up ignored We parse line by line, and used to keep track only of the next line. I added tracking of the previous line so that I can compare the indentations. That allows to distinguish descriptions and a parameter definitions. COPYBARA_INTEGRATE_REVIEW=google#201 from vbarbaresi:bugfix_189 8e6baa4 PiperOrigin-RevId: 297932310 Change-Id: Ia5ee774890a713c8ec1d5b3a895d2cb0163849c3
1 parent deb33cc commit b1f3f95

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

fire/docstrings.py

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,9 @@ def parse(docstring):
176176

177177
for index, line in enumerate(lines):
178178
has_next = index + 1 < lines_len
179+
previous_line = lines[index - 1] if index > 0 else None
179180
next_line = lines[index + 1] if has_next else None
180-
line_info = _create_line_info(line, next_line)
181+
line_info = _create_line_info(line, next_line, previous_line)
181182
_consume_line(line_info, state)
182183

183184
summary = ' '.join(state.summary.lines) if state.summary.lines else None
@@ -455,7 +456,7 @@ def _consume_line(line_info, state):
455456
# of the previous arg, or a new arg. TODO: Whitespace can distinguish.
456457
arg = _get_or_create_arg_by_name(state, line_stripped)
457458
state.current_arg = arg
458-
elif ':' in line_stripped:
459+
elif _line_is_numpy_parameter_type(line_info):
459460
possible_args, type_data = line_stripped.split(':', 1)
460461
arg_names = _as_arg_names(possible_args) # re.split(' |,', s)
461462
if arg_names:
@@ -492,8 +493,8 @@ def _consume_line(line_info, state):
492493
pass
493494

494495

495-
def _create_line_info(line, next_line):
496-
"""Returns information about the current and next line of the docstring."""
496+
def _create_line_info(line, next_line, previous_line):
497+
"""Returns information about the current line and surrounding lines."""
497498
line_info = Namespace() # TODO(dbieber): Switch to an explicit class.
498499
line_info.line = line
499500
line_info.stripped = line.strip()
@@ -506,6 +507,11 @@ def _create_line_info(line, next_line):
506507
line_info.next.stripped = next_line.strip() if next_line_exists else None
507508
line_info.next.indentation = (
508509
len(next_line) - len(next_line.lstrip()) if next_line_exists else None)
510+
line_info.previous.line = previous_line
511+
previous_line_exists = previous_line is not None
512+
line_info.previous.indentation = (
513+
len(previous_line) -
514+
len(previous_line.lstrip()) if previous_line_exists else None)
509515
# Note: This counts all whitespace equally.
510516
return line_info
511517

@@ -726,3 +732,29 @@ def _numpy_section(line_info):
726732
return _section_from_possible_title(possible_title)
727733
else:
728734
return None
735+
736+
737+
def _line_is_numpy_parameter_type(line_info):
738+
"""Returns whether the line contains a numpy style parameter type definition.
739+
740+
We look for a line of the form:
741+
x : type
742+
743+
And we have to exclude false positives on argument descriptions containing a
744+
colon by checking the indentation of the line above.
745+
746+
Args:
747+
line_info: Information about the current line.
748+
Returns:
749+
True if the line is a numpy parameter type definition, False otherwise.
750+
"""
751+
line_stripped = line_info.remaining.strip()
752+
if ':' in line_stripped:
753+
previous_indent = line_info.previous.indentation
754+
current_indent = line_info.indentation
755+
if ':' in line_info.previous.line and current_indent > previous_indent:
756+
# The parameter type was the previous line; this is the description.
757+
return False
758+
else:
759+
return True
760+
return False

fire/docstrings_test.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,32 @@ def test_strip_blank_lines(self):
253253

254254
self.assertEqual(expected_output, docstrings._strip_blank_lines(lines)) # pylint: disable=protected-access
255255

256+
def test_numpy_colon_in_description(self):
257+
docstring = """
258+
Greets name.
259+
260+
Arguments
261+
---------
262+
name : str
263+
name, default : World
264+
arg2 : int
265+
arg2, default:None
266+
arg3 : bool
267+
"""
268+
docstring_info = docstrings.parse(docstring)
269+
expected_docstring_info = DocstringInfo(
270+
summary='Greets name.',
271+
description=None,
272+
args=[
273+
ArgInfo(name='name', type='str',
274+
description='name, default : World'),
275+
ArgInfo(name='arg2', type='int',
276+
description='arg2, default:None'),
277+
ArgInfo(name='arg3', type='bool', description=None),
278+
]
279+
)
280+
self.assertEqual(expected_docstring_info, docstring_info)
281+
256282

257283
if __name__ == '__main__':
258284
testutils.main()

0 commit comments

Comments
 (0)
0