class_docstr: Base class for creating message passing layers of the form
  
  .. math::
      \mathbf{x}_i^{\prime} = \gamma_{\mathbf{\Theta}} \left( \mathbf{x}_i,
      \square_{j \in \mathcal{N}(i)} \, \phi_{\mathbf{\Theta}}
      \left(\mathbf{x}_i, \mathbf{x}_j,\mathbf{e}_{j,i}\right) \right),
  
  where :math:`\square` denotes a differentiable, permutation invariant
  function, *e.g.*, sum, mean or max, and :math:`\gamma_{\mathbf{\Theta}}`
  and :math:`\phi_{\mathbf{\Theta}}` denote differentiable functions such as
  MLPs.
  See `here <https://pytorch-geometric.readthedocs.io/en/latest/notes/
  create_gnn.html>`__ for the accompanying tutorial.
  
  Args:
      aggr (string, optional): The aggregation scheme to use
          (:obj:`"add"`, :obj:`"mean"`, :obj:`"max"` or :obj:`None`).
          (default: :obj:`"add"`)
      flow (string, optional): The flow direction of message passing
          (:obj:`"source_to_target"` or :obj:`"target_to_source"`).
          (default: :obj:`"source_to_target"`)
      node_dim (int, optional): The axis along which to propagate.
          (default: :obj:`-2`)
code: def __collect__(self, args, edge_index, size, kwargs):
      i, j = (1, 0) if self.flow == "source_to_target" else (0, 1)
  
      out = {}
      for arg in args:
          if arg[-2:] not in ["_i", "_j"]:
              out[arg] = kwargs.get(arg, Parameter.empty)
          else:
              dim = 0 if arg[-2:] == "_j" else 1
              data = kwargs.get(arg[:-2], Parameter.empty)
  
              if isinstance(data, (tuple, list)):
                  assert len(data) == 2
                  if isinstance(data[1 - dim], Tensor):
                      self.__set_size__(size, 1 - dim, data[1 - dim])
                  data = data[dim]
  
              if isinstance(data, Tensor):
                  self.__set_size__(size, dim, data)
                  data = self.__lift__(
                      data, edge_index, j if arg[-2:] == "_j" else i
                  )
  
              out[arg] = data
  
      if isinstance(edge_index, Tensor):
          out["adj_t"] = None
          out["edge_index"] = edge_index
          out["edge_index_i"] = edge_index[i]
          out["edge_index_j"] = edge_index[j]
          out["ptr"] = None
      elif isinstance(edge_index, SparseTensor):
          out["adj_t"] = edge_index
          out["edge_index"] = None
          out["edge_index_i"] = edge_index.storage.row()
          out["edge_index_j"] = edge_index.storage.col()
          out["ptr"] = edge_index.storage.rowptr()
          out["edge_weight"] = edge_index.storage.value()
          out["edge_attr"] = edge_index.storage.value()
          out["edge_type"] = edge_index.storage.value()
  
      out["index"] = out["edge_index_i"]
      out["size"] = size
      out["size_i"] = size[1] or size[0]
      out["size_j"] = size[0] or size[1]
      out["dim_size"] = out["size_i"]
  
      return out
  
imports: import os
  import re
  import inspect
  import os.path
  from uuid import uuid1
  from itertools import chain
  from inspect import Parameter
  from typing import List, Optional, Set
  from torch_geometric.typing import Adj, Size
  import torch
  from torch import Tensor
  from jinja2 import Template
  from torch_sparse import SparseTensor
  from torch_scatter import gather_csr, scatter, segment_csr
  from .utils.helpers import expand_left
  from .utils.jit import class_from_module_repr
  from .utils.typing import sanitize, split_types_repr, parse_types, resolve_types
  from .utils.inspector import Inspector, func_header_repr, func_body_repr
label_desc: Use image node_id 5 for calling the MessagePassing obj's underlying member method code with example usage: obj.__collect__(args, edge_index, size, kwargs) and returns: out