python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.33k stars 2.81k forks source link

Stubgen doesn't look at C type's docstring when inferring __init__'s type #14141

Open KovacsGG opened 1 year ago

KovacsGG commented 1 year ago

Bug Report

Given a class with a docstring similar to "ClassName(initparam: str)" or "ClassName(initparam: str) -> ClassName" or "(initparam: str)" or "__init__(initparam: str) -> None" the stub generation via runtime introspection will not digest this information.

This is relevant, because the CPython API doesn't allow setting the __init__ method's docstring, like other members' or type objects', making automatic annotation of constructors impossible.

To Reproduce

You have to build a C extension, but I can provide modules if needed for testing.

PyTypeObject TestType_ = {                                                  \
    PyVarObject_HEAD_INIT(NULL, 0)                                          \
    /* tp_name            */   "module.Test",                               \
    /* tp_basicsize       */   sizeof(t_test),                              \
    /* tp_itemsize        */   0,                                           \
    /* tp_dealloc         */   (destructor)dealloc,                         \
    /* tp_print           */   0,                                           \
    /* tp_getattr         */   0,                                           \
    /* tp_setattr         */   0,                                           \
    /* tp_compare         */   0,                                           \
    /* tp_repr            */   0,                                           \
    /* tp_as_number       */   0,                                           \
    /* tp_as_sequence     */   0,                                           \
    /* tp_as_mapping      */   0,                                           \
    /* tp_hash            */   0,                                           \
    /* tp_call            */   0,                                           \
    /* tp_str             */   0,                                           \
    /* tp_getattro        */   0,                                           \
    /* tp_setattro        */   0,                                           \
    /* tp_as_buffer       */   0,                                           \
    /* tp_flags           */   Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,    \
    /* tp_doc             */   PyDoc_STR("Test(param: int)"),               \
    /* tp_traverse        */   0,                                           \
    /* tp_clear           */   0,                                           \
    /* tp_richcompare     */   0,                                           \
    /* tp_weaklistoffset  */   0,                                           \
    /* tp_iter            */   0,                                           \
    /* tp_iternext        */   0,                                           \
    /* tp_methods         */   t_test_methods,                              \
    /* tp_members         */   0,                                           \
    /* tp_getset          */   0,                                           \
    /* tp_base            */   0,                                           \
    /* tp_dict            */   0,                                           \
    /* tp_descr_get       */   0,                                           \
    /* tp_descr_set       */   0,                                           \
    /* tp_dictoffset      */   0,                                           \
    /* tp_init            */   (initproc)t_type_init,                       \
    /* tp_alloc           */   0,                                           \
    /* tp_new             */   0,                                           \
};

Expected Behavior

Stubgen should generate the lines in .pyi:

class Test():
    def __init__ (self, param: int) -> None: ...
    [other methods]

Actual Behavior

Stubgen instead generates:

class Test():
    def init(self, *args, **kwargs) -> None
    [other methods]

Your Environment

AraHaan commented 4 months ago

It also incorrectly ignores tp_str which is NOT ok for me. It should only ignore it if it is 0 or null.