From edd4b6d23f4399960db4e16a8c269318aef033d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Mazzucotelli?= Date: Thu, 22 Sep 2022 23:37:12 +0200 Subject: [PATCH] fix: Show correct docstring line numbers on Python 3.7 Issue #98: https://github.com/mkdocstrings/griffe/issues/98 --- src/griffe/agents/nodes.py | 10 +++++++++- tests/test_visitor.py | 23 ++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/griffe/agents/nodes.py b/src/griffe/agents/nodes.py index 1b324bbd..d0596558 100644 --- a/src/griffe/agents/nodes.py +++ b/src/griffe/agents/nodes.py @@ -825,7 +825,15 @@ def get_docstring( if isinstance(doc, NodeConstant) and isinstance(doc.value, str): return doc.value, doc.lineno, doc.end_lineno # type: ignore[attr-defined] if isinstance(doc, NodeStr): - return doc.s, doc.lineno, doc.end_lineno # type: ignore[attr-defined] + + # TODO: remove once Python 3.7 support is dropped + # on Python 3.7, lineno seems to be the ending line of the string + # rather than the starting one, so we substract the number of newlines + lineno = doc.lineno + if sys.version_info < (3, 8): + lineno -= doc.s.count("\n") + + return doc.s, lineno, doc.end_lineno # type: ignore[attr-defined] return None, None, None diff --git a/tests/test_visitor.py b/tests/test_visitor.py index 7b9c31c2..b5b0b8be 100644 --- a/tests/test_visitor.py +++ b/tests/test_visitor.py @@ -227,7 +227,6 @@ def test_parse_complex__all__assignments(statements): assert package.exports == {"CONST_INIT", "CONST_A", "CONST_B", "CONST_C"} -# issue https://github.com/mkdocstrings/griffe/issues/68 def test_dont_crash_on_nested_functions_in_init(): """Assert we don't crash when visiting a nested function in `__init__` methods.""" with temporary_visited_module( @@ -239,3 +238,25 @@ def pl(i: int): """ ) as module: assert module + + +def test_get_correct_docstring_starting_line_number(): + """Assert we get the correct line numbers for docstring, even on Python 3.7.""" + with temporary_visited_module( + """ + ''' + Module docstring. + ''' + class C: + ''' + Class docstring. + ''' + def method(self): + ''' + Method docstring. + ''' + """ + ) as module: + assert module.docstring.lineno == 2 + assert module["C"].docstring.lineno == 6 + assert module["C.method"].docstring.lineno == 10