sphinx-autodoc-typehints icon indicating copy to clipboard operation
sphinx-autodoc-typehints copied to clipboard

Sphinx raises warning about custom typehints_formatter

Open jl-wynen opened this issue 1 year ago • 1 comments

Since Sphinx v7.3.0, there is a warning about config values that are not pickleable. When building with warning_is_error = True, this fails the build. See https://github.com/sphinx-doc/sphinx/issues/12300 for context.

For sphinx-autodoc-typehints, this means that a custom typehints_formatter leads to a build failure.

To reproduce, simply use this conf.py:

project = 'custom_formatter'
extensions = [
    'sphinx.ext.autodoc',
    'sphinx_autodoc_typehints',
]
warning_is_error = True
show_warning_types = True

def formatter(annotation, config):
    return None

typehints_formatter = formatter

It results in this warning:

sphinx.errors.SphinxWarning: cannot cache unpickable configuration value: 'typehints_formatter' (because it contains a function, class, or module object) [config.cache]

Apart from triggering a warning that needs to be silenced, this also prevents caching. So it would be great to have a solution that avoids specifying a callable as typehints_formatter. One option would be using a fully qualified path and make sphinx-autodoc-typehints import a function from that path. E.g. typehints_formatter = 'mypackage.sphinxext.typehints_formatter'. See also this comment: https://github.com/sphinx-doc/sphinx/issues/12300#issuecomment-2061054462

jl-wynen avatar May 28 '24 10:05 jl-wynen

I've had this same issue in sphinxcontrib/typer.

The only way to fix it is the method you suggest, where you load it from a string import path.

I use this function to convert the config value into a function object. If it is already a function object it returns that for backwards compatibility:


import typing as t
from importlib import import_module

def get_function(function: t.Union[str, t.Callable[..., t.Any]]):
    if callable(function):
        return function
    if isinstance(function, str):
        parts = function.split(".")
        return getattr(import_module(".".join(parts[0:-1])), parts[-1])

bckohan avatar Jan 17 '25 06:01 bckohan