Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit7d35c31

Browse files
authored
GH-103899: Provide a hint when accidentally calling a module (GH-103900)
1 parentf5c3838 commit7d35c31

File tree

3 files changed

+73
-6
lines changed

3 files changed

+73
-6
lines changed

‎Lib/test/test_call.py‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
importgc
1111
importcontextlib
1212
importsys
13+
importtypes
1314

1415

1516
classBadStr(str):
@@ -202,6 +203,37 @@ def test_oldargs1_2_kw(self):
202203
msg=r"count\(\) takes no keyword arguments"
203204
self.assertRaisesRegex(TypeError,msg, [].count,x=2,y=2)
204205

206+
deftest_object_not_callable(self):
207+
msg=r"^'object' object is not callable$"
208+
self.assertRaisesRegex(TypeError,msg,object())
209+
210+
deftest_module_not_callable_no_suggestion_0(self):
211+
msg=r"^'module' object is not callable$"
212+
self.assertRaisesRegex(TypeError,msg,types.ModuleType("mod"))
213+
214+
deftest_module_not_callable_no_suggestion_1(self):
215+
msg=r"^'module' object is not callable$"
216+
mod=types.ModuleType("mod")
217+
mod.mod=42
218+
self.assertRaisesRegex(TypeError,msg,mod)
219+
220+
deftest_module_not_callable_no_suggestion_2(self):
221+
msg=r"^'module' object is not callable$"
222+
mod=types.ModuleType("mod")
223+
delmod.__name__
224+
self.assertRaisesRegex(TypeError,msg,mod)
225+
226+
deftest_module_not_callable_no_suggestion_3(self):
227+
msg=r"^'module' object is not callable$"
228+
mod=types.ModuleType("mod")
229+
mod.__name__=42
230+
self.assertRaisesRegex(TypeError,msg,mod)
231+
232+
deftest_module_not_callable_suggestion(self):
233+
msg=r"^'module' object is not callable\. Did you mean: 'mod\.mod\(\.\.\.\)'\?$"
234+
mod=types.ModuleType("mod")
235+
mod.mod=lambda: ...
236+
self.assertRaisesRegex(TypeError,msg,mod)
205237

206238

207239
classTestCallingConventions(unittest.TestCase):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Provide a helpful hint in the:exc:`TypeError` message when accidentally
2+
calling a:term:`module` object that has a callable attribute of the same
3+
name (such as:func:`dis.dis` or:class:`datetime.datetime`).

‎Objects/call.c‎

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,42 @@ PyObject_VectorcallDict(PyObject *callable, PyObject *const *args,
157157
return_PyObject_FastCallDictTstate(tstate,callable,args,nargsf,kwargs);
158158
}
159159

160+
staticvoid
161+
object_is_not_callable(PyThreadState*tstate,PyObject*callable)
162+
{
163+
if (Py_IS_TYPE(callable,&PyModule_Type)) {
164+
// >>> import pprint
165+
// >>> pprint(thing)
166+
// Traceback (most recent call last):
167+
// File "<stdin>", line 1, in <module>
168+
// TypeError: 'module' object is not callable. Did you mean: 'pprint.pprint(...)'?
169+
PyObject*name=PyModule_GetNameObject(callable);
170+
if (name==NULL) {
171+
_PyErr_Clear(tstate);
172+
gotobasic_type_error;
173+
}
174+
PyObject*attr;
175+
intres=_PyObject_LookupAttr(callable,name,&attr);
176+
if (res<0) {
177+
_PyErr_Clear(tstate);
178+
}
179+
elseif (res>0&&PyCallable_Check(attr)) {
180+
_PyErr_Format(tstate,PyExc_TypeError,
181+
"'%.200s' object is not callable. "
182+
"Did you mean: '%U.%U(...)'?",
183+
Py_TYPE(callable)->tp_name,name,name);
184+
Py_DECREF(attr);
185+
Py_DECREF(name);
186+
return;
187+
}
188+
Py_XDECREF(attr);
189+
Py_DECREF(name);
190+
}
191+
basic_type_error:
192+
_PyErr_Format(tstate,PyExc_TypeError,"'%.200s' object is not callable",
193+
Py_TYPE(callable)->tp_name);
194+
}
195+
160196

161197
PyObject*
162198
_PyObject_MakeTpCall(PyThreadState*tstate,PyObject*callable,
@@ -171,9 +207,7 @@ _PyObject_MakeTpCall(PyThreadState *tstate, PyObject *callable,
171207
* temporary dictionary for keyword arguments (if any) */
172208
ternaryfunccall=Py_TYPE(callable)->tp_call;
173209
if (call==NULL) {
174-
_PyErr_Format(tstate,PyExc_TypeError,
175-
"'%.200s' object is not callable",
176-
Py_TYPE(callable)->tp_name);
210+
object_is_not_callable(tstate,callable);
177211
returnNULL;
178212
}
179213

@@ -322,9 +356,7 @@ _PyObject_Call(PyThreadState *tstate, PyObject *callable,
322356
else {
323357
call=Py_TYPE(callable)->tp_call;
324358
if (call==NULL) {
325-
_PyErr_Format(tstate,PyExc_TypeError,
326-
"'%.200s' object is not callable",
327-
Py_TYPE(callable)->tp_name);
359+
object_is_not_callable(tstate,callable);
328360
returnNULL;
329361
}
330362

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp