class_docstr: Partitions a GraphItem's variables according to the given strategy.
  
  Essentially, this does a few things:
  
  1. Reads the Strategy and finds which variables should be partitioned (and how).
  2. Creates new `PartitionedVariables` (essentially a list of `Variables`) and
     replaces the original `Variable` with these new vars. Also splits the original
     gradient to map to each variable shard.
  3. Deletes the original variables and recreates the Optimizer (since Optimizers
     can often have different logic for `PartitionedVariables`, and we don't want
     to rewire the optimizer internals as well).
  4. Returns a new graph and strategy modified to reflect the partitioning.
  
  Note that this currently does not work with variables that are part of a control
  flow (including batchnorm). In those cases, we currently do not have a way to
  replicate the control flow's `FuncGraph` for our new variables. Thus, we expect
  that any StrategyBuilder does not generate a strategy that tries to partition a
  control flow variable, otherwise this will likely error.
class_docstr_tok: ["Partitions","a","GraphItem","'s","variables","according","to","the","given","strategy",".","Essentially",",","this","does","a","few","things",":","1",".","Reads","the","Strategy","and","finds","which","variables","should","be","partitioned","(","and","how",")",".","2",".","Creates","new","`","PartitionedVariables","`","(","essentially","a","list","of","`","Variables","`",")","and","replaces","the","original","`","Variable","`","with","these","new","vars",".","Also","splits","the","original","gradient","to","map","to","each","variable","shard",".","3",".","Deletes","the","original","variables","and","recreates","the","Optimizer","(","since","Optimizers","can","often","have","different","logic","for","`","PartitionedVariables","`",",","and","we","do","n't","want","to","rewire","the","optimizer","internals","as","well",")",".","4",".","Returns","a","new","graph","and","strategy","modified","to","reflect","the","partitioning",".","Note","that","this","currently","does","not","work","with","variables","that","are","part","of","a","control","flow","(","including","batchnorm",")",".","In","those","cases",",","we","currently","do","not","have","a","way","to","replicate","the","control","flow","'s","`","FuncGraph","`","for","our","new","variables",".","Thus",",","we","expect","that","any","StrategyBuilder","does","not","generate","a","strategy","that","tries","to","partition","a","control","flow","variable",",","otherwise","this","will","likely","error","."]
code: def _handle_read(new_graph_item, var_op, partitioned_var):
      partitioned_var_tensor = partitioned_var.as_tensor()
      for op in get_consumers(var_op):
          op = new_graph_item.graph.get_operation_by_name(
              ops.prepend_name_scope(op.name, AUTODIST_TO_DELETE_SCOPE)
          )
          if op.type == "ResourceGather":
              # Only Resource Variable needs to be taken care of
              #   because ResourceGather consumes resource tensor rather than the tensor of read_var_op
              # Question: Is there any case where the op.type == "ResourceGather"
              #  but we can't use embedding_lookup_v2 to reconstruct the op consuming a partitioned resource
              # The second input to a ResourceGather op is always the indices per the opdef
              emb_lookup = embedding_ops.embedding_lookup_v2(
                  partitioned_var, ids=op.inputs[1]
              )
              update_consumers(
                  get_consumers(op), op.outputs[0], emb_lookup
              )
          if is_read_var_op(op, version=1):
              # Without our modification, Reference Vars in TF have a read op associated with them.
              # TF can sometimes look for this and expect it to exist (e.g. in graph.as_graph_element)
              # so we add one back to avoid errors.
              # read_out is already the output tensor of the generated identity op
              read_out = array_ops.identity(
                  partitioned_var_tensor,
                  name=ops.prepend_name_scope("read", var_op.name),
              )
              update_consumers(
                  get_consumers(op), op.outputs[0], read_out
              )
          elif is_read_var_op(op, version=2):
              read_out = array_ops.identity(
                  partitioned_var_tensor,
                  name=ops.prepend_name_scope(
                      "Read/ReadVariableOp", var_op.name
                  ),
              )
              update_consumers(
                  get_consumers(op), op.outputs[0], read_out
              )
  
imports: import collections
  import re
  from google.protobuf.pyext._message import RepeatedScalarContainer
  from tensorflow.core.framework import graph_pb2
  from tensorflow.python import ops
  from tensorflow.python.framework import dtypes, versions
  from tensorflow.python.ops import embedding_ops
  from tensorflow.python.ops import variable_scope, array_ops, math_ops
  from tensorflow.python.ops.variables import Variable, PartitionedVariable
  from tensorflow.python.util.compat import as_bytes
  from autodist.const import AUTODIST_TO_DELETE_SCOPE, COLOCATION_PREFIX
  from autodist.checkpoint.saver import Saver
  from autodist.graph_item import GraphItem, Info
  from autodist.kernel.common.op_info import MUTABLE_STATE_OP_DIRECT_CONSUMER_OPS
  from autodist.kernel.common.utils import get_op_name, get_consumers, update_consumers, parse_name_scope
  from autodist.kernel.common.variable_utils import is_read_var_op
  from autodist.kernel.kernel import Kernel
  from autodist.utils import logging
label_desc: Use image node_id 10 for calling the VariablePartitioner obj's underlying member method code with example usage: obj._handle_read(new_graph_item, var_op, partitioned_var) without return types