code: def canonical_shape(shape):
      """
      Return shape as tuple of int or Symbol.
  
      This utility function ensures the shape tuple
      using a single integer type (to its best effort).
  
      Args:
          shape: tuple(int|long|np.int*|Symbol|SymbolExpr...)
      """
  
      def try_cast(x):
          try:
              # In python2.7, long and int are different types.
              # If we cast a long int whose value is out of the range of int,
              # the result is still long, avoiding overflow:
              #
              #     `type(2<<64) == long        # True`
              #     `type(int(2<<64)) == long   # True`
              x = int(x)
          except TypeError:
              # ignore symbolic value (sm.Symbol or sm.Expr)
              pass
          return x
  
      return tuple(try_cast(x) for x in shape)
  
file_path: coremltools/coremltools/converters/mil/mil/types/type_tensor.py
imports: import numpy
  import sympy
  from coremltools import _logger
  from .get_type_info import get_type_info
  from .type_mapping import builtin_to_string, is_subtype, is_tensor, nptype_from_builtin, numpy_type_to_builtin_type, promote_types
  from .type_spec import Type
label_desc: Use image node_id 2 for calling a global function with example usage: canonical_shape(shape) and returns: tuple, x