class_docstr: A class for saving graphs and split in OGB-compatible manner
  Create submission_datasetname/ directory, and output the following two files:
      - datasetname.zip (OGB-compatible zipped dataset folder)
      - meta_dict.pt (torch files storing all the necessary dataset meta-information)
class_docstr_tok: ["A","class","for","saving","graphs","and","split","in","OGB-compatible","manner","Create","submission_datasetname\/","directory",",","and","output","the","following","two","files",":","-","datasetname.zip","(","OGB-compatible","zipped","dataset","folder",")","-","meta_dict.pt","(","torch","files","storing","all","the","necessary","dataset","meta-information",")"]
code: def _save_graph_list_homo(self, graph_list):
      dict_keys = graph_list[0].keys()
      # check necessary keys
      if not "edge_index" in dict_keys:
          raise RuntimeError(
              "edge_index needs to be provided in graph objects"
          )
      if not "num_nodes" in dict_keys:
          raise RuntimeError(
              "num_nodes needs to be provided in graph objects"
          )
  
      print(dict_keys)
  
      data_dict = {}
      # Store the following keys
      # - edge_index (necessary)
      # - num_nodes_list (necessary)
      # - num_edges_list (necessary)
      # - node_** (optional, node_feat is the default node features)
      # - edge_** (optional, edge_feat is the default edge features)
  
      # saving num_nodes_list
      num_nodes_list = np.array(
          [graph["num_nodes"] for graph in graph_list]
      ).astype(np.int64)
      data_dict["num_nodes_list"] = num_nodes_list
  
      # saving edge_index and num_edges_list
      print("Saving edge_index")
      edge_index = np.concatenate(
          [graph["edge_index"] for graph in graph_list], axis=1
      ).astype(np.int64)
      num_edges_list = np.array(
          [graph["edge_index"].shape[1] for graph in graph_list]
      ).astype(np.int64)
  
      if edge_index.shape[0] != 2:
          raise RuntimeError(
              "edge_index must have shape (2, num_edges)"
          )
  
      data_dict["edge_index"] = edge_index
      data_dict["num_edges_list"] = num_edges_list
  
      for key in dict_keys:
          if key == "edge_index" or key == "num_nodes":
              continue
          if graph_list[0][key] is None:
              continue
  
          if "node_" == key[:5]:
              # make sure saved in np.int64 or np.float32
              dtype = (
                  np.int64
                  if "int" in str(graph_list[0][key].dtype)
                  else np.float32
              )
              # check num_nodes
              for i in range(len(graph_list)):
                  if len(graph_list[i][key]) != num_nodes_list[i]:
                      raise RuntimeError(
                          f"num_nodes mistmatches with {key}"
                      )
  
              cat_feat = np.concatenate(
                  [graph[key] for graph in graph_list], axis=0
              ).astype(dtype)
              data_dict[key] = cat_feat
  
          elif "edge_" == key[:5]:
              # make sure saved in np.int64 or np.float32
              dtype = (
                  np.int64
                  if "int" in str(graph_list[0][key].dtype)
                  else np.float32
              )
              # check num_edges
              for i in range(len(graph_list)):
                  if len(graph_list[i][key]) != num_edges_list[i]:
                      raise RuntimeError(
                          f"num_edges mistmatches with {key}"
                      )
  
              cat_feat = np.concatenate(
                  [graph[key] for graph in graph_list], axis=0
              ).astype(dtype)
              data_dict[key] = cat_feat
  
          else:
              raise RuntimeError(
                  f"Keys in graph object should start from either 'node_' or 'edge_', but '{key}' given."
              )
  
      print("Saving all the files!")
      np.savez_compressed(
          osp.join(self.raw_dir, "data.npz"), **data_dict
      )
      print("Validating...")
      # testing
      print("Reading saved files")
      graph_list_read = read_binary_graph_raw(self.raw_dir, False)
  
      print("Checking read graphs and given graphs are the same")
      for i in tqdm(range(len(graph_list))):
          # assert(graph_list[i].keys() == graph_list_read[i].keys())
          for key in graph_list[i].keys():
              if graph_list[i][key] is not None:
                  if isinstance(graph_list[i][key], np.ndarray):
                      assert np.allclose(
                          graph_list[i][key],
                          graph_list_read[i][key],
                          rtol=1e-4,
                          atol=1e-4,
                          equal_nan=True,
                      )
                  else:
                      assert (
                          graph_list[i][key] == graph_list_read[i][key]
                      )
  
      del graph_list_read
  
imports: import torch
  import pandas
  import os
  import os.path
  from datetime import date
  import shutil
  from tqdm.auto import tqdm
  import numpy
  from ogb.io.read_graph_raw import read_binary_graph_raw, read_binary_heterograph_raw
  from ogb.utils.torch_util import all_numpy
label_desc: Use image node_id 3 for calling the DatasetSaver obj's underlying member method code with example usage: obj._save_graph_list_homo(graph_list) without return types