code: def test_observation_spec(self, mode):
      cvr = converter.Converter(
          settings=_make_converter_settings(mode),
          environment_info=_make_dummy_env_info(),
      )
  
      obs_spec = cvr.observation_spec()
      expected_fields = [
          "away_race_observed",
          "away_race_requested",
          "game_loop",
          "home_race_requested",
          "minimap_height_map",
          "minimap_visibility_map",
          "mmr",
          "opponent_player",
          "opponent_unit_counts_bow",
          "opponent_upgrades_fixed_length",
          "player",
          "unit_counts_bow",
          "upgrades_fixed_length",
      ]
  
      if mode == "raw":
          expected_fields += ["raw_units"]
      else:
          expected_fields += [
              "available_actions",
              "screen_height_map",
              "screen_player_relative",
          ]
  
      self.assertCountEqual(list(obs_spec), expected_fields)
  
      for k, v in obs_spec.items():
          self.assertEqual(k, v.name, msg=k)
          if k.startswith("minimap_") or k.startswith("screen_"):
              self.assertEqual(v.dtype, np.uint8, msg=k)
          else:
              self.assertEqual(v.dtype, np.int32, msg=k)
              if "upgrades_fixed_length" not in k:
                  self.assertFalse(hasattr(v, "min"), msg=k)
                  self.assertFalse(hasattr(v, "max"), msg=k)
  
      for k, v in {
          "minimap_height_map": 255,
          "minimap_visibility_map": 3,
          "upgrades_fixed_length": NUM_UPGRADE_TYPES + 1,
          "opponent_upgrades_fixed_length": NUM_UPGRADE_TYPES + 1,
      }.items():
          self.assertEqual(obs_spec[k].minimum, (0,), msg=k)
          self.assertEqual(obs_spec[k].maximum, (v,), msg=k)
  
      if mode == "visual":
          for k, v in {
              "screen_height_map": 255,
              "screen_player_relative": 4,
          }.items():
              self.assertEqual(obs_spec[k].minimum, (0,), msg=k)
              self.assertEqual(obs_spec[k].maximum, (v,), msg=k)
  
      for f in [
          "away_race_observed",
          "away_race_requested",
          "game_loop",
          "home_race_requested",
      ]:
          self.assertEqual(obs_spec[f].shape, (1,), msg=f)
  
      self.assertEqual(obs_spec["mmr"].shape, ())
  
      for k, v in {
          "player": 11,
          "opponent_player": 10,
          "unit_counts_bow": NUM_UNIT_TYPES,
          "opponent_unit_counts_bow": NUM_UNIT_TYPES,
          "upgrades_fixed_length": NUM_UPGRADES,
          "opponent_upgrades_fixed_length": NUM_UPGRADES,
      }.items():
          self.assertEqual(obs_spec[k].shape, (v,), k)
  
      if mode == "raw":
          self.assertEqual(
              obs_spec["raw_units"].shape,
              (MAX_UNIT_COUNT, NUM_UNIT_FEATURES + 2),
          )
      else:
          self.assertEqual(
              obs_spec["available_actions"].shape, (NUM_ACTION_TYPES,)
          )
  
imports: from absl.testing import absltest
  from absl.testing import parameterized
  import numpy
  from pysc2.env.converter import converter
  from pysc2.env.converter.proto import converter_pb2
  from s2clientprotocol import common_pb2
  from s2clientprotocol import raw_pb2
  from s2clientprotocol import sc2api_pb2
  from s2clientprotocol import spatial_pb2
label_desc: Use image node_id 3 for calling the ConverterTest obj's underlying member method code with example usage: obj.test_observation_spec(mode) without return types