From e1eb73ed7ad1a6ceb03ce9d1a164d0249b49910f Mon Sep 17 00:00:00 2001 From: hauntsaninja <> Date: Tue, 20 Oct 2020 23:10:21 -0700 Subject: [PATCH] bpo-42102: make callable runtime subscriptable --- Include/bltinmodule.h | 1 + Objects/object.c | 1 + Python/bltinmodule.c | 40 +++++++++++++++++++++++++++++++---- Python/clinic/bltinmodule.c.h | 30 +++++++++++++++++++++----- 4 files changed, 63 insertions(+), 9 deletions(-) diff --git a/Include/bltinmodule.h b/Include/bltinmodule.h index 868c9e6443bfc1..91b8edf762842d 100644 --- a/Include/bltinmodule.h +++ b/Include/bltinmodule.h @@ -4,6 +4,7 @@ extern "C" { #endif +PyAPI_DATA(PyTypeObject) PyCallable_Type; PyAPI_DATA(PyTypeObject) PyFilter_Type; PyAPI_DATA(PyTypeObject) PyMap_Type; PyAPI_DATA(PyTypeObject) PyZip_Type; diff --git a/Objects/object.c b/Objects/object.c index 7bc3e48d40a6fd..290dfa6ef5948e 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1774,6 +1774,7 @@ _PyTypes_Init(void) INIT_TYPE(&PyMemoryView_Type, "memoryview"); INIT_TYPE(&PyTuple_Type, "tuple"); INIT_TYPE(&PyEnum_Type, "enumerate"); + INIT_TYPE(&PyCallable_Type, "callable"); INIT_TYPE(&PyReversed_Type, "reversed"); INIT_TYPE(&PyStdPrinter_Type, "StdPrinter"); INIT_TYPE(&PyCode_Type, "code"); diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 89b7fce8f4a9cc..073bb8753b0cad 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -26,6 +26,11 @@ _Py_IDENTIFIER(stderr); #include "clinic/bltinmodule.c.h" +/*[clinic input] +class callable "callableobject *" "&PyCallable_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=186f9359829695da]*/ + static PyObject* update_bases(PyObject *bases, PyObject *const *args, Py_ssize_t nargs) { @@ -454,9 +459,14 @@ builtin_bin(PyObject *module, PyObject *number) return PyNumber_ToBase(number, 2); } +typedef struct { + PyObject_HEAD +} callableobject; + /*[clinic input] -callable as builtin_callable +@classmethod +callable.__new__ as callable_new obj: object / @@ -468,12 +478,34 @@ __call__() method. [clinic start generated code]*/ static PyObject * -builtin_callable(PyObject *module, PyObject *obj) -/*[clinic end generated code: output=2b095d59d934cb7e input=1423bab99cc41f58]*/ +callable_new_impl(PyTypeObject *type, PyObject *obj) +/*[clinic end generated code: output=46784af2d6033e5a input=c0902a59d22a1a02]*/ { return PyBool_FromLong((long)PyCallable_Check(obj)); } +static PyMethodDef callable_methods[] = { + {"__class_getitem__", (PyCFunction)Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(callable_doc, +"Return whether the object is callable (i.e., some kind of function).\n\n\ +Note that classes are callable, as are instances of classes with a\n\ +__call__() method."); + +PyTypeObject PyCallable_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + .tp_name = "callable", + .tp_basicsize = sizeof(callableobject), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_doc = callable_doc, + .tp_methods = callable_methods, + .tp_alloc = PyType_GenericAlloc, + .tp_new = callable_new, + .tp_free = PyObject_GC_Del, +}; + static PyObject * builtin_breakpoint(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *keywords) { @@ -2791,7 +2823,6 @@ static PyMethodDef builtin_methods[] = { BUILTIN_ASCII_METHODDEF BUILTIN_BIN_METHODDEF {"breakpoint", (PyCFunction)(void(*)(void))builtin_breakpoint, METH_FASTCALL | METH_KEYWORDS, breakpoint_doc}, - BUILTIN_CALLABLE_METHODDEF BUILTIN_CHR_METHODDEF BUILTIN_COMPILE_METHODDEF BUILTIN_DELATTR_METHODDEF @@ -2893,6 +2924,7 @@ _PyBuiltin_Init(PyThreadState *tstate) SETBUILTIN("complex", &PyComplex_Type); SETBUILTIN("dict", &PyDict_Type); SETBUILTIN("enumerate", &PyEnum_Type); + SETBUILTIN("callable", &PyCallable_Type); SETBUILTIN("filter", &PyFilter_Type); SETBUILTIN("float", &PyFloat_Type); SETBUILTIN("frozenset", &PyFrozenSet_Type); diff --git a/Python/clinic/bltinmodule.c.h b/Python/clinic/bltinmodule.c.h index bc3b518792811d..ac6f5685cc1dea 100644 --- a/Python/clinic/bltinmodule.c.h +++ b/Python/clinic/bltinmodule.c.h @@ -59,8 +59,8 @@ PyDoc_STRVAR(builtin_bin__doc__, #define BUILTIN_BIN_METHODDEF \ {"bin", (PyCFunction)builtin_bin, METH_O, builtin_bin__doc__}, -PyDoc_STRVAR(builtin_callable__doc__, -"callable($module, obj, /)\n" +PyDoc_STRVAR(callable_new__doc__, +"callable(obj, /)\n" "--\n" "\n" "Return whether the object is callable (i.e., some kind of function).\n" @@ -68,8 +68,28 @@ PyDoc_STRVAR(builtin_callable__doc__, "Note that classes are callable, as are instances of classes with a\n" "__call__() method."); -#define BUILTIN_CALLABLE_METHODDEF \ - {"callable", (PyCFunction)builtin_callable, METH_O, builtin_callable__doc__}, +static PyObject * +callable_new_impl(PyTypeObject *type, PyObject *obj); + +static PyObject * +callable_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *obj; + + if ((type == &PyCallable_Type) && + !_PyArg_NoKeywords("callable", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("callable", PyTuple_GET_SIZE(args), 1, 1)) { + goto exit; + } + obj = PyTuple_GET_ITEM(args, 0); + return_value = callable_new_impl(type, obj); + +exit: + return return_value; +} PyDoc_STRVAR(builtin_format__doc__, "format($module, value, format_spec=\'\', /)\n" @@ -830,4 +850,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs) exit: return return_value; } -/*[clinic end generated code: output=e2fcf0201790367c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=502b941e1122b6a0 input=a9049054013a1b77]*/