Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgraded Gymnasium to 1.0.0 and NumPy to 2.0.0+ #453

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ jobs:
--build-arg PYTHON_VERSION=${{ matrix.python-version }} \
--tag minigrid-docker .
- name: Run tests
run: docker run minigrid-docker pytest
run: docker run minigrid-docker pytest --ignore tests/test_wfc
- name: Run doctest
run: docker run minigrid-docker pytest --doctest-modules minigrid/
24 changes: 13 additions & 11 deletions minigrid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,6 @@
__version__ = "2.3.1"


try:
import sys

from farama_notifications import notifications

if "minigrid" in notifications and __version__ in notifications["minigrid"]:
print(notifications["minigrid"][__version__], file=sys.stderr)
except Exception: # nosec
pass


def register_minigrid_envs():
# BlockedUnlockPickup
# ----------------------------------------
Expand Down Expand Up @@ -1133,3 +1122,16 @@ def register_minigrid_envs():
id="BabyAI-BossLevelNoUnlock-v0",
entry_point="minigrid.envs.babyai:BossLevelNoUnlock",
)


register_minigrid_envs()

try:
import sys

from farama_notifications import notifications

if "minigrid" in notifications and __version__ in notifications["minigrid"]:
print(notifications["minigrid"][__version__], file=sys.stderr)
except Exception: # nosec
pass
1 change: 1 addition & 0 deletions minigrid/envs/babyai/core/verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def find_matching_objs(self, env, use_location=True):
the location of the object. e.g. A ball that was on "your right" initially will still be tracked as being "on
your right" when you move.
"""
env = env.unwrapped

if use_location:
self.obj_set = []
Expand Down
2 changes: 2 additions & 0 deletions minigrid/envs/crossing.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def __init__(
):
self.num_crossings = num_crossings
self.obstacle_type = obstacle_type
self.goal_position = None

if obstacle_type == Lava:
mission_space = MissionSpace(mission_func=self._gen_mission_lava)
Expand Down Expand Up @@ -133,6 +134,7 @@ def _gen_grid(self, width, height):

# Place a goal square in the bottom-right corner
self.put_obj(Goal(), width - 2, height - 2)
self.goal_position = (width - 2, height - 2)

# Place obstacles (lava or walls)
v, h = object(), object() # singleton `vertical` and `horizontal` objects
Expand Down
2 changes: 1 addition & 1 deletion minigrid/manual_control.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def start(self):

def step(self, action: Actions):
_, reward, terminated, truncated, _ = self.env.step(action)
print(f"step={self.env.step_count}, reward={reward:.2f}")
print(f"step={self.env.unwrapped.step_count}, reward={reward:.2f}")

if terminated:
print("terminated!")
Expand Down
43 changes: 28 additions & 15 deletions minigrid/wrappers.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ def __init__(self, env, tile_size=8):
)

def observation(self, obs):
rgb_img = self.get_frame(
rgb_img = self.unwrapped.get_frame(
highlight=self.unwrapped.highlight, tile_size=self.tile_size
)

Expand Down Expand Up @@ -374,7 +374,9 @@ def __init__(self, env, tile_size=8):
)

def observation(self, obs):
rgb_img_partial = self.get_frame(tile_size=self.tile_size, agent_pov=True)
rgb_img_partial = self.unwrapped.get_frame(
tile_size=self.tile_size, agent_pov=True
)

return {**obs, "image": rgb_img_partial}

Expand Down Expand Up @@ -403,7 +405,11 @@ def __init__(self, env):
new_image_space = spaces.Box(
low=0,
high=255,
shape=(self.env.width, self.env.height, 3), # number of cells
shape=(
self.env.unwrapped.width,
self.env.unwrapped.height,
3,
), # number of cells
dtype="uint8",
)

Expand Down Expand Up @@ -696,21 +702,21 @@ def reset(

if not self.goal_position:
self.goal_position = [
x for x, y in enumerate(self.grid.grid) if isinstance(y, Goal)
x for x, y in enumerate(self.unwrapped.grid.grid) if isinstance(y, Goal)
]
# in case there are multiple goals , needs to be handled for other env types
if len(self.goal_position) >= 1:
self.goal_position = (
int(self.goal_position[0] / self.height),
self.goal_position[0] % self.width,
int(self.goal_position[0] / self.unwrapped.height),
self.goal_position[0] % self.unwrapped.width,
)

return self.observation(obs), info

def observation(self, obs):
slope = np.divide(
self.goal_position[1] - self.agent_pos[1],
self.goal_position[0] - self.agent_pos[0],
self.goal_position[1] - self.unwrapped.agent_pos[1],
self.goal_position[0] - self.unwrapped.agent_pos[0],
)

if self.type == "angle":
Expand Down Expand Up @@ -746,7 +752,11 @@ def __init__(self, env):
new_image_space = spaces.Box(
low=0,
high=max(OBJECT_TO_IDX.values()),
shape=(self.env.width, self.env.height, 3), # number of cells
shape=(
self.env.unwrapped.width,
self.env.unwrapped.height,
3,
), # number of cells
dtype="uint8",
)
self.observation_space = spaces.Dict(
Expand All @@ -755,10 +765,13 @@ def __init__(self, env):

def observation(self, obs):
objects = np.array(
[OBJECT_TO_IDX[o.type] if o is not None else -1 for o in self.grid.grid]
[
OBJECT_TO_IDX[o.type] if o is not None else -1
for o in self.unwrapped.grid.grid
]
)
agent_pos = self.env.agent_pos
ncol, nrow = self.width, self.height
agent_pos = self.env.unwrapped.agent_pos
ncol, nrow = self.unwrapped.width, self.unwrapped.height
grid = np.mgrid[:ncol, :nrow]
_objects = np.transpose(objects.reshape(1, nrow, ncol), (0, 2, 1))

Expand Down Expand Up @@ -849,9 +862,9 @@ def __init__(self, env, no_death_types: tuple[str, ...], death_cost: float = -1.
def step(self, action):
# In Dynamic-Obstacles, obstacles move after the agent moves,
# so we need to check for collision before self.env.step()
front_cell = self.grid.get(*self.front_pos)
front_cell = self.unwrapped.grid.get(*self.unwrapped.front_pos)
going_to_death = (
action == self.actions.forward
action == self.unwrapped.actions.forward
and front_cell is not None
and front_cell.type in self.no_death_types
)
Expand All @@ -860,7 +873,7 @@ def step(self, action):

# We also check if the agent stays in death cells (e.g., lava)
# without moving
current_cell = self.grid.get(*self.agent_pos)
current_cell = self.unwrapped.grid.get(*self.unwrapped.agent_pos)
in_death = current_cell is not None and current_cell.type in self.no_death_types

if terminated and (going_to_death or in_death):
Expand Down
40 changes: 11 additions & 29 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ authors = [{ name = "Farama Foundation", email = "contact@farama.org" }]
license = { text = "MIT License" }
keywords = ["Memory, Environment, Agent, RL, Gymnasium"]
classifiers = [
"Development Status :: 4 - Beta", # change to `5 - Production/Stable` when ready
"Development Status :: 4 - Beta", # change to `5 - Production/Stable` when ready
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.7",
Expand All @@ -24,33 +24,19 @@ classifiers = [
'Intended Audience :: Science/Research',
'Topic :: Scientific/Engineering :: Artificial Intelligence',
]
dependencies = [
"numpy>=1.18.0",
"gymnasium>=0.28.1",
"pygame>=2.4.0",
]
dependencies = ["numpy>=1.18.0", "gymnasium>=0.28.1", "pygame>=2.4.0"]
dynamic = ["version"]

[project.optional-dependencies]
testing = [
"pytest>=7.0.1",
"pytest-mock>=3.10.0",
"matplotlib>=3.0"
]
wfc = [
"networkx",
"imageio>=2.31.1",
]
testing = ["pytest>=7.0.1", "pytest-mock>=3.10.0", "matplotlib>=3.0"]
wfc = ["networkx", "imageio>=2.31.1"]

[project.urls]
Homepage = "https://farama.org"
Repository = "https://minigrid.farama.org/"
Documentation = "https://minigrid.farama.org/"
"Bug Report" = "https://github.com/Farama-Foundation/Minigrid/issues"

[project.entry-points."gymnasium.envs"]
__root__ = "minigrid.__init__:register_minigrid_envs"

[tool.setuptools]
include-package-data = true

Expand All @@ -60,24 +46,18 @@ include = ["minigrid*"]
# Linters and Test tools #######################################################

[tool.black]
safe = true

[tool.isort]
atomic = true
profile = "black"
append_only = true
src_paths = ["minigrid", "tests"]
add_imports = [ "from __future__ import annotations" ]
add_imports = ["from __future__ import annotations"]

[tool.pyright]
include = [
"minigrid/**",
]
include = ["minigrid/**"]

exclude = [
"**/node_modules",
"**/__pycache__",
]
exclude = ["**/node_modules", "**/__pycache__"]

strict = []

Expand All @@ -98,8 +78,10 @@ reportPrivateUsage = "warning"
reportUntypedFunctionDecorator = "none"
reportMissingTypeStubs = false
reportUnboundVariable = "warning"
reportGeneralTypeIssues ="none"
reportGeneralTypeIssues = "none"
reportPrivateImportUsage = "none"

[tool.pytest.ini_options]
filterwarnings = ['ignore:.*step API.*:DeprecationWarning'] # TODO: to be removed when old step API is removed
filterwarnings = [
'ignore:.*step API.*:DeprecationWarning',
] # TODO: to be removed when old step API is removed
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
numpy>=1.18.0
gymnasium>=0.26
numpy>=2.0.0
gymnasium>=1.0.0
pygame>=2.2.0
8 changes: 4 additions & 4 deletions tests/test_envs.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,21 +121,21 @@ def test_render_modes(spec):
@pytest.mark.parametrize("env_id", ["MiniGrid-DoorKey-6x6-v0"])
def test_agent_sees_method(env_id):
env = gym.make(env_id)
goal_pos = (env.grid.width - 2, env.grid.height - 2)
goal_pos = (env.unwrapped.grid.width - 2, env.unwrapped.grid.height - 2)

# Test the env.agent_sees() function
env.reset()
# Test the "in" operator on grid objects
assert ("green", "goal") in env.grid
assert ("blue", "key") not in env.grid
assert ("green", "goal") in env.unwrapped.grid
assert ("blue", "key") not in env.unwrapped.grid
for i in range(0, 500):
action = env.action_space.sample()
obs, reward, terminated, truncated, info = env.step(action)

grid, _ = Grid.decode(obs["image"])
goal_visible = ("green", "goal") in grid

agent_sees_goal = env.agent_sees(*goal_pos)
agent_sees_goal = env.unwrapped.agent_sees(*goal_pos)
assert agent_sees_goal == goal_visible
if terminated or truncated:
env.reset()
Expand Down
6 changes: 3 additions & 3 deletions tests/test_obstructed_maze.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@


def find_ball_room(env):
for obj in env.grid.grid:
for obj in env.unwrapped.grid.grid:
if isinstance(obj, Ball) and obj.color == COLOR_NAMES[0]:
return env.room_from_pos(*obj.cur_pos)
return env.unwrapped.room_from_pos(*obj.cur_pos)


def find_target_key(env, color):
for obj in env.grid.grid:
for obj in env.unwrapped.grid.grid:
if isinstance(obj, Box) and obj.contains.color == color:
return True
return False
Expand Down
2 changes: 1 addition & 1 deletion tests/test_wfc/test_wfc_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def test_entropyLocationHeuristic() -> None:
wave = np.ones((5, 3, 4), dtype=bool) # everything is possible
wave[1:, 0, 0] = False # first cell is fully observed
wave[4, :, 2] = False
preferences: NDArray[np.float_] = np.ones((3, 4), dtype=np.float_) * 0.5
preferences: NDArray[np.float64] = np.ones((3, 4), dtype=np.float64) * 0.5
preferences[1, 2] = 0.3
preferences[1, 1] = 0.1
heu = wfc_solver.makeEntropyLocationHeuristic(preferences)
Expand Down
Loading
Loading