From 96f446d3b92f01d0bbe4fdaf833f1e8c0ca6c1ff Mon Sep 17 00:00:00 2001 From: uditDewan Date: Sat, 18 Jul 2026 16:29:17 -0400 Subject: [PATCH] Fix numpy docstring args being misparsed as section headers In a numpy-style Parameters section, an argument whose name matches a section title keyword (e.g. "argument", "param", "key") was misinterpreted as the start of a new Google-style Args section. The argument was then dropped from the parsed docstring and its description was appended to the previous argument, producing misaligned help text. Numpy parameter lines have whitespace before the colon ("argument : int"), while Google section headers do not ("Args:"), so treat such lines inside a numpy section as parameters rather than section headers. Fixes #439 --- fire/docstrings.py | 8 ++++++++ fire/docstrings_test.py | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/fire/docstrings.py b/fire/docstrings.py index 2adfe5ec..af15a8ae 100644 --- a/fire/docstrings.py +++ b/fire/docstrings.py @@ -597,6 +597,14 @@ def _google_section_permitted(line_info, state): """ if state.section.indentation is None: # We're not in a section yet. return True + if state.section.format == Formats.NUMPY: + colon_index = line_info.remaining.find(':') + if colon_index > 0 and line_info.remaining[colon_index - 1].isspace(): + # Numpy-style parameter lines have a space before the colon (e.g. + # "argument : int"), unlike Google section headers (e.g. "Args:"). Such + # a line is a parameter, not a new section, even if the parameter's name + # matches a section title (e.g. an argument named "argument"). + return False return (line_info.indentation <= state.section.indentation or line_info.indentation < state.section.line1_indentation) diff --git a/fire/docstrings_test.py b/fire/docstrings_test.py index ce516944..a21154c6 100644 --- a/fire/docstrings_test.py +++ b/fire/docstrings_test.py @@ -258,6 +258,28 @@ def test_numpy_format_multiline_arg_description(self): ) self.assertEqual(expected_docstring_info, docstring_info) + def test_numpy_format_arg_name_matches_section_title(self): + docstring = """Run. + + Parameters + ---------- + executable : + Executable to run + argument : + Positional argument to the executable + """ + docstring_info = docstrings.parse(docstring) + expected_docstring_info = DocstringInfo( + summary='Run.', + args=[ + ArgInfo(name='executable', type='', + description='Executable to run'), + ArgInfo(name='argument', type='', + description='Positional argument to the executable'), + ], + ) + self.assertEqual(expected_docstring_info, docstring_info) + def test_multisection_docstring(self): docstring = """Docstring summary.