code: def obs_space_info(obs_space):
      """
      Get dict-structured information about a gym.Space.
  
      Dict spaces are represented directly by their dict of subspaces.
      Tuple spaces are converted into a dict with keys indexing into the tuple.
      Unstructured spaces are represented by {None: obs_space}.
  
      :param obs_space: (gym.spaces.Space) an observation space
      :return (tuple) A tuple (keys, shapes, dtypes):
          keys: a list of dict keys.
          shapes: a dict mapping keys to shapes.
          dtypes: a dict mapping keys to dtypes.
      """
      if isinstance(obs_space, gym.spaces.Dict):
          assert isinstance(
              obs_space.spaces, OrderedDict
          ), "Dict space must have ordered subspaces"
          subspaces = obs_space.spaces
      elif isinstance(obs_space, gym.spaces.Tuple):
          subspaces = {
              i: space for i, space in enumerate(obs_space.spaces)
          }
      else:
          assert not hasattr(
              obs_space, "spaces"
          ), "Unsupported structured space '{}'".format(type(obs_space))
          subspaces = {None: obs_space}
      keys = []
      shapes = {}
      dtypes = {}
      for key, box in subspaces.items():
          keys.append(key)
          shapes[key] = box.shape
          dtypes[key] = box.dtype
      return keys, shapes, dtypes
  
imports: from collections import OrderedDict
  import gym
  import numpy
label_desc: Use image node_id 3 for calling a global function with example usage: obs_space_info(obs_space) and returns: keys,  shapes,  dtypes