class_docstr: A NestedDict containing `TensorSpec` and `Types`.
  
  It can be used to validate an incoming data against a nested dictionary of specs.
  
  Examples:
  
      Basic validation:
      -----------------
  
      .. testcode::
          :skipif: True
  
          spec_dict = SpecDict({
              "obs": {
                  "arm":      TensorSpec("b, dim_arm", dim_arm=64),
                  "gripper":  TensorSpec("b, dim_grip", dim_grip=12)
              },
              "action": TensorSpec("b, dim_action", dim_action=12),
              "action_dist": torch.distributions.Categorical
  
          spec_dict.validate({
              "obs": {
                  "arm":      torch.randn(32, 64),
                  "gripper":  torch.randn(32, 12)
              },
              "action": torch.randn(32, 12),
              "action_dist": torch.distributions.Categorical(torch.randn(32, 12))
          }) # No er
          spec_dict.validate({
              "obs": {
                  "arm":      torch.randn(32, 32), # Wrong shape
                  "gripper":  torch.randn(32, 12)
              },
              "action": torch.randn(32, 12),
              "action_dist": torch.distributions.Categorical(torch.randn(32, 12))
          }) # raises ValueError
  
      Filtering input data:
      ---------------------
  
      .. testcode::
          :skipif: True
  
          input_data = {
              "obs": {
                  "arm":      torch.randn(32, 64),
                  "gripper":  torch.randn(32, 12),
                  "unused":   torch.randn(32, 12)
              },
              "action": torch.randn(32, 12),
              "action_dist": torch.distributions.Categorical(torch.randn(32, 12)),
              "unused": torch.randn(32, 12)
          }
          input_data.filter(spec_dict) # returns a dict with only the keys in the spec
  
      .. testoutput::
  
          {
              "obs": {
                  "arm":      input_data["obs"]["arm"],
                  "gripper":  input_data["obs"]["gripper"]
              },
              "action": input_data["action"],
              "action_dist": input_data["action_dist"]
          }
  
  Raises:
      ValueError: If the data doesn't match the spec.
docstr: Checks whether the data matches the spec.
  
  Args:
      data: The data which should match the spec. It can also be a spec.
      exact_match: If true, the data and the spec must be exactly identical.
          Otherwise, the data is validated as long as it contains at least the
          elements of the spec, but can contain more entries.
  Raises:
      ValueError: If the data doesn't match the spec.
docstr_tok: ["Checks","whether","the","data","matches","the","spec",".","Args",":","data",":","The","data","which","should","match","the","spec",".","It","can","also","be","a","spec",".","exact_match",":","If","true",",","the","data","and","the","spec","must","be","exactly","identical",".","Otherwise",",","the","data","is","validated","as","long","as","it","contains","at","least","the","elements","of","the","spec",",","but","can","contain","more","entries",".","Raises",":","ValueError",":","If","the","data","does","n't","match","the","spec","."]
code: def validate(
      self,
      data: DATA_TYPE,
      exact_match: bool = False,
  ) -> None:
      """Checks whether the data matches the spec.
  
      Args:
          data: The data which should match the spec. It can also be a spec.
          exact_match: If true, the data and the spec must be exactly identical.
              Otherwise, the data is validated as long as it contains at least the
              elements of the spec, but can contain more entries.
      Raises:
          ValueError: If the data doesn't match the spec.
      """
      data = NestedDict(data)
      data_keys_set = set(data.keys())
  
      for spec_key in self:
          if spec_key not in data:
              raise ValueError(
                  _MISSING_KEYS_FROM_DATA.format(
                      spec_key, data_keys_set
                  )
              )
  
      if exact_match:
          data_spec_missing_keys = data_keys_set.difference(
              self._keys_set
          )
          if data_spec_missing_keys:
              raise ValueError(
                  _MISSING_KEYS_FROM_SPEC.format(data_spec_missing_keys)
              )
  
      for spec_name, spec in self.items():
          data_to_validate = data[spec_name]
          if spec is None:
              continue
  
          if isinstance(spec, Spec):
              try:
                  spec.validate(data_to_validate)
              except ValueError as e:
                  raise ValueError(
                      f"Mismatch found in data element {spec_name}, "
                      f"which is a TensorSpec: {e}"
                  )
          elif isinstance(spec, (type, tuple)):
              if not isinstance(data_to_validate, spec):
                  raise ValueError(
                      _TYPE_MISMATCH.format(
                          spec_name,
                          type(data_to_validate).__name__,
                          spec.__name__,
                      )
                  )
          else:
              raise ValueError(
                  f"The spec type has to be either TensorSpec or Type. "
                  f"got {type(spec)}"
              )
  
file_path: ray/rllib/core/models/specs/specs_dict.py
imports: from typing import Union, Mapping, Any
  from ray.rllib.utils.annotations import ExperimentalAPI, override
  from ray.rllib.utils.nested_dict import NestedDict
  from ray.rllib.core.models.specs.specs_base import Spec
label_desc: Use image node_id 2 for calling the SpecDict obj's underlying member method code with example usage: obj.validate(data, exact_match) without return types