code: def test_records_once_per_maze_step_in_multistep_envs():
      """In multi-step envs, events should be recorded once per Maze env step (not in each sub-step)."""
  
      class _SubStepEvents(ABC):
          @define_epoch_stats(sum)
          @define_episode_stats(len)
          @define_step_stats(len)
          def sub_step_event(self):
              """Dispatched in each sub step."""
  
      class _CoreEnvEvents(ABC):
          @define_epoch_stats(sum)
          @define_episode_stats(len)
          @define_step_stats(len)
          def core_env_step_event(self):
              """Dispatched when core env steps (only once per step)."""
  
      class EventDummyEnv(DummyCoreEnvironment):
          """Dummy core env, dispatches one step event in every step."""
  
          def __init__(self, observation_space: gym.spaces.space.Space):
              super().__init__(observation_space)
              self.dummy_events = self.pubsub.create_event_topic(
                  _CoreEnvEvents
              )
  
          def step(
              self, maze_action: Dict
          ) -> Tuple[
              Dict[str, np.ndarray], float, bool, Optional[Dict]
          ]:
              """Dispatch the step event..."""
              self.dummy_events.core_env_step_event()
              return super().step(maze_action)
  
      class DummyMultiStepEnv(DummyStructuredEnvironment):
          """Simulates simple two-step env. The underlying env is stepped only in the second step."""
  
          def __init__(self, maze_env):
              super().__init__(maze_env)
              self.dummy_events = self.pubsub.create_event_topic(
                  _SubStepEvents
              )
  
          def _action0(
              self, action
          ) -> Tuple[
              Dict, float, bool, Optional[Dict[str, np.ndarray]]
          ]:
              self.dummy_events.sub_step_event()
              return {}, 0, False, None
  
          def _action1(
              self, action
          ) -> Tuple[
              Dict, float, bool, Optional[Dict[str, np.ndarray]]
          ]:
              self.dummy_events.sub_step_event()
              return self.maze_env.step(action)
  
      class TestWriter(LogEventsWriter):
          """Testing writer. Keeps the episode event record."""
  
          def __init__(self):
              self.episode_record = None
  
          def write(self, episode_record: EpisodeEventLog):
              """Store the record"""
              self.episode_record = episode_record
  
      # Init the env hierarchy
      observation_conversion = ObservationConversion()
      maze_env = DummyEnvironment(
          core_env=EventDummyEnv(observation_conversion.space()),
          action_conversion=[DictActionConversion()],
          observation_conversion=[observation_conversion],
      )
      env = DummyMultiStepEnv(maze_env)
  
      # Run the rollout
      writer = TestWriter()
      _run_rollout_loop(
          env=env, n_episodes=1, n_steps_per_episode=10, writer=writer
      )
  
      # There should be one core env step event and two substep events recorded in every step.
      assert writer.episode_record is not None
      for step_id, step_event_log in enumerate(
          writer.episode_record.step_event_logs
      ):
          if (step_id + 1) % 2 == 0:
              assert (
                  len(
                      step_event_log.events.query_events(
                          _CoreEnvEvents.core_env_step_event
                      )
                  )
                  == 1
              )
          assert (
              len(
                  step_event_log.events.query_events(
                      _SubStepEvents.sub_step_event
                  )
              )
              == 2
          )
          assert step_event_log.env_time == step_id
  
imports: import random
  from abc import ABC
  from typing import Tuple, Optional
  from typing import Union, List, Type, Dict
  import gym
  import numpy
  from maze.core.env.base_env import BaseEnv
  from maze.core.env.base_env_events import BaseEnvEvents
  from maze.core.env.maze_state import MazeStateType
  from maze.core.env.time_env_mixin import TimeEnvMixin
  from maze.core.events.pubsub import Pubsub
  from maze.core.log_events.episode_event_log import EpisodeEventLog
  from maze.core.log_events.kpi_calculator import KpiCalculator
  from maze.core.log_events.log_events_writer import LogEventsWriter
  from maze.core.log_events.log_events_writer_registry import LogEventsWriterRegistry
  from maze.core.log_stats.event_decorators import define_episode_stats, define_step_stats, define_epoch_stats
  from maze.core.wrappers.log_stats_wrapper import LogStatsWrapper
  from maze.core.wrappers.maze_gym_env_wrapper import GymMazeEnv
  from maze.test.shared_test_utils.dummy_env.dummy_core_env import DummyCoreEnvironment
  from maze.test.shared_test_utils.dummy_env.dummy_maze_env import DummyEnvironment
  from maze.test.shared_test_utils.dummy_env.dummy_struct_env import DummyStructuredEnvironment
  from maze.test.shared_test_utils.dummy_env.reward.base import RewardAggregator
  from maze.test.shared_test_utils.dummy_env.space_interfaces.action_conversion.dict import DictActionConversion
  from maze.test.shared_test_utils.dummy_env.space_interfaces.action_conversion.dict import DictActionConversion
  from maze.test.shared_test_utils.dummy_env.space_interfaces.observation_conversion.dict import ObservationConversion
  from maze.test.shared_test_utils.dummy_env.space_interfaces.observation_conversion.dict import ObservationConversion
label_desc: Use image node_id 5 for calling a global function with example usage: test_records_once_per_maze_step_in_multistep_envs() and returns: super, dict,  int,  False,  None, self