Skip to content

[BUG] py::type constructor from object does not throw when passed a non-type object #2700

Closed
@phcerdan

Description

@phcerdan

Issue description

py::type(object) constructor is returning an instance, which is unexpected.

This report was suggested by @YannickJadoul in gitter: https://gitter.im/pybind/Lobby?at=5fc11de4b12c2622f909e92f

Reproducible example code

// py::type::of<int> fails at compilation time.
// But it works for any wrapped type.
template<typename T>
using IsCPPType = typename std::enable_if<std::is_base_of<pybind11::detail::type_caster_generic, pybind11::detail::make_caster<T>>::value>::type;

template<typename T>
using IsNotCPPType = typename std::enable_if<!std::is_base_of<pybind11::detail::type_caster_generic, pybind11::detail::make_caster<T>>::value>::type;

template<typename TT>
void def_TValue(
        pybind11::class_<TT, std::unique_ptr<TT>> & py_class,
        IsCPPType<typename TT::Value> * = nullptr) {
    py_class.def_property_readonly_static("TValue",
            [](pybind11::object /* self */ ) {
            return pybind11::type::of<typename TT::Value>();
            });
}
template<typename TT>
void def_TValue(pybind11::class_<TT, std::unique_ptr<TT>> & py_class,
        IsNotCPPType<typename TT::Value> * = nullptr) {
    py_class.def_property_readonly_static("TValue",
            [](pybind11::object /* self */ ) {
            return pybind11::type( // This is returning an instance,not a type, it should throw. <---
            // return pybind11::type::of( // This is the correct way of returning the type.
                        pybind11::cast(typename TT::Value())
                    );
            });
}
template<typename T>
struct foo {
  using Value = T;
}
using FooInt = foo<int>;
using FooWrapped = foo<other_cpp_class>;
py_class_with_int = py::class_<FooInt , std::unique_ptr<FooInt>>(m, "FooInt");
def_TValue(py_class_with_int);
py_class_with_wrapped_class = py::class_<FooWrapped , std::unique_ptr<FooWrapped>>(m, "FooWrapped");
def_TValue(py_class_with_wrapped_class);
print(FooInt().TValue)
0 # unexpected? returns an instance!!
print(FooFloat().TValue)
0.0 # same

print(FooWrapped().TValue)
`<class  'other_cpp_class'>` # correct

After changing pybind11::type( for pybind11::type::of( the result is the correct <class 'int'>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions