Skip to content

Commit fbb915f

Browse files
committed
API: Allow SciPy to get away with assuming trapz is a Python function
This wraps `trapz` into a proper python function and then copies all attributes expected on a Python function over from the "fake" version to the real one. This allows SciPy to pretend `trapz` is a Python function to create their own version.
1 parent eb4ed7f commit fbb915f

File tree

2 files changed

+38
-0
lines changed

2 files changed

+38
-0
lines changed

numpy/core/tests/test_overrides.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,3 +723,22 @@ def __array__(self):
723723
bound = np.mean.__get__(MyClass) # classmethod
724724
with pytest.raises(TypeError, match="unsupported operand type"):
725725
bound()
726+
727+
728+
def test_scipy_trapz_support_shim():
729+
# SciPy 1.10 and earlier "clone" trapz in this way, so we have a
730+
# support shim in place: https://github.com/scipy/scipy/issues/17811
731+
# That should be removed eventually. This test copies what SciPy does.
732+
# Hopefully removable 1 year after SciPy 1.11; shim added to NumPy 1.25.
733+
import types, functools
734+
735+
def _copy_func(f):
736+
# Based on http://stackoverflow.com/a/6528148/190597 (Glenn Maynard)
737+
g = types.FunctionType(f.__code__, f.__globals__, name=f.__name__,
738+
argdefs=f.__defaults__, closure=f.__closure__)
739+
g = functools.update_wrapper(g, f)
740+
g.__kwdefaults__ = f.__kwdefaults__
741+
return g
742+
743+
744+
trapezoid = _copy_func(np.trapz)

numpy/lib/function_base.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4912,6 +4912,25 @@ def trapz(y, x=None, dx=1.0, axis=-1):
49124912
return ret
49134913

49144914

4915+
if overrides.ARRAY_FUNCTION_ENABLED:
4916+
# If array-function is enabled (normal), we wrap everything into a C
4917+
# callable, which has no __code__ or other attributes normal Python funcs
4918+
# have. SciPy however, tries to "clone" `trapz` into a new Python function
4919+
# which requires `__code__` and a few other attributes.
4920+
# So we create a dummy clone and copy over its attributes allowing
4921+
# SciPy <= 1.10 to work: https://github.com/scipy/scipy/issues/17811
4922+
assert not hasattr(trapz, "__code__")
4923+
4924+
def _fake_trapz(y, x=None, dx=1.0, axis=-1):
4925+
return trapz(y, x=x, dx=dx, axis=axis)
4926+
4927+
trapz.__code__ = _fake_trapz.__code__
4928+
trapz.__globals__ = _fake_trapz.__globals__
4929+
trapz.__defaults__ = _fake_trapz.__defaults__
4930+
trapz.__closure__ = _fake_trapz.__closure__
4931+
trapz.__kwdefaults__ = _fake_trapz.__kwdefaults__
4932+
4933+
49154934
def _meshgrid_dispatcher(*xi, copy=None, sparse=None, indexing=None):
49164935
return xi
49174936

0 commit comments

Comments
 (0)