Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f008953

Browse files
authored
Merge pull request #20420 from anntzer/select_overload
Add a select_overload helper for signature-overloaded functions.
2 parents 33822f5 + 41bdf01 commit f008953

File tree

2 files changed

+61
-18
lines changed

2 files changed

+61
-18
lines changed

lib/matplotlib/_api/__init__.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,58 @@ def check_getitem(_mapping, **kwargs):
189189
.format(v, k, ', '.join(map(repr, mapping)))) from None
190190

191191

192+
def select_matching_signature(funcs, *args, **kwargs):
193+
"""
194+
Select and call the function that accepts ``*args, **kwargs``.
195+
196+
*funcs* is a list of functions which should not raise any exception (other
197+
than `TypeError` if the arguments passed do not match their signature).
198+
199+
`select_matching_signature` tries to call each of the functions in *funcs*
200+
with ``*args, **kwargs`` (in the order in which they are given). Calls
201+
that fail with a `TypeError` are silently skipped. As soon as a call
202+
succeeds, `select_matching_signature` returns its return value. If no
203+
function accepts ``*args, **kwargs``, then the `TypeError` raised by the
204+
last failing call is re-raised.
205+
206+
Callers should normally make sure that any ``*args, **kwargs`` can only
207+
bind a single *func* (to avoid any ambiguity), although this is not checked
208+
by `select_matching_signature`.
209+
210+
Notes
211+
-----
212+
`select_matching_signature` is intended to help implementing
213+
signature-overloaded functions. In general, such functions should be
214+
avoided, except for back-compatibility concerns. A typical use pattern is
215+
::
216+
217+
def my_func(*args, **kwargs):
218+
params = select_matching_signature(
219+
[lambda old1, old2: locals(), lambda new: locals()],
220+
*args, **kwargs)
221+
if "old1" in params:
222+
warn_deprecated(...)
223+
old1, old2 = params.values() # note that locals() is ordered.
224+
else:
225+
new, = params.values()
226+
# do things with params
227+
228+
which allows *my_func* to be called either with two parameters (*old1* and
229+
*old2*) or a single one (*new*). Note that the new signature is given
230+
last, so that callers get a `TypeError` corresponding to the new signature
231+
if the arguments they passed in do not match any signature.
232+
"""
233+
# Rather than relying on locals() ordering, one could have just used func's
234+
# signature (``bound = inspect.signature(func).bind(*args, **kwargs);
235+
# bound.apply_defaults(); return bound``) but that is significantly slower.
236+
for i, func in enumerate(funcs):
237+
try:
238+
return func(*args, **kwargs)
239+
except TypeError:
240+
if i == len(funcs) - 1:
241+
raise
242+
243+
192244
def warn_external(message, category=None):
193245
"""
194246
`warnings.warn` wrapper that sets *stacklevel* to "outside Matplotlib".

lib/matplotlib/collections.py

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,32 +1979,23 @@ def __init__(self, *args, **kwargs):
19791979
# signature deprecation since="3.5": Change to new signature after the
19801980
# deprecation has expired. Also remove setting __init__.__signature__,
19811981
# and remove the Notes from the docstring.
1982-
#
1983-
# We use lambdas to parse *args, **kwargs through the respective old
1984-
# and new signatures.
1985-
try:
1986-
# Old signature:
1987-
# The following raises a TypeError iif the args don't match.
1988-
w, h, coords, antialiased, shading, kwargs = (
1982+
params = _api.select_matching_signature(
1983+
[
19891984
lambda meshWidth, meshHeight, coordinates, antialiased=True,
1990-
shading='flat', **kwargs:
1991-
(meshWidth, meshHeight, coordinates, antialiased, shading,
1992-
kwargs))(*args, **kwargs)
1993-
except TypeError as exc:
1994-
# New signature:
1995-
# If the following raises a TypeError (i.e. args don't match),
1996-
# just let it propagate.
1997-
coords, antialiased, shading, kwargs = (
1985+
shading='flat', **kwargs: locals(),
19981986
lambda coordinates, antialiased=True, shading='flat', **kwargs:
1999-
(coordinates, antialiased, shading, kwargs))(*args, **kwargs)
2000-
coords = np.asarray(coords, np.float64)
2001-
else: # The old signature matched.
1987+
locals()
1988+
],
1989+
*args, **kwargs).values()
1990+
*old_w_h, coords, antialiased, shading, kwargs = params
1991+
if old_w_h: # The old signature matched.
20021992
_api.warn_deprecated(
20031993
"3.5",
20041994
message="This usage of Quadmesh is deprecated: Parameters "
20051995
"meshWidth and meshHeights will be removed; "
20061996
"coordinates must be 2D; all parameters except "
20071997
"coordinates will be keyword-only.")
1998+
w, h = old_w_h
20081999
coords = np.asarray(coords, np.float64).reshape((h + 1, w + 1, 2))
20092000
kwargs.setdefault("pickradius", 0)
20102001
# end of signature deprecation code

0 commit comments

Comments
 (0)