code: def spec_from_gym_space(
      space: gym.Space,
      simplify_box_bounds: bool = True,
      name: Optional[Text] = None,
  ) -> Union[
      specs.BoundedArraySpec,
      specs.ArraySpec,
      tuple[specs.ArraySpec, ...],
      list[specs.ArraySpec],
      collections.OrderedDict[str, specs.ArraySpec],
  ]:
      """Converts gymnasium spaces into array specs, or a collection thereof.
  
      Please note:
        Unlike OpenAI's gym, Farama's gymnasium provides a dtype for
        each current implementation of spaces. dtype should be defined
        in all specific subclasses of gymnasium.Space even if it is still
        optional in the superclass.
  
      Args:
        space: gymnasium.Space to turn into a spec.
        simplify_box_bounds: Whether to replace bounds of Box space that are arrays
          with identical values with one number and rely on broadcasting.
        name: Name of the spec.
  
      Returns:
        A BoundedArraySpec or an ArraySpec nest mirroring the given space structure.
        The result can be a tuple, sequence or dict of specs for specific Spaces.
      Raises:
        ValueError: If there is an unknown space type.
      """
  
      # We try to simplify redundant arrays to make logging and debugging less
      # verbose and easier to read since the printed spec bounds may be large.
      def try_simplify_array_to_value(np_array):
          """If given numpy array has all the same values, returns that value."""
          first_value = np_array.item(0)
          if np.all(np_array == first_value):
              return np.array(first_value, dtype=np_array.dtype)
          else:
              return np_array
  
      def nested_spec(spec, child_name):
          """Returns the nested spec with a unique name."""
          nested_name = name + "/" + child_name if name else child_name
          return spec_from_gym_space(
              spec, simplify_box_bounds, nested_name
          )
  
      if isinstance(space, gym.spaces.Discrete):
          # Discrete spaces span the set {0, 1, ... , n-1} while Bounded Array specs
          # are inclusive on their bounds.
          maximum = space.n - 1
          return specs.BoundedArraySpec(
              shape=(),
              dtype=np.int64,
              minimum=0,
              maximum=maximum,
              name=name,
          )
      elif isinstance(space, gym.spaces.MultiDiscrete):
          dtype = np.integer
          maximum = try_simplify_array_to_value(
              np.asarray(space.nvec - 1, dtype=dtype)
          )
          return specs.BoundedArraySpec(
              shape=space.shape,
              dtype=dtype,
              minimum=0,
              maximum=maximum,
              name=name,
          )
      elif isinstance(space, gym.spaces.MultiBinary):
          return specs.BoundedArraySpec(
              shape=space.shape,
              dtype=np.int8,
              minimum=0,
              maximum=1,
              name=name,
          )
      elif isinstance(space, gym.spaces.Box):
          dtype = space.dtype
          minimum = np.asarray(space.low, dtype=dtype)
          maximum = np.asarray(space.high, dtype=dtype)
          if simplify_box_bounds:
              simple_minimum = try_simplify_array_to_value(minimum)
              simple_maximum = try_simplify_array_to_value(maximum)
              # Can only simplify if both bounds are simplified. Otherwise
              # broadcasting doesn't work from non-simplified to simplified.
              if simple_minimum.shape == simple_maximum.shape:
                  minimum = simple_minimum
                  maximum = simple_maximum
          return specs.BoundedArraySpec(
              shape=space.shape,
              dtype=dtype,
              minimum=minimum,
              maximum=maximum,
              name=name,
          )
      elif isinstance(space, gym.spaces.Tuple):
          return tuple(
              [
                  nested_spec(s, "tuple_%d" % i)
                  for i, s in enumerate(space.spaces)
              ]
          )
      elif isinstance(space, gym.spaces.Dict):
          return collections.OrderedDict(
              [
                  (key, nested_spec(s, key))
                  for key, s in space.spaces.items()
              ]
          )
      elif isinstance(space, gym.spaces.Sequence):
          return list(
              [nested_spec(space.feature_space, "nested_space")]
          )
      elif isinstance(space, gym.spaces.Graph):
          return (
              nested_spec(space.node_space, "node_space"),
              nested_spec(space.edge_space, "edge_space"),
          )
      elif isinstance(space, gym.spaces.Text):
          return specs.ArraySpec(
              shape=space.shape, dtype=tf.string, name=name
          )
      else:
          raise ValueError(
              "The gymnasium space {} is currently not supported.".format(
                  space
              )
          )
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import collections
  from typing import Any, Optional, Text, Union
  import gymnasium
  from gymnasium.utils import seeding
  import numpy
  import tensorflow
  from tf_agents import specs
  from tf_agents.environments import py_environment
  from tf_agents.trajectories import time_step
  from tf_agents.typing import types
label_desc: Use image node_id 1 for calling a global function with example usage: spec_from_gym_space(space, simplify_box_bounds, name) and returns: spec_from_gym_space, specs, np, np_array, specs, specs, specs, tuple, collections, list, nested_spec,  nested_spec, specs