Skip to content

Commit 7ac01ba

Browse files
committed
feat: Add warnings parameter to docstring parsers, allowing to disable all warning logs when parsing docstrings
Issue-293: #293
1 parent c0c2c75 commit 7ac01ba

6 files changed

Lines changed: 297 additions & 133 deletions

File tree

src/_griffe/docstrings/google.py

Lines changed: 101 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
_RE_DOCTEST_FLAGS: Pattern = re.compile(r"(\s*#\s*doctest:.+)$")
8181

8282

83-
def _read_block_items(docstring: Docstring, *, offset: int, **options: Any) -> _ItemsBlock: # noqa: ARG001
83+
def _read_block_items(docstring: Docstring, *, offset: int, warnings: bool = True, **options: Any) -> _ItemsBlock: # noqa: ARG001
8484
lines = docstring.lines
8585
if offset >= len(lines):
8686
return [], offset
@@ -119,12 +119,13 @@ def _read_block_items(docstring: Docstring, *, offset: int, **options: Any) -> _
119119
# Indent between initial and continuation: append but warn.
120120
cont_indent = len(line) - len(line.lstrip())
121121
current_item[1].append(line[cont_indent:])
122-
docstring_warning(
123-
docstring,
124-
new_offset,
125-
f"Confusing indentation for continuation line {new_offset + 1} in docstring, "
126-
f"should be {indent} * 2 = {indent * 2} spaces, not {cont_indent}",
127-
)
122+
if warnings:
123+
docstring_warning(
124+
docstring,
125+
new_offset,
126+
f"Confusing indentation for continuation line {new_offset + 1} in docstring, "
127+
f"should be {indent} * 2 = {indent * 2} spaces, not {cont_indent}",
128+
)
128129

129130
elif line.startswith(indent * " "):
130131
# Indent equal to initial one: new item.
@@ -179,19 +180,25 @@ def _read_parameters(
179180
*,
180181
offset: int,
181182
warn_unknown_params: bool = True,
183+
warnings: bool = True,
182184
**options: Any,
183185
) -> tuple[list[DocstringParameter], int]:
184186
parameters = []
185187
annotation: str | Expr | None
186188

187-
block, new_offset = _read_block_items(docstring, offset=offset, **options)
189+
block, new_offset = _read_block_items(docstring, offset=offset, warnings=warnings, **options)
188190

189191
for line_number, param_lines in block:
190192
# Check the presence of a name and description, separated by a colon.
191193
try:
192194
name_with_type, description = param_lines[0].split(":", 1)
193195
except ValueError:
194-
docstring_warning(docstring, line_number, f"Failed to get 'name: description' pair from '{param_lines[0]}'")
196+
if warnings:
197+
docstring_warning(
198+
docstring,
199+
line_number,
200+
f"Failed to get 'name: description' pair from '{param_lines[0]}'",
201+
)
195202
continue
196203

197204
description = "\n".join([description.lstrip(), *param_lines[1:]]).rstrip("\n")
@@ -216,10 +223,10 @@ def _read_parameters(
216223
except (AttributeError, KeyError):
217224
default = None
218225

219-
if annotation is None:
226+
if warnings and annotation is None:
220227
docstring_warning(docstring, line_number, f"No type or annotation for parameter '{name}'")
221228

222-
if warn_unknown_params:
229+
if warnings and warn_unknown_params:
223230
with suppress(AttributeError): # For Parameters sections in objects without parameters.
224231
params = docstring.parent.parameters # type: ignore[union-attr]
225232
if name not in params:
@@ -260,17 +267,23 @@ def _read_attributes_section(
260267
docstring: Docstring,
261268
*,
262269
offset: int,
270+
warnings: bool = True,
263271
**options: Any,
264272
) -> tuple[DocstringSectionAttributes | None, int]:
265273
attributes = []
266-
block, new_offset = _read_block_items(docstring, offset=offset, **options)
274+
block, new_offset = _read_block_items(docstring, offset=offset, warnings=warnings, **options)
267275

268276
annotation: str | Expr | None = None
269277
for line_number, attr_lines in block:
270278
try:
271279
name_with_type, description = attr_lines[0].split(":", 1)
272280
except ValueError:
273-
docstring_warning(docstring, line_number, f"Failed to get 'name: description' pair from '{attr_lines[0]}'")
281+
if warnings:
282+
docstring_warning(
283+
docstring,
284+
line_number,
285+
f"Failed to get 'name: description' pair from '{attr_lines[0]}'",
286+
)
274287
continue
275288

276289
description = "\n".join([description.lstrip(), *attr_lines[1:]]).rstrip("\n")
@@ -296,21 +309,23 @@ def _read_functions_section(
296309
docstring: Docstring,
297310
*,
298311
offset: int,
312+
warnings: bool = True,
299313
**options: Any,
300314
) -> tuple[DocstringSectionFunctions | None, int]:
301315
functions = []
302-
block, new_offset = _read_block_items(docstring, offset=offset, **options)
316+
block, new_offset = _read_block_items(docstring, offset=offset, warnings=warnings, **options)
303317

304318
signature: str | Expr | None = None
305319
for line_number, func_lines in block:
306320
try:
307321
name_with_signature, description = func_lines[0].split(":", 1)
308322
except ValueError:
309-
docstring_warning(
310-
docstring,
311-
line_number,
312-
f"Failed to get 'signature: description' pair from '{func_lines[0]}'",
313-
)
323+
if warnings:
324+
docstring_warning(
325+
docstring,
326+
line_number,
327+
f"Failed to get 'signature: description' pair from '{func_lines[0]}'",
328+
)
314329
continue
315330

316331
description = "\n".join([description.lstrip(), *func_lines[1:]]).rstrip("\n")
@@ -331,21 +346,23 @@ def _read_classes_section(
331346
docstring: Docstring,
332347
*,
333348
offset: int,
349+
warnings: bool = True,
334350
**options: Any,
335351
) -> tuple[DocstringSectionClasses | None, int]:
336352
classes = []
337-
block, new_offset = _read_block_items(docstring, offset=offset, **options)
353+
block, new_offset = _read_block_items(docstring, offset=offset, warnings=warnings, **options)
338354

339355
signature: str | Expr | None = None
340356
for line_number, class_lines in block:
341357
try:
342358
name_with_signature, description = class_lines[0].split(":", 1)
343359
except ValueError:
344-
docstring_warning(
345-
docstring,
346-
line_number,
347-
f"Failed to get 'signature: description' pair from '{class_lines[0]}'",
348-
)
360+
if warnings:
361+
docstring_warning(
362+
docstring,
363+
line_number,
364+
f"Failed to get 'signature: description' pair from '{class_lines[0]}'",
365+
)
349366
continue
350367

351368
description = "\n".join([description.lstrip(), *class_lines[1:]]).rstrip("\n")
@@ -366,21 +383,24 @@ def _read_modules_section(
366383
docstring: Docstring,
367384
*,
368385
offset: int,
386+
warnings: bool = True,
369387
**options: Any,
370388
) -> tuple[DocstringSectionModules | None, int]:
371389
modules = []
372-
block, new_offset = _read_block_items(docstring, offset=offset, **options)
390+
block, new_offset = _read_block_items(docstring, offset=offset, warnings=warnings, **options)
373391

374392
for line_number, module_lines in block:
375393
try:
376394
name, description = module_lines[0].split(":", 1)
377395
except ValueError:
378-
docstring_warning(
379-
docstring,
380-
line_number,
381-
f"Failed to get 'name: description' pair from '{module_lines[0]}'",
382-
)
396+
if warnings:
397+
docstring_warning(
398+
docstring,
399+
line_number,
400+
f"Failed to get 'name: description' pair from '{module_lines[0]}'",
401+
)
383402
continue
403+
384404
description = "\n".join([description.lstrip(), *module_lines[1:]]).rstrip("\n")
385405
modules.append(DocstringModule(name=name, description=description))
386406

@@ -391,26 +411,29 @@ def _read_raises_section(
391411
docstring: Docstring,
392412
*,
393413
offset: int,
414+
warnings: bool = True,
394415
**options: Any,
395416
) -> tuple[DocstringSectionRaises | None, int]:
396417
exceptions = []
397-
block, new_offset = _read_block_items(docstring, offset=offset, **options)
418+
block, new_offset = _read_block_items(docstring, offset=offset, warnings=warnings, **options)
398419

399420
annotation: str | Expr
400421
for line_number, exception_lines in block:
401422
try:
402423
annotation, description = exception_lines[0].split(":", 1)
403424
except ValueError:
404-
docstring_warning(
405-
docstring,
406-
line_number,
407-
f"Failed to get 'exception: description' pair from '{exception_lines[0]}'",
408-
)
409-
else:
410-
description = "\n".join([description.lstrip(), *exception_lines[1:]]).rstrip("\n")
411-
# Try to compile the annotation to transform it into an expression.
412-
annotation = parse_docstring_annotation(annotation, docstring)
413-
exceptions.append(DocstringRaise(annotation=annotation, description=description))
425+
if warnings:
426+
docstring_warning(
427+
docstring,
428+
line_number,
429+
f"Failed to get 'exception: description' pair from '{exception_lines[0]}'",
430+
)
431+
continue
432+
433+
description = "\n".join([description.lstrip(), *exception_lines[1:]]).rstrip("\n")
434+
# Try to compile the annotation to transform it into an expression.
435+
annotation = parse_docstring_annotation(annotation, docstring)
436+
exceptions.append(DocstringRaise(annotation=annotation, description=description))
414437

415438
return DocstringSectionRaises(exceptions), new_offset
416439

@@ -419,23 +442,26 @@ def _read_warns_section(
419442
docstring: Docstring,
420443
*,
421444
offset: int,
445+
warnings: bool = True,
422446
**options: Any,
423447
) -> tuple[DocstringSectionWarns | None, int]:
424448
warns = []
425-
block, new_offset = _read_block_items(docstring, offset=offset, **options)
449+
block, new_offset = _read_block_items(docstring, offset=offset, warnings=warnings, **options)
426450

427451
for line_number, warning_lines in block:
428452
try:
429453
annotation, description = warning_lines[0].split(":", 1)
430454
except ValueError:
431-
docstring_warning(
432-
docstring,
433-
line_number,
434-
f"Failed to get 'warning: description' pair from '{warning_lines[0]}'",
435-
)
436-
else:
437-
description = "\n".join([description.lstrip(), *warning_lines[1:]]).rstrip("\n")
438-
warns.append(DocstringWarn(annotation=annotation, description=description))
455+
if warnings:
456+
docstring_warning(
457+
docstring,
458+
line_number,
459+
f"Failed to get 'warning: description' pair from '{warning_lines[0]}'",
460+
)
461+
continue
462+
463+
description = "\n".join([description.lstrip(), *warning_lines[1:]]).rstrip("\n")
464+
warns.append(DocstringWarn(annotation=annotation, description=description))
439465

440466
return DocstringSectionWarns(warns), new_offset
441467

@@ -459,15 +485,17 @@ def _get_name_annotation_description(
459485
lines: list[str],
460486
*,
461487
named: bool = True,
488+
warnings: bool = True,
462489
) -> tuple[str | None, Any, str]:
463490
if named:
464491
match = _RE_NAME_ANNOTATION_DESCRIPTION.match(lines[0])
465492
if not match:
466-
docstring_warning(
467-
docstring,
468-
line_number,
469-
f"Failed to get name, annotation or description from '{lines[0]}'",
470-
)
493+
if warnings:
494+
docstring_warning(
495+
docstring,
496+
line_number,
497+
f"Failed to get name, annotation or description from '{lines[0]}'",
498+
)
471499
raise ValueError
472500
name, annotation, description = match.groups()
473501
else:
@@ -507,6 +535,7 @@ def _read_returns_section(
507535
offset: int,
508536
returns_multiple_items: bool = True,
509537
returns_named_value: bool = True,
538+
warnings: bool = True,
510539
**options: Any,
511540
) -> tuple[DocstringSectionReturns | None, int]:
512541
returns = []
@@ -536,7 +565,7 @@ def _read_returns_section(
536565
# Try to retrieve the annotation from the docstring parent.
537566
annotation = _annotation_from_parent(docstring, gen_index=2, multiple=len(block) > 1, index=index)
538567

539-
if annotation is None:
568+
if warnings and annotation is None:
540569
returned_value = repr(name) if name else index + 1
541570
docstring_warning(docstring, line_number, f"No type or annotation for returned value {returned_value}")
542571

@@ -551,6 +580,7 @@ def _read_yields_section(
551580
offset: int,
552581
returns_multiple_items: bool = True,
553582
returns_named_value: bool = True,
583+
warnings: bool = True,
554584
**options: Any,
555585
) -> tuple[DocstringSectionYields | None, int]:
556586
yields = []
@@ -580,7 +610,7 @@ def _read_yields_section(
580610
# Try to retrieve the annotation from the docstring parent.
581611
annotation = _annotation_from_parent(docstring, gen_index=0, multiple=len(block) > 1, index=index)
582612

583-
if annotation is None:
613+
if warnings and annotation is None:
584614
yielded_value = repr(name) if name else index + 1
585615
docstring_warning(docstring, line_number, f"No type or annotation for yielded value {yielded_value}")
586616

@@ -595,6 +625,7 @@ def _read_receives_section(
595625
offset: int,
596626
receives_multiple_items: bool = True,
597627
receives_named_value: bool = True,
628+
warnings: bool = True,
598629
**options: Any,
599630
) -> tuple[DocstringSectionReceives | None, int]:
600631
receives = []
@@ -624,7 +655,7 @@ def _read_receives_section(
624655
# Try to retrieve the annotation from the docstring parent.
625656
annotation = _annotation_from_parent(docstring, gen_index=1, multiple=len(block) > 1, index=index)
626657

627-
if annotation is None:
658+
if warnings and annotation is None:
628659
received_value = repr(name) if name else index + 1
629660
docstring_warning(docstring, line_number, f"No type or annotation for received value {received_value}")
630661

@@ -725,6 +756,7 @@ def parse_google(
725756
receives_multiple_items: bool = True,
726757
receives_named_value: bool = True,
727758
warn_unknown_params: bool = True,
759+
warnings: bool = True,
728760
**options: Any,
729761
) -> list[DocstringSection]:
730762
"""Parse a Google-style docstring.
@@ -751,6 +783,7 @@ def parse_google(
751783
returns_type_in_property_summary: Whether to parse the return type of properties
752784
at the beginning of their summary: `str: Summary of the property`.
753785
warn_unknown_params: Warn about documented parameters not appearing in the signature.
786+
warnings: Whether to log warnings at all.
754787
**options: Additional parsing options.
755788
756789
Returns:
@@ -771,6 +804,7 @@ def parse_google(
771804
"receives_multiple_items": receives_multiple_items,
772805
"receives_named_value": receives_named_value,
773806
"warn_unknown_params": warn_unknown_params,
807+
"warnings": warnings,
774808
**options,
775809
}
776810

@@ -824,13 +858,14 @@ def parse_google(
824858
if indented_lines_below and blank_line_below:
825859
reasons.append(f"Extraneous blank line below {kind} title")
826860
if reasons:
827-
reasons_string = "; ".join(reasons)
828-
docstring_warning(
829-
docstring,
830-
offset,
831-
f"Possible {kind} skipped, reasons: {reasons_string}",
832-
LogLevel.debug,
833-
)
861+
if warnings:
862+
reasons_string = "; ".join(reasons)
863+
docstring_warning(
864+
docstring,
865+
offset,
866+
f"Possible {kind} skipped, reasons: {reasons_string}",
867+
LogLevel.debug,
868+
)
834869
current_section.append(lines[offset])
835870
offset += 1
836871
continue

0 commit comments

Comments
 (0)