Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

autodoc_preserve_defaults=True does not work for mixture of keyword only arguments with/without defaults #10266

Closed
saggitar opened this issue Mar 15, 2022 · 1 comment

Comments

@saggitar
Copy link

saggitar commented Mar 15, 2022

Describe the bug

If I understand PEP 0570 correctly, the following is a valid signature of a class method:

class Thing:
    def __init__(
            self, 
            kw_or_pos_without_default, 
            kw_or_pos_with_default=None, 
            *,
            kw_without_default,
            kw_with_default="Foo"
    ):
        pass

When documenting this with autodoc and autodoc_preserve_defaults=True, sphinx.ext.autodoc.preserve_defaults.update_defvalue generates a DefaultValue with name=None for the kw_with_default arguments. This later raises an exception in sphinx.util.inspect.object_description since the DefaultValue.__repr__ dunder method now returns None instead of a string.

Basically what happens is that ast generates a None value in the kw_defaults of the arguments since the first keyword argument is required, but update_defvalue simply ignores that argument because the default is empty. This leaves the None in the kw_defaults to be picked up when the keyword argument with default value is processed -- instead of the actual default.
This can't be resolved by the unparse call which therefore simply returns None, which ends up as the name of the DefaultValue.

Imo this could simply be resolved by poping the corresponding None from the kw_defaults if a KW_ONLY parameter with empty default is encountered.

How to Reproduce

Create a module with contents

class Thing:
    def __init__(
            self, 
            kw_or_pos_without_default, 
            kw_or_pos_with_default=None, 
            *,
            kw_without_default,
            kw_with_default="Foo"
    ):
        pass

and auto-document while setting autodoc_preserve_defaults=True in your conf.py

Make sure sphinx tries to document all parameters, (since it's a __init__ method, they will be documented when the autodoc directive has :undoc-members:, if you try the same with a module level method you need to document the parameters)

test.zip

Expected behavior

The correct default value should be documented. The Warning Message also is pretty worthless (probably the value should not be
formatted with a simple %s but instead with a %r?)

Your project

https://github.com/sphinx-doc/sphinx/files/8253301/test.zip

OS

Any

Python version

Tested with versions > 3.8

Sphinx version

4.4.0

Sphinx extensions

sphinx.ext.autodoc

@tk0miya
Copy link
Member

tk0miya commented Apr 2, 2022

Thank you for a good report! As you said, we have to consume None item from kw_defaults. I think #10321 will resolve this problem.

@tk0miya tk0miya closed this as completed in f5e4e70 Apr 3, 2022
tk0miya added a commit that referenced this issue Apr 3, 2022
…s_crashes_on_kwonlyargs_without_defaults

Fix #10266: autodoc_preserve_defaults crashes on kwonlyargs w/o defaults
@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 4, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants