Skip to content

Commit 79fa9e8

Browse files
committed
gh-64373: Convert _functools to Argument Clinic
1 parent aa3b4cf commit 79fa9e8

File tree

6 files changed

+183
-26
lines changed

6 files changed

+183
-26
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: 58 additions & 26 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 <perky@FreeBSD.org>
1219
with adaptations by Raymond Hettinger <python@rcn.com>
@@ -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,23 +634,29 @@ 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;
652+
state = get_functools_state(module);
635653

636-
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:cmp_to_key", kwargs, &cmp))
637-
return NULL;
638-
639-
state = get_functools_state(self);
654+
state = get_functools_state(module);
640655
object = PyObject_GC_New(keyobject, state->keyobject_type);
641656
if (!object)
642657
return NULL;
643-
Py_INCREF(cmp);
644-
object->cmp = cmp;
658+
Py_INCREF(mycmp);
659+
object->cmp = mycmp;
645660
object->object = NULL;
646661
PyObject_GC_Track(object);
647662
return (PyObject *)object;
@@ -652,6 +667,8 @@ PyDoc_STRVAR(functools_cmp_to_key_doc,
652667

653668
/* reduce (used to be a builtin) ********************************************/
654669

670+
// Not converted to argument clinic, because of `args` in-place modification.
671+
// AC will affect performance.
655672
static PyObject *
656673
functools_reduce(PyObject *self, PyObject *args)
657674
{
@@ -1299,25 +1316,41 @@ lru_cache_descr_get(PyObject *self, PyObject *obj, PyObject *type)
12991316
return PyMethod_New(self, obj);
13001317
}
13011318

1319+
/*[clinic input]
1320+
_functools._lru_cache_wrapper.cache_info
1321+
1322+
Report cache statistics
1323+
[clinic start generated code]*/
1324+
13021325
static PyObject *
1303-
lru_cache_cache_info(lru_cache_object *self, PyObject *unused)
1326+
_functools__lru_cache_wrapper_cache_info_impl(PyObject *self)
1327+
/*[clinic end generated code: output=cc796a0b06dbd717 input=f05e5b6ebfe38645]*/
13041328
{
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));
1329+
lru_cache_object *_self = (lru_cache_object *) self;
1330+
if (_self->maxsize == -1) {
1331+
return PyObject_CallFunction(_self->cache_info_type, "nnOn",
1332+
_self->hits, _self->misses, Py_None,
1333+
PyDict_GET_SIZE(_self->cache));
1334+
}
1335+
return PyObject_CallFunction(_self->cache_info_type, "nnnn",
1336+
_self->hits, _self->misses, _self->maxsize,
1337+
PyDict_GET_SIZE(_self->cache));
13131338
}
13141339

1340+
/*[clinic input]
1341+
_functools._lru_cache_wrapper.cache_clear
1342+
1343+
Clear the cache and cache statistics
1344+
[clinic start generated code]*/
1345+
13151346
static PyObject *
1316-
lru_cache_cache_clear(lru_cache_object *self, PyObject *unused)
1347+
_functools__lru_cache_wrapper_cache_clear_impl(PyObject *self)
1348+
/*[clinic end generated code: output=58423b35efc3e381 input=6ca59dba09b12584]*/
13171349
{
1318-
lru_list_elem *list = lru_cache_unlink_list(self);
1319-
self->hits = self->misses = 0;
1320-
PyDict_Clear(self->cache);
1350+
lru_cache_object *_self = (lru_cache_object *) self;
1351+
lru_list_elem *list = lru_cache_unlink_list(_self);
1352+
_self->hits = _self->misses = 0;
1353+
PyDict_Clear(_self->cache);
13211354
lru_cache_clear_list(list);
13221355
Py_RETURN_NONE;
13231356
}
@@ -1381,8 +1414,8 @@ cache_info_type: namedtuple class with the fields:\n\
13811414
);
13821415

13831416
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},
1417+
_FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_INFO_METHODDEF
1418+
_FUNCTOOLS__LRU_CACHE_WRAPPER_CACHE_CLEAR_METHODDEF
13861419
{"__reduce__", (PyCFunction)lru_cache_reduce, METH_NOARGS},
13871420
{"__copy__", (PyCFunction)lru_cache_copy, METH_VARARGS},
13881421
{"__deepcopy__", (PyCFunction)lru_cache_deepcopy, METH_VARARGS},
@@ -1432,8 +1465,7 @@ PyDoc_STRVAR(_functools_doc,
14321465

14331466
static PyMethodDef _functools_methods[] = {
14341467
{"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},
1468+
_FUNCTOOLS_CMP_TO_KEY_METHODDEF
14371469
{NULL, NULL} /* sentinel */
14381470
};
14391471

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)