diff options
author | Brandt Bucher <brandtbucher@microsoft.com> | 2023-05-04 22:07:42 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-04 22:07:42 (GMT) |
commit | 7d35c3121ade679dd6e8b4a0bac7b3702aee6921 (patch) | |
tree | 85e22e1940226bf45e95e7dbe334e966c659f196 /Objects/call.c | |
parent | f5c38382f9c40f0017cef086896a8160e313ac9e (diff) | |
download | cpython-7d35c3121ade679dd6e8b4a0bac7b3702aee6921.zip cpython-7d35c3121ade679dd6e8b4a0bac7b3702aee6921.tar.gz cpython-7d35c3121ade679dd6e8b4a0bac7b3702aee6921.tar.bz2 |
GH-103899: Provide a hint when accidentally calling a module (GH-103900)
Diffstat (limited to 'Objects/call.c')
-rw-r--r-- | Objects/call.c | 44 |
1 files changed, 38 insertions, 6 deletions
diff --git a/Objects/call.c b/Objects/call.c index cf6e357..0d548dc 100644 --- a/Objects/call.c +++ b/Objects/call.c @@ -157,6 +157,42 @@ PyObject_VectorcallDict(PyObject *callable, PyObject *const *args, return _PyObject_FastCallDictTstate(tstate, callable, args, nargsf, kwargs); } +static void +object_is_not_callable(PyThreadState *tstate, PyObject *callable) +{ + if (Py_IS_TYPE(callable, &PyModule_Type)) { + // >>> import pprint + // >>> pprint(thing) + // Traceback (most recent call last): + // File "<stdin>", line 1, in <module> + // TypeError: 'module' object is not callable. Did you mean: 'pprint.pprint(...)'? + PyObject *name = PyModule_GetNameObject(callable); + if (name == NULL) { + _PyErr_Clear(tstate); + goto basic_type_error; + } + PyObject *attr; + int res = _PyObject_LookupAttr(callable, name, &attr); + if (res < 0) { + _PyErr_Clear(tstate); + } + else if (res > 0 && PyCallable_Check(attr)) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object is not callable. " + "Did you mean: '%U.%U(...)'?", + Py_TYPE(callable)->tp_name, name, name); + Py_DECREF(attr); + Py_DECREF(name); + return; + } + Py_XDECREF(attr); + Py_DECREF(name); + } +basic_type_error: + _PyErr_Format(tstate, PyExc_TypeError, "'%.200s' object is not callable", + Py_TYPE(callable)->tp_name); +} + PyObject * _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable, @@ -171,9 +207,7 @@ _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable, * temporary dictionary for keyword arguments (if any) */ ternaryfunc call = Py_TYPE(callable)->tp_call; if (call == NULL) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object is not callable", - Py_TYPE(callable)->tp_name); + object_is_not_callable(tstate, callable); return NULL; } @@ -322,9 +356,7 @@ _PyObject_Call(PyThreadState *tstate, PyObject *callable, else { call = Py_TYPE(callable)->tp_call; if (call == NULL) { - _PyErr_Format(tstate, PyExc_TypeError, - "'%.200s' object is not callable", - Py_TYPE(callable)->tp_name); + object_is_not_callable(tstate, callable); return NULL; } |