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

Skip to content

Commit 41bdf01

Browse files
committed
Add a helper for signature-overloaded functions.
1 parent 02f2ea7 commit 41bdf01

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
@@ -1994,32 +1994,23 @@ def __init__(self, *args, **kwargs):
19941994
# signature deprecation since="3.5": Change to new signature after the
19951995
# deprecation has expired. Also remove setting __init__.__signature__,
19961996
# and remove the Notes from the docstring.
1997-
#
1998-
# We use lambdas to parse *args, **kwargs through the respective old
1999-
# and new signatures.
2000-
try:
2001-
# Old signature:
2002-
# The following raises a TypeError iif the args don't match.
2003-
w, h, coords, antialiased, shading, kwargs = (
1997+
params = _api.select_matching_signature(
1998+
[
20041999
lambda meshWidth, meshHeight, coordinates, antialiased=True,
2005-
shading='flat', **kwargs:
2006-
(meshWidth, meshHeight, coordinates, antialiased, shading,
2007-
kwargs))(*args, **kwargs)
2008-
except TypeError as exc:
2009-
# New signature:
2010-
# If the following raises a TypeError (i.e. args don't match),
2011-
# just let it propagate.
2012-
coords, antialiased, shading, kwargs = (
2000+
shading='flat', **kwargs: locals(),
20132001
lambda coordinates, antialiased=True, shading='flat', **kwargs:
2014-
(coordinates, antialiased, shading, kwargs))(*args, **kwargs)
2015-
coords = np.asarray(coords, np.float64)
2016-
else: # The old signature matched.
2002+
locals()
2003+
],
2004+
*args, **kwargs).values()
2005+
*old_w_h, coords, antialiased, shading, kwargs = params
2006+
if old_w_h: # The old signature matched.
20172007
_api.warn_deprecated(
20182008
"3.5",
20192009
message="This usage of Quadmesh is deprecated: Parameters "
20202010
"meshWidth and meshHeights will be removed; "
20212011
"coordinates must be 2D; all parameters except "
20222012
"coordinates will be keyword-only.")
2013+
w, h = old_w_h
20232014
coords = np.asarray(coords, np.float64).reshape((h + 1, w + 1, 2))
20242015
kwargs.setdefault("pickradius", 0)
20252016
# end of signature deprecation code

0 commit comments

Comments
 (0)