Browse Source

Some typing improvements, add py.typed (#284)

Co-authored-by: Mark Towers <mark.m.towers@gmail.com>
Michael Joseph Rosenthal 2 years ago
parent
commit
fc41b5e7c3
58 changed files with 251 additions and 169 deletions
  1. 1 0
      .gitignore
  2. 4 2
      docs/conf.py
  3. 2 0
      docs/scripts/gen_envs_display.py
  4. 2 0
      docs/scripts/gen_gifs.py
  5. 2 0
      docs/scripts/move404.py
  6. 2 0
      docs/scripts/utils.py
  7. 2 0
      minigrid/__init__.py
  8. 2 0
      minigrid/benchmark.py
  9. 2 0
      minigrid/core/actions.py
  10. 2 0
      minigrid/core/constants.py
  11. 31 25
      minigrid/core/grid.py
  12. 5 3
      minigrid/core/mission.py
  13. 22 22
      minigrid/core/roomgrid.py
  14. 11 7
      minigrid/core/world_object.py
  15. 2 0
      minigrid/envs/__init__.py
  16. 2 0
      minigrid/envs/babyai/__init__.py
  17. 3 1
      minigrid/envs/babyai/core/levelgen.py
  18. 3 3
      minigrid/envs/babyai/core/roomgrid_level.py
  19. 2 0
      minigrid/envs/babyai/core/verifier.py
  20. 4 2
      minigrid/envs/babyai/goto.py
  21. 4 6
      minigrid/envs/babyai/open.py
  22. 5 5
      minigrid/envs/babyai/other.py
  23. 3 3
      minigrid/envs/babyai/pickup.py
  24. 4 3
      minigrid/envs/babyai/putnext.py
  25. 5 3
      minigrid/envs/babyai/synth.py
  26. 4 4
      minigrid/envs/babyai/unlock.py
  27. 2 2
      minigrid/envs/blockedunlockpickup.py
  28. 5 4
      minigrid/envs/crossing.py
  29. 4 4
      minigrid/envs/distshift.py
  30. 2 2
      minigrid/envs/doorkey.py
  31. 5 4
      minigrid/envs/dynamicobstacles.py
  32. 4 4
      minigrid/envs/empty.py
  33. 2 2
      minigrid/envs/fetch.py
  34. 3 1
      minigrid/envs/fourrooms.py
  35. 2 2
      minigrid/envs/gotodoor.py
  36. 2 2
      minigrid/envs/gotoobject.py
  37. 2 2
      minigrid/envs/keycorridor.py
  38. 3 3
      minigrid/envs/lavagap.py
  39. 2 2
      minigrid/envs/lockedroom.py
  40. 3 3
      minigrid/envs/memory.py
  41. 4 4
      minigrid/envs/multiroom.py
  42. 2 2
      minigrid/envs/obstructedmaze.py
  43. 3 1
      minigrid/envs/playground.py
  44. 2 2
      minigrid/envs/putnear.py
  45. 2 2
      minigrid/envs/redbluedoors.py
  46. 3 3
      minigrid/envs/unlock.py
  47. 2 2
      minigrid/envs/unlockpickup.py
  48. 2 0
      minigrid/manual_control.py
  49. 40 27
      minigrid/minigrid_env.py
  50. 0 0
      minigrid/py.typed
  51. 2 0
      minigrid/utils/rendering.py
  52. 2 0
      minigrid/wrappers.py
  53. 5 0
      pyproject.toml
  54. 2 0
      setup.py
  55. 2 0
      tests/test_envs.py
  56. 2 0
      tests/test_scripts.py
  57. 2 0
      tests/test_wrappers.py
  58. 2 0
      tests/utils.py

+ 1 - 0
.gitignore

@@ -21,4 +21,5 @@ __pycache__
 
 
 # Virtual environments
 # Virtual environments
 .env
 .env
+.venv
 venv
 venv

+ 4 - 2
docs/conf.py

@@ -18,9 +18,11 @@
 # TODO: change to minigrid version
 # TODO: change to minigrid version
 # from TODO import __version__ as minigrid_version
 # from TODO import __version__ as minigrid_version
 
 
+from __future__ import annotations
+
 import os
 import os
 import sys
 import sys
-from typing import Any, Dict
+from typing import Any
 
 
 project = "MiniGrid"
 project = "MiniGrid"
 copyright = "2022"
 copyright = "2022"
@@ -79,7 +81,7 @@ html_theme_options = {
     "dark_logo": "img/minigrid-white.svg",
     "dark_logo": "img/minigrid-white.svg",
     "gtag": "G-FBXJQQLXKD",
     "gtag": "G-FBXJQQLXKD",
 }
 }
-html_context: Dict[str, Any] = {}
+html_context: dict[str, Any] = {}
 html_context["conf_py_path"] = "/docs/"
 html_context["conf_py_path"] = "/docs/"
 html_context["display_github"] = True
 html_context["display_github"] = True
 html_context["github_user"] = "Farama-Foundation"
 html_context["github_user"] = "Farama-Foundation"

+ 2 - 0
docs/scripts/gen_envs_display.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import os
 import os
 
 
 import gymnasium
 import gymnasium

+ 2 - 0
docs/scripts/gen_gifs.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import os
 import os
 import re
 import re
 
 

+ 2 - 0
docs/scripts/move404.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import sys
 import sys
 
 
 if __name__ == "__main__":
 if __name__ == "__main__":

+ 2 - 0
docs/scripts/utils.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import re
 import re
 
 
 
 

+ 2 - 0
minigrid/__init__.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 from gymnasium.envs.registration import register
 from gymnasium.envs.registration import register
 
 
 from minigrid import minigrid_env, wrappers
 from minigrid import minigrid_env, wrappers

+ 2 - 0
minigrid/benchmark.py

@@ -1,5 +1,7 @@
 #!/usr/bin/env python3
 #!/usr/bin/env python3
 
 
+from __future__ import annotations
+
 import time
 import time
 
 
 import gymnasium as gym
 import gymnasium as gym

+ 2 - 0
minigrid/core/actions.py

@@ -1,4 +1,6 @@
 # Enumeration of possible actions
 # Enumeration of possible actions
+from __future__ import annotations
+
 from enum import IntEnum
 from enum import IntEnum
 
 
 
 

+ 2 - 0
minigrid/core/constants.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import numpy as np
 import numpy as np
 
 
 TILE_PIXELS = 32
 TILE_PIXELS = 32

+ 31 - 25
minigrid/core/grid.py

@@ -1,5 +1,7 @@
+from __future__ import annotations
+
 import math
 import math
-from typing import Any, List, Optional, Tuple, Type
+from typing import Any, Callable
 
 
 import numpy as np
 import numpy as np
 
 
@@ -21,7 +23,7 @@ class Grid:
     """
     """
 
 
     # Static cache of pre-renderer tiles
     # Static cache of pre-renderer tiles
-    tile_cache = {}
+    tile_cache: dict[tuple[Any, ...], Any] = {}
 
 
     def __init__(self, width: int, height: int):
     def __init__(self, width: int, height: int):
         assert width >= 3
         assert width >= 3
@@ -30,7 +32,7 @@ class Grid:
         self.width: int = width
         self.width: int = width
         self.height: int = height
         self.height: int = height
 
 
-        self.grid: List[Optional[WorldObj]] = [None] * width * height
+        self.grid: list[WorldObj | None] = [None] * (width * height)
 
 
     def __contains__(self, key: Any) -> bool:
     def __contains__(self, key: Any) -> bool:
         if isinstance(key, WorldObj):
         if isinstance(key, WorldObj):
@@ -47,25 +49,29 @@ class Grid:
                     return True
                     return True
         return False
         return False
 
 
-    def __eq__(self, other: "Grid") -> bool:
+    def __eq__(self, other: Grid) -> bool:
         grid1 = self.encode()
         grid1 = self.encode()
         grid2 = other.encode()
         grid2 = other.encode()
         return np.array_equal(grid2, grid1)
         return np.array_equal(grid2, grid1)
 
 
-    def __ne__(self, other: "Grid") -> bool:
+    def __ne__(self, other: Grid) -> bool:
         return not self == other
         return not self == other
 
 
-    def copy(self) -> "Grid":
+    def copy(self) -> Grid:
         from copy import deepcopy
         from copy import deepcopy
 
 
         return deepcopy(self)
         return deepcopy(self)
 
 
-    def set(self, i: int, j: int, v: Optional[WorldObj]):
-        assert 0 <= i < self.width
-        assert 0 <= j < self.height
+    def set(self, i: int, j: int, v: WorldObj | None):
+        assert (
+            0 <= i < self.width
+        ), f"column index {j} outside of grid of width {self.width}"
+        assert (
+            0 <= j < self.height
+        ), f"row index {j} outside of grid of height {self.height}"
         self.grid[j * self.width + i] = v
         self.grid[j * self.width + i] = v
 
 
-    def get(self, i: int, j: int) -> Optional[WorldObj]:
+    def get(self, i: int, j: int) -> WorldObj | None:
         assert 0 <= i < self.width
         assert 0 <= i < self.width
         assert 0 <= j < self.height
         assert 0 <= j < self.height
         assert self.grid is not None
         assert self.grid is not None
@@ -75,8 +81,8 @@ class Grid:
         self,
         self,
         x: int,
         x: int,
         y: int,
         y: int,
-        length: Optional[int] = None,
-        obj_type: Type[WorldObj] = Wall,
+        length: int | None = None,
+        obj_type: Callable[[], WorldObj] = Wall,
     ):
     ):
         if length is None:
         if length is None:
             length = self.width - x
             length = self.width - x
@@ -87,8 +93,8 @@ class Grid:
         self,
         self,
         x: int,
         x: int,
         y: int,
         y: int,
-        length: Optional[int] = None,
-        obj_type: Type[WorldObj] = Wall,
+        length: int | None = None,
+        obj_type: Callable[[], WorldObj] = Wall,
     ):
     ):
         if length is None:
         if length is None:
             length = self.height - y
             length = self.height - y
@@ -101,7 +107,7 @@ class Grid:
         self.vert_wall(x, y, h)
         self.vert_wall(x, y, h)
         self.vert_wall(x + w - 1, y, h)
         self.vert_wall(x + w - 1, y, h)
 
 
-    def rotate_left(self) -> "Grid":
+    def rotate_left(self) -> Grid:
         """
         """
         Rotate the grid to the left (counter-clockwise)
         Rotate the grid to the left (counter-clockwise)
         """
         """
@@ -115,7 +121,7 @@ class Grid:
 
 
         return grid
         return grid
 
 
-    def slice(self, topX: int, topY: int, width: int, height: int) -> "Grid":
+    def slice(self, topX: int, topY: int, width: int, height: int) -> Grid:
         """
         """
         Get a subset of the grid
         Get a subset of the grid
         """
         """
@@ -139,8 +145,8 @@ class Grid:
     @classmethod
     @classmethod
     def render_tile(
     def render_tile(
         cls,
         cls,
-        obj: WorldObj,
-        agent_dir: Optional[int] = None,
+        obj: WorldObj | None,
+        agent_dir: int | None = None,
         highlight: bool = False,
         highlight: bool = False,
         tile_size: int = TILE_PIXELS,
         tile_size: int = TILE_PIXELS,
         subdivs: int = 3,
         subdivs: int = 3,
@@ -150,7 +156,7 @@ class Grid:
         """
         """
 
 
         # Hash map lookup key for the cache
         # Hash map lookup key for the cache
-        key = (agent_dir, highlight, tile_size)
+        key: tuple[Any, ...] = (agent_dir, highlight, tile_size)
         key = obj.encode() + key if obj else key
         key = obj.encode() + key if obj else key
 
 
         if key in cls.tile_cache:
         if key in cls.tile_cache:
@@ -194,9 +200,9 @@ class Grid:
     def render(
     def render(
         self,
         self,
         tile_size: int,
         tile_size: int,
-        agent_pos: Tuple[int, int],
-        agent_dir: Optional[int] = None,
-        highlight_mask: Optional[np.ndarray] = None,
+        agent_pos: tuple[int, int],
+        agent_dir: int | None = None,
+        highlight_mask: np.ndarray | None = None,
     ) -> np.ndarray:
     ) -> np.ndarray:
         """
         """
         Render this grid at a given scale
         Render this grid at a given scale
@@ -235,7 +241,7 @@ class Grid:
 
 
         return img
         return img
 
 
-    def encode(self, vis_mask: Optional[np.ndarray] = None) -> np.ndarray:
+    def encode(self, vis_mask: np.ndarray | None = None) -> np.ndarray:
         """
         """
         Produce a compact numpy encoding of the grid
         Produce a compact numpy encoding of the grid
         """
         """
@@ -262,7 +268,7 @@ class Grid:
         return array
         return array
 
 
     @staticmethod
     @staticmethod
-    def decode(array: np.ndarray) -> Tuple["Grid", np.ndarray]:
+    def decode(array: np.ndarray) -> tuple[Grid, np.ndarray]:
         """
         """
         Decode an array grid encoding back into a grid
         Decode an array grid encoding back into a grid
         """
         """
@@ -282,7 +288,7 @@ class Grid:
 
 
         return grid, vis_mask
         return grid, vis_mask
 
 
-    def process_vis(self, agent_pos: Tuple[int, int]) -> np.ndarray:
+    def process_vis(self, agent_pos: tuple[int, int]) -> np.ndarray:
         mask = np.zeros(shape=(self.width, self.height), dtype=bool)
         mask = np.zeros(shape=(self.width, self.height), dtype=bool)
 
 
         mask[agent_pos[0], agent_pos[1]] = True
         mask[agent_pos[0], agent_pos[1]] = True

+ 5 - 3
minigrid/core/mission.py

@@ -1,4 +1,6 @@
-from typing import Any, Callable, Optional, Union
+from __future__ import annotations
+
+from typing import Any, Callable
 
 
 from gymnasium import spaces
 from gymnasium import spaces
 from gymnasium.utils import seeding
 from gymnasium.utils import seeding
@@ -26,8 +28,8 @@ class MissionSpace(spaces.Space[str]):
     def __init__(
     def __init__(
         self,
         self,
         mission_func: Callable[..., str],
         mission_func: Callable[..., str],
-        ordered_placeholders: Optional["list[list[str]]"] = None,
-        seed: Optional[Union[int, seeding.RandomNumberGenerator]] = None,
+        ordered_placeholders: list[list[str]] | None = None,
+        seed: int | seeding.RandomNumberGenerator | None = None,
     ):
     ):
         r"""Constructor of :class:`MissionSpace` space.
         r"""Constructor of :class:`MissionSpace` space.
 
 

+ 22 - 22
minigrid/core/roomgrid.py

@@ -1,4 +1,4 @@
-from typing import List, Optional, Tuple, Union
+from __future__ import annotations
 
 
 import numpy as np
 import numpy as np
 
 
@@ -8,7 +8,7 @@ from minigrid.core.world_object import Ball, Box, Door, Key, WorldObj
 from minigrid.minigrid_env import MiniGridEnv
 from minigrid.minigrid_env import MiniGridEnv
 
 
 
 
-def reject_next_to(env: MiniGridEnv, pos: Tuple[int, int]):
+def reject_next_to(env: MiniGridEnv, pos: tuple[int, int]):
     """
     """
     Function to filter out object positions that are right next to
     Function to filter out object positions that are right next to
     the agent's starting point
     the agent's starting point
@@ -21,27 +21,27 @@ def reject_next_to(env: MiniGridEnv, pos: Tuple[int, int]):
 
 
 
 
 class Room:
 class Room:
-    def __init__(self, top: Tuple[int, int], size: Tuple[int, int]):
+    def __init__(self, top: tuple[int, int], size: tuple[int, int]):
         # Top-left corner and size (tuples)
         # Top-left corner and size (tuples)
         self.top = top
         self.top = top
         self.size = size
         self.size = size
 
 
         # List of door objects and door positions
         # List of door objects and door positions
         # Order of the doors is right, down, left, up
         # Order of the doors is right, down, left, up
-        self.doors: List[Optional[Union[bool, Door]]] = [None] * 4
-        self.door_pos: List[Optional[Tuple[int, int]]] = [None] * 4
+        self.doors: list[bool | Door | None] = [None] * 4
+        self.door_pos: list[tuple[int, int] | None] = [None] * 4
 
 
         # List of rooms adjacent to this one
         # List of rooms adjacent to this one
         # Order of the neighbors is right, down, left, up
         # Order of the neighbors is right, down, left, up
-        self.neighbors: List[Optional[Room]] = [None] * 4
+        self.neighbors: list[Room | None] = [None] * 4
 
 
         # Indicates if this room is behind a locked door
         # Indicates if this room is behind a locked door
         self.locked: bool = False
         self.locked: bool = False
 
 
         # List of objects contained
         # List of objects contained
-        self.objs: List[WorldObj] = []
+        self.objs: list[WorldObj] = []
 
 
-    def rand_pos(self, env: MiniGridEnv) -> Tuple[int, int]:
+    def rand_pos(self, env: MiniGridEnv) -> tuple[int, int]:
         topX, topY = self.top
         topX, topY = self.top
         sizeX, sizeY = self.size
         sizeX, sizeY = self.size
         return env._randPos(topX + 1, topX + sizeX - 1, topY + 1, topY + sizeY - 1)
         return env._randPos(topX + 1, topX + sizeX - 1, topY + 1, topY + sizeY - 1)
@@ -180,7 +180,7 @@ class RoomGrid(MiniGridEnv):
 
 
     def place_in_room(
     def place_in_room(
         self, i: int, j: int, obj: WorldObj
         self, i: int, j: int, obj: WorldObj
-    ) -> Tuple[WorldObj, Tuple[int, int]]:
+    ) -> tuple[WorldObj, tuple[int, int]]:
         """
         """
         Add an existing object to room (i, j)
         Add an existing object to room (i, j)
         """
         """
@@ -199,9 +199,9 @@ class RoomGrid(MiniGridEnv):
         self,
         self,
         i: int,
         i: int,
         j: int,
         j: int,
-        kind: Optional[str] = None,
-        color: Optional[str] = None,
-    ) -> Tuple[WorldObj, Tuple[int, int]]:
+        kind: str | None = None,
+        color: str | None = None,
+    ) -> tuple[WorldObj, tuple[int, int]]:
         """
         """
         Add a new object to room (i, j)
         Add a new object to room (i, j)
         """
         """
@@ -231,10 +231,10 @@ class RoomGrid(MiniGridEnv):
         self,
         self,
         i: int,
         i: int,
         j: int,
         j: int,
-        door_idx: Optional[int] = None,
-        color: Optional[str] = None,
-        locked: Optional[bool] = None,
-    ) -> Tuple[Door, Tuple[int, int]]:
+        door_idx: int | None = None,
+        color: str | None = None,
+        locked: bool | None = None,
+    ) -> tuple[Door, tuple[int, int]]:
         """
         """
         Add a door to a room, connecting it to a neighbor
         Add a door to a room, connecting it to a neighbor
         """
         """
@@ -311,7 +311,7 @@ class RoomGrid(MiniGridEnv):
         neighbor.doors[(wall_idx + 2) % 4] = True
         neighbor.doors[(wall_idx + 2) % 4] = True
 
 
     def place_agent(
     def place_agent(
-        self, i: Optional[int] = None, j: Optional[int] = None, rand_dir: bool = True
+        self, i: int | None = None, j: int | None = None, rand_dir: bool = True
     ) -> np.ndarray:
     ) -> np.ndarray:
         """
         """
         Place the agent in a room
         Place the agent in a room
@@ -334,8 +334,8 @@ class RoomGrid(MiniGridEnv):
         return self.agent_pos
         return self.agent_pos
 
 
     def connect_all(
     def connect_all(
-        self, door_colors: List[str] = COLOR_NAMES, max_itrs: int = 5000
-    ) -> List[Door]:
+        self, door_colors: list[str] = COLOR_NAMES, max_itrs: int = 5000
+    ) -> list[Door]:
         """
         """
         Make sure that all rooms are reachable by the agent from its
         Make sure that all rooms are reachable by the agent from its
         starting position
         starting position
@@ -395,11 +395,11 @@ class RoomGrid(MiniGridEnv):
 
 
     def add_distractors(
     def add_distractors(
         self,
         self,
-        i: Optional[int] = None,
-        j: Optional[int] = None,
+        i: int | None = None,
+        j: int | None = None,
         num_distractors: int = 10,
         num_distractors: int = 10,
         all_unique: bool = True,
         all_unique: bool = True,
-    ) -> List[WorldObj]:
+    ) -> list[WorldObj]:
         """
         """
         Add random objects that can potentially distract/confuse the agent.
         Add random objects that can potentially distract/confuse the agent.
         """
         """

+ 11 - 7
minigrid/core/world_object.py

@@ -1,4 +1,6 @@
-from typing import TYPE_CHECKING, Optional, Tuple
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Tuple
 
 
 import numpy as np
 import numpy as np
 
 
@@ -19,6 +21,8 @@ from minigrid.utils.rendering import (
 if TYPE_CHECKING:
 if TYPE_CHECKING:
     from minigrid.minigrid_env import MiniGridEnv
     from minigrid.minigrid_env import MiniGridEnv
 
 
+Point = Tuple[int, int]
+
 
 
 class WorldObj:
 class WorldObj:
 
 
@@ -34,10 +38,10 @@ class WorldObj:
         self.contains = None
         self.contains = None
 
 
         # Initial position of the object
         # Initial position of the object
-        self.init_pos = None
+        self.init_pos: Point | None = None
 
 
         # Current position of the object
         # Current position of the object
-        self.cur_pos = None
+        self.cur_pos: Point | None = None
 
 
     def can_overlap(self) -> bool:
     def can_overlap(self) -> bool:
         """Can the agent overlap with this?"""
         """Can the agent overlap with this?"""
@@ -55,16 +59,16 @@ class WorldObj:
         """Can the agent see behind this object?"""
         """Can the agent see behind this object?"""
         return True
         return True
 
 
-    def toggle(self, env: "MiniGridEnv", pos: Tuple[int, int]) -> bool:
+    def toggle(self, env: MiniGridEnv, pos: tuple[int, int]) -> bool:
         """Method to trigger/toggle an action this object performs"""
         """Method to trigger/toggle an action this object performs"""
         return False
         return False
 
 
-    def encode(self) -> Tuple[int, int, int]:
+    def encode(self) -> tuple[int, int, int]:
         """Encode the a description of this object as a 3-tuple of integers"""
         """Encode the a description of this object as a 3-tuple of integers"""
         return (OBJECT_TO_IDX[self.type], COLOR_TO_IDX[self.color], 0)
         return (OBJECT_TO_IDX[self.type], COLOR_TO_IDX[self.color], 0)
 
 
     @staticmethod
     @staticmethod
-    def decode(type_idx: int, color_idx: int, state: int) -> Optional["WorldObj"]:
+    def decode(type_idx: int, color_idx: int, state: int) -> WorldObj | None:
         """Create an object from a 3-tuple state description"""
         """Create an object from a 3-tuple state description"""
 
 
         obj_type = IDX_TO_OBJECT[type_idx]
         obj_type = IDX_TO_OBJECT[type_idx]
@@ -267,7 +271,7 @@ class Ball(WorldObj):
 
 
 
 
 class Box(WorldObj):
 class Box(WorldObj):
-    def __init__(self, color, contains: Optional[WorldObj] = None):
+    def __init__(self, color, contains: WorldObj | None = None):
         super().__init__("box", color)
         super().__init__("box", color)
         self.contains = contains
         self.contains = contains
 
 

+ 2 - 0
minigrid/envs/__init__.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 from minigrid.envs.blockedunlockpickup import BlockedUnlockPickupEnv
 from minigrid.envs.blockedunlockpickup import BlockedUnlockPickupEnv
 from minigrid.envs.crossing import CrossingEnv
 from minigrid.envs.crossing import CrossingEnv
 from minigrid.envs.distshift import DistShiftEnv
 from minigrid.envs.distshift import DistShiftEnv

+ 2 - 0
minigrid/envs/babyai/__init__.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 from minigrid.envs.babyai.goto import (
 from minigrid.envs.babyai.goto import (
     GoTo,
     GoTo,
     GoToDoor,
     GoToDoor,

+ 3 - 1
minigrid/envs/babyai/core/levelgen.py

@@ -1,6 +1,8 @@
 """
 """
 Copied and adapted from https://github.com/mila-iqia/babyai
 Copied and adapted from https://github.com/mila-iqia/babyai
 """
 """
+from __future__ import annotations
+
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.roomgrid import Room
 from minigrid.core.roomgrid import Room
 from minigrid.envs.babyai.core.roomgrid_level import RoomGridLevel
 from minigrid.envs.babyai.core.roomgrid_level import RoomGridLevel
@@ -37,7 +39,7 @@ class LevelGen(RoomGridLevel):
         implicit_unlock=True,
         implicit_unlock=True,
         action_kinds=["goto", "pickup", "open", "putnext"],
         action_kinds=["goto", "pickup", "open", "putnext"],
         instr_kinds=["action", "and", "seq"],
         instr_kinds=["action", "and", "seq"],
-        **kwargs
+        **kwargs,
     ):
     ):
         self.num_dists = num_dists
         self.num_dists = num_dists
         self.locked_room_prob = locked_room_prob
         self.locked_room_prob = locked_room_prob

+ 3 - 3
minigrid/envs/babyai/core/roomgrid_level.py

@@ -1,7 +1,7 @@
 """
 """
 Copied and adapted from https://github.com/mila-iqia/babyai
 Copied and adapted from https://github.com/mila-iqia/babyai
 """
 """
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.roomgrid import RoomGrid
 from minigrid.core.roomgrid import RoomGrid
 from minigrid.envs.babyai.core.verifier import (
 from minigrid.envs.babyai.core.verifier import (
@@ -50,7 +50,7 @@ class RoomGridLevel(RoomGrid):
     of approximately similar difficulty.
     of approximately similar difficulty.
     """
     """
 
 
-    def __init__(self, room_size=8, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, room_size=8, max_steps: int | None = None, **kwargs):
         mission_space = BabyAIMissionSpace()
         mission_space = BabyAIMissionSpace()
 
 
         # If `max_steps` arg is passed it will be fixed for every episode,
         # If `max_steps` arg is passed it will be fixed for every episode,
@@ -64,7 +64,7 @@ class RoomGridLevel(RoomGrid):
             room_size=room_size,
             room_size=room_size,
             mission_space=mission_space,
             mission_space=mission_space,
             max_steps=max_steps,
             max_steps=max_steps,
-            **kwargs
+            **kwargs,
         )
         )
 
 
     def reset(self, **kwargs):
     def reset(self, **kwargs):

+ 2 - 0
minigrid/envs/babyai/core/verifier.py

@@ -1,6 +1,8 @@
 """
 """
 Copied and adapted from https://github.com/mila-iqia/babyai
 Copied and adapted from https://github.com/mila-iqia/babyai
 """
 """
+from __future__ import annotations
+
 import os
 import os
 from abc import ABC, abstractmethod
 from abc import ABC, abstractmethod
 
 

+ 4 - 2
minigrid/envs/babyai/goto.py

@@ -2,6 +2,8 @@
 Copied and adapted from https://github.com/mila-iqia/babyai.
 Copied and adapted from https://github.com/mila-iqia/babyai.
 Levels described in the Baby AI ICLR 2019 submission, with the `Go to` instruction.
 Levels described in the Baby AI ICLR 2019 submission, with the `Go to` instruction.
 """
 """
+from __future__ import annotations
+
 from minigrid.envs.babyai.core.levelgen import LevelGen
 from minigrid.envs.babyai.core.levelgen import LevelGen
 from minigrid.envs.babyai.core.roomgrid_level import RejectSampling, RoomGridLevel
 from minigrid.envs.babyai.core.roomgrid_level import RejectSampling, RoomGridLevel
 from minigrid.envs.babyai.core.verifier import GoToInstr, ObjDesc
 from minigrid.envs.babyai.core.verifier import GoToInstr, ObjDesc
@@ -106,7 +108,7 @@ class GoTo(RoomGridLevel):
         num_cols=3,
         num_cols=3,
         num_dists=18,
         num_dists=18,
         doors_open=False,
         doors_open=False,
-        **kwargs
+        **kwargs,
     ):
     ):
         self.num_dists = num_dists
         self.num_dists = num_dists
         self.doors_open = doors_open
         self.doors_open = doors_open
@@ -198,7 +200,7 @@ class GoToSeq(LevelGen):
             locked_room_prob=0,
             locked_room_prob=0,
             locations=False,
             locations=False,
             unblocking=False,
             unblocking=False,
-            **kwargs
+            **kwargs,
         )
         )
 
 
 
 

+ 4 - 6
minigrid/envs/babyai/open.py

@@ -2,7 +2,7 @@
 Copied and adapted from https://github.com/mila-iqia/babyai.
 Copied and adapted from https://github.com/mila-iqia/babyai.
 Levels described in the Baby AI ICLR 2019 submission, with the `Open` instruction.
 Levels described in the Baby AI ICLR 2019 submission, with the `Open` instruction.
 """
 """
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.envs.babyai.core.roomgrid_level import RoomGridLevel
 from minigrid.envs.babyai.core.roomgrid_level import RoomGridLevel
@@ -103,8 +103,8 @@ class OpenTwoDoors(RoomGridLevel):
         first_color=None,
         first_color=None,
         second_color=None,
         second_color=None,
         strict=False,
         strict=False,
-        max_steps: Optional[int] = None,
-        **kwargs
+        max_steps: int | None = None,
+        **kwargs,
     ):
     ):
         self.first_color = first_color
         self.first_color = first_color
         self.second_color = second_color
         self.second_color = second_color
@@ -142,9 +142,7 @@ class OpenDoorsOrder(RoomGridLevel):
     Open one or two doors in the order specified.
     Open one or two doors in the order specified.
     """
     """
 
 
-    def __init__(
-        self, num_doors, debug=False, max_steps: Optional[int] = None, **kwargs
-    ):
+    def __init__(self, num_doors, debug=False, max_steps: int | None = None, **kwargs):
         assert num_doors >= 2
         assert num_doors >= 2
         self.num_doors = num_doors
         self.num_doors = num_doors
         self.debug = debug
         self.debug = debug

+ 5 - 5
minigrid/envs/babyai/other.py

@@ -2,7 +2,7 @@
 Copied and adapted from https://github.com/mila-iqia/babyai.
 Copied and adapted from https://github.com/mila-iqia/babyai.
 Levels described in the Baby AI ICLR 2019 submission, with different instructions than those in other files.
 Levels described in the Baby AI ICLR 2019 submission, with different instructions than those in other files.
 """
 """
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.envs.babyai.core.roomgrid_level import RoomGridLevel
 from minigrid.envs.babyai.core.roomgrid_level import RoomGridLevel
 from minigrid.envs.babyai.core.verifier import (
 from minigrid.envs.babyai.core.verifier import (
@@ -56,7 +56,7 @@ class FindObjS5(RoomGridLevel):
     This level requires potentially exhaustive exploration
     This level requires potentially exhaustive exploration
     """
     """
 
 
-    def __init__(self, room_size=5, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, room_size=5, max_steps: int | None = None, **kwargs):
 
 
         if max_steps is None:
         if max_steps is None:
             max_steps = 20 * room_size**2
             max_steps = 20 * room_size**2
@@ -85,8 +85,8 @@ class KeyCorridor(RoomGridLevel):
         num_rows=3,
         num_rows=3,
         obj_type="ball",
         obj_type="ball",
         room_size=6,
         room_size=6,
-        max_steps: Optional[int] = None,
-        **kwargs
+        max_steps: int | None = None,
+        **kwargs,
     ):
     ):
         self.obj_type = obj_type
         self.obj_type = obj_type
 
 
@@ -143,7 +143,7 @@ class MoveTwoAcross(RoomGridLevel):
     """
     """
 
 
     def __init__(
     def __init__(
-        self, room_size, objs_per_room, max_steps: Optional[int] = None, **kwargs
+        self, room_size, objs_per_room, max_steps: int | None = None, **kwargs
     ):
     ):
         assert objs_per_room <= 9
         assert objs_per_room <= 9
         self.objs_per_room = objs_per_room
         self.objs_per_room = objs_per_room

+ 3 - 3
minigrid/envs/babyai/pickup.py

@@ -2,7 +2,7 @@
 Copied and adapted from https://github.com/mila-iqia/babyai.
 Copied and adapted from https://github.com/mila-iqia/babyai.
 Levels described in the Baby AI ICLR 2019 submission, with the `Pick up` instruction.
 Levels described in the Baby AI ICLR 2019 submission, with the `Pick up` instruction.
 """
 """
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.envs.babyai.core.levelgen import LevelGen
 from minigrid.envs.babyai.core.levelgen import LevelGen
 from minigrid.envs.babyai.core.roomgrid_level import RejectSampling, RoomGridLevel
 from minigrid.envs.babyai.core.roomgrid_level import RejectSampling, RoomGridLevel
@@ -63,7 +63,7 @@ class PickupLoc(LevelGen):
             locked_room_prob=0,
             locked_room_prob=0,
             locations=True,
             locations=True,
             unblocking=False,
             unblocking=False,
-            **kwargs
+            **kwargs,
         )
         )
 
 
 
 
@@ -102,7 +102,7 @@ class PickupAbove(RoomGridLevel):
     This task requires to use the compass to be solved effectively.
     This task requires to use the compass to be solved effectively.
     """
     """
 
 
-    def __init__(self, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, max_steps: int | None = None, **kwargs):
         room_size = 6
         room_size = 6
         if max_steps is None:
         if max_steps is None:
             max_steps = 8 * room_size**2
             max_steps = 8 * room_size**2

+ 4 - 3
minigrid/envs/babyai/putnext.py

@@ -2,7 +2,7 @@
 Copied and adapted from https://github.com/mila-iqia/babyai.
 Copied and adapted from https://github.com/mila-iqia/babyai.
 Levels described in the Baby AI ICLR 2019 submission, with the `Put Next` instruction.
 Levels described in the Baby AI ICLR 2019 submission, with the `Put Next` instruction.
 """
 """
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.envs.babyai.core.roomgrid_level import RoomGridLevel
 from minigrid.envs.babyai.core.roomgrid_level import RoomGridLevel
 from minigrid.envs.babyai.core.verifier import ObjDesc, PutNextInstr
 from minigrid.envs.babyai.core.verifier import ObjDesc, PutNextInstr
@@ -41,8 +41,8 @@ class PutNext(RoomGridLevel):
         room_size,
         room_size,
         objs_per_room,
         objs_per_room,
         start_carrying=False,
         start_carrying=False,
-        max_steps: Optional[int] = None,
-        **kwargs
+        max_steps: int | None = None,
+        **kwargs,
     ):
     ):
         assert room_size >= 4
         assert room_size >= 4
         assert objs_per_room <= 9
         assert objs_per_room <= 9
@@ -86,6 +86,7 @@ class PutNext(RoomGridLevel):
 
 
         # If the agent starts off carrying the object
         # If the agent starts off carrying the object
         if self.start_carrying:
         if self.start_carrying:
+            assert self.obj_a.init_pos is not None
             self.grid.set(*self.obj_a.init_pos, None)
             self.grid.set(*self.obj_a.init_pos, None)
             self.carrying = self.obj_a
             self.carrying = self.obj_a
 
 

+ 5 - 3
minigrid/envs/babyai/synth.py

@@ -4,6 +4,8 @@ Levels described in the Baby AI ICLR 2019 submission.
 The instructions are a synthesis of those from `PutNext`, `Open`, `GoTo`, and `Pickup`.
 The instructions are a synthesis of those from `PutNext`, `Open`, `GoTo`, and `Pickup`.
 """
 """
 
 
+from __future__ import annotations
+
 from minigrid.envs.babyai.core.levelgen import LevelGen
 from minigrid.envs.babyai.core.levelgen import LevelGen
 
 
 
 
@@ -28,7 +30,7 @@ class Synth(LevelGen):
             locations=False,
             locations=False,
             unblocking=True,
             unblocking=True,
             implicit_unlock=False,
             implicit_unlock=False,
-            **kwargs
+            **kwargs,
         )
         )
 
 
 
 
@@ -53,7 +55,7 @@ class SynthLoc(LevelGen):
             locations=True,
             locations=True,
             unblocking=True,
             unblocking=True,
             implicit_unlock=False,
             implicit_unlock=False,
-            **kwargs
+            **kwargs,
         )
         )
 
 
 
 
@@ -81,7 +83,7 @@ class MiniBossLevel(LevelGen):
             room_size=5,
             room_size=5,
             num_dists=7,
             num_dists=7,
             locked_room_prob=0.25,
             locked_room_prob=0.25,
-            **kwargs
+            **kwargs,
         )
         )
 
 
 
 

+ 4 - 4
minigrid/envs/babyai/unlock.py

@@ -2,7 +2,7 @@
 Copied and adapted from https://github.com/mila-iqia/babyai.
 Copied and adapted from https://github.com/mila-iqia/babyai.
 Levels described in the Baby AI ICLR 2019 submission, with the `Unlock` instruction.
 Levels described in the Baby AI ICLR 2019 submission, with the `Unlock` instruction.
 """
 """
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.world_object import Ball, Box, Key
 from minigrid.core.world_object import Ball, Box, Key
@@ -110,7 +110,7 @@ class UnlockPickup(RoomGridLevel):
     Unlock a door, then pick up a box in another room
     Unlock a door, then pick up a box in another room
     """
     """
 
 
-    def __init__(self, distractors=False, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, distractors=False, max_steps: int | None = None, **kwargs):
         self.distractors = distractors
         self.distractors = distractors
         room_size = 6
         room_size = 6
         if max is None:
         if max is None:
@@ -141,7 +141,7 @@ class BlockedUnlockPickup(RoomGridLevel):
     in another room
     in another room
     """
     """
 
 
-    def __init__(self, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, max_steps: int | None = None, **kwargs):
         room_size = 6
         room_size = 6
         if max_steps is None:
         if max_steps is None:
             max_steps = 16 * room_size**2
             max_steps = 16 * room_size**2
@@ -171,7 +171,7 @@ class UnlockToUnlock(RoomGridLevel):
     Unlock a door A that requires to unlock a door B before
     Unlock a door A that requires to unlock a door B before
     """
     """
 
 
-    def __init__(self, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, max_steps: int | None = None, **kwargs):
         room_size = 6
         room_size = 6
         if max_steps is None:
         if max_steps is None:
             max_steps = 30 * room_size**2
             max_steps = 30 * room_size**2

+ 2 - 2
minigrid/envs/blockedunlockpickup.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.mission import MissionSpace
 from minigrid.core.mission import MissionSpace
@@ -64,7 +64,7 @@ class BlockedUnlockPickupEnv(RoomGrid):
 
 
     """
     """
 
 
-    def __init__(self, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, max_steps: int | None = None, **kwargs):
         mission_space = MissionSpace(
         mission_space = MissionSpace(
             mission_func=self._gen_mission,
             mission_func=self._gen_mission,
             ordered_placeholders=[COLOR_NAMES, ["box", "key"]],
             ordered_placeholders=[COLOR_NAMES, ["box", "key"]],

+ 5 - 4
minigrid/envs/crossing.py

@@ -1,5 +1,6 @@
+from __future__ import annotations
+
 import itertools as itt
 import itertools as itt
-from typing import Optional
 
 
 import numpy as np
 import numpy as np
 
 
@@ -88,8 +89,8 @@ class CrossingEnv(MiniGridEnv):
         size=9,
         size=9,
         num_crossings=1,
         num_crossings=1,
         obstacle_type=Lava,
         obstacle_type=Lava,
-        max_steps: Optional[int] = None,
-        **kwargs
+        max_steps: int | None = None,
+        **kwargs,
     ):
     ):
         self.num_crossings = num_crossings
         self.num_crossings = num_crossings
         self.obstacle_type = obstacle_type
         self.obstacle_type = obstacle_type
@@ -107,7 +108,7 @@ class CrossingEnv(MiniGridEnv):
             grid_size=size,
             grid_size=size,
             see_through_walls=False,  # Set this to True for maximum speed
             see_through_walls=False,  # Set this to True for maximum speed
             max_steps=max_steps,
             max_steps=max_steps,
-            **kwargs
+            **kwargs,
         )
         )
 
 
     @staticmethod
     @staticmethod

+ 4 - 4
minigrid/envs/distshift.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
 from minigrid.core.mission import MissionSpace
 from minigrid.core.mission import MissionSpace
@@ -69,8 +69,8 @@ class DistShiftEnv(MiniGridEnv):
         agent_start_pos=(1, 1),
         agent_start_pos=(1, 1),
         agent_start_dir=0,
         agent_start_dir=0,
         strip2_row=2,
         strip2_row=2,
-        max_steps: Optional[int] = None,
-        **kwargs
+        max_steps: int | None = None,
+        **kwargs,
     ):
     ):
         self.agent_start_pos = agent_start_pos
         self.agent_start_pos = agent_start_pos
         self.agent_start_dir = agent_start_dir
         self.agent_start_dir = agent_start_dir
@@ -89,7 +89,7 @@ class DistShiftEnv(MiniGridEnv):
             # Set this to True for maximum speed
             # Set this to True for maximum speed
             see_through_walls=True,
             see_through_walls=True,
             max_steps=max_steps,
             max_steps=max_steps,
-            **kwargs
+            **kwargs,
         )
         )
 
 
     @staticmethod
     @staticmethod

+ 2 - 2
minigrid/envs/doorkey.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
 from minigrid.core.mission import MissionSpace
 from minigrid.core.mission import MissionSpace
@@ -60,7 +60,7 @@ class DoorKeyEnv(MiniGridEnv):
 
 
     """
     """
 
 
-    def __init__(self, size=8, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, size=8, max_steps: int | None = None, **kwargs):
         if max_steps is None:
         if max_steps is None:
             max_steps = 10 * size**2
             max_steps = 10 * size**2
         mission_space = MissionSpace(mission_func=self._gen_mission)
         mission_space = MissionSpace(mission_func=self._gen_mission)

+ 5 - 4
minigrid/envs/dynamicobstacles.py

@@ -1,5 +1,6 @@
+from __future__ import annotations
+
 from operator import add
 from operator import add
-from typing import Optional
 
 
 from gymnasium.spaces import Discrete
 from gymnasium.spaces import Discrete
 
 
@@ -74,8 +75,8 @@ class DynamicObstaclesEnv(MiniGridEnv):
         agent_start_pos=(1, 1),
         agent_start_pos=(1, 1),
         agent_start_dir=0,
         agent_start_dir=0,
         n_obstacles=4,
         n_obstacles=4,
-        max_steps: Optional[int] = None,
-        **kwargs
+        max_steps: int | None = None,
+        **kwargs,
     ):
     ):
         self.agent_start_pos = agent_start_pos
         self.agent_start_pos = agent_start_pos
         self.agent_start_dir = agent_start_dir
         self.agent_start_dir = agent_start_dir
@@ -97,7 +98,7 @@ class DynamicObstaclesEnv(MiniGridEnv):
             # Set this to True for maximum speed
             # Set this to True for maximum speed
             see_through_walls=True,
             see_through_walls=True,
             max_steps=max_steps,
             max_steps=max_steps,
-            **kwargs
+            **kwargs,
         )
         )
         # Allow only 3 actions permitted: left, right, forward
         # Allow only 3 actions permitted: left, right, forward
         self.action_space = Discrete(self.actions.forward + 1)
         self.action_space = Discrete(self.actions.forward + 1)

+ 4 - 4
minigrid/envs/empty.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
 from minigrid.core.mission import MissionSpace
 from minigrid.core.mission import MissionSpace
@@ -70,8 +70,8 @@ class EmptyEnv(MiniGridEnv):
         size=8,
         size=8,
         agent_start_pos=(1, 1),
         agent_start_pos=(1, 1),
         agent_start_dir=0,
         agent_start_dir=0,
-        max_steps: Optional[int] = None,
-        **kwargs
+        max_steps: int | None = None,
+        **kwargs,
     ):
     ):
         self.agent_start_pos = agent_start_pos
         self.agent_start_pos = agent_start_pos
         self.agent_start_dir = agent_start_dir
         self.agent_start_dir = agent_start_dir
@@ -87,7 +87,7 @@ class EmptyEnv(MiniGridEnv):
             # Set this to True for maximum speed
             # Set this to True for maximum speed
             see_through_walls=True,
             see_through_walls=True,
             max_steps=max_steps,
             max_steps=max_steps,
-            **kwargs
+            **kwargs,
         )
         )
 
 
     @staticmethod
     @staticmethod

+ 2 - 2
minigrid/envs/fetch.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
@@ -71,7 +71,7 @@ class FetchEnv(MiniGridEnv):
 
 
     """
     """
 
 
-    def __init__(self, size=8, numObjs=3, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, size=8, numObjs=3, max_steps: int | None = None, **kwargs):
         self.numObjs = numObjs
         self.numObjs = numObjs
         self.obj_types = ["key", "ball"]
         self.obj_types = ["key", "ball"]
 
 

+ 3 - 1
minigrid/envs/fourrooms.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
 from minigrid.core.mission import MissionSpace
 from minigrid.core.mission import MissionSpace
 from minigrid.core.world_object import Goal
 from minigrid.core.world_object import Goal
@@ -67,7 +69,7 @@ class FourRoomsEnv(MiniGridEnv):
             width=self.size,
             width=self.size,
             height=self.size,
             height=self.size,
             max_steps=max_steps,
             max_steps=max_steps,
-            **kwargs
+            **kwargs,
         )
         )
 
 
     @staticmethod
     @staticmethod

+ 2 - 2
minigrid/envs/gotodoor.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
@@ -63,7 +63,7 @@ class GoToDoorEnv(MiniGridEnv):
 
 
     """
     """
 
 
-    def __init__(self, size=5, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, size=5, max_steps: int | None = None, **kwargs):
         assert size >= 5
         assert size >= 5
         self.size = size
         self.size = size
         mission_space = MissionSpace(
         mission_space = MissionSpace(

+ 2 - 2
minigrid/envs/gotoobject.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
@@ -13,7 +13,7 @@ class GoToObjectEnv(MiniGridEnv):
     named using an English text string
     named using an English text string
     """
     """
 
 
-    def __init__(self, size=6, numObjs=2, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, size=6, numObjs=2, max_steps: int | None = None, **kwargs):
 
 
         self.numObjs = numObjs
         self.numObjs = numObjs
         self.size = size
         self.size = size

+ 2 - 2
minigrid/envs/keycorridor.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.mission import MissionSpace
 from minigrid.core.mission import MissionSpace
@@ -77,7 +77,7 @@ class KeyCorridorEnv(RoomGrid):
         num_rows=3,
         num_rows=3,
         obj_type="ball",
         obj_type="ball",
         room_size=6,
         room_size=6,
-        max_steps: Optional[int] = None,
+        max_steps: int | None = None,
         **kwargs,
         **kwargs,
     ):
     ):
         self.obj_type = obj_type
         self.obj_type = obj_type

+ 3 - 3
minigrid/envs/lavagap.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 import numpy as np
 import numpy as np
 
 
@@ -67,7 +67,7 @@ class LavaGapEnv(MiniGridEnv):
     """
     """
 
 
     def __init__(
     def __init__(
-        self, size, obstacle_type=Lava, max_steps: Optional[int] = None, **kwargs
+        self, size, obstacle_type=Lava, max_steps: int | None = None, **kwargs
     ):
     ):
         self.obstacle_type = obstacle_type
         self.obstacle_type = obstacle_type
         self.size = size
         self.size = size
@@ -87,7 +87,7 @@ class LavaGapEnv(MiniGridEnv):
             # Set this to True for maximum speed
             # Set this to True for maximum speed
             see_through_walls=False,
             see_through_walls=False,
             max_steps=max_steps,
             max_steps=max_steps,
-            **kwargs
+            **kwargs,
         )
         )
 
 
     @staticmethod
     @staticmethod

+ 2 - 2
minigrid/envs/lockedroom.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
@@ -76,7 +76,7 @@ class LockedRoomEnv(MiniGridEnv):
 
 
     """
     """
 
 
-    def __init__(self, size=19, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, size=19, max_steps: int | None = None, **kwargs):
         self.size = size
         self.size = size
 
 
         if max_steps is None:
         if max_steps is None:

+ 3 - 3
minigrid/envs/memory.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 import numpy as np
 import numpy as np
 
 
@@ -68,7 +68,7 @@ class MemoryEnv(MiniGridEnv):
     """
     """
 
 
     def __init__(
     def __init__(
-        self, size=8, random_length=False, max_steps: Optional[int] = None, **kwargs
+        self, size=8, random_length=False, max_steps: int | None = None, **kwargs
     ):
     ):
         self.size = size
         self.size = size
         self.random_length = random_length
         self.random_length = random_length
@@ -84,7 +84,7 @@ class MemoryEnv(MiniGridEnv):
             # Set this to True for maximum speed
             # Set this to True for maximum speed
             see_through_walls=False,
             see_through_walls=False,
             max_steps=max_steps,
             max_steps=max_steps,
-            **kwargs
+            **kwargs,
         )
         )
 
 
     @staticmethod
     @staticmethod

+ 4 - 4
minigrid/envs/multiroom.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
@@ -77,8 +77,8 @@ class MultiRoomEnv(MiniGridEnv):
         minNumRooms,
         minNumRooms,
         maxNumRooms,
         maxNumRooms,
         maxRoomSize=10,
         maxRoomSize=10,
-        max_steps: Optional[int] = None,
-        **kwargs
+        max_steps: int | None = None,
+        **kwargs,
     ):
     ):
         assert minNumRooms > 0
         assert minNumRooms > 0
         assert maxNumRooms >= minNumRooms
         assert maxNumRooms >= minNumRooms
@@ -102,7 +102,7 @@ class MultiRoomEnv(MiniGridEnv):
             width=self.size,
             width=self.size,
             height=self.size,
             height=self.size,
             max_steps=max_steps,
             max_steps=max_steps,
-            **kwargs
+            **kwargs,
         )
         )
 
 
     @staticmethod
     @staticmethod

+ 2 - 2
minigrid/envs/obstructedmaze.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.constants import COLOR_NAMES, DIR_TO_VEC
 from minigrid.core.constants import COLOR_NAMES, DIR_TO_VEC
 from minigrid.core.mission import MissionSpace
 from minigrid.core.mission import MissionSpace
@@ -76,7 +76,7 @@ class ObstructedMazeEnv(RoomGrid):
         num_rows,
         num_rows,
         num_cols,
         num_cols,
         num_rooms_visited,
         num_rooms_visited,
-        max_steps: Optional[int] = None,
+        max_steps: int | None = None,
         **kwargs,
         **kwargs,
     ):
     ):
         room_size = 6
         room_size = 6

+ 3 - 1
minigrid/envs/playground.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
 from minigrid.core.mission import MissionSpace
 from minigrid.core.mission import MissionSpace
@@ -19,7 +21,7 @@ class PlaygroundEnv(MiniGridEnv):
             width=self.size,
             width=self.size,
             height=self.size,
             height=self.size,
             max_steps=max_steps,
             max_steps=max_steps,
-            **kwargs
+            **kwargs,
         )
         )
 
 
     @staticmethod
     @staticmethod

+ 2 - 2
minigrid/envs/putnear.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
@@ -67,7 +67,7 @@ class PutNearEnv(MiniGridEnv):
 
 
     """
     """
 
 
-    def __init__(self, size=6, numObjs=2, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, size=6, numObjs=2, max_steps: int | None = None, **kwargs):
         self.size = size
         self.size = size
         self.numObjs = numObjs
         self.numObjs = numObjs
         self.obj_types = ["key", "ball", "box"]
         self.obj_types = ["key", "ball", "box"]

+ 2 - 2
minigrid/envs/redbluedoors.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
 from minigrid.core.mission import MissionSpace
 from minigrid.core.mission import MissionSpace
@@ -59,7 +59,7 @@ class RedBlueDoorEnv(MiniGridEnv):
 
 
     """
     """
 
 
-    def __init__(self, size=8, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, size=8, max_steps: int | None = None, **kwargs):
         self.size = size
         self.size = size
         mission_space = MissionSpace(mission_func=self._gen_mission)
         mission_space = MissionSpace(mission_func=self._gen_mission)
 
 

+ 3 - 3
minigrid/envs/unlock.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.mission import MissionSpace
 from minigrid.core.mission import MissionSpace
 from minigrid.core.roomgrid import RoomGrid
 from minigrid.core.roomgrid import RoomGrid
@@ -53,7 +53,7 @@ class UnlockEnv(RoomGrid):
 
 
     """
     """
 
 
-    def __init__(self, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, max_steps: int | None = None, **kwargs):
         room_size = 6
         room_size = 6
         mission_space = MissionSpace(mission_func=self._gen_mission)
         mission_space = MissionSpace(mission_func=self._gen_mission)
 
 
@@ -66,7 +66,7 @@ class UnlockEnv(RoomGrid):
             num_cols=2,
             num_cols=2,
             room_size=room_size,
             room_size=room_size,
             max_steps=max_steps,
             max_steps=max_steps,
-            **kwargs
+            **kwargs,
         )
         )
 
 
     @staticmethod
     @staticmethod

+ 2 - 2
minigrid/envs/unlockpickup.py

@@ -1,4 +1,4 @@
-from typing import Optional
+from __future__ import annotations
 
 
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.constants import COLOR_NAMES
 from minigrid.core.mission import MissionSpace
 from minigrid.core.mission import MissionSpace
@@ -57,7 +57,7 @@ class UnlockPickupEnv(RoomGrid):
 
 
     """
     """
 
 
-    def __init__(self, max_steps: Optional[int] = None, **kwargs):
+    def __init__(self, max_steps: int | None = None, **kwargs):
         room_size = 6
         room_size = 6
         mission_space = MissionSpace(
         mission_space = MissionSpace(
             mission_func=self._gen_mission,
             mission_func=self._gen_mission,

+ 2 - 0
minigrid/manual_control.py

@@ -1,5 +1,7 @@
 #!/usr/bin/env python3
 #!/usr/bin/env python3
 
 
+from __future__ import annotations
+
 import gymnasium as gym
 import gymnasium as gym
 
 
 from minigrid.minigrid_env import MiniGridEnv
 from minigrid.minigrid_env import MiniGridEnv

+ 40 - 27
minigrid/minigrid_env.py

@@ -1,8 +1,10 @@
+from __future__ import annotations
+
 import hashlib
 import hashlib
 import math
 import math
 from abc import abstractmethod
 from abc import abstractmethod
 from enum import IntEnum
 from enum import IntEnum
-from typing import Optional
+from typing import Iterable, TypeVar
 
 
 import gymnasium as gym
 import gymnasium as gym
 import numpy as np
 import numpy as np
@@ -11,8 +13,11 @@ from gymnasium import spaces
 from minigrid.core.constants import COLOR_NAMES, DIR_TO_VEC, TILE_PIXELS
 from minigrid.core.constants import COLOR_NAMES, DIR_TO_VEC, TILE_PIXELS
 from minigrid.core.grid import Grid
 from minigrid.core.grid import Grid
 from minigrid.core.mission import MissionSpace
 from minigrid.core.mission import MissionSpace
+from minigrid.core.world_object import Point, WorldObj
 from minigrid.utils.window import Window
 from minigrid.utils.window import Window
 
 
+T = TypeVar("T")
+
 
 
 class MiniGridEnv(gym.Env):
 class MiniGridEnv(gym.Env):
     """
     """
@@ -43,13 +48,13 @@ class MiniGridEnv(gym.Env):
     def __init__(
     def __init__(
         self,
         self,
         mission_space: MissionSpace,
         mission_space: MissionSpace,
-        grid_size: int = None,
-        width: int = None,
-        height: int = None,
+        grid_size: int | None = None,
+        width: int | None = None,
+        height: int | None = None,
         max_steps: int = 100,
         max_steps: int = 100,
         see_through_walls: bool = False,
         see_through_walls: bool = False,
         agent_view_size: int = 7,
         agent_view_size: int = 7,
-        render_mode: Optional[str] = None,
+        render_mode: str | None = None,
         highlight: bool = True,
         highlight: bool = True,
         tile_size: int = TILE_PIXELS,
         tile_size: int = TILE_PIXELS,
         agent_pov: bool = False,
         agent_pov: bool = False,
@@ -62,6 +67,7 @@ class MiniGridEnv(gym.Env):
             assert width is None and height is None
             assert width is None and height is None
             width = grid_size
             width = grid_size
             height = grid_size
             height = grid_size
+        assert width is not None and height is not None
 
 
         # Action enumeration for this environment
         # Action enumeration for this environment
         self.actions = MiniGridEnv.Actions
         self.actions = MiniGridEnv.Actions
@@ -107,7 +113,7 @@ class MiniGridEnv(gym.Env):
         self.see_through_walls = see_through_walls
         self.see_through_walls = see_through_walls
 
 
         # Current position and direction of the agent
         # Current position and direction of the agent
-        self.agent_pos: np.ndarray = None
+        self.agent_pos: np.ndarray | tuple[int, int] = None
         self.agent_dir: int = None
         self.agent_dir: int = None
 
 
         # Current grid and mission and carrying
         # Current grid and mission and carrying
@@ -228,35 +234,35 @@ class MiniGridEnv(gym.Env):
     def _gen_grid(self, width, height):
     def _gen_grid(self, width, height):
         pass
         pass
 
 
-    def _reward(self):
+    def _reward(self) -> float:
         """
         """
         Compute the reward to be given upon success
         Compute the reward to be given upon success
         """
         """
 
 
         return 1 - 0.9 * (self.step_count / self.max_steps)
         return 1 - 0.9 * (self.step_count / self.max_steps)
 
 
-    def _rand_int(self, low, high):
+    def _rand_int(self, low: int, high: int) -> int:
         """
         """
         Generate random integer in [low,high[
         Generate random integer in [low,high[
         """
         """
 
 
         return self.np_random.integers(low, high)
         return self.np_random.integers(low, high)
 
 
-    def _rand_float(self, low, high):
+    def _rand_float(self, low: float, high: float) -> float:
         """
         """
         Generate random float in [low,high[
         Generate random float in [low,high[
         """
         """
 
 
         return self.np_random.uniform(low, high)
         return self.np_random.uniform(low, high)
 
 
-    def _rand_bool(self):
+    def _rand_bool(self) -> bool:
         """
         """
         Generate random boolean value
         Generate random boolean value
         """
         """
 
 
         return self.np_random.integers(0, 2) == 0
         return self.np_random.integers(0, 2) == 0
 
 
-    def _rand_elem(self, iterable):
+    def _rand_elem(self, iterable: Iterable[T]) -> T:
         """
         """
         Pick a random element in a list
         Pick a random element in a list
         """
         """
@@ -265,7 +271,7 @@ class MiniGridEnv(gym.Env):
         idx = self._rand_int(0, len(lst))
         idx = self._rand_int(0, len(lst))
         return lst[idx]
         return lst[idx]
 
 
-    def _rand_subset(self, iterable, num_elems):
+    def _rand_subset(self, iterable: Iterable[T], num_elems: int) -> list[T]:
         """
         """
         Sample a random subset of distinct elements of a list
         Sample a random subset of distinct elements of a list
         """
         """
@@ -273,7 +279,7 @@ class MiniGridEnv(gym.Env):
         lst = list(iterable)
         lst = list(iterable)
         assert num_elems <= len(lst)
         assert num_elems <= len(lst)
 
 
-        out = []
+        out: list[T] = []
 
 
         while len(out) < num_elems:
         while len(out) < num_elems:
             elem = self._rand_elem(lst)
             elem = self._rand_elem(lst)
@@ -282,24 +288,33 @@ class MiniGridEnv(gym.Env):
 
 
         return out
         return out
 
 
-    def _rand_color(self):
+    def _rand_color(self) -> str:
         """
         """
         Generate a random color name (string)
         Generate a random color name (string)
         """
         """
 
 
         return self._rand_elem(COLOR_NAMES)
         return self._rand_elem(COLOR_NAMES)
 
 
-    def _rand_pos(self, xLow, xHigh, yLow, yHigh):
+    def _rand_pos(
+        self, x_low: int, x_high: int, y_low: int, y_high: int
+    ) -> tuple[int, int]:
         """
         """
         Generate a random (x,y) position tuple
         Generate a random (x,y) position tuple
         """
         """
 
 
         return (
         return (
-            self.np_random.integers(xLow, xHigh),
-            self.np_random.integers(yLow, yHigh),
+            self.np_random.integers(x_low, x_high),
+            self.np_random.integers(y_low, y_high),
         )
         )
 
 
-    def place_obj(self, obj, top=None, size=None, reject_fn=None, max_tries=math.inf):
+    def place_obj(
+        self,
+        obj: WorldObj | None,
+        top: Point = None,
+        size: tuple[int, int] = None,
+        reject_fn=None,
+        max_tries=math.inf,
+    ):
         """
         """
         Place an object at an empty position in the grid
         Place an object at an empty position in the grid
 
 
@@ -326,15 +341,11 @@ class MiniGridEnv(gym.Env):
 
 
             num_tries += 1
             num_tries += 1
 
 
-            pos = np.array(
-                (
-                    self._rand_int(top[0], min(top[0] + size[0], self.grid.width)),
-                    self._rand_int(top[1], min(top[1] + size[1], self.grid.height)),
-                )
+            pos = (
+                self._rand_int(top[0], min(top[0] + size[0], self.grid.width)),
+                self._rand_int(top[1], min(top[1] + size[1], self.grid.height)),
             )
             )
 
 
-            pos = tuple(pos)
-
             # Don't place the object on top of another object
             # Don't place the object on top of another object
             if self.grid.get(*pos) is not None:
             if self.grid.get(*pos) is not None:
                 continue
                 continue
@@ -357,7 +368,7 @@ class MiniGridEnv(gym.Env):
 
 
         return pos
         return pos
 
 
-    def put_obj(self, obj, i, j):
+    def put_obj(self, obj: WorldObj, i: int, j: int):
         """
         """
         Put an object at a specific position in the grid
         Put an object at a specific position in the grid
         """
         """
@@ -387,7 +398,9 @@ class MiniGridEnv(gym.Env):
         of forward movement.
         of forward movement.
         """
         """
 
 
-        assert self.agent_dir >= 0 and self.agent_dir < 4
+        assert (
+            self.agent_dir >= 0 and self.agent_dir < 4
+        ), f"Invalid agent_dir: {self.agent_dir} is not within range(0, 4)"
         return DIR_TO_VEC[self.agent_dir]
         return DIR_TO_VEC[self.agent_dir]
 
 
     @property
     @property

+ 0 - 0
minigrid/py.typed


+ 2 - 0
minigrid/utils/rendering.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import math
 import math
 
 
 import numpy as np
 import numpy as np

+ 2 - 0
minigrid/wrappers.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import math
 import math
 import operator
 import operator
 from functools import reduce
 from functools import reduce

+ 5 - 0
pyproject.toml

@@ -35,3 +35,8 @@ reportPrivateImportUsage = "none"
 
 
 [tool.pytest.ini_options]
 [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
+
+[tool.isort]
+profile = "black"
+add_imports = [ "from __future__ import annotations" ]
+append_only = true

+ 2 - 0
setup.py

@@ -1,5 +1,7 @@
 """Setups up the Minigrid module."""
 """Setups up the Minigrid module."""
 
 
+from __future__ import annotations
+
 from setuptools import find_packages, setup
 from setuptools import find_packages, setup
 
 
 
 

+ 2 - 0
tests/test_envs.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import pickle
 import pickle
 import warnings
 import warnings
 
 

+ 2 - 0
tests/test_scripts.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import gymnasium as gym
 import gymnasium as gym
 import numpy as np
 import numpy as np
 from pytest_mock import MockerFixture
 from pytest_mock import MockerFixture

+ 2 - 0
tests/test_wrappers.py

@@ -1,3 +1,5 @@
+from __future__ import annotations
+
 import math
 import math
 
 
 import gymnasium as gym
 import gymnasium as gym

+ 2 - 0
tests/utils.py

@@ -1,4 +1,6 @@
 """Finds all the specs that we can test with"""
 """Finds all the specs that we can test with"""
+from __future__ import annotations
+
 import gymnasium as gym
 import gymnasium as gym
 import numpy as np
 import numpy as np