class_docstr: Utility to find and replace the `source_type` in Python objects.
  
  `source_type` can either be a single type or a tuple of multiple types.
  
  The caller must first call `find_nodes()`, then compute a replacement table and
  pass it to `replace_nodes`.
  
  This uses cloudpickle under the hood, so all sub-objects that are not `source_type`
  must be serializable.
  
  Args:
      source_type: the type(s) of object to find and replace. Default to DAGNodeBase.
docstr: Find top-level DAGNodes.
docstr_tok: ["Find","top-level","DAGNodes","."]
code: def find_nodes(self, obj: Any) -> List[SourceType]:
      """Find top-level DAGNodes."""
      assert (
          self._found is None
      ), "find_nodes cannot be called twice on the same PyObjScanner instance."
      self._found = []
      self._objects = []
      self.dump(obj)
      return self._found
  
file_path: ray/python/ray/dag/py_obj_scanner.py
imports: import io
  from typing import Any, Dict, Generic, List, Tuple, Type, TypeVar, Union
  import pickle
  import ray
  from ray.dag.base import DAGNodeBase
label_desc: Use image node_id 3 for calling the _PyObjScanner obj's underlying member method code with example usage: obj.find_nodes(obj) and returns: self