8000 MAINT: Deprecate `.T` property for non-2dim arrays and scalars · numpy/numpy@76387e3 · GitHub
[go: up one dir, main page]

Skip to content

Commit 76387e3

Browse files
committed
MAINT: Deprecate .T property for non-2dim arrays and scalars
1 parent 734e2cd commit 76387e3

17 files changed

+94
-64
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
* ``arr.T`` property has been deprecated for array scalars and arrays with
2+
dimensionality different than ``2``.

numpy/_core/_add_newdocs.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2888,7 +2888,8 @@
28882888
"""
28892889
View of the transposed array.
28902890
2891-
Same as ``self.transpose()``.
2891+
Same as ``self.transpose()`` except that it requires
2892+
the array to be 2-dimensional.
28922893
28932894
Examples
28942895
--------
@@ -2901,12 +2902,6 @@
29012902
array([[1, 3],
29022903
[2, 4]])
29032904
2904-
>>> a = np.array([1, 2, 3, 4])
2905-
>>> a
2906-
array([1, 2, 3, 4])
2907-
>>> a.T
2908-
array([1, 2, 3, 4])
2909-
29102905
See Also
29112906
--------
29122907
transpose

numpy/_core/src/multiarray/getset.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,15 @@ array_flat_set(PyArrayObject *self, PyObject *val, void *NPY_UNUSED(ignored))
848848
static PyObject *
849849
array_transpose_get(PyArrayObject *self, void *NPY_UNUSED(ignored))
850850
{
851+
int ndim = PyArray_NDIM(self);
852+
if (ndim != 2) {
853+
if (PyErr_WarnFormat(PyExc_UserWarning, 1,
854+
"In the future `.T` property will be supported for "
855+
"2-dim arrays only. Here it is %d-dim array.",
856+
ndim) < 0) {
857+
return NULL;
858+
}
859+
}
851860
return PyArray_Transpose(self, NULL);
852861
}
853862

numpy/_core/src/multiarray/scalartypes.c.src

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1910,6 +1910,11 @@ gentype_flat_get(PyObject *self, void *NPY_UNUSED(ignored))
19101910
static PyObject *
19111911
gentype_transpose_get(PyObject *self, < 10000 span class=pl-smi>void *NPY_UNUSED(ignored))
19121912
{
1913+
if (PyErr_WarnEx(PyExc_UserWarning,
1914+
"In the future `.T` property for array scalars will "
1915+
"raise an error.", 1) < 0) {
1916+
return NULL;
1917+
}
19131918
Py_INCREF(self);
19141919
return self;
19151920
}

numpy/_core/tests/test_deprecations.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,3 +454,17 @@ def test_deprecated(self):
454454
struct_ufunc.add_triplet, "new docs"
455455
)
456456
)
457+
458+
459+
def test_deprecated_T_non_2dim():
460+
# Deprecated in Numpy 2.3, 2025-04
461+
with pytest.warns(UserWarning, match="In the future `.T` property for "
462+
"array scalars will raise an error."):
463+
np.int64(1).T
464+
for shape in [(5,), (2, 3, 4)]:
465+
with pytest.warns(
466+
UserWarning,
467+
match="In the future `.T` property will be "
468+
"supported for 2-dim arrays only. "
469+
f"Here it is {len(shape)}-dim array."):
470+
np.ones(shape).T

numpy/_core/tests/test_einsum.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,9 @@ def check_einsum_sums(self, dtype, do_opt=False):
435435
a = np.arange(n * 3 * 2, dtype=dtype).reshape(n, 3, 2)
436436
b = np.arange(n, dtype=dtype)
437437
assert_equal(np.einsum("i..., i...", a, b, optimize=do_opt),
438-
np.inner(a.T, b.T).T)
438+
np.inner(a.transpose(), b.transpose()).transpose())
439439
assert_equal(np.einsum(a, [0, Ellipsis], b, [0, Ellipsis], optimize=do_opt),
440-
np.inner(a.T, b.T).T)
440+
np.inner(a.transpose(), b.transpose()).transpose())
441441

442442
# outer(a,b)
443443
for n in range(1, 17):
@@ -477,22 +477,22 @@ def check_einsum_sums(self, dtype, do_opt=False):
477477
for n in range(1, 17):
478478
a = np.arange(4 * n, dtype=dtype).reshape(4, n)
479479
b = np.arange(n, dtype=dtype)
480-
assert_equal(np.einsum("ji,j", a.T, b.T, optimize=do_opt),
481-
np.dot(b.T, a.T))
482-
assert_equal(np.einsum(a.T, [1, 0], b.T, [1], optimize=do_opt),
483-
np.dot(b.T, a.T))
480+
assert_equal(np.einsum("ji,j", a.T, b, optimize=do_opt),
481+
np.dot(b, a.T))
482+
assert_equal(np.einsum(a.T, [1, 0], b, [1], optimize=do_opt),
483+
np.dot(b, a.T))
484484

485485
c = np.arange(4, dtype=dtype)
486-
np.einsum("ji,j", a.T, b.T, out=c,
486+
np.einsum("ji,j", a.T, b, out=c,
487487
dtype='f8', casting='unsafe', optimize=do_opt)
488488
assert_equal(c,
489-
np.dot(b.T.astype('f8'),
489+
np.dot(b.astype('f8'),
490490
a.T.astype('f8')).astype(dtype))
491491
c[...] = 0
492-
np.einsum(a.T, [1, 0], b.T, [1], out=c,
492+
np.einsum(a.T, [1, 0], b, [1], out=c,
493493
dtype='f8', casting='unsafe', optimize=do_opt)
494494
assert_equal(c,
495-
np.dot(b.T.astype('f8'),
495+
np.dot(b.astype('f8'),
496496
a.T.astype('f8')).astype(dtype))
497497

498498
# matmat(a,b) / a.dot(b) where a is matrix, b is matrix

numpy/_core/tests/test_indexing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,8 @@ def test_uncontiguous_subspace_assignment(self):
312312
a = np.full((3, 4, 2), -1)
313313
b = np.full((3, 4, 2), -1)
314314

315-
a[[0, 1]] = np.arange(2 * 4 * 2).reshape(2, 4, 2).T
316-
b[[0, 1]] = np.arange(2 * 4 * 2).reshape(2, 4, 2).T.copy()
315+
a[[0, 1]] = np.arange(2 * 4 * 2).reshape(2, 4, 2).transpose()
316+
b[[0, 1]] = np.arange(2 * 4 * 2).reshape(2, 4, 2).transpose().copy()
317317

318318
assert_equal(a, b)
319319

numpy/_core/tests/test_multiarray.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3218,7 +3218,7 @@ def test_flatten(self):
32183218
assert_equal(x0.flatten('F'), x0.T.flatten())
32193219
assert_equal(x1.flatten(), y1)
32203220
assert_equal(x1.flatten('F'), y1f)
3221-
assert_equal(x1.flatten('F'), x1.T.flatten())
3221+
assert_equal(x1.flatten('F'), x1.transpose().flatten())
32223222

32233223
@pytest.mark.parametrize('func', (np.dot, np.matmul))
32243224
def test_arr_mult(self, func):
@@ -3323,8 +3323,8 @@ def test_no_dgemv(self, func, dtype):
33233323
ret2 = func(a.copy(), b.copy())
33243324
assert_equal(ret1, ret2)
33253325

3326-
ret1 = func(b.T, a.T)
3327-
ret2 = func(b.T.copy(), a.T.copy())
3326+
ret1 = func(b.transpose(), a.transpose())
3327+
ret2 = func(b.transpose().copy(), a.transpose().copy())
33283328
assert_equal(ret1, ret2)
33293329

33303330
def test_dot(self):
@@ -4626,7 +4626,7 @@ def test_np_argmin_argmax_keepdims(self, size, axis, method):
46264626
wrong_shape[0] = 2
46274627
wrong_outarray = np.empty(wrong_shape, dtype=res.dtype)
46284628
with pytest.raises(ValueError):
4629-
method(arr.T, axis=axis,
4629+
method(arr.transpose(), axis=axis,
46304630
out=wrong_outarray, keepdims=True)
46314631

46324632
# non-contiguous arrays
@@ -4637,14 +4637,14 @@ def test_np_argmin_argmax_keepdims(self, size, axis, method):
46374637
new_shape[axis] = 1
46384638
new_shape = tuple(new_shape)
46394639

4640-
_res_orig = method(arr.T, axis=axis)
4640+
_res_orig = method(arr.transpose(), axis=axis)
46414641
res_orig = _res_orig.reshape(new_shape)
4642-
res = method(arr.T, axis=axis, keepdims=True)
4642+
res = method(arr.transpose(), axis=axis, keepdims=True)
46434643
assert_equal(res, res_orig)
46444644
assert_(res.shape == new_shape)
46454645
outarray = np.empty(new_shape[::-1], dtype=res.dtype)
4646-
outarray = outarray.T
4647-
res1 = method(arr.T, axis=axis, out=outarray,
4646+
outarray = outarray.transpose()
4647+
res1 = method(arr.transpose(), axis=axis, out=outarray,
46484648
keepdims=True)
46494649
assert_(res1 is outarray)
46504650
assert_equal(res, outarray)
@@ -4664,7 +4664,7 @@ def test_np_argmin_argmax_keepdims(self, size, axis, method):
46644664
wrong_shape[0] = 2
46654665
wrong_outarray = np.empty(wrong_shape, dtype=res.dtype)
46664666
with pytest.raises(ValueError):
4667-
method(arr.T, axis=axis,
4667+
method(arr.transpose(), axis=axis,
46684668
out=wrong_outarray, keepdims=True)
46694669

46704670
@pytest.mark.parametrize('method', ['max', 'min'])
@@ -8296,7 +8296,7 @@ def test_relaxed_strides(self, c=np.ones((1, 10, 10), dtype='i8')):
82968296
fd = io.BytesIO()
82978297
fd.write(c.data)
82988298

8299-
fortran = c.T
8299+
fortran = c.transpose()
83008300
assert_(memoryview(fortran).strides == (8, 80, 800))
83018301

83028302
arr = np.ones((1, 10))

numpy/_core/tests/test_nditer.py

Lines changed: 22 additions & 21 deletions
< 10000 table aria-label="Diff for: numpy/_core/tests/test_nditer.py" class="tab-size width-full DiffLines-module__tableLayoutFixed--YZcIJ" data-diff-anchor="diff-152735d36b517d662c89133ff7c799da74875566c40a54b2b2c3ef306cb52b2e" data-tab-size="8" data-paste-markdown-skip="true" role="grid" style="--line-number-cell-width:52px;--line-number-cell-width-unified:104px">Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def test_iter_best_order():
100100
i = nditer(aview, [], [['readonly']])
101101
assert_equal(list(i), a)
102102
# Fortran-order
103-
i = nditer(aview.T, [], [['readonly']])
103+
i = nditer(aview.transpose(), [], [['readonly']])
104104
assert_equal(list(i), a)
105105
# Other order
106106
if len(shape) > 2:
@@ -126,8 +126,8 @@ def test_iter_c_order():
126126
i = nditer(aview, order='C')
127127
assert_equal(list(i), aview.ravel(order='C'))
128128
# Fortran-order
129-
i = nditer(aview.T, order='C')
130-
assert_equal(list(i), aview.T.ravel(order='C'))
129+
i = nditer(aview.transpose(), order='C')
130+
assert_equal(list(i), aview.transpose().ravel(order='C'))
131131
# Other order
132132
if len(shape) > 2:
133133
i = nditer(aview.swapaxes(0, 1), order='C')
@@ -153,8 +153,8 @@ def test_iter_f_order():
153153
i = nditer(aview, order='F')
154154
assert_equal(list(i), aview.ravel(order='F'))
155155
# Fortran-order
156-
i = nditer(aview.T, order='F')
157-
assert_equal(list(i), aview.T.ravel(order='F'))
156+
i = nditer(aview.transpose(), order='F')
157+
assert_equal(list(i), aview.transpose().ravel(order='F'))
158158
# Other order
159159
if len(shape) > 2:
160160
i = nditer(aview.swapaxes(0, 1), order='F')
@@ -180,8 +180,8 @@ def test_iter_c_or_f_order():
180180
i = nditer(aview, order='A')
181181
assert_equal(list(i), aview.ravel(order='A'))
182182
# Fortran-order
183-
i = nditer(aview.T, order='A')
184-
assert_equal(list(i), aview.T.ravel(order='A'))
183+
i = nditer(aview.transpose(), order='A')
184+
assert_equal(list(i), aview.transpose().ravel(order='A'))
185185
# Other order
186186
if len(shape) > 2:
187187
i = nditer(aview.swapaxes(0, 1), order='A')
@@ -467,7 +467,7 @@ def test_iter_no_inner_full_coalesce():
467467
assert_equal(i.ndim, 1)
468468
assert_equal(i[0].shape, (size,))
469469
# Fortran-order
470-
i = nditer(aview.T, ['external_loop'], [['readonly']])
470+
i = nditer(aview.transpose(), ['external_loop'], [['readonly']])
471471
assert_equal(i.ndim, 1)
472472
assert_equal(i[0].shape, (size,))
473473
# Other order
@@ -515,26 +515,26 @@ def test_iter_dim_coalescing():
515515
assert_equal(i.ndim, 1)
516516
i = nditer(a3d.swapaxes(0, 1), ['c_index'], [['readonly']])
517517
assert_equal(i.ndim, 3)
518-
i = nditer(a3d.T, ['c_index'], [['readonly']])
518+
i = nditer(a3d.transpose(), ['c_index'], [['readonly']])
519519
assert_equal(i.ndim, 3)
520-
i = nditer(a3d.T, ['f_index'], [['readonly']])
520+
i = nditer(a3d.transpose(), ['f_index'], [['readonly']])
521521
assert_equal(i.ndim, 1)
522-
i = nditer(a3d.T.swapaxes(0, 1), ['f_index'], [['readonly']])
522+
i = nditer(a3d.transpose().swapaxes(0, 1), ['f_index'], [['readonly']])
523523
assert_equal(i.ndim, 3)
524524

525525
# When C or F order is forced, coalescing may still occur
526526
a3d = arange(24).reshape(2, 3, 4)
527527
i = nditer(a3d, order='C')
528528
assert_equal(i.ndim, 1)
529-
i = nditer(a3d.T, order='C')
529+
i = nditer(a3d.transpose(), order='C')
530530
assert_equal(i.ndim, 3)
531531
i = nditer(a3d, order='F')
532532
assert_equal(i.ndim, 3)
533-
i = nditer(a3d.T, order='F')
533+
i = nditer(a3d.transpose(), order='F')
534534
assert_equal(i.ndim, 1)
535535
i = nditer(a3d, order='A')
536536
assert_equal(i.ndim, 1)
537-
i = nditer(a3d.T, order='A')
537+
i = nditer(a3d.transpose(), order='A')
538538
assert_equal(i.ndim, 1)
539539

540540
def test_iter_broadcasting():
@@ -800,7 +800,7 @@ def test_iter_slice():
800800
assert_equal(i[0:2], [3, 12])
801801

802802
def test_iter_assign_mapping():
803-
a = np.arange(24, dtype='f8').reshape(2, 3, 4).T
803+
a = np.arange(24, dtype='f8').reshape(2, 3, 4).transpose()
804804
it = np.nditer(a, [], [['readwrite', 'updateifcopy']],
805805
casting='same_kind', op_dtypes=[np.dtype('f4')])
806806
with it:
@@ -919,7 +919,7 @@ def test_iter_array_cast():
919919
assert_equal(i.operands[0].strides, (96, 8, 32))
920920

921921
# Same-kind cast 'f8' -> 'f4' -> 'f8'
922-
a = np.arange(24, dtype='f8').reshape(2, 3, 4).T
922+
a = np.arange(24, dtype='f8').reshape(2, 3, 4).transpose()
923923
with nditer(a, [],
924924
[['readwrite', 'updateifcopy']],
925925
casting='same_kind',
@@ -1292,7 +1292,8 @@ def test_iter_op_axes():
12921292
i = nditer([a, a.T], [], [['readonly']] * 2, op_axes=[[0, 1], [1, 0]])
12931293
assert_(all([x == y for (x, y) in i]))
12941294
a = arange(24).reshape(2, 3, 4)
1295-
i = nditer([a.T, a], [], [['readonly']] * 2, op_axes=[[2, 1, 0], None])
1295+
i = nditer([a.transpose(), a], [], [['readonly']] * 2,
1296+
op_axes=[[2, 1, 0], None])
12961297
assert_(all([x == y for (x, y) in i]))
12971298

12981299
# Broadcast 1D to any dimension
@@ -1527,7 +1528,7 @@ def test_iter_allocate_output_itorder():
15271528
assert_equal(i.operands[1].strides, a.strides)
15281529
assert_equal(i.operands[1].dtype, np.dtype('f4'))
15291530
# F-order input, best iteration order
1530-
a = arange(24, dtype='i4').reshape(2, 3, 4).T
1531+
a = arange(24, dtype='i4').reshape(2, 3, 4).transpose()
15311532
i = nditer([a, None], [], [['readonly'], ['writeonly', 'allocate']],
15321533
op_dtypes=[None, np.dtype('f4')])
15331534
assert_equal(i.operands[1].shape, a.shape)
@@ -1791,7 +1792,7 @@ def test_iter_buffering():
17911792
# Test buffering with several buffer sizes and types
17921793
arrays = []
17931794
# F-order swapped array
1794-
_tmp = np.arange(24, dtype='c16').reshape(2, 3, 4).T
1795+
_tmp = np.arange(24, dtype='c16').reshape(2, 3, 4).transpose()
17951796
_tmp = _tmp.view(_tmp.dtype.newbyteorder()).byteswap()
17961797
arrays.append(_tmp)
17971798
# Contiguous 1-dimensional array
@@ -1802,7 +1803,7 @@ def test_iter_buffering():
18021803
a[:] = np.arange(16, dtype='i4')
18031804
arrays.append(a)
18041805
# 4-D F-order array
1805-
arrays.append(np.arange(120, dtype='i4').reshape(5, 3, 2, 4).T)
1806+
arrays.append(np.arange(120, dtype='i4').reshape(5, 3, 2, 4).transpose())
18061807
for a in arrays:
18071808
for buffersize in (1, 2, 3, 5, 8, 11, 16, 1024):
18081809
vals = []
@@ -1821,7 +1822,7 @@ def test_iter_write_buffering():
18211822
# Test that buffering of writes is working
18221823

18231824
# F-order swapped array
1824-
a = np.arange(24).reshape(2, 3, 4).T
1825+
a = np.arange(24).reshape(2, 3, 4).transpose()
18251826
a = a.view(a.dtype.newbyteorder()).byteswap()
18261827
i = nditer(a, ['buffered'],
18271828
[['readwrite', 'nbo', 'aligned']],

numpy/_core/tests/test_regression.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,7 @@ def test_string_sort_with_zeros(self):
876876

877877
def test_copy_detection_zero_dim(self):
878878
# Ticket #658
879-
np.indices((0, 3, 4)).T.reshape(-1, 3)
879+
np.indices((0, 3, 4)).transpose().reshape(-1, 3)
880880

881881
def test_flat_byteorder(self):
882882
# Ticket #657
@@ -895,7 +895,7 @@ def test_flat_index_byteswap(self):
895895

896896
def test_copy_detection_corner_case(self):
897897
# Ticket #658
898-
np.indices((0, 3, 4)).T.reshape(-1, 3)
898+
np.indices((0, 3, 4)).transpose().reshape(-1, 3)
899899

900900
def test_object_array_refcounting(self):
901901
# Ticket #633

numpy/_core/tests/test_shape_base.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,10 @@ def test_concatenate(self):
341341
a2 = res[..., 6:]
342342
assert_array_equal(concatenate((a0, a1, a2), 2), res)
343343
assert_array_equal(concatenate((a0, a1, a2), -1), res)
344-
assert_array_equal(concatenate((a0.T, a1.T, a2.T), 0), res.T)
344+
assert_array_equal(
345+
concatenate((a0.transpose(), a1.transpose(), a2.transpose()), 0),
346+
res.transpose(),
347+
)
345348

346349
out = res.copy()
347350
rout = concatenate((a0, a1, a2), 2, out=out)

numpy/_core/tests/test_ufunc.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,8 +1033,8 @@ def test_incontiguous_array(self):
10331033
assert_equal(x[0, 0, 0, 0, 0, 0], -1, err_msg=msg2)
10341034
assert_array_equal(np.vecdot(a, b), np.sum(a * b, axis=-1), err_msg=msg)
10351035
x = np.arange(24).reshape(2, 3, 4)
1036-
a = x.T
1037-
b = x.T
1036+
a = x.transpose()
1037+
b = x.transpose()
10381038
a[0, 0, 0] = -1
10391039
assert_equal(x[0, 0, 0], -1, err_msg=msg2)
10401040
assert_array_equal(np.vecdot(a, b), np.sum(a * b, axis=-1), err_msg=msg)

numpy/fft/tests/test_pocketfft.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ def test_all_1d_norm_preserving(self):
413413
def test_fftn_out_argument(self, dtype, transpose, axes):
414414
def zeros_like(x):
415415
if transpose:
416-
return np.zeros_like(x.T).T
416+
return np.zeros_like(x.transpose()).transpose()
417417
else:
418418
return np.zeros_like(x)
419419

numpy/lib/_function_base_impl.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2752,7 +2752,7 @@ def cov(m, y=None, rowvar=True, bias=False, ddof=None, fweights=None,
27522752
>>> v1 = np.sum(w)
27532753
>>> v2 = np.sum(w * a)
27542754
>>> m -= np.sum(m * w, axis=None, keepdims=True) / v1
2755-
>>> cov = np.dot(m * w, m.T) * v1 / (v1**2 - ddof * v2)
2755+
>>> cov = np.dot(m * w, m) * v1 / (v1**2 - ddof * v2)
27562756
27572757
Note that when ``a == 1``, the normalization factor
27582758
``v1 / (v1**2 - ddof * v2)`` goes over to ``1 / (np.sum(f) - ddof)``

0 commit comments

Comments
 (0)
0