diff --git a/Metaworld/zarr_path: data/metaworld_door-lock_expert.zarr/data/action/.zarray b/Metaworld/zarr_path: data/metaworld_door-lock_expert.zarr/data/action/.zarray new file mode 100644 index 0000000000000000000000000000000000000000..88743f3db80197f5462f98b9e078621c7c162692 --- /dev/null +++ b/Metaworld/zarr_path: data/metaworld_door-lock_expert.zarr/data/action/.zarray @@ -0,0 +1,22 @@ +{ + "chunks": [ + 100, + 4 + ], + "compressor": { + "blocksize": 0, + "clevel": 3, + "cname": "zstd", + "id": "blosc", + "shuffle": 1 + }, + "dtype": " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gym-0.21.0/gym/envs/robotics/assets/hand/manipulate_pen.xml b/gym-0.21.0/gym/envs/robotics/assets/hand/manipulate_pen.xml new file mode 100644 index 0000000000000000000000000000000000000000..20a6fb5e06d745a45435c673c488eb516f6af4fa --- /dev/null +++ b/gym-0.21.0/gym/envs/robotics/assets/hand/manipulate_pen.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gym-0.21.0/gym/envs/robotics/assets/hand/robot_touch_sensors_92.xml b/gym-0.21.0/gym/envs/robotics/assets/hand/robot_touch_sensors_92.xml new file mode 100644 index 0000000000000000000000000000000000000000..fa6d41c0a85266036fd78dfdf1b4d374ed2df36d --- /dev/null +++ b/gym-0.21.0/gym/envs/robotics/assets/hand/robot_touch_sensors_92.xml @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/head_pan_link_collision.stl b/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/head_pan_link_collision.stl new file mode 100644 index 0000000000000000000000000000000000000000..c77b5b187257f0ca97da05b5222d6115e01eff09 Binary files /dev/null and b/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/head_pan_link_collision.stl differ diff --git a/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/laser_link.stl b/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/laser_link.stl new file mode 100644 index 0000000000000000000000000000000000000000..fa4882fc9830423e8f0b623636c325f9154feba9 Binary files /dev/null and b/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/laser_link.stl differ diff --git a/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/shoulder_lift_link_collision.stl b/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/shoulder_lift_link_collision.stl new file mode 100644 index 0000000000000000000000000000000000000000..c9aff0dda920b09c76639d737fbb6a3d83c29d10 Binary files /dev/null and b/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/shoulder_lift_link_collision.stl differ diff --git a/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/torso_fixed_link.stl b/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/torso_fixed_link.stl new file mode 100644 index 0000000000000000000000000000000000000000..7cf7fc147ebeae583d537a0a9842398921f8495f Binary files /dev/null and b/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/torso_fixed_link.stl differ diff --git a/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/torso_lift_link_collision.stl b/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/torso_lift_link_collision.stl new file mode 100644 index 0000000000000000000000000000000000000000..4ce5fcf9c58c885b37dc012f6a539f3e89776006 Binary files /dev/null and b/gym-0.21.0/gym/envs/robotics/assets/stls/fetch/torso_lift_link_collision.stl differ diff --git a/gym-0.21.0/gym/envs/robotics/assets/stls/hand/wrist.stl b/gym-0.21.0/gym/envs/robotics/assets/stls/hand/wrist.stl new file mode 100644 index 0000000000000000000000000000000000000000..420d5f9c678de1f13ace2fb50a9ba3531ab90194 Binary files /dev/null and b/gym-0.21.0/gym/envs/robotics/assets/stls/hand/wrist.stl differ diff --git a/gym-0.21.0/tests/envs/robotics/__init__.py b/gym-0.21.0/tests/envs/robotics/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/gym-0.21.0/tests/envs/robotics/hand/test_manipulate.py b/gym-0.21.0/tests/envs/robotics/hand/test_manipulate.py new file mode 100644 index 0000000000000000000000000000000000000000..55b393f09b0bf24700243b4bd3f106476805e9f1 --- /dev/null +++ b/gym-0.21.0/tests/envs/robotics/hand/test_manipulate.py @@ -0,0 +1,26 @@ +import pickle + +import pytest + +from gym import envs +from tests.envs.spec_list import skip_mujoco, SKIP_MUJOCO_WARNING_MESSAGE + + +ENVIRONMENT_IDS = ( + "HandManipulateEgg-v0", + "HandManipulatePen-v0", + "HandManipulateBlock-v0", +) + + +@pytest.mark.skipif(skip_mujoco, reason=SKIP_MUJOCO_WARNING_MESSAGE) +@pytest.mark.parametrize("environment_id", ENVIRONMENT_IDS) +def test_serialize_deserialize(environment_id): + env1 = envs.make(environment_id, target_position="fixed") + env1.reset() + env2 = pickle.loads(pickle.dumps(env1)) + + assert env1.target_position == env2.target_position, ( + env1.target_position, + env2.target_position, + ) diff --git a/gym-0.21.0/tests/envs/robotics/hand/test_manipulate_touch_sensors.py b/gym-0.21.0/tests/envs/robotics/hand/test_manipulate_touch_sensors.py new file mode 100644 index 0000000000000000000000000000000000000000..bff261a2585ddcc615bc2eb7cf069866e73fc5db --- /dev/null +++ b/gym-0.21.0/tests/envs/robotics/hand/test_manipulate_touch_sensors.py @@ -0,0 +1,26 @@ +import pickle + +import pytest + +from gym import envs +from tests.envs.spec_list import skip_mujoco, SKIP_MUJOCO_WARNING_MESSAGE + + +ENVIRONMENT_IDS = ( + "HandManipulateEggTouchSensors-v1", + "HandManipulatePenTouchSensors-v0", + "HandManipulateBlockTouchSensors-v0", +) + + +@pytest.mark.skipif(skip_mujoco, reason=SKIP_MUJOCO_WARNING_MESSAGE) +@pytest.mark.parametrize("environment_id", ENVIRONMENT_IDS) +def test_serialize_deserialize(environment_id): + env1 = envs.make(environment_id, target_position="fixed") + env1.reset() + env2 = pickle.loads(pickle.dumps(env1)) + + assert env1.target_position == env2.target_position, ( + env1.target_position, + env2.target_position, + ) diff --git a/gym-0.21.0/tests/envs/rollout.json b/gym-0.21.0/tests/envs/rollout.json new file mode 100644 index 0000000000000000000000000000000000000000..9e26dfeeb6e641a33dae4961196235bdb965b21b --- /dev/null +++ b/gym-0.21.0/tests/envs/rollout.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/gym-0.21.0/tests/envs/test_atari_legacy_env_specs.py b/gym-0.21.0/tests/envs/test_atari_legacy_env_specs.py new file mode 100644 index 0000000000000000000000000000000000000000..ae41082a780cf667b80ccb4e9a77c38de2211ce9 --- /dev/null +++ b/gym-0.21.0/tests/envs/test_atari_legacy_env_specs.py @@ -0,0 +1,136 @@ +import pytest + +pytest.importorskip("gym.envs.atari") + +from gym.envs.registration import registry + +from itertools import product + + +def test_ale_legacy_env_specs(): + versions = ["-v0", "-v4"] + suffixes = ["", "NoFrameskip", "Deterministic"] + obs_types = ["", "-ram"] + games = [ + "adventure", + "air_raid", + "alien", + "amidar", + "assault", + "asterix", + "asteroids", + "atlantis", + "bank_heist", + "battle_zone", + "beam_rider", + "berzerk", + "bowling", + "boxing", + "breakout", + "carnival", + "centipede", + "chopper_command", + "crazy_climber", + "defender", + "demon_attack", + "double_dunk", + "elevator_action", + "enduro", + "fishing_derby", + "freeway", + "frostbite", + "gopher", + "gravitar", + "hero", + "ice_hockey", + "jamesbond", + "journey_escape", + "kangaroo", + "krull", + "kung_fu_master", + "montezuma_revenge", + "ms_pacman", + "name_this_game", + "phoenix", + "pitfall", + "pong", + "pooyan", + "private_eye", + "qbert", + "riverraid", + "road_runner", + "robotank", + "seaquest", + "skiing", + "solaris", + "space_invaders", + "star_gunner", + "tennis", + "time_pilot", + "tutankham", + "up_n_down", + "venture", + "video_pinball", + "wizard_of_wor", + "yars_revenge", + "zaxxon", + ] + + # Convert snake case to camel case + games = list(map(lambda x: x.title().replace("_", ""), games)) + specs = list(map("".join, product(games, obs_types, suffixes, versions))) + + """ + defaults: + repeat_action_probability = 0.0 + full_action_space = False + frameskip = (2, 5) + game = "Pong" + obs_type = "ram" + mode = None + difficulty = None + + v0: repeat_action_probability = 0.25 + v4: inherits defaults + + -NoFrameskip: frameskip = 1 + -Deterministic: frameskip = 4 or 3 for space_invaders + """ + for spec in specs: + assert spec in registry.env_specs + kwargs = registry.env_specs[spec]._kwargs + + # Assert necessary parameters are set + assert "frameskip" in kwargs + assert "game" in kwargs + assert "obs_type" in kwargs + assert "repeat_action_probability" in kwargs + assert "full_action_space" in kwargs + + # Common defaults + assert kwargs["full_action_space"] is False + assert "mode" not in kwargs + assert "difficulty" not in kwargs + + if "-ram" in spec: + assert kwargs["obs_type"] == "ram" + else: + assert kwargs["obs_type"] == "rgb" + + if "NoFrameskip" in spec: + assert kwargs["frameskip"] == 1 + elif "Deterministic" in spec: + assert isinstance(kwargs["frameskip"], int) + frameskip = 3 if "SpaceInvaders" in spec else 4 + assert kwargs["frameskip"] == frameskip + else: + assert isinstance(kwargs["frameskip"], tuple) and kwargs["frameskip"] == ( + 2, + 5, + ) + + assert spec.endswith("v0") or spec.endswith("v4") + if spec.endswith("v0"): + assert kwargs["repeat_action_probability"] == 0.25 + elif spec.endswith("v4"): + assert kwargs["repeat_action_probability"] == 0.0 diff --git a/gym-0.21.0/tests/envs/test_determinism.py b/gym-0.21.0/tests/envs/test_determinism.py new file mode 100644 index 0000000000000000000000000000000000000000..2c288189b75906a17816aa743dd9e4a8ef38aa2a --- /dev/null +++ b/gym-0.21.0/tests/envs/test_determinism.py @@ -0,0 +1,83 @@ +import numpy as np +import pytest + +from tests.envs.spec_list import spec_list + + +@pytest.mark.parametrize("spec", spec_list) +def test_env(spec): + # Note that this precludes running this test in multiple + # threads. However, we probably already can't do multithreading + # due to some environments. + env1 = spec.make() + env1.seed(0) + initial_observation1 = env1.reset() + env1.action_space.seed(0) + action_samples1 = [env1.action_space.sample() for i in range(4)] + step_responses1 = [env1.step(action) for action in action_samples1] + env1.close() + + env2 = spec.make() + env2.seed(0) + initial_observation2 = env2.reset() + env2.action_space.seed(0) + action_samples2 = [env2.action_space.sample() for i in range(4)] + step_responses2 = [env2.step(action) for action in action_samples2] + env2.close() + + for i, (action_sample1, action_sample2) in enumerate( + zip(action_samples1, action_samples2) + ): + try: + assert_equals(action_sample1, action_sample2) + except AssertionError: + print("env1.action_space=", env1.action_space) + print("env2.action_space=", env2.action_space) + print("action_samples1=", action_samples1) + print("action_samples2=", action_samples2) + print( + "[{}] action_sample1: {}, action_sample2: {}".format( + i, action_sample1, action_sample2 + ) + ) + raise + + # Don't check rollout equality if it's a a nondeterministic + # environment. + if spec.nondeterministic: + return + + assert_equals(initial_observation1, initial_observation2) + + for i, ((o1, r1, d1, i1), (o2, r2, d2, i2)) in enumerate( + zip(step_responses1, step_responses2) + ): + assert_equals(o1, o2, "[{}] ".format(i)) + assert r1 == r2, "[{}] r1: {}, r2: {}".format(i, r1, r2) + assert d1 == d2, "[{}] d1: {}, d2: {}".format(i, d1, d2) + + # Go returns a Pachi game board in info, which doesn't + # properly check equality. For now, we hack around this by + # just skipping Go. + if spec.id not in ["Go9x9-v0", "Go19x19-v0"]: + assert_equals(i1, i2, "[{}] ".format(i)) + + +def assert_equals(a, b, prefix=None): + assert type(a) == type(b), "{}Differing types: {} and {}".format(prefix, a, b) + if isinstance(a, dict): + assert list(a.keys()) == list(b.keys()), "{}Key sets differ: {} and {}".format( + prefix, a, b + ) + + for k in a.keys(): + v_a = a[k] + v_b = b[k] + assert_equals(v_a, v_b) + elif isinstance(a, np.ndarray): + np.testing.assert_array_equal(a, b) + elif isinstance(a, tuple): + for elem_from_a, elem_from_b in zip(a, b): + assert_equals(elem_from_a, elem_from_b) + else: + assert a == b diff --git a/gym-0.21.0/tests/envs/test_envs_semantics.py b/gym-0.21.0/tests/envs/test_envs_semantics.py new file mode 100644 index 0000000000000000000000000000000000000000..2a7f2b9a46c32f2359a47cbc869209ac2b5fccba --- /dev/null +++ b/gym-0.21.0/tests/envs/test_envs_semantics.py @@ -0,0 +1,122 @@ +""" +Currently disabled since this was done in a very poor way +Hashed str representation of objects +""" + + +import json +import hashlib +import os + +import pytest +from gym import spaces, logger +from tests.envs.spec_list import spec_list + +DATA_DIR = os.path.dirname(__file__) +ROLLOUT_STEPS = 100 +episodes = ROLLOUT_STEPS +steps = ROLLOUT_STEPS + +ROLLOUT_FILE = os.path.join(DATA_DIR, "rollout.json") + +if not os.path.isfile(ROLLOUT_FILE): + with open(ROLLOUT_FILE, "w") as outfile: + json.dump({}, outfile, indent=2) + + +def hash_object(unhashed): + return hashlib.sha256( + str(unhashed).encode("utf-16") + ).hexdigest() # This is really bad, str could be same while values change + + +def generate_rollout_hash(spec): + spaces.seed(0) + env = spec.make() + env.seed(0) + + observation_list = [] + action_list = [] + reward_list = [] + done_list = [] + + total_steps = 0 + for episode in range(episodes): + if total_steps >= ROLLOUT_STEPS: + break + observation = env.reset() + + for step in range(steps): + action = env.action_space.sample() + observation, reward, done, _ = env.step(action) + + action_list.append(action) + observation_list.append(observation) + reward_list.append(reward) + done_list.append(done) + + total_steps += 1 + if total_steps >= ROLLOUT_STEPS: + break + + if done: + break + + observations_hash = hash_object(observation_list) + actions_hash = hash_object(action_list) + rewards_hash = hash_object(reward_list) + dones_hash = hash_object(done_list) + + env.close() + return observations_hash, actions_hash, rewards_hash, dones_hash + + +@pytest.mark.parametrize("spec", spec_list) +def test_env_semantics(spec): + logger.warn("Skipping this test. Existing hashes were generated in a bad way") + return + with open(ROLLOUT_FILE) as data_file: + rollout_dict = json.load(data_file) + + if spec.id not in rollout_dict: + if not spec.nondeterministic: + logger.warn( + "Rollout does not exist for {}, run generate_json.py to generate rollouts for new envs".format( + spec.id + ) + ) + return + + logger.info("Testing rollout for {} environment...".format(spec.id)) + + observations_now, actions_now, rewards_now, dones_now = generate_rollout_hash(spec) + + errors = [] + if rollout_dict[spec.id]["observations"] != observations_now: + errors.append( + "Observations not equal for {} -- expected {} but got {}".format( + spec.id, rollout_dict[spec.id]["observations"], observations_now + ) + ) + if rollout_dict[spec.id]["actions"] != actions_now: + errors.append( + "Actions not equal for {} -- expected {} but got {}".format( + spec.id, rollout_dict[spec.id]["actions"], actions_now + ) + ) + if rollout_dict[spec.id]["rewards"] != rewards_now: + errors.append( + "Rewards not equal for {} -- expected {} but got {}".format( + spec.id, rollout_dict[spec.id]["rewards"], rewards_now + ) + ) + if rollout_dict[spec.id]["dones"] != dones_now: + errors.append( + "Dones not equal for {} -- expected {} but got {}".format( + spec.id, rollout_dict[spec.id]["dones"], dones_now + ) + ) + if len(errors): + for error in errors: + logger.warn(error) + raise ValueError(errors) diff --git a/gym-0.21.0/tests/envs/test_frozenlake_dfs.py b/gym-0.21.0/tests/envs/test_frozenlake_dfs.py new file mode 100644 index 0000000000000000000000000000000000000000..5731a6d4fe25fa0c5a992c08c20f766abb7e6c50 --- /dev/null +++ b/gym-0.21.0/tests/envs/test_frozenlake_dfs.py @@ -0,0 +1,33 @@ +import pytest +import numpy as np + +from gym.envs.toy_text.frozen_lake import generate_random_map + + +# Test that FrozenLake map generation creates valid maps of various sizes. +def test_frozenlake_dfs_map_generation(): + def frozenlake_dfs_path_exists(res): + frontier, discovered = [], set() + frontier.append((0, 0)) + while frontier: + r, c = frontier.pop() + if not (r, c) in discovered: + discovered.add((r, c)) + directions = [(1, 0), (0, 1), (-1, 0), (0, -1)] + for x, y in directions: + r_new = r + x + c_new = c + y + if r_new < 0 or r_new >= size or c_new < 0 or c_new >= size: + continue + if res[r_new][c_new] == "G": + return True + if res[r_new][c_new] not in "#H": + frontier.append((r_new, c_new)) + return False + + map_sizes = [5, 10, 200] + for size in map_sizes: + new_frozenlake = generate_random_map(size) + assert len(new_frozenlake) == size + assert len(new_frozenlake[0]) == size + assert frozenlake_dfs_path_exists(new_frozenlake) diff --git a/gym-0.21.0/tests/spaces/test_utils.py b/gym-0.21.0/tests/spaces/test_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..37dac4ca9bed51066c9918b2be9670958cc436f8 --- /dev/null +++ b/gym-0.21.0/tests/spaces/test_utils.py @@ -0,0 +1,258 @@ +from collections import OrderedDict + +import numpy as np +import pytest + +from gym.spaces import Box, Dict, Discrete, MultiBinary, MultiDiscrete, Tuple, utils + + +spaces = [ + Discrete(3), + Box(low=0.0, high=np.inf, shape=(2, 2)), + Box(low=0.0, high=np.inf, shape=(2, 2), dtype=np.float16), + Tuple([Discrete(5), Discrete(10)]), + Tuple( + [ + Discrete(5), + Box(low=np.array([0, 0]), high=np.array([1, 5]), dtype=np.float32), + ] + ), + Tuple((Discrete(5), Discrete(2), Discrete(2))), + MultiDiscrete([2, 2, 10]), + MultiBinary(10), + Dict( + { + "position": Discrete(5), + "velocity": Box( + low=np.array([0, 0]), high=np.array([1, 5]), dtype=np.float32 + ), + } + ), +] + +flatdims = [3, 4, 4, 15, 7, 9, 14, 10, 7] + + +@pytest.mark.parametrize(["space", "flatdim"], zip(spaces, flatdims)) +def test_flatdim(space, flatdim): + dim = utils.flatdim(space) + assert dim == flatdim, "Expected {} to equal {}".format(dim, flatdim) + + +@pytest.mark.parametrize("space", spaces) +def test_flatten_space_boxes(space): + flat_space = utils.flatten_space(space) + assert isinstance(flat_space, Box), "Expected {} to equal {}".format( + type(flat_space), Box + ) + flatdim = utils.flatdim(space) + (single_dim,) = flat_space.shape + assert single_dim == flatdim, "Expected {} to equal {}".format(single_dim, flatdim) + + +@pytest.mark.parametrize("space", spaces) +def test_flat_space_contains_flat_points(space): + some_samples = [space.sample() for _ in range(10)] + flattened_samples = [utils.flatten(space, sample) for sample in some_samples] + flat_space = utils.flatten_space(space) + for i, flat_sample in enumerate(flattened_samples): + assert flat_sample in flat_space, "Expected sample #{} {} to be in {}".format( + i, flat_sample, flat_space + ) + + +@pytest.mark.parametrize("space", spaces) +def test_flatten_dim(space): + sample = utils.flatten(space, space.sample()) + (single_dim,) = sample.shape + flatdim = utils.flatdim(space) + assert single_dim == flatdim, "Expected {} to equal {}".format(single_dim, flatdim) + + +@pytest.mark.parametrize("space", spaces) +def test_flatten_roundtripping(space): + some_samples = [space.sample() for _ in range(10)] + flattened_samples = [utils.flatten(space, sample) for sample in some_samples] + roundtripped_samples = [ + utils.unflatten(space, sample) for sample in flattened_samples + ] + for i, (original, roundtripped) in enumerate( + zip(some_samples, roundtripped_samples) + ): + assert compare_nested( + original, roundtripped + ), "Expected sample #{} {} to equal {}".format(i, original, roundtripped) + + +def compare_nested(left, right): + if isinstance(left, np.ndarray) and isinstance(right, np.ndarray): + return np.allclose(left, right) + elif isinstance(left, OrderedDict) and isinstance(right, OrderedDict): + res = len(left) == len(right) + for ((left_key, left_value), (right_key, right_value)) in zip( + left.items(), right.items() + ): + if not res: + return False + res = left_key == right_key and compare_nested(left_value, right_value) + return res + elif isinstance(left, (tuple, list)) and isinstance(right, (tuple, list)): + res = len(left) == len(right) + for (x, y) in zip(left, right): + if not res: + return False + res = compare_nested(x, y) + return res + else: + return left == right + + +""" +Expecteded flattened types are based off: +1. The type that the space is hardcoded as(ie. multi_discrete=np.int64, discrete=np.int64, multi_binary=np.int8) +2. The type that the space is instantiated with(ie. box=np.float32 by default unless instantiated with a different type) +3. The smallest type that the composite space(tuple, dict) can be represented as. In flatten, this is determined + internally by numpy when np.concatenate is called. +""" + +expected_flattened_dtypes = [ + np.int64, + np.float32, + np.float16, + np.int64, + np.float64, + np.int64, + np.int64, + np.int8, + np.float64, +] + + +@pytest.mark.parametrize( + ["original_space", "expected_flattened_dtype"], + zip(spaces, expected_flattened_dtypes), +) +def test_dtypes(original_space, expected_flattened_dtype): + flattened_space = utils.flatten_space(original_space) + + original_sample = original_space.sample() + flattened_sample = utils.flatten(original_space, original_sample) + unflattened_sample = utils.unflatten(original_space, flattened_sample) + + assert flattened_space.contains( + flattened_sample + ), "Expected flattened_space to contain flattened_sample" + assert ( + flattened_space.dtype == expected_flattened_dtype + ), "Expected flattened_space's dtype to equal " "{}".format( + expected_flattened_dtype + ) + + assert flattened_sample.dtype == flattened_space.dtype, ( + "Expected flattened_space's dtype to equal " "flattened_sample's dtype " + ) + + compare_sample_types(original_space, original_sample, unflattened_sample) + + +def compare_sample_types(original_space, original_sample, unflattened_sample): + if isinstance(original_space, Discrete): + assert isinstance(unflattened_sample, int), ( + "Expected unflattened_sample to be an int. unflattened_sample: " + "{} original_sample: {}".format(unflattened_sample, original_sample) + ) + elif isinstance(original_space, Tuple): + for index in range(len(original_space)): + compare_sample_types( + original_space.spaces[index], + original_sample[index], + unflattened_sample[index], + ) + elif isinstance(original_space, Dict): + for key, space in original_space.spaces.items(): + compare_sample_types(space, original_sample[key], unflattened_sample[key]) + else: + assert unflattened_sample.dtype == original_sample.dtype, ( + "Expected unflattened_sample's dtype to equal " + "original_sample's dtype. unflattened_sample: " + "{} original_sample: {}".format(unflattened_sample, original_sample) + ) + + +samples = [ + 2, + np.array([[1.0, 3.0], [5.0, 8.0]], dtype=np.float32), + np.array([[1.0, 3.0], [5.0, 8.0]], dtype=np.float16), + (3, 7), + (2, np.array([0.5, 3.5], dtype=np.float32)), + (3, 0, 1), + np.array([0, 1, 7], dtype=np.int64), + np.array([0, 1, 1, 0, 0, 0, 1, 1, 1, 1], dtype=np.int8), + OrderedDict( + [("position", 3), ("velocity", np.array([0.5, 3.5], dtype=np.float32))] + ), +] + + +expected_flattened_samples = [ + np.array([0, 0, 1], dtype=np.int64), + np.array([1.0, 3.0, 5.0, 8.0], dtype=np.float32), + np.array([1.0, 3.0, 5.0, 8.0], dtype=np.float16), + np.array([0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], dtype=np.int64), + np.array([0, 0, 1, 0, 0, 0.5, 3.5], dtype=np.float64), + np.array([0, 0, 0, 1, 0, 1, 0, 0, 1], dtype=np.int64), + np.array([1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], dtype=np.int64), + np.array([0, 1, 1, 0, 0, 0, 1, 1, 1, 1], dtype=np.int8), + np.array([0, 0, 0, 1, 0, 0.5, 3.5], dtype=np.float64), +] + + +@pytest.mark.parametrize( + ["space", "sample", "expected_flattened_sample"], + zip(spaces, samples, expected_flattened_samples), +) +def test_flatten(space, sample, expected_flattened_sample): + assert sample in space + + flattened_sample = utils.flatten(space, sample) + assert flattened_sample.shape == expected_flattened_sample.shape + assert flattened_sample.dtype == expected_flattened_sample.dtype + assert np.all(flattened_sample == expected_flattened_sample) + + +@pytest.mark.parametrize( + ["space", "flattened_sample", "expected_sample"], + zip(spaces, expected_flattened_samples, samples), +) +def test_unflatten(space, flattened_sample, expected_sample): + sample = utils.unflatten(space, flattened_sample) + assert compare_nested(sample, expected_sample) + + +expected_flattened_spaces = [ + Box(low=0, high=1, shape=(3,), dtype=np.int64), + Box(low=0.0, high=np.inf, shape=(4,), dtype=np.float32), + Box(low=0.0, high=np.inf, shape=(4,), dtype=np.float16), + Box(low=0, high=1, shape=(15,), dtype=np.int64), + Box( + low=np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], dtype=np.float64), + high=np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 5.0], dtype=np.float64), + dtype=np.float64, + ), + Box(low=0, high=1, shape=(9,), dtype=np.int64), + Box(low=0, high=1, shape=(14,), dtype=np.int64), + Box(low=0, high=1, shape=(10,), dtype=np.int8), + Box( + low=np.array([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], dtype=np.float64), + high=np.array([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 5.0], dtype=np.float64), + dtype=np.float64, + ), +] + + +@pytest.mark.parametrize( + ["space", "expected_flattened_space"], zip(spaces, expected_flattened_spaces) +) +def test_flatten_space(space, expected_flattened_space): + flattened_space = utils.flatten_space(space) + assert flattened_space == expected_flattened_space diff --git a/gym-0.21.0/tests/utils/__init__.py b/gym-0.21.0/tests/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/gym-0.21.0/tests/wrappers/__init__.py b/gym-0.21.0/tests/wrappers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/gym-0.21.0/tests/wrappers/flatten_test.py b/gym-0.21.0/tests/wrappers/flatten_test.py new file mode 100644 index 0000000000000000000000000000000000000000..b0ef0f61859f0e2ca41ac4797d07a196db471ee7 --- /dev/null +++ b/gym-0.21.0/tests/wrappers/flatten_test.py @@ -0,0 +1,96 @@ +"""Tests for the flatten observation wrapper.""" + +from collections import OrderedDict + +import numpy as np +import pytest + +import gym +from gym.spaces import Box, Dict, unflatten, flatten +from gym.wrappers import FlattenObservation + + +class FakeEnvironment(gym.Env): + def __init__(self, observation_space): + self.observation_space = observation_space + + def reset(self): + self.observation = self.observation_space.sample() + return self.observation + + +OBSERVATION_SPACES = ( + ( + Dict( + OrderedDict( + [ + ("key1", Box(shape=(2, 3), low=0, high=0, dtype=np.float32)), + ("key2", Box(shape=(), low=1, high=1, dtype=np.float32)), + ("key3", Box(shape=(2,), low=2, high=2, dtype=np.float32)), + ] + ) + ), + True, + ), + ( + Dict( + OrderedDict( + [ + ("key2", Box(shape=(), low=0, high=0, dtype=np.float32)), + ("key3", Box(shape=(2,), low=1, high=1, dtype=np.float32)), + ("key1", Box(shape=(2, 3), low=2, high=2, dtype=np.float32)), + ] + ) + ), + True, + ), + ( + Dict( + { + "key1": Box(shape=(2, 3), low=-1, high=1, dtype=np.float32), + "key2": Box(shape=(), low=-1, high=1, dtype=np.float32), + "key3": Box(shape=(2,), low=-1, high=1, dtype=np.float32), + } + ), + False, + ), +) + + +class TestFlattenEnvironment(object): + @pytest.mark.parametrize("observation_space, ordered_values", OBSERVATION_SPACES) + def test_flattened_environment(self, observation_space, ordered_values): + """ + make sure that flattened observations occur in the order expected + """ + env = FakeEnvironment(observation_space=observation_space) + wrapped_env = FlattenObservation(env) + flattened = wrapped_env.reset() + + unflattened = unflatten(env.observation_space, flattened) + original = env.observation + + self._check_observations(original, flattened, unflattened, ordered_values) + + @pytest.mark.parametrize("observation_space, ordered_values", OBSERVATION_SPACES) + def test_flatten_unflatten(self, observation_space, ordered_values): + """ + test flatten and unflatten functions directly + """ + original = observation_space.sample() + + flattened = flatten(observation_space, original) + unflattened = unflatten(observation_space, flattened) + + self._check_observations(original, flattened, unflattened, ordered_values) + + def _check_observations(self, original, flattened, unflattened, ordered_values): + # make sure that unflatten(flatten(original)) == original + assert set(unflattened.keys()) == set(original.keys()) + for k, v in original.items(): + np.testing.assert_allclose(unflattened[k], v) + + if ordered_values: + # make sure that the values were flattened in the order they appeared in the + # OrderedDict + np.testing.assert_allclose(sorted(flattened), flattened) diff --git a/gym-0.21.0/tests/wrappers/monitoring/helpers.py b/gym-0.21.0/tests/wrappers/monitoring/helpers.py new file mode 100644 index 0000000000000000000000000000000000000000..cc4259f330f6bd9c3e832c4d6577869156b56b5b --- /dev/null +++ b/gym-0.21.0/tests/wrappers/monitoring/helpers.py @@ -0,0 +1,10 @@ +import contextlib +import shutil +import tempfile + + +@contextlib.contextmanager +def tempdir(): + temp = tempfile.mkdtemp() + yield temp + shutil.rmtree(temp) diff --git a/gym-0.21.0/tests/wrappers/nested_dict_test.py b/gym-0.21.0/tests/wrappers/nested_dict_test.py new file mode 100644 index 0000000000000000000000000000000000000000..a390675b55e20c9ec578576cdcfd0d76ff66e138 --- /dev/null +++ b/gym-0.21.0/tests/wrappers/nested_dict_test.py @@ -0,0 +1,119 @@ +"""Tests for the filter observation wrapper.""" + + +import pytest +import numpy as np + +import gym +from gym.spaces import Dict, Box, Discrete, Tuple +from gym.wrappers import FilterObservation, FlattenObservation + + +class FakeEnvironment(gym.Env): + def __init__(self, observation_space): + self.observation_space = observation_space + self.obs_keys = self.observation_space.spaces.keys() + self.action_space = Box(shape=(1,), low=-1, high=1, dtype=np.float32) + + def render(self, width=32, height=32, *args, **kwargs): + del args + del kwargs + image_shape = (height, width, 3) + return np.zeros(image_shape, dtype=np.uint8) + + def reset(self): + observation = self.observation_space.sample() + return observation + + def step(self, action): + del action + observation = self.observation_space.sample() + reward, terminal, info = 0.0, False, {} + return observation, reward, terminal, info + + +NESTED_DICT_TEST_CASES = ( + ( + Dict( + { + "key1": Box(shape=(2,), low=-1, high=1, dtype=np.float32), + "key2": Dict( + { + "subkey1": Box(shape=(2,), low=-1, high=1, dtype=np.float32), + "subkey2": Box(shape=(2,), low=-1, high=1, dtype=np.float32), + } + ), + } + ), + (6,), + ), + ( + Dict( + { + "key1": Box(shape=(2, 3), low=-1, high=1, dtype=np.float32), + "key2": Box(shape=(), low=-1, high=1, dtype=np.float32), + "key3": Box(shape=(2,), low=-1, high=1, dtype=np.float32), + } + ), + (9,), + ), + ( + Dict( + { + "key1": Tuple( + ( + Box(shape=(2,), low=-1, high=1, dtype=np.float32), + Box(shape=(2,), low=-1, high=1, dtype=np.float32), + ) + ), + "key2": Box(shape=(), low=-1, high=1, dtype=np.float32), + "key3": Box(shape=(2,), low=-1, high=1, dtype=np.float32), + } + ), + (7,), + ), + ( + Dict( + { + "key1": Tuple((Box(shape=(2,), low=-1, high=1, dtype=np.float32),)), + "key2": Box(shape=(), low=-1, high=1, dtype=np.float32), + "key3": Box(shape=(2,), low=-1, high=1, dtype=np.float32), + } + ), + (5,), + ), + ( + Dict( + { + "key1": Tuple( + (Dict({"key9": Box(shape=(2,), low=-1, high=1, dtype=np.float32)}),) + ), + "key2": Box(shape=(), low=-1, high=1, dtype=np.float32), + "key3": Box(shape=(2,), low=-1, high=1, dtype=np.float32), + } + ), + (5,), + ), +) + + +class TestNestedDictWrapper(object): + @pytest.mark.parametrize("observation_space, flat_shape", NESTED_DICT_TEST_CASES) + def test_nested_dicts_size(self, observation_space, flat_shape): + env = FakeEnvironment(observation_space=observation_space) + + # Make sure we are testing the right environment for the test. + observation_space = env.observation_space + assert isinstance(observation_space, Dict) + + wrapped_env = FlattenObservation(FilterObservation(env, env.obs_keys)) + assert wrapped_env.observation_space.shape == flat_shape + + assert wrapped_env.observation_space.dtype == np.float32 + + @pytest.mark.parametrize("observation_space, flat_shape", NESTED_DICT_TEST_CASES) + def test_nested_dicts_ravel(self, observation_space, flat_shape): + env = FakeEnvironment(observation_space=observation_space) + wrapped_env = FlattenObservation(FilterObservation(env, env.obs_keys)) + obs = wrapped_env.reset() + assert obs.shape == wrapped_env.observation_space.shape diff --git a/gym-0.21.0/tests/wrappers/test_clip_action.py b/gym-0.21.0/tests/wrappers/test_clip_action.py new file mode 100644 index 0000000000000000000000000000000000000000..392a40ea81c1c9840f1619b0a5e2892d6cacaed9 --- /dev/null +++ b/gym-0.21.0/tests/wrappers/test_clip_action.py @@ -0,0 +1,28 @@ +import numpy as np + +import gym +from gym.wrappers import ClipAction + + +def test_clip_action(): + # mountaincar: action-based rewards + make_env = lambda: gym.make("MountainCarContinuous-v0") + env = make_env() + wrapped_env = ClipAction(make_env()) + + seed = 0 + env.seed(seed) + wrapped_env.seed(seed) + + env.reset() + wrapped_env.reset() + + actions = [[0.4], [1.2], [-0.3], [0.0], [-2.5]] + for action in actions: + obs1, r1, d1, _ = env.step( + np.clip(action, env.action_space.low, env.action_space.high) + ) + obs2, r2, d2, _ = wrapped_env.step(action) + assert np.allclose(r1, r2) + assert np.allclose(obs1, obs2) + assert d1 == d2 diff --git a/gym-0.21.0/tests/wrappers/test_flatten_observation.py b/gym-0.21.0/tests/wrappers/test_flatten_observation.py new file mode 100644 index 0000000000000000000000000000000000000000..06daaa352f958ed4092662eb208f9cd4dd39e276 --- /dev/null +++ b/gym-0.21.0/tests/wrappers/test_flatten_observation.py @@ -0,0 +1,22 @@ +import pytest + +import numpy as np + +import gym +from gym.wrappers import FlattenObservation +from gym import spaces + + +@pytest.mark.parametrize("env_id", ["Blackjack-v1"]) +def test_flatten_observation(env_id): + env = gym.make(env_id) + wrapped_env = FlattenObservation(env) + + obs = env.reset() + wrapped_obs = wrapped_env.reset() + + space = spaces.Tuple((spaces.Discrete(32), spaces.Discrete(11), spaces.Discrete(2))) + wrapped_space = spaces.Box(0, 1, [32 + 11 + 2], dtype=np.int64) + + assert space.contains(obs) + assert wrapped_space.contains(wrapped_obs) diff --git a/gym-0.21.0/tests/wrappers/test_normalize.py b/gym-0.21.0/tests/wrappers/test_normalize.py new file mode 100644 index 0000000000000000000000000000000000000000..2225bd4eaa40428a9525477ae9b1959d3193ceac --- /dev/null +++ b/gym-0.21.0/tests/wrappers/test_normalize.py @@ -0,0 +1,108 @@ +import gym +import numpy as np +from numpy.testing import assert_almost_equal + +from gym.wrappers.normalize import NormalizeObservation, NormalizeReward + + +class DummyRewardEnv(gym.Env): + metadata = {} + + def __init__(self, return_reward_idx=0): + self.action_space = gym.spaces.Discrete(2) + self.observation_space = gym.spaces.Box( + low=np.array([-1.0]), high=np.array([1.0]) + ) + self.returned_rewards = [0, 1, 2, 3, 4] + self.return_reward_idx = return_reward_idx + self.t = self.return_reward_idx + + def step(self, action): + self.t += 1 + return np.array([self.t]), self.t, self.t == len(self.returned_rewards), {} + + def reset(self): + self.t = self.return_reward_idx + return np.array([self.t]) + + +def make_env(return_reward_idx): + def thunk(): + env = DummyRewardEnv(return_reward_idx) + return env + + return thunk + + +def test_normalize_observation(): + env = DummyRewardEnv(return_reward_idx=0) + env = NormalizeObservation(env) + env.reset() + env.step(env.action_space.sample()) + assert_almost_equal(env.obs_rms.mean, 0.5, decimal=4) + env.step(env.action_space.sample()) + assert_almost_equal(env.obs_rms.mean, 1.0, decimal=4) + + +def test_normalize_return(): + env = DummyRewardEnv(return_reward_idx=0) + env = NormalizeReward(env) + env.reset() + env.step(env.action_space.sample()) + assert_almost_equal( + env.return_rms.mean, + np.mean([1]), # [first return] + decimal=4, + ) + env.step(env.action_space.sample()) + assert_almost_equal( + env.return_rms.mean, + np.mean([2 + env.gamma * 1, 1]), # [second return, first return] + decimal=4, + ) + + +def test_normalize_observation_vector_env(): + env_fns = [make_env(0), make_env(1)] + envs = gym.vector.SyncVectorEnv(env_fns) + envs.reset() + obs, reward, _, _ = envs.step(envs.action_space.sample()) + np.testing.assert_almost_equal(obs, np.array([[1], [2]]), decimal=4) + np.testing.assert_almost_equal(reward, np.array([1, 2]), decimal=4) + + env_fns = [make_env(0), make_env(1)] + envs = gym.vector.SyncVectorEnv(env_fns) + envs = NormalizeObservation(envs) + envs.reset() + assert_almost_equal( + envs.obs_rms.mean, + np.mean([0.5]), # the mean of first observations [[0, 1]] + decimal=4, + ) + obs, reward, _, _ = envs.step(envs.action_space.sample()) + assert_almost_equal( + envs.obs_rms.mean, + np.mean([1.0]), # the mean of first and second observations [[0, 1], [1, 2]] + decimal=4, + ) + + +def test_normalize_return_vector_env(): + env_fns = [make_env(0), make_env(1)] + envs = gym.vector.SyncVectorEnv(env_fns) + envs = NormalizeReward(envs) + obs = envs.reset() + obs, reward, _, _ = envs.step(envs.action_space.sample()) + assert_almost_equal( + envs.return_rms.mean, + np.mean([1.5]), # the mean of first returns [[1, 2]] + decimal=4, + ) + obs, reward, _, _ = envs.step(envs.action_space.sample()) + assert_almost_equal( + envs.return_rms.mean, + np.mean( + [[1, 2], [2 + envs.gamma * 1, 3 + envs.gamma * 2]] + ), # the mean of first and second returns [[1, 2], [2 + envs.gamma * 1, 3 + envs.gamma * 2]] + decimal=4, + ) diff --git a/gym-0.21.0/tests/wrappers/test_pixel_observation.py b/gym-0.21.0/tests/wrappers/test_pixel_observation.py new file mode 100644 index 0000000000000000000000000000000000000000..8e3e7f218d7ae94aaa7884527d3daa0618b64018 --- /dev/null +++ b/gym-0.21.0/tests/wrappers/test_pixel_observation.py @@ -0,0 +1,123 @@ +"""Tests for the pixel observation wrapper.""" + + +import pytest +import numpy as np + +import gym +from gym import spaces +from gym.wrappers.pixel_observation import PixelObservationWrapper, STATE_KEY + + +class FakeEnvironment(gym.Env): + def __init__(self): + self.action_space = spaces.Box(shape=(1,), low=-1, high=1, dtype=np.float32) + + def render(self, width=32, height=32, *args, **kwargs): + del args + del kwargs + image_shape = (height, width, 3) + return np.zeros(image_shape, dtype=np.uint8) + + def reset(self): + observation = self.observation_space.sample() + return observation + + def step(self, action): + del action + observation = self.observation_space.sample() + reward, terminal, info = 0.0, False, {} + return observation, reward, terminal, info + + +class FakeArrayObservationEnvironment(FakeEnvironment): + def __init__(self, *args, **kwargs): + self.observation_space = spaces.Box( + shape=(2,), low=-1, high=1, dtype=np.float32 + ) + super(FakeArrayObservationEnvironment, self).__init__(*args, **kwargs) + + +class FakeDictObservationEnvironment(FakeEnvironment): + def __init__(self, *args, **kwargs): + self.observation_space = spaces.Dict( + { + "state": spaces.Box(shape=(2,), low=-1, high=1, dtype=np.float32), + } + ) + super(FakeDictObservationEnvironment, self).__init__(*args, **kwargs) + + +class TestPixelObservationWrapper(object): + @pytest.mark.parametrize("pixels_only", (True, False)) + def test_dict_observation(self, pixels_only): + pixel_key = "rgb" + + env = FakeDictObservationEnvironment() + + # Make sure we are testing the right environment for the test. + observation_space = env.observation_space + assert isinstance(observation_space, spaces.Dict) + + width, height = (320, 240) + + # The wrapper should only add one observation. + wrapped_env = PixelObservationWrapper( + env, + pixel_keys=(pixel_key,), + pixels_only=pixels_only, + render_kwargs={pixel_key: {"width": width, "height": height}}, + ) + + assert isinstance(wrapped_env.observation_space, spaces.Dict) + + if pixels_only: + assert len(wrapped_env.observation_space.spaces) == 1 + assert list(wrapped_env.observation_space.spaces.keys()) == [pixel_key] + else: + assert ( + len(wrapped_env.observation_space.spaces) + == len(observation_space.spaces) + 1 + ) + expected_keys = list(observation_space.spaces.keys()) + [pixel_key] + assert list(wrapped_env.observation_space.spaces.keys()) == expected_keys + + # Check that the added space item is consistent with the added observation. + observation = wrapped_env.reset() + rgb_observation = observation[pixel_key] + + assert rgb_observation.shape == (height, width, 3) + assert rgb_observation.dtype == np.uint8 + + @pytest.mark.parametrize("pixels_only", (True, False)) + def test_single_array_observation(self, pixels_only): + pixel_key = "depth" + + env = FakeArrayObservationEnvironment() + observation_space = env.observation_space + assert isinstance(observation_space, spaces.Box) + + wrapped_env = PixelObservationWrapper( + env, pixel_keys=(pixel_key,), pixels_only=pixels_only + ) + wrapped_env.observation_space = wrapped_env.observation_space + assert isinstance(wrapped_env.observation_space, spaces.Dict) + + if pixels_only: + assert len(wrapped_env.observation_space.spaces) == 1 + assert list(wrapped_env.observation_space.spaces.keys()) == [pixel_key] + else: + assert len(wrapped_env.observation_space.spaces) == 2 + assert list(wrapped_env.observation_space.spaces.keys()) == [ + STATE_KEY, + pixel_key, + ] + + observation = wrapped_env.reset() + depth_observation = observation[pixel_key] + + assert depth_observation.shape == (32, 32, 3) + assert depth_observation.dtype == np.uint8 + + if not pixels_only: + assert isinstance(observation[STATE_KEY], np.ndarray) diff --git a/gym-0.21.0/tests/wrappers/test_time_aware_observation.py b/gym-0.21.0/tests/wrappers/test_time_aware_observation.py new file mode 100644 index 0000000000000000000000000000000000000000..a996d608cdc0e3346785827a4faaa25c8566508a --- /dev/null +++ b/gym-0.21.0/tests/wrappers/test_time_aware_observation.py @@ -0,0 +1,33 @@ +import pytest + +import gym +from gym.wrappers import TimeAwareObservation + + +@pytest.mark.parametrize("env_id", ["CartPole-v1", "Pendulum-v1"]) +def test_time_aware_observation(env_id): + env = gym.make(env_id) + wrapped_env = TimeAwareObservation(env) + + assert wrapped_env.observation_space.shape[0] == env.observation_space.shape[0] + 1 + + obs = env.reset() + wrapped_obs = wrapped_env.reset() + assert wrapped_env.t == 0.0 + assert wrapped_obs[-1] == 0.0 + assert wrapped_obs.shape[0] == obs.shape[0] + 1 + + wrapped_obs, _, _, _ = wrapped_env.step(env.action_space.sample()) + assert wrapped_env.t == 1.0 + assert wrapped_obs[-1] == 1.0 + assert wrapped_obs.shape[0] == obs.shape[0] + 1 + + wrapped_obs, _, _, _ = wrapped_env.step(env.action_space.sample()) + assert wrapped_env.t == 2.0 + assert wrapped_obs[-1] == 2.0 + assert wrapped_obs.shape[0] == obs.shape[0] + 1 + + wrapped_obs = wrapped_env.reset() + assert wrapped_env.t == 0.0 + assert wrapped_obs[-1] == 0.0 + assert wrapped_obs.shape[0] == obs.shape[0] + 1