class_docstr: A transparent environment Wrapper that works with any manifestation of :class:`~maze.core.env.base_env.BaseEnv`.
  It is intended as drop-in replacement for gym.core.Wrapper.
  
  Gym Wrappers elegantly expose methods and attributes of all nested envs. However wrapping destroys the class
  hierarchy, querying the base classes is not straight-forward. This environment wrapper fixes the behaviour
  of isinstance() for arbitrarily nested wrappers.
  
  Suppose we want to check the base class:
  
      class MyGymWrapper(Wrapper[gym.Env]):
          ...
  
      # construct an env and wrap it
      env = MyEnv()
      env = MyGymWrapper(env)
  
      # this assertion fails
      assert isinstance(env, MyEnv) == True
  
  TypingWrapper makes `isinstance()` work as intuitively expected:
  
      # this time use MyWrapper, which is derived from this Wrapper class
      env = MyEnv()
      env = MyWrapper(env)
  
      # now the assertions hold
      assert isinstance(env, MyEnv) == True
      assert isinstance(env, MyWrapper) == True
  
  
  Note:
  
  gym.core.Wrapper assumes the existence of certain attributes (action_space, observation_space, reward_range,
  metadata) and duplicates these attributes. This behaviour is unnecessary, because __getattr__ makes these
  members of the inner environment transparently available anyway.
class_docstr_tok: ["A","transparent","environment","Wrapper","that","works","with","any","manifestation","of",":","class",":","`","~maze.core.env.base_env.BaseEnv","`",".","It","is","intended","as","drop-in","replacement","for","gym.core.Wrapper",".","Gym","Wrappers","elegantly","expose","methods","and","attributes","of","all","nested","envs",".","However","wrapping","destroys","the","class","hierarchy",",","querying","the","base","classes","is","not","straight-forward",".","This","environment","wrapper","fixes","the","behaviour","of","isinstance","(",")","for","arbitrarily","nested","wrappers",".","Suppose","we","want","to","check","the","base","class",":","class","MyGymWrapper","(","Wrapper","[","gym.Env","]",")",":","...","#","construct","an","env","and","wrap","it","env","=","MyEnv","(",")","env","=","MyGymWrapper","(","env",")","#","this","assertion","fails","assert","isinstance","(","env",",","MyEnv",")","==","True","TypingWrapper","makes","`","isinstance","(",")","`","work","as","intuitively","expected",":","#","this","time","use","MyWrapper",",","which","is","derived","from","this","Wrapper","class","env","=","MyEnv","(",")","env","=","MyWrapper","(","env",")","#","now","the","assertions","hold","assert","isinstance","(","env",",","MyEnv",")","==","True","assert","isinstance","(","env",",","MyWrapper",")","==","True","Note",":","gym.core.Wrapper","assumes","the","existence","of","certain","attributes","(","action_space",",","observation_space",",","reward_range",",","metadata",")","and","duplicates","these","attributes",".","This","behaviour","is","unnecessary",",","because","__getattr__","makes","these","members","of","the","inner","environment","transparently","available","anyway","."]
docstr: Convert MazeState and MazeAction back into raw action and observation.
  
  This method is mostly used when working with trajectory data, e.g. for imitation learning. As part
  of trajectory data, MazeState and MazeActions are recorded. For imitation learning, they then need to be
  converted
  to raw observations and actions in the desired format (i.e. using all the required wrappers etc.)
  
  The conversion is done by first transforming the MazeState and MazeAction using the space interfaces in
  MazeEnv, and then running them through the entire wrapper stack ("back up").
  
  Both the MazeState and the MazeAction on top of it are converted as part of this single method,
  as some wrappers (mostly multi-step ones) need them both together (to be able to split them
  into observations and actions taken in different sub-steps). If you are not using multi-step wrappers,
  you don't need to convert both MazeState and MazeAction, you can pass in just one of them. Not all wrappers
  have to support this though.
  
  See below for an example implementation.
  
  Note: The conversion of MazeState to observation is in the "natural" direction, how it takes place when stepping
  the env. This is not true for the MazeAction to action conversion -- when stepping the env, actions are
  converted to MazeActions, whereas here the MazeAction needs to be converted back into the "raw" action (i.e.
  in reverse direction).
  
  (!) Attention: In case that there are some stateful wrappers in the wrapper stack (e.g. a wrapper stacking
  observations from previous steps), you should ensure that (1) the first_step_in_episode flag is passed
  to this function correctly and (2) that all states and MazeActions are converted in order -- as they happened
  during the recorded episode.
  
  :param maze_state: MazeState to convert. If none, only MazeAction will be converted
                    (not all wrappers support this).
  :param maze_action: MazeAction (the one following the state given as the first param). If none, only MazeState
                    will be converted (not all wrappers support this, some need both).
  :param first_step_in_episode: True if this is the first step in the episode. Serves to notify stateful wrappers
                                (e.g. observation stacking) that they should reset their state.
  :return: observation and action dictionaries (keys are IDs of sub-steps)
code: def get_observation_and_action_dicts(
      self,
      maze_state: Optional[MazeStateType],
      maze_action: Optional[MazeActionType],
      first_step_in_episode: bool,
  ) -> Tuple[
      Optional[Dict[Union[int, str], Any]],
      Optional[Dict[Union[int, str], Any]],
  ]:
      """Convert MazeState and MazeAction back into raw action and observation.
  
      This method is mostly used when working with trajectory data, e.g. for imitation learning. As part
      of trajectory data, MazeState and MazeActions are recorded. For imitation learning, they then need to be
      converted
      to raw observations and actions in the desired format (i.e. using all the required wrappers etc.)
  
      The conversion is done by first transforming the MazeState and MazeAction using the space interfaces in
      MazeEnv, and then running them through the entire wrapper stack ("back up").
  
      Both the MazeState and the MazeAction on top of it are converted as part of this single method,
      as some wrappers (mostly multi-step ones) need them both together (to be able to split them
      into observations and actions taken in different sub-steps). If you are not using multi-step wrappers,
      you don't need to convert both MazeState and MazeAction, you can pass in just one of them. Not all wrappers
      have to support this though.
  
      See below for an example implementation.
  
      Note: The conversion of MazeState to observation is in the "natural" direction, how it takes place when stepping
      the env. This is not true for the MazeAction to action conversion -- when stepping the env, actions are
      converted to MazeActions, whereas here the MazeAction needs to be converted back into the "raw" action (i.e.
      in reverse direction).
  
      (!) Attention: In case that there are some stateful wrappers in the wrapper stack (e.g. a wrapper stacking
      observations from previous steps), you should ensure that (1) the first_step_in_episode flag is passed
      to this function correctly and (2) that all states and MazeActions are converted in order -- as they happened
      during the recorded episode.
  
      :param maze_state: MazeState to convert. If none, only MazeAction will be converted
                        (not all wrappers support this).
      :param maze_action: MazeAction (the one following the state given as the first param). If none, only MazeState
                        will be converted (not all wrappers support this, some need both).
      :param first_step_in_episode: True if this is the first step in the episode. Serves to notify stateful wrappers
                                    (e.g. observation stacking) that they should reset their state.
      :return: observation and action dictionaries (keys are IDs of sub-steps)
      """
  
      # First pass maze_state and maze_action down the wrapper stack:
      #
      # obs_dict, act_dict = self.env.get_observation_and_action_dicts(maze_state, maze_action, first_step_in_episode)
      #
      # if first_step_in_episode:
      #   # If the wrapper keeps any state (e.g. stack of past observations), reset it
      #
      # Now do the conversion and return the observation and action dicts back up:
      # ...
      # return converted_obs_dict, converted_act_dict
  
      raise NotImplementedError
  
imports: from abc import abstractmethod, ABC
  from typing import Generator, TypeVar, Generic, Type, Union, Dict, Tuple, Any, Optional
  from maze.core.annotations import override
  from maze.core.env.action_conversion import ActionType
  from maze.core.env.base_env import BaseEnv
  from maze.core.env.environment_context import EnvironmentContext
  from maze.core.env.maze_action import MazeActionType
  from maze.core.env.maze_state import MazeStateType
  from maze.core.env.simulated_env_mixin import SimulatedEnvMixin
label_desc: Use image node_id 9 for calling the Wrapper obj's underlying member method code with example usage: obj.get_observation_and_action_dicts(maze_state, maze_action, first_step_in_episode) without return types