Skip to content

Various stubgen regressions in mypy 1.7.0 #16486

Closed
@bluenote10

Description

@bluenote10

Bug Report

Trying to update mypy from 1.6.1 to 1.7.0 has revealed a few regressions in the stub generator output related to pybind11 modules.

To Reproduce

Consider this pybind11 module:

#include <filesystem>
#include <optional>
#include <utility>
#include <vector>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

namespace py = pybind11;

std::vector<float> funcReturningVector()
{
  return std::vector<float>{1.0, 2.0, 3.0, 4.0};
}

std::pair<int, float> funcReturningPair()
{
  return std::pair{42, 1.0};
}

std::optional<int> funcReturningOptional()
{
  return std::nullopt;
}

std::filesystem::path funcIncompleteSignature()
{
  // This example does not include <pybind11/stl/filesystem.h> on purpose
  // to demonstrate the signature of an incomplete binding.
  return std::filesystem::path{"foobar"};
}

struct MyStruct
{
  int a;
  int b;
  int c;
};

PYBIND11_MODULE(my_native_module, m)
{
  m.def("func_returning_vector", &funcReturningVector);
  m.def("func_returning_pair", &funcReturningPair);
  m.def("func_returning_optional", &funcReturningOptional);

  m.def("func_incomplete_signature", &funcIncompleteSignature);

  py::class_<MyStruct>(m, "MyStruct")
      .def_readwrite("a", &MyStruct::a)
      .def_readwrite("b", &MyStruct::b, "some docstring")
      .def_property_readonly(
          "c",
          [](const MyStruct& x) {
            return x.c;
          },
          "some docstring");
}

To reproduce, store the above snippet as my_native_module.cpp and then:

# Install latest pybind11:
pip install pybind11==2.11.1

# Compile pybind11 module:
c++ -O3 -Wall -shared -std=c++17 -fPIC $(python3 -m pybind11 --includes) my_native_module.cpp -o my_native_module.so

# Run the stub generator on it:
stubgen -p my_native_module

Expected Behavior

mypy 1.6.1 outputs the following, which is pretty reasonable:

from typing import Any, List, Optional, Tuple

class MyStruct:
    a: int
    b: int
    def __init__(self, *args, **kwargs) -> None: ...
    @property
    def c(self) -> int: ...

def func_incomplete_signature(*args, **kwargs) -> Any: ...
def func_returning_optional() -> Optional[int]: ...
def func_returning_pair() -> Tuple[int,float]: ...
def func_returning_vector() -> List[float]: ...

Actual Behavior

mypy 1.7.0 outputs the following:

from _typeshed import Incomplete

class MyStruct:
    a: int
    b: Incomplete
    def __init__(self, *args, **kwargs) -> None: ...
    @property
    def c(self): ...

def func_incomplete_signature(*args, **kwargs): ...
def func_returning_optional() -> Optional[int]: ...
def func_returning_pair() -> Tuple[int, float]: ...
def func_returning_vector() -> List[float]: ...

The regressions are:

  • The most obvious thing is that the imports for List, Tuple, and Optional are missing. This makes the resulting .pyi invalid, because it uses symbols that have not been imported. The stub output does not type check. This is not limited to these three types, but applies to other types like Iterable, Iterator, Dict, Set, Union, etc.
  • The type annotation of field b has regressed from int to Incomplete, apparently due to the explicit docstring.
  • The type annotation of field c has regressed from int to not annotated at all, probably also because of the explicit docstring.
  • The signature of the func_incomplete_signature has also slightly worsened: Before, it was at least annotated as -> Any but now it misses any return type annotation at all. This is problematic when users want to validate their generated stubs for completeness, i.e., run mypy --disallow-untyped-defs on the output. Of course semantically it is the same, but still it would be nicer to always produce some return type (arguably a broken signature may be rather annotated as -> object instead of -> Incomplete to avoid running into bugs from incomplete stub output).

Your Environment

  • Mypy version used: 1.7.0
  • Mypy command-line flags: irrelevant for stubgen
  • Mypy configuration options from mypy.ini (and other config files): irrelevant for stubgen
  • Python version used: 3.10

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions