class_docstr: Class to traverse the DAG of nodes.
docstr: Visit an `OperationNode`.
docstr_tok: ["Visit","an","`","OperationNode","`","."]
code: def _visit_operation(self, operation: OperationNode):
      """Visit an `OperationNode`."""
      if operation in self._stack:
          cycle = self._stack[self._stack.index(operation) :] + [
              operation
          ]
          # For readability, just print the label of `operation_def`s
          cycle = ", ".join(
              operation.operation_def.label for operation in cycle
          )
          raise AssertionError("Cycle detected: [{}]".format(cycle))
      self._stack.append(operation)
      input_values = tuple(
          map(self._maybe_visit_value_node, operation.inputs)
      )
      assert operation is self._stack.pop()
      output_values = self._visitor.visit(
          operation.operation_def, input_values
      )
      outputs = operation.outputs
  
      # Expect a tuple of outputs.  Since ValueNode and OperationDef are both
      # subclasses of tuple, we also explicitly disallow them, since returning
      # a single ValueNode or OperationDef is almost certainly an error.
      try:
          _ = iter(output_values)
          output_iterable = not isinstance(output_values, str)
      except TypeError:
          output_iterable = False
      if not output_iterable or isinstance(
          output_values, (ValueNode, OperationDef)
      ):
          raise ValueError(
              "When running operation {} expected visitor to return a tuple, got "
              "{} of type {}".format(
                  operation.operation_def.label,
                  output_values,
                  type(output_values),
              )
          )
      # DoOutputsTuple doesn't work with len().
      if hasattr(output_values, "__len__") and len(
          output_values
      ) != len(outputs):
          raise ValueError(
              "Operation {} has {} outputs but visitor returned {} values: "
              "{}".format(
                  operation.operation_def,
                  len(outputs),
                  len(output_values),
                  output_values,
              )
          )
  
      for output, value in zip(outputs, output_values):
          self._visitor.validate_value(value)
          self._cached_value_nodes_values[output] = value
  
imports: import abc
  import collections
  import dataclasses
  from typing import Any, Collection, Dict, List, Optional, Tuple
  import pydot
label_desc: Use image node_id 4 for calling the Traverser obj's underlying member method code with example usage: obj._visit_operation(operation) without return types