Skip to content

Commit 83cbe84

Browse files
authored
gh-64373: Convert _functools to Argument Clinic (#96640)
1 parent 5ba4875 commit 83cbe84

File tree

6 files changed

+182
-29
lines changed

6 files changed

+182
-29
lines changed

Include/internal/pycore_global_strings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ struct _Py_global_strings {
468468
STRUCT_FOR_ID(modules)
469469
STRUCT_FOR_ID(mro)
470470
STRUCT_FOR_ID(msg)
471+
STRUCT_FOR_ID(mycmp)
471472
STRUCT_FOR_ID(n)
472473
STRUCT_FOR_ID(n_arg)
473474
STRUCT_FOR_ID(n_fields)

Include/internal/pycore_runtime_init_generated.h

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

Lib/test/test_functools.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import gc
1818
from weakref import proxy
1919
import contextlib
20+
from inspect import Signature
2021

2122
from test.support import import_helper
2223
from test.support import threading_helper
@@ -941,6 +942,10 @@ def mycmp(x, y):
941942
self.assertRaises(TypeError, hash, k)
942943
self.assertNotIsInstance(k, collections.abc.Hashable)
943944

945+
def test_cmp_to_signature(self):
946+
self.assertEqual(str(Signature.from_callable(self.cmp_to_key)),
947+
'(mycmp)')
948+
944949

945950
@unittest.skipUnless(c_functools, 'requires the C _functools module')
946951
class TestCmpToKeyC(TestCmpToKey, unittest.TestCase):
@@ -1853,6 +1858,13 @@ def test_staticmethod(x):
18531858
for ref in refs:
18541859
self.assertIsNone(ref())
18551860

1861+
def test_common_signatures(self):
1862+
def orig(): ...
1863+
lru = self.module.lru_cache(1)(orig)
1864+
1865+
self.assertEqual(str(Signature.from_callable(lru.cache_info)), '()')
1866+
self.assertEqual(str(Signature.from_callable(lru.cache_clear)), '()')
1867+
18561868

18571869
@py_functools.lru_cache()
18581870
def py_cached_func(x, y):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Convert :mod:`_functools` to argument clinic.

Modules/_functoolsmodule.c

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
#include "pycore_tuple.h" // _PyTuple_ITEMS()
88
#include "structmember.h" // PyMemberDef
99

10+
#include "clinic/_functoolsmodule.c.h"
11+
/*[clinic input]
12+
module _functools
13+
class _functools._lru_cache_wrapper "PyObject *" "&lru_cache_type_spec"
14+
[clinic start generated code]*/
15+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=bece4053896b09c0]*/
16+
1017
/* _functools module written and maintained
1118
by Hye-Shik Chang <[email protected]>
1219
with adaptations by Raymond Hettinger <[email protected]>
@@ -58,6 +65,7 @@ get_functools_state_by_type(PyTypeObject *type)
5865
return get_functools_state(module);
5966
}
6067

68+
// Not converted to argument clinic, because of `*args, **kwargs` arguments.
6169
static PyObject *
6270
partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
6371
{
@@ -282,6 +290,7 @@ partial_setvectorcall(partialobject *pto)
282290
}
283291

284292

293+
// Not converted to argument clinic, because of `*args, **kwargs` arguments.
285294
static PyObject *
286295
partial_call(partialobject *pto, PyObject *args, PyObject *kwargs)
287296
{
@@ -625,33 +634,37 @@ keyobject_richcompare(PyObject *ko, PyObject *other, int op)
625634
return answer;
626635
}
627636

637+
/*[clinic input]
638+
_functools.cmp_to_key
639+
640+
mycmp: object
641+
Function that compares two objects.
642+
643+
Convert a cmp= function into a key= function.
644+
[clinic start generated code]*/
645+
628646
static PyObject *
629-
functools_cmp_to_key(PyObject *self, PyObject *args, PyObject *kwds)
647+
_functools_cmp_to_key_impl(PyObject *module, PyObject *mycmp)
648+
/*[clinic end generated code: output=71eaad0f4fc81f33 input=d1b76f231c0dfeb3]*/
630649
{
631-
PyObject *cmp;
632-
static char *kwargs[] = {"mycmp", NULL};
633650
keyobject *object;
634651
_functools_state *state;
635652

636-
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
637-
return NULL;
638-
639-
state = get_functools_state(self);
653+
state = get_functools_state(module);
640654
object = PyObject_GC_New(keyobject, state->keyobject_type);
641655
if (!object)
642656
return NULL;
643-
Py_INCREF(cmp);
644-
object->cmp = cmp;
657+
Py_INCREF(mycmp);
658+
object->cmp = mycmp;
645659
object->object = NULL;
646660
PyObject_GC_Track(object);
647661
return (PyObject *)object;
648662
}
649663

650-
PyDoc_STRVAR(functools_cmp_to_key_doc,
651-
"Convert a cmp= function into a key= function.");
652-
653664
/* reduce (used to be a builtin) ********************************************/
654665

666+
// Not converted to argument clinic, because of `args` in-place modification.
667+
// AC will affect performance.
655668
static PyObject *
656669
functools_reduce(PyObject *self, PyObject *args)
657670
{
@@ -1299,25 +1312,41 @@ lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
12991312
return PyMethod_New(self, obj);
13001313
}
13011314

1315+
/*[clinic input]
1316+
_functools._lru_cache_wrapper.cache_info
1317+
1318+
Report cache statistics
1319+
[clinic start generated code]*/
1320+
13021321
static PyObject *
1303-
lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1322+
_functools__lru_cache_wrapper_cache_info_impl(PyObject *self)
1323+
/*[clinic end generated code: output=cc796a0b06dbd717 input=f05e5b6ebfe38645]*/
13041324
{
1305-
if (self->maxsize == -1) {
1306-
return PyObject_CallFunction(self->cache_info_type, "nnOn",
1307-
self->hits, self->misses, Py_None,
1308-
PyDict_GET_SIZE(self->cache));
1309-
}
1310-
return PyObject_CallFunction(self->cache_info_type, "nnnn",
1311-
self->hits, self->misses, self->maxsize,
1312-
PyDict_GET_SIZE(self->cache));
1325+
lru_cache_object *_self = (lru_cache_object *) self;
1326+
if (_self->maxsize == -1) {
1327+
return PyObject_CallFunction(_self->cache_info_type, "nnOn",
1328+
_self->hits, _self->misses, Py_None,
1329+
PyDict_GET_SIZE(_self->cache));
1330+
}
1331+
return PyObject_CallFunction(_self->cache_info_type, "nnnn",
1332+
_self->hits, _self->misses, _self->maxsize,
1333+
PyDict_GET_SIZE(_self->cache));
13131334
}
13141335

1336+
/*[clinic input]
1337+
_functools._lru_cache_wrapper.cache_clear
1338+
1339+
Clear the cache and cache statistics
1340+
[clinic start generated code]*/
1341+
13151342
static PyObject *
1316-
lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1343+
_functools__lru_cache_wrapper_cache_clear_impl(PyObject *self)
1344+
/*[clinic end generated code: output=58423b35efc3e381 input=6ca59dba09b12584]*/
13171345
{
1318-
lru_list_elem *list = lru_cache_unlink_list(self);
1319-
self->hits = self->misses = 0;
1320-
PyDict_Clear(self->cache);
1346+
lru_cache_object *_self = (lru_cache_object *) self;
1347+
lru_list_elem *list = lru_cache_unlink_list(_self);
1348+
_self->hits = _self->misses = 0;
1349+
PyDict_Clear(_self->cache);
13211350
lru_cache_clear_list(list);
13221351
Py_RETURN_NONE;
13231352
}
@@ -1381,8 +1410,8 @@ cache_info_type: namedtuple class with the fields:\n\
13811410
);
13821411

13831412
static PyMethodDef lru_cache_methods[] = {
1384-
{"cache_info", (PyCFunction)lru_cache_cache_info, METH_NOARGS},
1385-
{"cache_clear", (PyCFunction)lru_cache_cache_clear, METH_NOARGS},
1413+
_FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_INFO_METHODDEF
1414+
_FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_CLEAR_METHODDEF
13861415
{"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
13871416
{"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
13881417
{"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
@@ -1432,8 +1461,7 @@ PyDoc_STRVAR(_functools_doc,
14321461

14331462
static PyMethodDef _functools_methods[] = {
14341463
{"reduce", functools_reduce, METH_VARARGS, functools_reduce_doc},
1435-
{"cmp_to_key", _PyCFunction_CAST(functools_cmp_to_key),
1436-
METH_VARARGS | METH_KEYWORDS, functools_cmp_to_key_doc},
1464+
_FUNCTOOLS_CMP_TO_KEY_METHODDEF
14371465
{NULL, NULL} /* sentinel */
14381466
};
14391467

Modules/clinic/_functoolsmodule.c.h

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

0 commit comments

Comments
 (0)