Skip to content

Commit b47bd25

Browse files
API: register NEP 35 functions as array_functions (#27490)
Register `like=` functions as array-functions. This is currently decided based on finding the magic `${ARRAY_FUNCTION_LIKE}` string in the documentation. Close gh-27451
1 parent 2cac1c5 commit b47bd25

8 files changed

Lines changed: 58 additions & 69 deletions

File tree

‎numpy/_core/_add_newdocs.py‎

Lines changed: 13 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"""
1111

1212
from numpy._core.function_base import add_newdoc
13-
from numpy._core.overrides import array_function_like_doc
13+
from numpy._core.overrides import get_array_function_like_doc
1414

1515

1616
###############################################################################
@@ -927,10 +927,7 @@
927927
matrix([[1, 2],
928928
[3, 4]])
929929
930-
""".replace(
931-
"${ARRAY_FUNCTION_LIKE}",
932-
array_function_like_doc,
933-
))
930+
""")
934931

935932
add_newdoc('numpy._core.multiarray', 'asarray',
936933
"""
@@ -1022,10 +1019,7 @@
10221019
>>> np.asanyarray(a) is a
10231020
True
10241021
1025-
""".replace(
1026-
"${ARRAY_FUNCTION_LIKE}",
1027-
array_function_like_doc,
1028-
))
1022+
""")
10291023

10301024
add_newdoc('numpy._core.multiarray', 'asanyarray',
10311025
"""
@@ -1101,10 +1095,7 @@
11011095
>>> np.asanyarray(a) is a
11021096
True
11031097
1104-
""".replace(
1105-
"${ARRAY_FUNCTION_LIKE}",
1106-
array_function_like_doc,
1107-
))
1098+
""")
11081099

11091100
add_newdoc('numpy._core.multiarray', 'ascontiguousarray',
11101101
"""
@@ -1167,10 +1158,7 @@
11671158
Note: This function returns an array with at least one-dimension (1-d)
11681159
so it will not preserve 0-d arrays.
11691160
1170-
""".replace(
1171-
"${ARRAY_FUNCTION_LIKE}",
1172-
array_function_like_doc,
1173-
))
1161+
""")
11741162

11751163
add_newdoc('numpy._core.multiarray', 'asfortranarray',
11761164
"""
@@ -1233,10 +1221,7 @@
12331221
Note: This function returns an array with at least one-dimension (1-d)
12341222
so it will not preserve 0-d arrays.
12351223
1236-
""".replace(
1237-
"${ARRAY_FUNCTION_LIKE}",
1238-
array_function_like_doc,
1239-
))
1224+
""")
12401225

12411226
add_newdoc('numpy._core.multiarray', 'empty',
12421227
"""
@@ -1296,10 +1281,7 @@
12961281
array([[-1073741821, -1067949133],
12971282
[ 496041986, 19249760]]) #uninitialized
12981283
1299-
""".replace(
1300-
"${ARRAY_FUNCTION_LIKE}",
1301-
array_function_like_doc,
1302-
))
1284+
""")
13031285

13041286
add_newdoc('numpy._core.multiarray', 'scalar',
13051287
"""
@@ -1370,10 +1352,7 @@
13701352
array([(0, 0), (0, 0)],
13711353
dtype=[('x', '<i4'), ('y', '<i4')])
13721354
1373-
""".replace(
1374-
"${ARRAY_FUNCTION_LIKE}",
1375-
array_function_like_doc,
1376-
))
1355+
""")
13771356

13781357
add_newdoc('numpy._core.multiarray', 'set_typeDict',
13791358
"""set_typeDict(dict)
@@ -1441,10 +1420,7 @@
14411420
>>> np.fromstring('1, 2', dtype=int, sep=',')
14421421
array([1, 2])
14431422
1444-
""".replace(
1445-
"${ARRAY_FUNCTION_LIKE}",
1446-
array_function_like_doc,
1447-
))
1423+
""")
14481424

14491425
add_newdoc('numpy._core.multiarray', 'compare_chararrays',
14501426
"""
@@ -1537,10 +1513,7 @@
15371513
[5, 6]])
15381514
15391515
1540-
""".replace(
1541-
"${ARRAY_FUNCTION_LIKE}",
1542-
array_function_like_doc,
1543-
))
1516+
""")
15441517

15451518
add_newdoc('numpy._core.multiarray', 'fromfile',
15461519
"""
@@ -1623,10 +1596,7 @@
16231596
array([((10, 0), 98.25)],
16241597
dtype=[('time', [('min', '<i8'), ('sec', '<i8')]), ('temp', '<f8')])
16251598
1626-
""".replace(
1627-
"${ARRAY_FUNCTION_LIKE}",
1628-
array_function_like_doc,
1629-
))
1599+
""")
16301600

16311601
add_newdoc('numpy._core.multiarray', 'frombuffer',
16321602
"""
@@ -1686,10 +1656,7 @@
16861656
>>> np.frombuffer(b'\\x01\\x02\\x03\\x04\\x05', dtype=np.uint8, count=3)
16871657
array([1, 2, 3], dtype=uint8)
16881658
1689-
""".replace(
1690-
"${ARRAY_FUNCTION_LIKE}",
1691-
array_function_like_doc,
1692-
))
1659+
""")
16931660

16941661
add_newdoc('numpy._core.multiarray', 'from_dlpack',
16951662
"""
@@ -1855,10 +1822,7 @@
18551822
>>> np.arange(3,7,2)
18561823
array([3, 5])
18571824
1858-
""".replace(
1859-
"${ARRAY_FUNCTION_LIKE}",
1860-
array_function_like_doc,
1861-
))
1825+
""")
18621826

18631827
add_newdoc('numpy._core.multiarray', '_get_ndarray_c_version',
18641828
"""_get_ndarray_c_version()

‎numpy/_core/_asarray.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"""
66
from .overrides import (
77
array_function_dispatch,
8-
set_array_function_like_doc,
8+
finalize_array_function_like,
99
set_module,
1010
)
1111
from .multiarray import array, asanyarray
@@ -24,7 +24,7 @@
2424
}
2525

2626

27-
@set_array_function_like_doc
27+
@finalize_array_function_like
2828
@set_module('numpy')
2929
def require(a, dtype=None, requirements=None, *, like=None):
3030
"""

‎numpy/_core/function_base.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,8 @@ def add_newdoc(place, obj, doc, warn_on_python=True):
533533
"""
534534
new = getattr(__import__(place, globals(), {}, [obj]), obj)
535535
if isinstance(doc, str):
536+
if "${ARRAY_FUNCTION_LIKE}" in doc:
537+
doc = overrides.get_array_function_like_doc(new, doc)
536538
_add_docstring(new, doc.strip(), warn_on_python)
537539
elif isinstance(doc, tuple):
538540
attr, docstring = doc

‎numpy/_core/numeric.py‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from . import overrides
2424
from . import umath
2525
from . import shape_base
26-
from .overrides import set_array_function_like_doc, set_module
26+
from .overrides import finalize_array_function_like, set_module
2727
from .umath import (multiply, invert, sin, PINF, NAN)
2828
from . import numerictypes
2929
from ..exceptions import AxisError
@@ -134,7 +134,7 @@ def zeros_like(
134134
return res
135135

136136

137-
@set_array_function_like_doc
137+
@finalize_array_function_like
138138
@set_module('numpy')
139139
def ones(shape, dtype=None, order='C', *, device=None, like=None):
140140
"""
@@ -287,7 +287,7 @@ def _full_dispatcher(
287287
return(like,)
288288

289289

290-
@set_array_function_like_doc
290+
@finalize_array_function_like
291291
@set_module('numpy')
292292
def full(shape, fill_value, dtype=None, order='C', *, device=None, like=None):
293293
"""
@@ -1844,7 +1844,7 @@ def indices(dimensions, dtype=int, sparse=False):
18441844
return res
18451845

18461846

1847-
@set_array_function_like_doc
1847+
@finalize_array_function_like
18481848
@set_module('numpy')
18491849
def fromfunction(function, shape, *, dtype=float, like=None, **kwargs):
18501850
"""
@@ -2192,7 +2192,7 @@ def _maketup(descr, val):
21922192
return tuple(res)
21932193

21942194

2195-
@set_array_function_like_doc
2195+
@finalize_array_function_like
21962196
@set_module('numpy')
21972197
def identity(n, dtype=None, *, like=None):
21982198
"""

‎numpy/_core/overrides.py‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@
1919
compatible with that passed in via this argument."""
2020
)
2121

22-
def set_array_function_like_doc(public_api):
23-
if public_api.__doc__ is not None:
24-
public_api.__doc__ = public_api.__doc__.replace(
25-
"${ARRAY_FUNCTION_LIKE}",
26-
array_function_like_doc,
27-
)
22+
def get_array_function_like_doc(public_api, docstring_template=None):
23+
ARRAY_FUNCTIONS.add(public_api)
24+
docstring = public_api.__doc__ or docstring_template
25+
return docstring.replace("${ARRAY_FUNCTION_LIKE}", array_function_like_doc)
26+
27+
def finalize_array_function_like(public_api):
28+
public_api.__doc__ = get_array_function_like_doc(public_api)
2829
return public_api
2930

3031

‎numpy/_core/tests/test_overrides.py‎

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@
1111
import numpy as np
1212
from numpy.testing import (
1313
assert_, assert_equal, assert_raises, assert_raises_regex)
14+
from numpy.testing.overrides import get_overridable_numpy_array_functions
1415
from numpy._core.overrides import (
1516
_get_implementing_args, array_function_dispatch,
1617
verify_matching_signatures)
1718

18-
1919
def _return_not_implemented(self, *args, **kwargs):
2020
return NotImplemented
2121

@@ -627,6 +627,28 @@ def test_array_like_not_implemented(self):
627627
delimiter=',')),
628628
]
629629

630+
631+
def test_nep35_functions_as_array_functions(self,):
632+
all_array_functions = get_overridable_numpy_array_functions()
633+
like_array_functions_subset = {
634+
getattr(np, func_name) for func_name, *_ in self.__class__._array_tests
635+
}
636+
assert like_array_functions_subset.issubset(all_array_functions)
637+
638+
nep35_python_functions = {
639+
np.eye, np.fromfunction, np.full, np.genfromtxt,
640+
np.identity, np.loadtxt, np.ones, np.require, np.tri,
641+
}
642+
assert nep35_python_functions.issubset(all_array_functions)
643+
644+
nep35_C_functions = {
645+
np.arange, np.array, np.asanyarray, np.asarray,
646+
np.ascontiguousarray, np.asfortranarray, np.empty,
647+
np.frombuffer, np.fromfile, np.fromiter, np.fromstring,
648+
np.zeros,
649+
}
650+
assert nep35_C_functions.issubset(all_array_functions)
651+
630652
@pytest.mark.parametrize('function, args, kwargs', _array_tests)
631653
@pytest.mark.parametrize('numpy_ref', [True, False])
632654
def test_array_like(self, function, args, kwargs, numpy_ref):

‎numpy/lib/_npyio_impl.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from numpy._core import overrides
2020
from numpy._core.multiarray import packbits, unpackbits
2121
from numpy._core._multiarray_umath import _load_from_filelike
22-
from numpy._core.overrides import set_array_function_like_doc, set_module
22+
from numpy._core.overrides import finalize_array_function_like, set_module
2323
from ._iotools import (
2424
LineSplitter, NameValidator, StringConverter, ConverterError,
2525
ConverterLockError, ConversionWarning, _is_string_like,
@@ -1126,7 +1126,7 @@ def _read(fname, *, delimiter=',', comment='#', quote='"',
11261126
return arr
11271127

11281128

1129-
@set_array_function_like_doc
1129+
@finalize_array_function_like
11301130
@set_module('numpy')
11311131
def loadtxt(fname, dtype=float, comments='#', delimiter=None,
11321132
converters=None, skiprows=0, usecols=None, unpack=False,
@@ -1744,7 +1744,7 @@ def fromregex(file, regexp, dtype, encoding=None):
17441744
#####--------------------------------------------------------------------------
17451745

17461746

1747-
@set_array_function_like_doc
1747+
@finalize_array_function_like
17481748
@set_module('numpy')
17491749
def genfromtxt(fname, dtype=float, comments='#', delimiter=None,
17501750
skip_header=0, skip_footer=0, converters=None,

‎numpy/lib/_twodim_base_impl.py‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
asarray, where, int8, int16, int32, int64, intp, empty, promote_types,
1111
diagonal, nonzero, indices
1212
)
13-
from numpy._core.overrides import set_array_function_like_doc, set_module
13+
from numpy._core.overrides import finalize_array_function_like, set_module
1414
from numpy._core import overrides
1515
from numpy._core import iinfo
1616
from numpy.lib._stride_tricks_impl import broadcast_to
@@ -160,7 +160,7 @@ def flipud(m):
160160
return m[::-1, ...]
161161

162162

163-
@set_array_function_like_doc
163+
@finalize_array_function_like
164164
@set_module('numpy')
165165
def eye(N, M=None, k=0, dtype=float, order='C', *, device=None, like=None):
166166
"""
@@ -373,7 +373,7 @@ def diagflat(v, k=0):
373373
return conv.wrap(res)
374374

375375

376-
@set_array_function_like_doc
376+
@finalize_array_function_like
377377
@set_module('numpy')
378378
def tri(N, M=None, k=0, dtype=float, *, like=None):
379379
"""

0 commit comments

Comments
 (0)