def _get_tensor_shape(tensor: tf.Tensor,
                      context: _Context) -> Sequence[Union[int, tf.Tensor]]:
  """Gets actual shape of a Tensor: `int`s for static; `Tensor` for dynamic."""

  # This code is derived from BERT's `common_utils.get_shape_list`, but does
  # not necessarily assert.
  try:
    shape = tensor.shape.as_list()
  except ValueError:
    # `as_list()` is undefined for fully unknown TensorShapes.
    # TODO(jhclark): Support fully unknown shapes. (~15 minutes of work)
    raise ValueError(
        "Analyzing function `{}`: tensor_contracts does not yet support fully "
        "unknown shapes. Tensor: {}".format(context.func_name, tensor.name))

  non_static_indexes = []
  for index, dim in enumerate(shape):
    if dim is None:
      non_static_indexes.append(index)

  if not non_static_indexes:
    return shape

  dyn_shape = tf.shape(tensor)
  for index in non_static_indexes:
    shape[index] = dyn_shape[index]
  return shape
Gets actual shape of a Tensor: `int`s for static; `Tensor` for dynamic.
language/canine/tensor_contracts.py