Skip to content

Commit 8f5be78

Browse files
furkanonderVgr255
andauthored
gh-72249: Include the module name in the repr of partial object (GH-101910)
Co-authored-by: Anilyka Barry <[email protected]>
1 parent f082a05 commit 8f5be78

File tree

4 files changed

+27
-18
lines changed

4 files changed

+27
-18
lines changed

Lib/functools.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,13 @@ def __call__(self, /, *args, **keywords):
303303

304304
@recursive_repr()
305305
def __repr__(self):
306-
qualname = type(self).__qualname__
306+
cls = type(self)
307+
qualname = cls.__qualname__
308+
module = cls.__module__
307309
args = [repr(self.func)]
308310
args.extend(repr(x) for x in self.args)
309311
args.extend(f"{k}={v!r}" for (k, v) in self.keywords.items())
310-
if type(self).__module__ == "functools":
311-
return f"functools.{qualname}({', '.join(args)})"
312-
return f"{qualname}({', '.join(args)})"
312+
return f"{module}.{qualname}({', '.join(args)})"
313313

314314
def __reduce__(self):
315315
return type(self), (self.func,), (self.func, self.args,

Lib/test/test_functools.py

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@
3131

3232
decimal = import_helper.import_fresh_module('decimal', fresh=['_decimal'])
3333

34-
_partial_types = [py_functools.partial]
35-
if c_functools:
36-
_partial_types.append(c_functools.partial)
37-
3834

3935
@contextlib.contextmanager
4036
def replaced_module(name, replacement):
@@ -207,10 +203,7 @@ def test_repr(self):
207203
kwargs = {'a': object(), 'b': object()}
208204
kwargs_reprs = ['a={a!r}, b={b!r}'.format_map(kwargs),
209205
'b={b!r}, a={a!r}'.format_map(kwargs)]
210-
if self.partial in _partial_types:
211-
name = 'functools.partial'
212-
else:
213-
name = self.partial.__name__
206+
name = f"{self.partial.__module__}.{self.partial.__qualname__}"
214207

215208
f = self.partial(capture)
216209
self.assertEqual(f'{name}({capture!r})', repr(f))
@@ -229,10 +222,7 @@ def test_repr(self):
229222
for kwargs_repr in kwargs_reprs])
230223

231224
def test_recursive_repr(self):
232-
if self.partial in _partial_types:
233-
name = 'functools.partial'
234-
else:
235-
name = self.partial.__name__
225+
name = f"{self.partial.__module__}.{self.partial.__qualname__}"
236226

237227
f = self.partial(capture)
238228
f.__setstate__((f, (), {}, {}))
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:func:`functools.partial`s of :func:`repr` has been improved to include the
2+
:term:`module` name. Patched by Furkan Onder and Anilyka Barry.

Modules/_functoolsmodule.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,8 @@ partial_repr(partialobject *pto)
365365
{
366366
PyObject *result = NULL;
367367
PyObject *arglist;
368+
PyObject *mod;
369+
PyObject *name;
368370
Py_ssize_t i, n;
369371
PyObject *key, *value;
370372
int status;
@@ -399,13 +401,28 @@ partial_repr(partialobject *pto)
399401
if (arglist == NULL)
400402
goto done;
401403
}
402-
result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
403-
pto->fn, arglist);
404+
405+
mod = _PyType_GetModuleName(Py_TYPE(pto));
406+
if (mod == NULL) {
407+
goto error;
408+
}
409+
name = PyType_GetQualName(Py_TYPE(pto));
410+
if (name == NULL) {
411+
Py_DECREF(mod);
412+
goto error;
413+
}
414+
result = PyUnicode_FromFormat("%S.%S(%R%U)", mod, name, pto->fn, arglist);
415+
Py_DECREF(mod);
416+
Py_DECREF(name);
404417
Py_DECREF(arglist);
405418

406419
done:
407420
Py_ReprLeave((PyObject *)pto);
408421
return result;
422+
error:
423+
Py_DECREF(arglist);
424+
Py_ReprLeave((PyObject *)pto);
425+
return NULL;
409426
}
410427

411428
/* Pickle strategy:

0 commit comments

Comments
 (0)