griffe
griffe copied to clipboard
feature: I'd like to be able to use `Docstring` without requiring `parent` but get no warning
Thanks again for griffe - it's doing exactly what I need.
I have the following code:
import inspect
from typing import Literal, Callable, Any
from griffe.dataclasses import Docstring
from griffe.enumerations import DocstringSectionKind
def parameter_descriptions(
func: Callable[..., Any], *, style: Literal['google', 'numpy', 'sphinx'] = 'google'
) -> dict[str, str]:
docstring = Docstring(func.__doc__, lineno=1, parser=style)
try:
parameters = next(p for p in docstring.parse() if p.kind == DocstringSectionKind.parameters)
except StopIteration:
return {}
else:
return {p.name: p.description for p in parameters.value}
It works perfectly, but emits a warning (or similar, depending on the style)
<module>:1: No matching parameter for 'a'
<module>:1: No matching parameter for 'b'
To avoid that warning I can pass parent=inspect.signature(func) to Docstring, but that's unfortunate since inspect.signature doesn't actually return griffe's Object type - future changes to griffe could break my code.
Please could you provide either:
- a way to silence those warnings through
options - a way to safely convert a
inspect.Signatureto a griffeObject
?
Hi @samuelcolvin, thanks for the kind words and the feature request :slightly_smiling_face:
Have you tried the warn_unknown_params=False option? There's a quick mention here: https://mkdocstrings.github.io/griffe/docstrings/#google-options. It exists for the three parsers, google, numpy and sphinx.
a way to silence those warnings through
options
I have a draft PR that will bring configuration of all the log messages throughout the code base. It still needs some work, and I think it will end up in post 1.0 (which I'm working on too), and Insiders :thinking: So not viable for this issue here.
In any case we can rework warn_unknown_params first if it's not enough.
a way to safely convert a inspect.Signature to a griffe Object
Good idea for a utility function, yes. We can do that too :slightly_smiling_face:
future changes to griffe could break my code.
Even though Griffe is still in v0, we do use deprecation periods for every breaking change, and they are generally documented in the changelog. As mentioned above, 1.0 is coming soon though, and will remove all the legacy code, so you might want to add an upper bound to Griffe :smile:
Ye I tried warn_unknown_params, it doesn't work in this case.
Thanks. OK so there's an additional place in the Sphinx parser that emits such warnings without checking the value of warn_unknown_params. We should fix that.
But even then, the parsers will still emit warnings like "No type or annotation for parameter 'a'" (when the parameter types are not added to the docstring). So we would need to add an option to ignore these ones too.
Since there's work in progress for logs configuration, which will supersede such parser options, I'll first go with the signature-to-Griffe-function utility.
I'm not sure where your func comes from, but an alternative solution is to actually inspect its whole parent module. It's a bit heavy though, you'd have to cache the griffe_module below to avoid running introspection on the same module over and over.
import inspect
from pathlib import Path
from typing import Literal, Callable, Any
from griffe.agents.inspector import Inspector, ObjectNode
from griffe.enumerations import DocstringSectionKind
from griffe.extensions import load_extensions
def parameter_descriptions(
func: Callable[..., Any], *, style: Literal['google', 'numpy', 'sphinx'] = 'google'
) -> dict[str, str]:
module = inspect.getmodule(func)
module_name = module.__name__.rsplit(".", 1)[-1]
node = ObjectNode(module, module_name)
inspector = Inspector(module_name, filepath=Path(module.__file__), extensions=load_extensions())
inspector.inspect_module(node)
griffe_module = inspector.current
docstring = griffe_module[func.__qualname__].docstring
try:
parameters = next(p for p in docstring.parse(style) if p.kind == DocstringSectionKind.parameters)
except StopIteration:
return {}
else:
return {p.name: p.description for p in parameters.value}
I have implemented this utility:
def convert_function(func: Callable, parent: Module | Class | None = None) -> Function:
"""Convert a runtime function to a Griffe function.
Parameters:
func: The function to convert.
parent: The parent of the function.
Returns:
The Griffe function.
"""
parent = parent or Module("__griffe_helpers__")
sig = signature(func)
parameters = [convert_parameter(parameter, parent=parent) for parameter in sig.parameters.values()]
return_annotation = sig.return_annotation
returns = None if return_annotation is empty else convert_object_to_annotation(return_annotation, parent=parent)
return Function(func.__name__, parameters=Parameters(*parameters), returns=returns)
As you can see it has to fake a parent module. That's why I thought of the alternative solution mentioned above. I'm still pondering what's best in terms of API :thinking: Maybe it's just easier to add an option to the docstring parsers to ignore warnings in the end...
Another alternative while I'm making up my mind: temporarily disabling logging.
import logging
from contextlib import contextmanager
@contextmanager
def disable_logging():
old_level = logging.root.getEffectiveLevel()
logging.root.setLevel(logging.CRITICAL + 1)
yield
logging.root.setLevel(old_level)
...
with disable_logging():
parameters = next(p for p in docstring.parse() if p.kind == DocstringSectionKind.parameters)
WDYT?
Do you want to disable all warnings emitted during docstring parsing or only the "unknown parameter" and "no type or annotation" ones?
Oh that makes sense, I thought warning, was from the warnings module. I'll do that.
In the end, the recommended way will be to disable logging when parsing the docstring, as demonstrated above, or with a future configuration system for log messages. Closing, feel free to comment further :slightly_smiling_face:
Now that many projects are imitating Pydantic AI and using Griffe to parse docstrings, while disabling the logger to prevent warnings, and since the "logs configuration" PR hasn't progressed, I'd like to come back to this and add a warnings: bool = True parameter on the parse functions to make this easier 🙂
Available in v1.7.0, example: https://mkdocstrings.github.io/griffe/reference/api/docstrings/parsers/#griffe.parse_google(warnings).