Skip to content

Commit 2160311

Browse files
committed
Merge branch 'main' into add-push-null
2 parents c80fbcf + 580cd9a commit 2160311

19 files changed

+388
-155
lines changed

Doc/library/inspect.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,14 @@ attributes:
429429
Return ``True`` if the object is a built-in function or a bound built-in method.
430430

431431

432+
.. function:: ismethodwrapper(object)
433+
434+
Return ``True`` if the type of object is a :class:`~types.MethodWrapperType`.
435+
436+
These are instances of :class:`~types.MethodWrapperType`, such as :meth:`~object().__str__`,
437+
:meth:`~object().__eq__` and :meth:`~object().__repr__`
438+
439+
432440
.. function:: isroutine(object)
433441

434442
Return ``True`` if the object is a user-defined or built-in function or method.

Include/internal/pycore_code.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ int _Py_Specialize_CallNoKw(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
276276
void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
277277
SpecializedCacheEntry *cache);
278278
void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache);
279+
void _Py_Specialize_UnpackSequence(PyObject *seq, _Py_CODEUNIT *instr,
280+
SpecializedCacheEntry *cache);
279281

280282
/* Deallocator function for static codeobjects used in deepfreeze.py */
281283
void _PyStaticCode_Dealloc(PyCodeObject *co);

Include/opcode.h

Lines changed: 9 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/inspect.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
"ismemberdescriptor",
122122
"ismethod",
123123
"ismethoddescriptor",
124+
"ismethodwrapper",
124125
"ismodule",
125126
"isroutine",
126127
"istraceback",
@@ -509,12 +510,17 @@ def isbuiltin(object):
509510
__self__ instance to which a method is bound, or None"""
510511
return isinstance(object, types.BuiltinFunctionType)
511512

513+
def ismethodwrapper(object):
514+
"""Return true if the object is a method wrapper."""
515+
return isinstance(object, types.MethodWrapperType)
516+
512517
def isroutine(object):
513518
"""Return true if the object is any kind of function or method."""
514519
return (isbuiltin(object)
515520
or isfunction(object)
516521
or ismethod(object)
517-
or ismethoddescriptor(object))
522+
or ismethoddescriptor(object)
523+
or ismethodwrapper(object))
518524

519525
def isabstract(object):
520526
"""Return true if the object is an abstract base class (ABC)."""
@@ -1887,13 +1893,9 @@ def getcoroutinelocals(coroutine):
18871893
###############################################################################
18881894

18891895

1890-
_WrapperDescriptor = type(type.__call__)
1891-
_MethodWrapper = type(all.__call__)
1892-
_ClassMethodWrapper = type(int.__dict__['from_bytes'])
1893-
1894-
_NonUserDefinedCallables = (_WrapperDescriptor,
1895-
_MethodWrapper,
1896-
_ClassMethodWrapper,
1896+
_NonUserDefinedCallables = (types.WrapperDescriptorType,
1897+
types.MethodWrapperType,
1898+
types.ClassMethodDescriptorType,
18971899
types.BuiltinFunctionType)
18981900

18991901

@@ -2533,7 +2535,7 @@ def _signature_from_callable(obj, *,
25332535
elif not isinstance(obj, _NonUserDefinedCallables):
25342536
# An object with __call__
25352537
# We also check that the 'obj' is not an instance of
2536-
# _WrapperDescriptor or _MethodWrapper to avoid
2538+
# types.WrapperDescriptorType or types.MethodWrapperType to avoid
25372539
# infinite recursion (and even potential segfault)
25382540
call = _signature_get_user_defined_method(type(obj), '__call__')
25392541
if call is not None:

Lib/opcode.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,10 @@ def jabs_op(name, op):
282282
"STORE_ATTR_INSTANCE_VALUE",
283283
"STORE_ATTR_SLOT",
284284
"STORE_ATTR_WITH_HINT",
285+
"UNPACK_SEQUENCE_ADAPTIVE",
286+
"UNPACK_SEQUENCE_LIST",
287+
"UNPACK_SEQUENCE_TUPLE",
288+
"UNPACK_SEQUENCE_TWO_TUPLE",
285289
# Super instructions
286290
"LOAD_FAST__LOAD_FAST",
287291
"STORE_FAST__LOAD_FAST",

Lib/test/test_inspect.py

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
# isbuiltin, isroutine, isgenerator, isgeneratorfunction, getmembers,
4545
# getdoc, getfile, getmodule, getsourcefile, getcomments, getsource,
4646
# getclasstree, getargvalues, formatargvalues,
47-
# currentframe, stack, trace, isdatadescriptor
47+
# currentframe, stack, trace, isdatadescriptor,
48+
# ismethodwrapper
4849

4950
# NOTE: There are some additional tests relating to interaction with
5051
# zipimport in the test_zipimport_support test module.
@@ -93,7 +94,8 @@ class IsTestBase(unittest.TestCase):
9394
inspect.ismodule, inspect.istraceback,
9495
inspect.isgenerator, inspect.isgeneratorfunction,
9596
inspect.iscoroutine, inspect.iscoroutinefunction,
96-
inspect.isasyncgen, inspect.isasyncgenfunction])
97+
inspect.isasyncgen, inspect.isasyncgenfunction,
98+
inspect.ismethodwrapper])
9799

98100
def istest(self, predicate, exp):
99101
obj = eval(exp)
@@ -169,6 +171,14 @@ def test_excluding_predicates(self):
169171
self.istest(inspect.ismemberdescriptor, 'datetime.timedelta.days')
170172
else:
171173
self.assertFalse(inspect.ismemberdescriptor(datetime.timedelta.days))
174+
self.istest(inspect.ismethodwrapper, "object().__str__")
175+
self.istest(inspect.ismethodwrapper, "object().__eq__")
176+
self.istest(inspect.ismethodwrapper, "object().__repr__")
177+
self.assertFalse(inspect.ismethodwrapper(type))
178+
self.assertFalse(inspect.ismethodwrapper(int))
179+
self.assertFalse(inspect.ismethodwrapper(type("AnyClass", (), {})))
180+
181+
172182

173183
def test_iscoroutine(self):
174184
async_gen_coro = async_generator_function_example(1)
@@ -241,8 +251,38 @@ class NotFuture: pass
241251
coro.close(); gen_coro.close() # silence warnings
242252

243253
def test_isroutine(self):
244-
self.assertTrue(inspect.isroutine(mod.spam))
254+
# method
255+
self.assertTrue(inspect.isroutine(git.argue))
256+
self.assertTrue(inspect.isroutine(mod.custom_method))
245257
self.assertTrue(inspect.isroutine([].count))
258+
# function
259+
self.assertTrue(inspect.isroutine(mod.spam))
260+
self.assertTrue(inspect.isroutine(mod.StupidGit.abuse))
261+
# slot-wrapper
262+
self.assertTrue(inspect.isroutine(object.__init__))
263+
self.assertTrue(inspect.isroutine(object.__str__))
264+
self.assertTrue(inspect.isroutine(object.__lt__))
265+
self.assertTrue(inspect.isroutine(int.__lt__))
266+
# method-wrapper
267+
self.assertTrue(inspect.isroutine(object().__init__))
268+
self.assertTrue(inspect.isroutine(object().__str__))
269+
self.assertTrue(inspect.isroutine(object().__lt__))
270+
self.assertTrue(inspect.isroutine((42).__lt__))
271+
# method-descriptor
272+
self.assertTrue(inspect.isroutine(str.join))
273+
self.assertTrue(inspect.isroutine(list.append))
274+
self.assertTrue(inspect.isroutine(''.join))
275+
self.assertTrue(inspect.isroutine([].append))
276+
# object
277+
self.assertFalse(inspect.isroutine(object))
278+
self.assertFalse(inspect.isroutine(object()))
279+
self.assertFalse(inspect.isroutine(str()))
280+
# module
281+
self.assertFalse(inspect.isroutine(mod))
282+
# type
283+
self.assertFalse(inspect.isroutine(type))
284+
self.assertFalse(inspect.isroutine(int))
285+
self.assertFalse(inspect.isroutine(type('some_class', (), {})))
246286

247287
def test_isclass(self):
248288
self.istest(inspect.isclass, 'mod.StupidGit')
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Specialize :opcode:`UNPACK_SEQUENCE` for :class:`tuple` and :class:`list`
2+
unpackings.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add more detailed specialization failure statistics for :opcode:`BINARY_OP`.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Implement :func:`inspect.ismethodwrapper` and fix :func:`inspect.isroutine` for cases where methodwrapper is given. Patch by Hakan Çelik.

Modules/_csv.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ module instead.
1010

1111
#define MODULE_VERSION "1.0"
1212

13-
#define NEEDS_PY_IDENTIFIER
14-
1513
#include "Python.h"
1614
#include "structmember.h" // PyMemberDef
1715
#include <stdbool.h>
@@ -27,6 +25,7 @@ typedef struct {
2725
PyTypeObject *reader_type;
2826
PyTypeObject *writer_type;
2927
long field_limit; /* max parsed field size */
28+
PyObject *str_write;
3029
} _csvstate;
3130

3231
static struct PyModuleDef _csvmodule;
@@ -48,6 +47,7 @@ _csv_clear(PyObject *module)
4847
Py_CLEAR(module_state->dialect_type);
4948
Py_CLEAR(module_state->reader_type);
5049
Py_CLEAR(module_state->writer_type);
50+
Py_CLEAR(module_state->str_write);
5151
return 0;
5252
}
5353

@@ -60,6 +60,7 @@ _csv_traverse(PyObject *module, visitproc visit, void *arg)
6060
Py_VISIT(module_state->dialect_type);
6161
Py_VISIT(module_state->reader_type);
6262
Py_VISIT(module_state->writer_type);
63+
Py_VISIT(module_state->str_write);
6364
return 0;
6465
}
6566

@@ -1430,7 +1431,6 @@ csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args)
14301431
PyObject * output_file, * dialect = NULL;
14311432
_csvstate *module_state = get_csv_state(module);
14321433
WriterObj * self = PyObject_GC_New(WriterObj, module_state->writer_type);
1433-
_Py_IDENTIFIER(write);
14341434

14351435
if (!self)
14361436
return NULL;
@@ -1449,7 +1449,9 @@ csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args)
14491449
Py_DECREF(self);
14501450
return NULL;
14511451
}
1452-
if (_PyObject_LookupAttrId(output_file, &PyId_write, &self->write) < 0) {
1452+
if (_PyObject_LookupAttr(output_file,
1453+
module_state->str_write,
1454+
&self->write) < 0) {
14531455
Py_DECREF(self);
14541456
return NULL;
14551457
}
@@ -1751,6 +1753,10 @@ csv_exec(PyObject *module) {
17511753
return -1;
17521754
}
17531755

1756+
module_state->str_write = PyUnicode_InternFromString("write");
1757+
if (module_state->str_write == NULL) {
1758+
return -1;
1759+
}
17541760
return 0;
17551761
}
17561762

0 commit comments

Comments
 (0)