class_docstr: An input filter is a module that filters the input from an environment to the agent.
class_docstr_tok: ["An","input","filter","is","a","module","that","filters","the","input","from","an","environment","to","the","agent","."]
docstr: A wrapper around _filter which first copies the env_response so that we don't change the original one
  This function should not be updated!
  :param unfiltered_data: the input data
  :param update_internal_state: should the filter's internal state change due to this call
  :return: the filtered env_response
code: def filter(
      self,
      unfiltered_data: Union[
          EnvResponse, List[EnvResponse], Transition, List[Transition]
      ],
      update_internal_state: bool = True,
      deep_copy: bool = True,
  ) -> Union[List[EnvResponse], List[Transition]]:
      """
      A wrapper around _filter which first copies the env_response so that we don't change the original one
      This function should not be updated!
      :param unfiltered_data: the input data
      :param update_internal_state: should the filter's internal state change due to this call
      :return: the filtered env_response
      """
      if self.i_am_a_reference_filter:
          raise Exception(
              "The filter being used is a reference filter. It is not to be used directly. "
              "Instead get a duplicate from it by calling __call__."
          )
      if deep_copy:
          filtered_data = copy.deepcopy(unfiltered_data)
      else:
          filtered_data = [copy.copy(t) for t in unfiltered_data]
      filtered_data = force_list(filtered_data)
  
      # TODO: implement observation space validation
      # filter observations
      if isinstance(filtered_data[0], Transition):
          state_objects_to_filter = [
              [f.state for f in filtered_data],
              [f.next_state for f in filtered_data],
          ]
      elif isinstance(filtered_data[0], EnvResponse):
          state_objects_to_filter = [
              [f.next_state for f in filtered_data]
          ]
      else:
          raise ValueError(
              "unfiltered_data should be either of type EnvResponse or Transition. "
          )
  
      for state_object_list in state_objects_to_filter:
          for (
              observation_name,
              filters,
          ) in self._observation_filters.items():
              if observation_name in state_object_list[0].keys():
                  for filter in filters.values():
                      data_to_filter = [
                          state_object[observation_name]
                          for state_object in state_object_list
                      ]
                      if filter.supports_batching:
                          filtered_observations = filter.filter(
                              data_to_filter,
                              update_internal_state=update_internal_state,
                          )
                      else:
                          filtered_observations = []
                          for data_point in data_to_filter:
                              filtered_observations.append(
                                  filter.filter(
                                      data_point,
                                      update_internal_state=update_internal_state,
                                  )
                              )
  
                      for i, state_object in enumerate(
                          state_object_list
                      ):
                          state_object[
                              observation_name
                          ] = filtered_observations[i]
  
      # filter reward
      for filter in self._reward_filters.values():
          if filter.supports_batching:
              filtered_rewards = filter.filter(
                  [f.reward for f in filtered_data],
                  update_internal_state,
              )
              for d, filtered_reward in zip(
                  filtered_data, filtered_rewards
              ):
                  d.reward = filtered_reward
          else:
              for d in filtered_data:
                  d.reward = filter.filter(
                      d.reward, update_internal_state
                  )
  
      return filtered_data
  
imports: import copy
  import os
  from collections import OrderedDict
  from copy import deepcopy
  from typing import Dict, Union, List
  from rl_coach.core_types import EnvResponse, ActionInfo, Transition
  from rl_coach.spaces import ActionSpace, RewardSpace, ObservationSpace
  from rl_coach.utils import force_list
label_desc: Use image node_id 5 for calling the InputFilter obj's underlying member method code with example usage: obj.filter(unfiltered_data, update_internal_state, deep_copy) and returns: filtered_data