class_docstr: Test various aspects of the directed GrapohSAGE node generator, with the focus
  on the sampled neighbourhoods and the extracted features.
code: def test_two_hop(self):
      g = create_simple_graph()
      nodes = list(g.nodes())
  
      gen = DirectedGraphSAGENodeGenerator(
          g,
          batch_size=g.number_of_nodes(),
          in_samples=[1, 1],
          out_samples=[1, 1],
      )
      flow = gen.flow(node_ids=nodes, shuffle=False)
  
      node_ilocs = g.node_ids_to_ilocs(nodes)
      features = gen.sample_features(node_ilocs, 0)
      num_hops = 2
      tree_len = 2 ** (num_hops + 1) - 1
      assert len(features) == tree_len
  
      # Check node features
      node_features = features[0]
      assert len(node_features) == len(nodes)
      assert node_features.shape == (len(nodes), 1, 1)
      for idx, node in enumerate(nodes):
          assert node_features[idx, 0, 0] == -1.0 * node
  
      # Check in-node features
      in_features = features[1]
      assert in_features.shape == (len(nodes), 1, 1)
      for idx, node in enumerate(nodes):
          if node == 1:
              # *None -> 1
              assert in_features[idx, 0, 0] == 0.0
          elif node == 2:
              # *1 -> 2
              assert in_features[idx, 0, 0] == -1.0
          elif node == 3:
              # *2 -> 3
              assert in_features[idx, 0, 0] == -2.0
          else:
              assert False
  
      # Check out-node features
      out_features = features[2]
      assert out_features.shape == (len(nodes), 1, 1)
      for idx, node in enumerate(nodes):
          if node == 1:
              # 1 -> *2
              assert out_features[idx, 0, 0] == -2.0
          elif node == 2:
              # 2 -> *3
              assert out_features[idx, 0, 0] == -3.0
          elif node == 3:
              # 3 -> *None
              assert out_features[idx, 0, 0] == 0.0
          else:
              assert False
  
      # Check in-in-node features
      in_features = features[3]
      assert in_features.shape == (len(nodes), 1, 1)
      for idx, node in enumerate(nodes):
          if node == 1:
              # *None -> None -> 1
              assert in_features[idx, 0, 0] == 0.0
          elif node == 2:
              # *None -> 1 -> 2
              assert in_features[idx, 0, 0] == 0.0
          elif node == 3:
              # *1 -> 2 -> 3
              assert in_features[idx, 0, 0] == -1.0
          else:
              assert False
  
      # Check in-out-node features
      in_features = features[4]
      assert in_features.shape == (len(nodes), 1, 1)
      for idx, node in enumerate(nodes):
          if node == 1:
              # *None <- None -> 1
              assert in_features[idx, 0, 0] == 0.0
          elif node == 2:
              # *2 <- 1 -> 2
              assert in_features[idx, 0, 0] == -2.0
          elif node == 3:
              # *3 <- 2 -> 3
              assert in_features[idx, 0, 0] == -3.0
          else:
              assert False
  
      # Check out-in-node features
      out_features = features[5]
      assert out_features.shape == (len(nodes), 1, 1)
      for idx, node in enumerate(nodes):
          if node == 1:
              # 1 -> 2 <- *1
              assert out_features[idx, 0, 0] == -1.0
          elif node == 2:
              # 2 -> 3 <- *2
              assert out_features[idx, 0, 0] == -2.0
          elif node == 3:
              # 3 -> None <- *None
              assert out_features[idx, 0, 0] == 0.0
          else:
              assert False
  
      # Check out-out-node features
      out_features = features[6]
      assert out_features.shape == (len(nodes), 1, 1)
      for idx, node in enumerate(nodes):
          if node == 1:
              # 1 -> 2 -> *3
              assert out_features[idx, 0, 0] == -3.0
          elif node == 2:
              # 2 -> 3 -> *None
              assert out_features[idx, 0, 0] == 0.0
          elif node == 3:
              # 3 -> None -> *None
              assert out_features[idx, 0, 0] == 0.0
          else:
              assert False
  
file_path: stellargraph/tests/mapper/test_directed_node_generator.py
imports: import networkx
  import pandas
  from stellargraph.mapper import DirectedGraphSAGENodeGenerator
  from stellargraph.core.graph import StellarDiGraph
  from ..test_utils.graphs import weighted_tree
label_desc: Use image node_id 3 for calling the TestDirectedNodeGenerator obj's underlying member method code with example usage: obj.test_two_hop() without return types