Skip to content

Commit

Permalink
prototype
Browse files Browse the repository at this point in the history
  • Loading branch information
InvincibleRMC committed Jul 26, 2024
1 parent 8e7307f commit bb82934
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 1 deletion.
9 changes: 9 additions & 0 deletions include/pybind11/pytypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ class object_api : public pyobject_tag {
/// Get or set the object's docstring, i.e. ``obj.__doc__``.
str_attr_accessor doc() const;

/// Get or set the object's type_params, i.e. ``obj.__type_params__``.
str_attr_accessor type_params() const;


/// Return the object's current reference count
ssize_t ref_count() const {
#ifdef PYPY_VERSION
Expand Down Expand Up @@ -2534,6 +2538,11 @@ str_attr_accessor object_api<D>::doc() const {
return attr("__doc__");
}

template <typename D>
str_attr_accessor object_api<D>::type_params() const {
return attr("__type_params__");
}

template <typename D>
handle object_api<D>::get_type() const {
return type::handle_of(derived());
Expand Down
37 changes: 36 additions & 1 deletion include/pybind11/typing.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class Literal : public object {
PYBIND11_OBJECT_DEFAULT(Literal, object, PyObject_Type)
};

// Example syntax for creating a TypeVar.
// Example syntax for creating a type annotation of a TypeVar, ParamSpec, and TypeVarTuple.
// typedef typing::TypeVar<"T"> TypeVarT;
template <StringLiteral>
class TypeVar : public object {
Expand All @@ -124,6 +124,41 @@ class TypeVar : public object {
};
#endif



template <typename T>
class TypeVarObject : public object {
PYBIND11_OBJECT_DEFAULT(TypeVarObject, object, PyObject_Type)
using object::object;
TypeVarObject(const char *name){
attr("__name__") = name;
attr("__bound__") = make_caster<T>;
attr("__constraints__") = pybind11::make_tuple();
}
// TypeVarObject(const char *name, py::typing::Tuple<pybind11::type, pybind11::ellipse> tuple){
// attr("__name__") = name;
// attr("__bound__") = py::none();
// attr("__constraints__") = tuple;
// }
};

class ParamSpec : public object {
PYBIND11_OBJECT_DEFAULT(ParamSpec, object, PyObject_Type)
using object::object;
ParamSpec(const char *name){
attr("__name__") = name;
attr("__bound__") = pybind11::none();
}
};

class TypeVarTuple : public object {
PYBIND11_OBJECT_DEFAULT(TypeVarTuple, object, PyObject_Type)
using object::object;
TypeVarTuple(const char *name){
attr("__name__") = name;
}
};

PYBIND11_NAMESPACE_END(typing)

PYBIND11_NAMESPACE_BEGIN(detail)
Expand Down
17 changes: 17 additions & 0 deletions tests/test_pytypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -923,4 +923,21 @@ TEST_SUBMODULE(pytypes, m) {
#else
m.attr("defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL") = false;
#endif

struct TypeVarObject {};
py::class_<TypeVarObject>(m, "TypeVarObject").type_params() = py::make_tuple(py::typing::TypeVarObject<int>("T"));

struct ParamSpec {};
py::class_<ParamSpec>(m, "ParamSpec").type_params() = py::make_tuple(py::typing::ParamSpec("P"));

struct TypeVarTuple {};
py::class_<TypeVarTuple>(m, "TypeVarTuple").type_params() = py::make_tuple(py::typing::TypeVarTuple("T"));


struct NoTypeParams {};
struct TypeParams {};
py::class_<NoTypeParams>(m, "NoTypeParams");
// TODO: Use custom objects
py::class_<TypeParams>(m, "TypeParams").type_params() = py::make_tuple("foo", 3, py::none());
m.def("type_params", []() -> void {}).type_params() = py::make_tuple("foo", 3, py::none());
}
28 changes: 28 additions & 0 deletions tests/test_pytypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import sys
import types

from typing import TypeVar
import pytest

import env
Expand Down Expand Up @@ -1048,3 +1049,30 @@ def test_typevar(doc):
assert doc(m.annotate_listT_to_T) == "annotate_listT_to_T(arg0: list[T]) -> T"

assert doc(m.annotate_object_to_T) == "annotate_object_to_T(arg0: object) -> T"

def test_typevar_object():
assert len(m.TypeVarObject.__type_params__) == 1
type_var = m.TypeVarObject.__type_params__[0]
assert type_var.__name__ == "T"
assert type_var.__bound__ == int
assert type_var.__constraints__ == ()

def test_param_spec():
assert len(m.ParamSpec.__type_params__) == 1
param_spec = m.ParamSpec.__type_params__[0]

assert param_spec.__name__ == "P"
assert param_spec.__bound__ == None

def test_type_var_tuple():
assert len(m.TypeVarTuple.__type_params__) == 1
type_var_tuple = m.TypeVarTuple.__type_params__[0]

assert type_var_tuple.__name__ == "T"
with pytest.raises(AttributeError):
param_spec.__bound__

def test_type_params():
assert m.NoTypeParams.__type_params__ == ()
assert m.TypeParams.__type_params__ == ("foo", 3, None)
assert m.type_params.__type_params__ == ("foo", 3, None)

0 comments on commit bb82934

Please sign in to comment.