Skip to content

Commit 91aed7b

Browse files
authored
Merge pull request numpy#27716 from mtsokol/module-attribute
ENH: Make ``__module__`` attribute coherent across API
2 parents c045306 + 629f2c6 commit 91aed7b

18 files changed

+284
-137
lines changed

doc/source/reference/routines.emath.rst

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,37 @@
33
Mathematical functions with automatic domain
44
********************************************
55

6-
.. currentmodule:: numpy
6+
.. currentmodule:: numpy.emath
77

8-
.. note:: :mod:`numpy.emath` is a preferred alias for ``numpy.lib.scimath``,
8+
.. note:: ``numpy.emath`` is a preferred alias for ``numpy.lib.scimath``,
99
available after :mod:`numpy` is imported.
1010

11-
.. automodule:: numpy.emath
11+
Wrapper functions to more user-friendly calling of certain math functions
12+
whose output data-type is different than the input data-type in certain
13+
domains of the input.
14+
15+
For example, for functions like `log` with branch cuts, the versions in this
16+
module provide the mathematically valid answers in the complex plane::
17+
18+
>>> import math
19+
>>> np.emath.log(-math.exp(1)) == (1+1j*math.pi)
20+
True
21+
22+
Similarly, `sqrt`, other base logarithms, `power` and trig functions
23+
are correctly handled. See their respective docstrings for specific examples.
24+
25+
Functions
26+
---------
27+
28+
.. autosummary::
29+
:toctree: generated/
30+
31+
arccos
32+
arcsin
33+
arctanh
34+
log
35+
log2
36+
logn
37+
log10
38+
power
39+
sqrt

numpy/__config__.py.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,5 @@ def show(mode=DisplayModes.stdout.value):
160160
raise AttributeError(
161161
f"Invalid `mode`, use one of: {', '.join([e.value for e in DisplayModes])}"
162162
)
163+
164+
show.__module__ = "numpy"

numpy/_core/defchararray.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ def less(x1, x2):
262262
return compare_chararrays(x1, x2, '<', True)
263263

264264

265+
@set_module("numpy.char")
265266
def multiply(a, i):
266267
"""
267268
Return (a * i), that is string multiple concatenation,
@@ -313,6 +314,7 @@ def multiply(a, i):
313314
raise ValueError("Can only multiply by integers")
314315

315316

317+
@set_module("numpy.char")
316318
def partition(a, sep):
317319
"""
318320
Partition each element in `a` around `sep`.
@@ -354,6 +356,7 @@ def partition(a, sep):
354356
return np.stack(strings_partition(a, sep), axis=-1)
355357

356358

359+
@set_module("numpy.char")
357360
def rpartition(a, sep):
358361
"""
359362
Partition (split) each element around the right-most separator.

numpy/_core/multiarray.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,34 @@
6666
promote_types.__module__ = 'numpy'
6767
zeros.__module__ = 'numpy'
6868
normalize_axis_index.__module__ = 'numpy.lib.array_utils'
69+
add_docstring.__module__ = 'numpy.lib'
70+
compare_chararrays.__module__ = 'numpy.char'
71+
72+
73+
def _override___module__():
74+
namespace_names = globals()
75+
for ufunc_name in [
76+
'absolute', 'arccos', 'arccosh', 'add', 'arcsin', 'arcsinh', 'arctan',
77+
'arctan2', 'arctanh', 'bitwise_and', 'bitwise_count', 'invert',
78+
'left_shift', 'bitwise_or', 'right_shift', 'bitwise_xor', 'cbrt',
79+
'ceil', 'conjugate', 'copysign', 'cos', 'cosh', 'deg2rad', 'degrees',
80+
'divide', 'divmod', 'equal', 'exp', 'exp2', 'expm1', 'fabs',
81+
'float_power', 'floor', 'floor_divide', 'fmax', 'fmin', 'fmod',
82+
'frexp', 'gcd', 'greater', 'greater_equal', 'heaviside', 'hypot',
83+
'isfinite', 'isinf', 'isnan', 'isnat', 'lcm', 'ldexp', 'less',
84+
'less_equal', 'log', 'log10', 'log1p', 'log2', 'logaddexp',
85+
'logaddexp2', 'logical_and', 'logical_not', 'logical_or',
86+
'logical_xor', 'matmul', 'maximum', 'minimum', 'remainder', 'modf',
87+
'multiply', 'negative', 'nextafter', 'not_equal', 'positive', 'power',
88+
'rad2deg', 'radians', 'reciprocal', 'rint', 'sign', 'signbit', 'sin',
89+
'sinh', 'spacing', 'sqrt', 'square', 'subtract', 'tan', 'tanh',
90+
'trunc', 'vecdot',
91+
]:
92+
ufunc = namespace_names[ufunc_name]
93+
ufunc.__module__ = "numpy"
94+
95+
96+
_override___module__()
6997

7098

7199
# We can't verify dispatcher signatures because NumPy's C functions don't

numpy/_core/strings.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
add, multiply as _multiply_ufunc,
1111
)
1212
from numpy._core.multiarray import _vec_string
13+
from numpy._core.overrides import set_module
1314
from numpy._core.umath import (
1415
isalpha,
1516
isdigit,
@@ -48,6 +49,17 @@
4849
)
4950

5051

52+
def _override___module__():
53+
for ufunc in [
54+
isalnum, isalpha, isdecimal, isdigit, islower, isnumeric, isspace,
55+
istitle, isupper, str_len,
56+
]:
57+
ufunc.__module__ = "numpy.strings"
58+
59+
60+
_override___module__()
61+
62+
5163
__all__ = [
5264
# UFuncs
5365
"equal", "not_equal", "less", "less_equal", "greater", "greater_equal",
@@ -116,6 +128,7 @@ def _clean_args(*args):
116128
return newargs
117129

118130

131+
@set_module("numpy.strings")
119132
def multiply(a, i):
120133
"""
121134
Return (a * i), that is string multiple concatenation,
@@ -179,6 +192,7 @@ def multiply(a, i):
179192
return _multiply_ufunc(a, i, out=out)
180193

181194

195+
@set_module("numpy.strings")
182196
def mod(a, values):
183197
"""
184198
Return (a % i), that is pre-Python 2.6 string formatting
@@ -215,6 +229,7 @@ def mod(a, values):
215229
_vec_string(a, np.object_, '__mod__', (values,)), a)
216230

217231

232+
@set_module("numpy.strings")
218233
def find(a, sub, start=0, end=None):
219234
"""
220235
For each element, return the lowest index in the string where
@@ -252,6 +267,7 @@ def find(a, sub, start=0, end=None):
252267
return _find_ufunc(a, sub, start, end)
253268

254269

270+
@set_module("numpy.strings")
255271
def rfind(a, sub, start=0, end=None):
256272
"""
257273
For each element, return the highest index in the string where
@@ -294,6 +310,7 @@ def rfind(a, sub, start=0, end=None):
294310
return _rfind_ufunc(a, sub, start, end)
295311

296312

313+
@set_module("numpy.strings")
297314
def index(a, sub, start=0, end=None):
298315
"""
299316
Like `find`, but raises :exc:`ValueError` when the substring is not found.
@@ -327,6 +344,7 @@ def index(a, sub, start=0, end=None):
327344
return _index_ufunc(a, sub, start, end)
328345

329346

347+
@set_module("numpy.strings")
330348
def rindex(a, sub, start=0, end=None):
331349
"""
332350
Like `rfind`, but raises :exc:`ValueError` when the substring `sub` is
@@ -360,6 +378,7 @@ def rindex(a, sub, start=0, end=None):
360378
return _rindex_ufunc(a, sub, start, end)
361379

362380

381+
@set_module("numpy.strings")
363382
def count(a, sub, start=0, end=None):
364383
"""
365384
Returns an array with the number of non-overlapping occurrences of
@@ -404,6 +423,7 @@ def count(a, sub, start=0, end=None):
404423
return _count_ufunc(a, sub, start, end)
405424

406425

426+
@set_module("numpy.strings")
407427
def startswith(a, prefix, start=0, end=None):
408428
"""
409429
Returns a boolean array which is `True` where the string element
@@ -444,6 +464,7 @@ def startswith(a, prefix, start=0, end=None):
444464
return _startswith_ufunc(a, prefix, start, end)
445465

446466

467+
@set_module("numpy.strings")
447468
def endswith(a, suffix, start=0, end=None):
448469
"""
449470
Returns a boolean array which is `True` where the string element
@@ -484,6 +505,7 @@ def endswith(a, suffix, start=0, end=None):
484505
return _endswith_ufunc(a, suffix, start, end)
485506

486507

508+
@set_module("numpy.strings")
487509
def decode(a, encoding=None, errors=None):
488510
r"""
489511
Calls :meth:`bytes.decode` element-wise.
@@ -531,6 +553,7 @@ def decode(a, encoding=None, errors=None):
531553
np.str_(''))
532554

533555

556+
@set_module("numpy.strings")
534557
def encode(a, encoding=None, errors=None):
535558
"""
536559
Calls :meth:`str.encode` element-wise.
@@ -575,6 +598,7 @@ def encode(a, encoding=None, errors=None):
575598
np.bytes_(b''))
576599

577600

601+
@set_module("numpy.strings")
578602
def expandtabs(a, tabsize=8):
579603
"""
580604
Return a copy of each string element where all tab characters are
@@ -626,6 +650,7 @@ def expandtabs(a, tabsize=8):
626650
return _expandtabs(a, tabsize, out=out)
627651

628652

653+
@set_module("numpy.strings")
629654
def center(a, width, fillchar=' '):
630655
"""
631656
Return a copy of `a` with its elements centered in a string of
@@ -693,6 +718,7 @@ def center(a, width, fillchar=' '):
693718
return _center(a, width, fillchar, out=out)
694719

695720

721+
@set_module("numpy.strings")
696722
def ljust(a, width, fillchar=' '):
697723
"""
698724
Return an array with the elements of `a` left-justified in a
@@ -756,6 +782,7 @@ def ljust(a, width, fillchar=' '):
756782
return _ljust(a, width, fillchar, out=out)
757783

758784

785+
@set_module("numpy.strings")
759786
def rjust(a, width, fillchar=' '):
760787
"""
761788
Return an array with the elements of `a` right-justified in a
@@ -819,6 +846,7 @@ def rjust(a, width, fillchar=' '):
819846
return _rjust(a, width, fillchar, out=out)
820847

821848

849+
@set_module("numpy.strings")
822850
def zfill(a, width):
823851
"""
824852
Return the numeric string left-filled with zeros. A leading
@@ -865,6 +893,7 @@ def zfill(a, width):
865893
return _zfill(a, width, out=out)
866894

867895

896+
@set_module("numpy.strings")
868897
def lstrip(a, chars=None):
869898
"""
870899
For each element in `a`, return a copy with the leading characters
@@ -912,6 +941,7 @@ def lstrip(a, chars=None):
912941
return _lstrip_chars(a, chars)
913942

914943

944+
@set_module("numpy.strings")
915945
def rstrip(a, chars=None):
916946
"""
917947
For each element in `a`, return a copy with the trailing characters
@@ -954,6 +984,7 @@ def rstrip(a, chars=None):
954984
return _rstrip_chars(a, chars)
955985

956986

987+
@set_module("numpy.strings")
957988
def strip(a, chars=None):
958989
"""
959990
For each element in `a`, return a copy with the leading and
@@ -1000,6 +1031,7 @@ def strip(a, chars=None):
10001031
return _strip_chars(a, chars)
10011032

10021033

1034+
@set_module("numpy.strings")
10031035
def upper(a):
10041036
"""
10051037
Return an array with the elements converted to uppercase.
@@ -1036,6 +1068,7 @@ def upper(a):
10361068
return _vec_string(a_arr, a_arr.dtype, 'upper')
10371069

10381070

1071+
@set_module("numpy.strings")
10391072
def lower(a):
10401073
"""
10411074
Return an array with the elements converted to lowercase.
@@ -1072,6 +1105,7 @@ def lower(a):
10721105
return _vec_string(a_arr, a_arr.dtype, 'lower')
10731106

10741107

1108+
@set_module("numpy.strings")
10751109
def swapcase(a):
10761110
"""
10771111
Return element-wise a copy of the string with
@@ -1111,6 +1145,7 @@ def swapcase(a):
11111145
return _vec_string(a_arr, a_arr.dtype, 'swapcase')
11121146

11131147

1148+
@set_module("numpy.strings")
11141149
def capitalize(a):
11151150
"""
11161151
Return a copy of ``a`` with only the first character of each element
@@ -1150,6 +1185,7 @@ def capitalize(a):
11501185
return _vec_string(a_arr, a_arr.dtype, 'capitalize')
11511186

11521187

1188+
@set_module("numpy.strings")
11531189
def title(a):
11541190
"""
11551191
Return element-wise title cased version of string or unicode.
@@ -1191,6 +1227,7 @@ def title(a):
11911227
return _vec_string(a_arr, a_arr.dtype, 'title')
11921228

11931229

1230+
@set_module("numpy.strings")
11941231
def replace(a, old, new, count=-1):
11951232
"""
11961233
For each element in ``a``, return a copy of the string with
@@ -1416,6 +1453,7 @@ def _splitlines(a, keepends=None):
14161453
a, np.object_, 'splitlines', _clean_args(keepends))
14171454

14181455

1456+
@set_module("numpy.strings")
14191457
def partition(a, sep):
14201458
"""
14211459
Partition each element in ``a`` around ``sep``.
@@ -1483,6 +1521,7 @@ def partition(a, sep):
14831521
return _partition_index(a, sep, pos, out=(out["f0"], out["f1"], out["f2"]))
14841522

14851523

1524+
@set_module("numpy.strings")
14861525
def rpartition(a, sep):
14871526
"""
14881527
Partition (split) each element around the right-most separator.
@@ -1551,6 +1590,7 @@ def rpartition(a, sep):
15511590
a, sep, pos, out=(out["f0"], out["f1"], out["f2"]))
15521591

15531592

1593+
@set_module("numpy.strings")
15541594
def translate(a, table, deletechars=None):
15551595
"""
15561596
For each element in `a`, return a copy of the string where all

numpy/_core/tests/test_umath.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4019,14 +4019,15 @@ def test_array_ufunc_direct_call(self):
40194019
def test_ufunc_docstring(self):
40204020
original_doc = np.add.__doc__
40214021
new_doc = "new docs"
4022+
expected_dict = {} if IS_PYPY else {"__module__": "numpy"}
40224023

40234024
np.add.__doc__ = new_doc
40244025
assert np.add.__doc__ == new_doc
40254026
assert np.add.__dict__["__doc__"] == new_doc
40264027

40274028
del np.add.__doc__
40284029
assert np.add.__doc__ == original_doc
4029-
assert np.add.__dict__ == {}
4030+
assert np.add.__dict__ == expected_dict
40304031

40314032
np.add.__dict__["other"] = 1
40324033
np.add.__dict__["__doc__"] = new_doc
@@ -4035,7 +4036,7 @@ def test_ufunc_docstring(self):
40354036
del np.add.__dict__["__doc__"]
40364037
assert np.add.__doc__ == original_doc
40374038
del np.add.__dict__["other"]
4038-
assert np.add.__dict__ == {}
4039+
assert np.add.__dict__ == expected_dict
40394040

40404041

40414042
class TestChoose:

numpy/_pytesttester.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ class PytestTester:
7474
"""
7575
def __init__(self, module_name):
7676
self.module_name = module_name
77+
self.__module__ = module_name
7778

7879
def __call__(self, label='fast', verbose=1, extra_argv=None,
7980
doctests=False, coverage=False, durations=-1, tests=None):

0 commit comments

Comments
 (0)