From a0b0f91bff8189fafc4cf13c88337eb5563661fe Mon Sep 17 00:00:00 2001 From: Maddipatla Chatan Date: Fri, 16 Oct 2026 20:35:57 +0530 Subject: [PATCH 1/2] Validate source and destination for repeated axes Add checks for repeated axes in source and destination arguments to prevent ValueErrors. --- tensorflow/python/ops/numpy_ops/np_array_ops.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tensorflow/python/ops/numpy_ops/np_array_ops.py b/tensorflow/python/ops/numpy_ops/np_array_ops.py index 727fd5f4605..e0594e56d10 100644 --- a/tensorflow/python/ops/numpy_ops/np_array_ops.py +++ b/tensorflow/python/ops/numpy_ops/np_array_ops.py @@ -1204,6 +1204,18 @@ def moveaxis(a, source, destination): # pylint: disable=missing-docstring and builtins.all(isinstance(x, (int, np.integer)) for x in source) and builtins.all(isinstance(x, (int, np.integer)) for x in destination) ): + # NumPy rejects a repeated axis in `source` or `destination` with a + # clear ValueError. Without this check, a duplicate silently leaves + # `perm` the wrong length (since building it skips each `source` axis + # only once, while the insert loop below runs once per (dest, src) + # pair, including the duplicate), which either fails deep inside the + # Transpose op with a confusing "expects a vector of size N" error or, + # for other duplicate-value combinations, produces a malformed + # permutation without raising any error at all. + if len(set(source)) != len(source): + raise ValueError('repeated axis in `source` argument') + if len(set(destination)) != len(destination): + raise ValueError('repeated axis in `destination` argument') perm = [i for i in range(a_rank) if i not in source] for dest, src in sorted(zip(destination, source)): assert dest <= len(perm) From 93d13620416c6edceccd2ef1274daa3344447889 Mon Sep 17 00:00:00 2001 From: Maddipatla Chatan Date: Mon, 19 Oct 2026 20:15:00 +0530 Subject: [PATCH 2/2] Add moveaxis repeated-axis tests and shorten comment --- tensorflow/python/ops/numpy_ops/np_array_ops.py | 9 +-------- .../python/ops/numpy_ops/np_array_ops_test.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/tensorflow/python/ops/numpy_ops/np_array_ops.py b/tensorflow/python/ops/numpy_ops/np_array_ops.py index e0594e56d10..b3e2d7ac454 100644 --- a/tensorflow/python/ops/numpy_ops/np_array_ops.py +++ b/tensorflow/python/ops/numpy_ops/np_array_ops.py @@ -1204,14 +1204,7 @@ def moveaxis(a, source, destination): # pylint: disable=missing-docstring and builtins.all(isinstance(x, (int, np.integer)) for x in source) and builtins.all(isinstance(x, (int, np.integer)) for x in destination) ): - # NumPy rejects a repeated axis in `source` or `destination` with a - # clear ValueError. Without this check, a duplicate silently leaves - # `perm` the wrong length (since building it skips each `source` axis - # only once, while the insert loop below runs once per (dest, src) - # pair, including the duplicate), which either fails deep inside the - # Transpose op with a confusing "expects a vector of size N" error or, - # for other duplicate-value combinations, produces a malformed - # permutation without raising any error at all. + # NumPy rejects a repeated axis in `source` or `destination`. if len(set(source)) != len(source): raise ValueError('repeated axis in `source` argument') if len(set(destination)) != len(destination): diff --git a/tensorflow/python/ops/numpy_ops/np_array_ops_test.py b/tensorflow/python/ops/numpy_ops/np_array_ops_test.py index aa5406b5182..1dbe3b07899 100644 --- a/tensorflow/python/ops/numpy_ops/np_array_ops_test.py +++ b/tensorflow/python/ops/numpy_ops/np_array_ops_test.py @@ -1577,6 +1577,22 @@ class ArrayMethodsTest(test.TestCase): np_array_ops.moveaxis(a, -8, 0) with self.assertRaisesRegex(ValueError, 'out of bounds'): np_array_ops.moveaxis(a, 0, 8) + with self.assertRaisesRegex( + ValueError, 'repeated axis in `source` argument' + ): + np_array_ops.moveaxis(a, (0, 0), (1, 2)) + with self.assertRaisesRegex( + ValueError, 'repeated axis in `source` argument' + ): + np_array_ops.moveaxis(a, (0, -6), (1, 2)) + with self.assertRaisesRegex( + ValueError, 'repeated axis in `destination` argument' + ): + np_array_ops.moveaxis(a, (0, 1), (2, 2)) + with self.assertRaisesRegex( + ValueError, 'repeated axis in `destination` argument' + ): + np_array_ops.moveaxis(a, (0, 1), (2, -4)) def testFlip(self): np.random.seed(0)