Skip to content

Commit

Permalink
gh-72249: Include the module name in the repr of partial object (GH-1…
Browse files Browse the repository at this point in the history
…01910)

Co-authored-by: Anilyka Barry <vgr255@live.ca>
  • Loading branch information
furkanonder and Vgr255 committed Feb 25, 2024
1 parent f082a05 commit 8f5be78
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 18 deletions.
8 changes: 4 additions & 4 deletions Lib/functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,13 +303,13 @@ def __call__(self, /, *args, **keywords):

@recursive_repr()
def __repr__(self):
qualname = type(self).__qualname__
cls = type(self)
qualname = cls.__qualname__
module = cls.__module__
args = [repr(self.func)]
args.extend(repr(x) for x in self.args)
args.extend(f"{k}={v!r}" for (k, v) in self.keywords.items())
if type(self).__module__ == "functools":
return f"functools.{qualname}({', '.join(args)})"
return f"{qualname}({', '.join(args)})"
return f"{module}.{qualname}({', '.join(args)})"

def __reduce__(self):
return type(self), (self.func,), (self.func, self.args,
Expand Down
14 changes: 2 additions & 12 deletions Lib/test/test_functools.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@

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

_partial_types = [py_functools.partial]
if c_functools:
_partial_types.append(c_functools.partial)


@contextlib.contextmanager
def replaced_module(name, replacement):
Expand Down Expand Up @@ -207,10 +203,7 @@ def test_repr(self):
kwargs = {'a': object(), 'b': object()}
kwargs_reprs = ['a={a!r}, b={b!r}'.format_map(kwargs),
'b={b!r}, a={a!r}'.format_map(kwargs)]
if self.partial in _partial_types:
name = 'functools.partial'
else:
name = self.partial.__name__
name = f"{self.partial.__module__}.{self.partial.__qualname__}"

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

def test_recursive_repr(self):
if self.partial in _partial_types:
name = 'functools.partial'
else:
name = self.partial.__name__
name = f"{self.partial.__module__}.{self.partial.__qualname__}"

f = self.partial(capture)
f.__setstate__((f, (), {}, {}))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:func:`functools.partial`s of :func:`repr` has been improved to include the
:term:`module` name. Patched by Furkan Onder and Anilyka Barry.
21 changes: 19 additions & 2 deletions Modules/_functoolsmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,8 @@ partial_repr(partialobject *pto)
{
PyObject *result = NULL;
PyObject *arglist;
PyObject *mod;
PyObject *name;
Py_ssize_t i, n;
PyObject *key, *value;
int status;
Expand Down Expand Up @@ -399,13 +401,28 @@ partial_repr(partialobject *pto)
if (arglist == NULL)
goto done;
}
result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name,
pto->fn, arglist);

mod = _PyType_GetModuleName(Py_TYPE(pto));
if (mod == NULL) {
goto error;
}
name = PyType_GetQualName(Py_TYPE(pto));
if (name == NULL) {
Py_DECREF(mod);
goto error;
}
result = PyUnicode_FromFormat("%S.%S(%R%U)", mod, name, pto->fn, arglist);
Py_DECREF(mod);
Py_DECREF(name);
Py_DECREF(arglist);

done:
Py_ReprLeave((PyObject *)pto);
return result;
error:
Py_DECREF(arglist);
Py_ReprLeave((PyObject *)pto);
return NULL;
}

/* Pickle strategy:
Expand Down

0 comments on commit 8f5be78

Please sign in to comment.