code: def test_gather_eval_data(self):
      batch_num = 2
      batches = []
      # generate several data batches
      for _ in range(batch_num):
          inp = DiscreteDqnInput(
              state=FeatureData(
                  float_features=torch.rand(
                      self.batch_size, self.state_dim
                  )
              ),
              next_state=FeatureData(
                  float_features=torch.rand(
                      self.batch_size, self.state_dim
                  )
              ),
              reward=torch.ones(self.batch_size, 1),
              time_diff=torch.ones(self.batch_size, 1) * 2,
              step=torch.ones(self.batch_size, 1) * 2,
              not_terminal=torch.ones(self.batch_size, 1),
              action=torch.tensor([[0, 1], [1, 0], [0, 1]]),
              next_action=torch.tensor([[1, 0], [0, 1], [1, 0]]),
              possible_actions_mask=torch.ones(
                  self.batch_size, self.action_dim
              ),
              possible_next_actions_mask=torch.ones(
                  self.batch_size, self.action_dim
              ),
              extras=ExtraData(),
          )
          batches.append(inp)
      trainer = self._construct_trainer()
      trainer.q_network = self.q_network
      trainer.q_network_target = self.q_network_target
      trainer.q_network_cpe = self.q_network_cpe
      trainer.reward_network = self.reward_network
      # generate evaluation datapages for each batch
      data_pages = [
          trainer.validation_step(batch=inp, batch_idx=idx + 1)
          for idx, inp in enumerate(batches)
      ]
      # aggregate datapages
      eval_data = trainer.gather_eval_data(data_pages)
      self.assertEqual(
          eval_data.model_rewards.shape[0],
          batch_num * data_pages[0].model_rewards.shape[0],
      )
      self.assertEqual(
          eval_data.logged_rewards.shape[0],
          batch_num * data_pages[0].logged_rewards.shape[0],
      )
      self.assertEqual(
          eval_data.action_mask.shape[0],
          batch_num * data_pages[0].action_mask.shape[0],
      )
      self.assertEqual(
          eval_data.model_propensities.shape[0],
          batch_num * data_pages[0].model_propensities.shape[0],
      )
      self.assertEqual(
          eval_data.model_values.shape[0],
          batch_num * data_pages[0].model_values.shape[0],
      )
      self.assertEqual(
          eval_data.possible_actions_mask.shape[0],
          batch_num * data_pages[0].possible_actions_mask.shape[0],
      )
      self.assertEqual(
          eval_data.optimal_q_values.shape[0],
          batch_num * data_pages[0].optimal_q_values.shape[0],
      )
      self.assertEqual(
          eval_data.eval_action_idxs.shape[0],
          batch_num * data_pages[0].eval_action_idxs.shape[0],
      )
  
imports: import unittest
  from typing import List, Optional, Tuple
  import torch
  from reagent.core.parameters import EvaluationParameters, RLParameters
  from reagent.core.torch_utils import masked_softmax
  from reagent.core.types import DiscreteDqnInput, ExtraData, FeatureData
  from reagent.evaluation.evaluation_data_page import EvaluationDataPage
  from reagent.evaluation.evaluator import get_metrics_to_score
  from reagent.models.dqn import FullyConnectedDQN
  from reagent.training.dqn_trainer_base import DQNTrainerBaseLightning
  from reagent.training.parameters import DQNTrainerParameters
  from reagent.workflow.types import RewardOptions
label_desc: Use image node_id 10 for calling the TestDQNTrainerBaseLightning obj's underlying member method code with example usage: obj.test_gather_eval_data() without return types