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

Skip to content

Add a select_overload helper for signature-overloaded functions. #20420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions lib/matplotlib/_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,58 @@ def check_getitem(_mapping, **kwargs):
.format(v, k, ', '.join(map(repr, mapping)))) from None


def select_matching_signature(funcs, *args, **kwargs):
"""
Select and call the function that accepts ``*args, **kwargs``.

*funcs* is a list of functions which should not raise any exception (other
than `TypeError` if the arguments passed do not match their signature).

`select_matching_signature` tries to call each of the functions in *funcs*
with ``*args, **kwargs`` (in the order in which they are given). Calls
that fail with a `TypeError` are silently skipped. As soon as a call
succeeds, `select_matching_signature` returns its return value. If no
function accepts ``*args, **kwargs``, then the `TypeError` raised by the
last failing call is re-raised.

Callers should normally make sure that any ``*args, **kwargs`` can only
bind a single *func* (to avoid any ambiguity), although this is not checked
by `select_matching_signature`.

Notes
-----
`select_matching_signature` is intended to help implementing
signature-overloaded functions. In general, such functions should be
avoided, except for back-compatibility concerns. A typical use pattern is
::

def my_func(*args, **kwargs):
params = select_matching_signature(
[lambda old1, old2: locals(), lambda new: locals()],
*args, **kwargs)
if "old1" in params:
warn_deprecated(...)
old1, old2 = params.values() # note that locals() is ordered.
else:
new, = params.values()
# do things with params

which allows *my_func* to be called either with two parameters (*old1* and
*old2*) or a single one (*new*). Note that the new signature is given
last, so that callers get a `TypeError` corresponding to the new signature
if the arguments they passed in do not match any signature.
"""
# Rather than relying on locals() ordering, one could have just used func's
# signature (``bound = inspect.signature(func).bind(*args, **kwargs);
# bound.apply_defaults(); return bound``) but that is significantly slower.
for i, func in enumerate(funcs):
try:
return func(*args, **kwargs)
except TypeError:
if i == len(funcs) - 1:
raise


def warn_external(message, category=None):
"""
`warnings.warn` wrapper that sets *stacklevel* to "outside Matplotlib".
Expand Down
27 changes: 9 additions & 18 deletions lib/matplotlib/collections.py
Original file line number Diff line number Diff line change
Expand Up @@ -1994,32 +1994,23 @@ def __init__(self, *args, **kwargs):
# signature deprecation since="3.5": Change to new signature after the
# deprecation has expired. Also remove setting __init__.__signature__,
# and remove the Notes from the docstring.
#
# We use lambdas to parse *args, **kwargs through the respective old
# and new signatures.
try:
# Old signature:
# The following raises a TypeError iif the args don't match.
w, h, coords, antialiased, shading, kwargs = (
params = _api.select_matching_signature(
[
lambda meshWidth, meshHeight, coordinates, antialiased=True,
shading='flat', **kwargs:
(meshWidth, meshHeight, coordinates, antialiased, shading,
kwargs))(*args, **kwargs)
except TypeError as exc:
# New signature:
# If the following raises a TypeError (i.e. args don't match),
# just let it propagate.
coords, antialiased, shading, kwargs = (
shading='flat', **kwargs: locals(),
lambda coordinates, antialiased=True, shading='flat', **kwargs:
(coordinates, antialiased, shading, kwargs))(*args, **kwargs)
coords = np.asarray(coords, np.float64)
else: # The old signature matched.
locals()
],
*args, **kwargs).values()
*old_w_h, coords, antialiased, shading, kwargs = params
if old_w_h: # The old signature matched.
_api.warn_deprecated(
"3.5",
message="This usage of Quadmesh is deprecated: Parameters "
"meshWidth and meshHeights will be removed; "
"coordinates must be 2D; all parameters except "
"coordinates will be keyword-only.")
w, h = old_w_h
coords = np.asarray(coords, np.float64).reshape((h + 1, w + 1, 2))
kwargs.setdefault("pickradius", 0)
# end of signature deprecation code
Expand Down