Improving error messages in array_ops.py, including ensuring passed and expected values are set, and updating to python 3 format string styles.

Also fixing a bug where an error message used an undefined variable due to a misaligned scope (line 1673).

PiperOrigin-RevId: 398318391
Change-Id: Ia887b9731f02ca3966ca61880e0b661fa0d568d2
diff --git a/tensorflow/python/kernel_tests/array_ops/stack_op_test.py b/tensorflow/python/kernel_tests/array_ops/stack_op_test.py
index d863b55..63cee28 100644
--- a/tensorflow/python/kernel_tests/array_ops/stack_op_test.py
+++ b/tensorflow/python/kernel_tests/array_ops/stack_op_test.py
@@ -254,12 +254,14 @@
 
   def testDimOutOfRange(self):
     t = [constant_op.constant([1, 2, 3]), constant_op.constant([4, 5, 6])]
-    with self.assertRaisesRegex(ValueError, r"axis = 2 not in \[-2, 2\)"):
+    with self.assertRaisesRegex(ValueError,
+                                r"Argument `axis` = 2 not in range \[-2, 2\)"):
       array_ops.stack(t, axis=2)
 
   def testDimOutOfNegativeRange(self):
     t = [constant_op.constant([1, 2, 3]), constant_op.constant([4, 5, 6])]
-    with self.assertRaisesRegex(ValueError, r"axis = -3 not in \[-2, 2\)"):
+    with self.assertRaisesRegex(ValueError,
+                                r"Argument `axis` = -3 not in range \[-2, 2\)"):
       array_ops.stack(t, axis=-3)
 
   def testComplex(self):
diff --git a/tensorflow/python/kernel_tests/array_ops/unstack_op_test.py b/tensorflow/python/kernel_tests/array_ops/unstack_op_test.py
index eaa369d..71bbc06 100644
--- a/tensorflow/python/kernel_tests/array_ops/unstack_op_test.py
+++ b/tensorflow/python/kernel_tests/array_ops/unstack_op_test.py
@@ -149,8 +149,8 @@
     # Testing unknown shape in graph mode.
     with ops.Graph().as_default():
       x = array_ops.placeholder(np.float32)
-      with self.assertRaisesRegex(ValueError,
-                                  r'Cannot infer num from shape <unknown>'):
+      with self.assertRaisesRegex(
+          ValueError, r'Cannot infer argument `num` from shape <unknown>'):
         array_ops.unstack(x)
 
   def testUnknownShapeOkWithNum(self):
@@ -164,7 +164,7 @@
     with ops.Graph().as_default():
       x = array_ops.placeholder(np.float32, shape=(None,))
       with self.assertRaisesRegex(
-          ValueError, r'Cannot infer num from shape \((\?|None),\)'):
+          ValueError, r'Cannot infer argument `num` from shape \((\?|None),\)'):
         array_ops.unstack(x)
 
   def testAgainstNumpy(self):
@@ -190,12 +190,14 @@
 
   def testAxisOutOfRange(self):
     a = constant_op.constant([[1, 2, 3], [4, 5, 6]], name='a')
-    with self.assertRaisesRegex(ValueError, r'axis = 2 not in \[-2, 2\)'):
+    with self.assertRaisesRegex(ValueError,
+                                r'Argument `axis` = 2 not in range \[-2, 2\)'):
       array_ops.unstack(a, axis=2)
 
   def testAxisOutOfNegativeRange(self):
     a = constant_op.constant([[1, 2, 3], [4, 5, 6]], name='a')
-    with self.assertRaisesRegex(ValueError, r'axis = -3 not in \[-2, 2\)'):
+    with self.assertRaisesRegex(ValueError,
+                                r'Argument `axis` = -3 not in range \[-2, 2\)'):
       array_ops.unstack(a, axis=-3)
 
   def testZeroLengthDim(self):
diff --git a/tensorflow/python/kernel_tests/array_ops_test.py b/tensorflow/python/kernel_tests/array_ops_test.py
index 1fde90e..8c6492d 100644
--- a/tensorflow/python/kernel_tests/array_ops_test.py
+++ b/tensorflow/python/kernel_tests/array_ops_test.py
@@ -1368,7 +1368,7 @@
 
   def testExceptions(self):
     with self.cached_session():
-      with self.assertRaisesRegex(ValueError, "maxlen must be scalar"):
+      with self.assertRaisesRegex(ValueError, "`maxlen` must be scalar"):
         array_ops.sequence_mask([10, 20], [10, 20])
 
   def testOneDimensionalWithMaxlen(self):
diff --git a/tensorflow/python/kernel_tests/pad_op_test.py b/tensorflow/python/kernel_tests/pad_op_test.py
index c1f97c1..bc51cb7 100644
--- a/tensorflow/python/kernel_tests/pad_op_test.py
+++ b/tensorflow/python/kernel_tests/pad_op_test.py
@@ -224,7 +224,9 @@
   def testInvalid(self):
     with self.cached_session():
       x = [[1, 2, 3], [4, 5, 6]]
-      with self.assertRaisesRegex(ValueError, "Unknown padding mode"):
+      with self.assertRaisesRegex(
+          ValueError,
+          "Value of argument `mode` expected to be .* Received `mode` = WEIRD"):
         self.evaluate(array_ops.pad(x, [[1, 0], [2, 1]], mode="weird"))
 
   def testPaddingTypes(self):
diff --git a/tensorflow/python/kernel_tests/split_op_test.py b/tensorflow/python/kernel_tests/split_op_test.py
index 58674ab..a272d8b 100644
--- a/tensorflow/python/kernel_tests/split_op_test.py
+++ b/tensorflow/python/kernel_tests/split_op_test.py
@@ -95,7 +95,8 @@
     with self.session() as sess:
       with self.assertRaises(ValueError) as context:
         sess.run(array_ops.split(value, size_splits), {size_splits: [2, 2, 6]})
-      self.assertTrue("Cannot infer num from shape" in str(context.exception))
+      self.assertIn("Cannot infer argument `num` from shape",
+                    str(context.exception))
 
   @test_util.run_in_graph_and_eager_modes
   def testExplicitNum(self):
diff --git a/tensorflow/python/ops/array_ops.py b/tensorflow/python/ops/array_ops.py
index c714d5f..9d31fc7 100644
--- a/tensorflow/python/ops/array_ops.py
+++ b/tensorflow/python/ops/array_ops.py
@@ -1419,8 +1419,8 @@
   if value_shape is not None:
     expanded_num_dims = len(value_shape) + 1
     if axis < -expanded_num_dims or axis >= expanded_num_dims:
-      raise ValueError("axis = %d not in [%d, %d)" %
-                       (axis, -expanded_num_dims, expanded_num_dims))
+      raise ValueError(f"Argument `axis` = {axis} not in range "
+                       f"[{-expanded_num_dims}, {expanded_num_dims})")
 
   return gen_array_ops.pack(values, axis=axis, name=name)
 
@@ -1448,9 +1448,8 @@
     for i, elem in enumerate(list_or_tuple):
       if isinstance(elem, core.Tensor):
         if dtype is not None and elem.dtype.base_dtype != dtype:
-          raise TypeError("Cannot convert a list containing a tensor of dtype "
-                          "%s to %s (Tensor is: %r)" %
-                          (elem.dtype, dtype, elem))
+          raise TypeError(f"Cannot convert a list containing a tensor of dtype "
+                          f"{elem.dtype} to {dtype} (Tensor is: {elem!r})")
         converted_elems.append(elem)
         must_pack = True
       elif isinstance(elem, (list, tuple)):
@@ -1638,7 +1637,7 @@
   >>> bad(tf.constant([1,2,3]))
   Traceback (most recent call last):
   ...
-  ValueError: Cannot infer num from shape (None,)
+  ValueError: Cannot infer argument `num` from shape (None,)
 
   If you know the `axis` length you can pass it as the `num` argument. But this
   must be a constant value.
@@ -1667,11 +1666,11 @@
     value_shape = value.get_shape()
     if value_shape.ndims is not None:
       if axis < -value_shape.ndims or axis >= value_shape.ndims:
-        raise ValueError("axis = %d not in [%d, %d)" %
-                         (axis, -value_shape.ndims, value_shape.ndims))
+        raise ValueError(f"Argument `axis` = {axis} not in range "
+                         f"[{-value_shape.ndims}, {value_shape.ndims})")
       num = value_shape.dims[axis].value
-  if num is None:
-    raise ValueError("Cannot infer num from shape %s" % value_shape)
+    if num is None:
+      raise ValueError(f"Cannot infer argument `num` from shape {value_shape}")
   return gen_array_ops.unpack(value, num=num, axis=axis, name=name)
 
 
@@ -2142,7 +2141,8 @@
     if size_splits_shape:
       num = size_splits_shape[0]
     if num is None:
-      raise ValueError("Cannot infer num from shape %s" % num_or_size_splits)
+      raise ValueError(
+          "Cannot infer argument `num` from shape {num_or_size_splits}")
 
   return gen_array_ops.split_v(
       value=value, size_splits=size_splits, axis=axis, num_split=num, name=name)
@@ -2387,9 +2387,8 @@
     ndims = a_shape.ndims
     if ndims is not None:
       if ndims < 2:
-        raise ValueError(
-            "Argument 'a' should be a (batch) matrix, with rank >= 2.  Found: "
-            "%s" % a_shape)
+        raise ValueError("Argument `a` should be a (batch) matrix with rank "
+                         f">= 2.  Received `a` = {a} with shape: {a_shape}")
       perm = list(range(ndims - 2)) + [ndims - 1] + [ndims - 2]
     else:
       a_rank = rank(a)
@@ -3577,7 +3576,9 @@
     result = gen_array_ops.mirror_pad(
         tensor, paddings, mode="SYMMETRIC", name=name)
   else:
-    raise ValueError("Unknown padding mode: %s" % mode)
+    raise ValueError("Value of argument `mode` expected to be "
+                     """one of "CONSTANT", "REFLECT", or "SYMMETRIC". """
+                     f"Received `mode` = {mode}")
 
   # Restore shape information where possible.
   if not context.executing_eagerly():
@@ -3672,7 +3673,8 @@
                     "for this function".format(key))
 
   if indexing not in ("xy", "ij"):
-    raise ValueError("indexing parameter must be either 'xy' or 'ij'")
+    raise ValueError("Argument `indexing` parameter must be either "
+                     f"'xy' or 'ij', got '{indexing}'")
 
   with ops.name_scope(name, "meshgrid", args) as name:
     ndim = len(args)
@@ -4452,7 +4454,9 @@
     else:
       maxlen = ops.convert_to_tensor(maxlen)
     if maxlen.get_shape().ndims is not None and maxlen.get_shape().ndims != 0:
-      raise ValueError("maxlen must be scalar for sequence_mask")
+      raise ValueError("Argument `maxlen` must be scalar for sequence_mask, "
+                       f"received `maxlen` = {maxlen} "
+                       f"with shape '{maxlen.get_shape()}' instead")
 
     # The basic idea is to compare a range row vector of size maxlen:
     # [0, 1, 2, 3, 4]
@@ -5189,7 +5193,8 @@
     ValueError: if `indices` has an unknown shape.
   """
   if batch_dims is not None and not isinstance(batch_dims, int):
-    raise TypeError("batch_dims must be an int; got %r" % (batch_dims,))
+    raise TypeError("Argument `batch_dims` must be an int. "
+                    f"Received `batch_dims` = {batch_dims} instead")
   indices = ops.convert_to_tensor(indices, name="indices")
   params = ops.convert_to_tensor(params, name="params")
 
@@ -5202,11 +5207,11 @@
   if batch_dims < 0:
     batch_dims += indices_ndims
   if batch_dims < 0 or batch_dims >= indices_ndims:
-    raise ValueError("batch_dims = %d must be less than rank(indices) = %d" %
-                     (batch_dims, indices_ndims))
+    raise ValueError(f"Argument `batch_dims` = {batch_dims} must be less than "
+                     f"rank(`indices`) = {indices_ndims}")
   if params.shape.ndims is not None and batch_dims >= params.shape.ndims:
-    raise ValueError("batch_dims = %d must be less than rank(params) = %d" %
-                     (batch_dims, params.shape.ndims))
+    raise ValueError(f"Argument `batch_dims` = {batch_dims} must be less than "
+                     f"rank(`params`) = {params.shape.ndims}")
 
   # Handle axis by transposing the axis dimension to be the first non-batch
   # dimension, recursively calling batch_gather with axis=0, and then
@@ -5220,13 +5225,13 @@
       axis = axis + array_ops.rank(params)
     else:
       if (axis < -params.shape.ndims) or (axis >= params.shape.ndims):
-        raise ValueError("axis (%d) out of range [%d, %d)" %
-                         (axis, -params.shape.ndims, params.shape.ndims))
+        raise ValueError(f"Argument `axis` = {axis} out of range "
+                         f"[{-params.shape.ndims}, {params.shape.ndims})")
       if axis < 0:
         axis += params.shape.ndims
       if axis < batch_dims:
-        raise ValueError("batch_dims = %d must be less than or equal to "
-                         "axis = %d" % (batch_dims, axis))
+        raise ValueError(f"Argument `batch_dims` = {batch_dims} must be less "
+                         f"than or equal to argument `axis` = {axis}")
 
     # Move params[axis] up to params[batch_dims].
     perm = [
@@ -5464,17 +5469,17 @@
     params = ops.convert_to_tensor(params, name="params")
 
     if not isinstance(batch_dims, int):
-      raise TypeError("batch_dims must be an int; got %r" % (batch_dims,))
+      raise TypeError(f"Argument `batch_dims` must be an int; got {batch_dims}")
     if batch_dims < 0:
       raise ValueError("tf.gather_nd does not allow negative batch_dims.")
     params_ndims = params.shape.ndims
     indices_ndims = indices.shape.ndims
     if indices_ndims is not None and batch_dims >= indices_ndims:
-      raise ValueError("batch_dims = %d must be less than rank(indices) = %d" %
-                       (batch_dims, indices_ndims))
+      raise ValueError(f"Argument `batch_dims` = {batch_dims} must be "
+                       f"less than rank(`indices`) = {indices_ndims}")
     if params_ndims is not None and batch_dims >= params_ndims:
-      raise ValueError("batch_dims = %d must be less than rank(params) = %d" %
-                       (batch_dims, params_ndims))
+      raise ValueError(f"Argument `batch_dims` = {batch_dims} must be "
+                       f"less than rank(`params`) = {params_ndims}")
 
     expand = batch_dims == 0
     if expand:
@@ -6188,7 +6193,8 @@
     output = gen_array_ops.lower_bound(sorted_sequence_2d, values_2d, out_type,
                                        name)
   else:
-    raise ValueError("side must be either 'right' or 'left'.  Saw: %s." % side)
+    raise ValueError("Argument `side` must be either 'right' or 'left'. "
+                     f"Received: `side` = '{side}'.")
   return reshape(output, shape_internal(values))
 
 
@@ -6422,8 +6428,8 @@
   if tensor.dtype.is_integer:
     tensor = gen_math_ops.cast(tensor, dtype)
   else:
-    raise TypeError("%s must be an integer tensor; dtype=%s" %
-                    (name, tensor.dtype))
+    raise TypeError(f"Argument `tensor` (name: {name}) must be of type integer."
+                    f" Received `tensor` = {tensor} of dtype: {tensor.dtype}")
   return tensor
 
 
@@ -6450,19 +6456,18 @@
       `ndims is None`.
   """
   if not isinstance(axis, int):
-    raise TypeError("%s must be an int; got %s" %
-                    (axis_name, type(axis).__name__))
+    raise TypeError(f"{axis_name} must be an int; got {type(axis).__name__}")
   if ndims is not None:
     if 0 <= axis < ndims:
       return axis
     elif -ndims <= axis < 0:
       return axis + ndims
     else:
-      raise ValueError("%s=%s out of bounds: expected %s<=%s<%s" %
-                       (axis_name, axis, -ndims, axis_name, ndims))
+      raise ValueError(f"{axis_name}={axis} out of bounds: "
+                       f"expected {-ndims}<={axis_name}<{ndims}")
   elif axis < 0:
-    raise ValueError("%s may only be negative if %s is statically known." %
-                     (axis_name, ndims_name))
+    raise ValueError(f"{axis_name}={axis} may only be negative "
+                     f"if {ndims_name} is statically known.")
   return axis
 
 
@@ -6508,7 +6513,8 @@
 
   """
   if not isinstance(axis, int):
-    raise TypeError("axis must be an int; got %s" % type(axis).__name__)
+    raise TypeError("Argument `axis` must be an int. "
+                    f"Received `axis` = {axis} of type {type(axis).__name__}")
 
   with ops.name_scope(name, "Repeat", [data, repeats]):
     data = ops.convert_to_tensor(data, name="data")
diff --git a/tensorflow/python/ops/ragged/ragged_batch_gather_op_test.py b/tensorflow/python/ops/ragged/ragged_batch_gather_op_test.py
index fd40764..9c80489 100644
--- a/tensorflow/python/ops/ragged/ragged_batch_gather_op_test.py
+++ b/tensorflow/python/ops/ragged/ragged_batch_gather_op_test.py
@@ -477,12 +477,12 @@
         indices, [0, 2, 4])
 
     with self.assertRaisesRegex(
-        ValueError, r'batch_dims may only be negative '
+        ValueError, r'batch_dims=-1 may only be negative '
         r'if rank\(indices\) is statically known.'):
       ragged_batch_gather_ops.batch_gather(params, indices)
 
     with self.assertRaisesRegex(
-        ValueError, r'batch_dims may only be negative '
+        ValueError, r'batch_dims=-1 may only be negative '
         r'if rank\(indices\) is statically known.'):
       ragged_batch_gather_ops.batch_gather(params, ragged_indices)
 
diff --git a/tensorflow/python/ops/ragged/ragged_concat_op_test.py b/tensorflow/python/ops/ragged/ragged_concat_op_test.py
index 1ce07f2..000e4bd 100644
--- a/tensorflow/python/ops/ragged/ragged_concat_op_test.py
+++ b/tensorflow/python/ops/ragged/ragged_concat_op_test.py
@@ -305,7 +305,8 @@
         array_ops.placeholder(dtypes.int64)
     ]
     self.assertRaisesRegex(
-        ValueError, r'axis may only be negative if ndims is statically known.',
+        ValueError,
+        r'axis=-1 may only be negative if ndims is statically known.',
         ragged_concat_ops.concat, rt_inputs, -1)
 
   def testSingleTensorInput(self):
diff --git a/tensorflow/python/ops/ragged/ragged_from_tensor_op_test.py b/tensorflow/python/ops/ragged/ragged_from_tensor_op_test.py
index cce83c3..562ec92 100644
--- a/tensorflow/python/ops/ragged/ragged_from_tensor_op_test.py
+++ b/tensorflow/python/ops/ragged/ragged_from_tensor_op_test.py
@@ -577,7 +577,9 @@
       {
           'tensor': [[1]],
           'lengths': [0.5],
-          'error': (TypeError, 'lengths must be an integer tensor')
+          'error': (
+              TypeError,
+              r'Argument `tensor` \(name\: lengths\) must be of type integer.*')
       },
       {
           'tensor': [[1, 2, 3]],
diff --git a/tensorflow/python/ops/ragged/ragged_segment_ids_to_row_splits_op_test.py b/tensorflow/python/ops/ragged/ragged_segment_ids_to_row_splits_op_test.py
index 16559a2..e092e7c 100644
--- a/tensorflow/python/ops/ragged/ragged_segment_ids_to_row_splits_op_test.py
+++ b/tensorflow/python/ops/ragged/ragged_segment_ids_to_row_splits_op_test.py
@@ -39,10 +39,10 @@
     self.assertAllEqual(segment_ids, [0])
 
   def testErrors(self):
-    self.assertRaisesRegex(TypeError,
-                           r'segment_ids must be an integer tensor.*',
-                           segment_id_ops.segment_ids_to_row_splits,
-                           constant_op.constant([0.5]))
+    self.assertRaisesRegex(
+        TypeError,
+        r'Argument `tensor` \(name\: segment_ids\) must be of type integer.*',
+        segment_id_ops.segment_ids_to_row_splits, constant_op.constant([0.5]))
     self.assertRaisesRegex(ValueError, r'Shape \(\) must have rank 1',
                            segment_id_ops.segment_ids_to_row_splits, 0)
     self.assertRaisesRegex(ValueError, r'Shape \(1, 1\) must have rank 1',
diff --git a/tensorflow/python/ops/ragged/ragged_util_test.py b/tensorflow/python/ops/ragged/ragged_util_test.py
index c2a4b3d..77e5aba 100644
--- a/tensorflow/python/ops/ragged/ragged_util_test.py
+++ b/tensorflow/python/ops/ragged/ragged_util_test.py
@@ -194,7 +194,7 @@
           repeats=2,
           axis='foo',
           exception=TypeError,
-          error='axis must be an int'),
+          error='`axis` must be an int'),
   ])
   def testError(self,
                 descr,