From 0bcd49ec10e7ec3833bf16a8a2d6fd9ad60e030a Mon Sep 17 00:00:00 2001 From: Mark Towers Date: Thu, 1 Sep 2022 16:02:31 +0100 Subject: [PATCH] Updates the make and registration functions with better parameters and hints (#3041) * Initial commit * Add missing __init__ for EnvSpec * third time a charm * Replace entry_point=None with entry_point="no-entry-point" * Readd make overloads, updated with all gym envs * pre-commit * Add apply_step_compatibility to make and add testing * Code review by Arjun --- gym/envs/__relocated__.py | 430 ------------------------------------ gym/envs/registration.py | 197 +++++++---------- tests/envs/test_make.py | 45 +++- tests/envs/test_register.py | 18 +- tests/envs/test_spec.py | 12 +- tests/testing_env.py | 2 +- 6 files changed, 138 insertions(+), 566 deletions(-) delete mode 100644 gym/envs/__relocated__.py diff --git a/gym/envs/__relocated__.py b/gym/envs/__relocated__.py deleted file mode 100644 index 2d296ab5f..000000000 --- a/gym/envs/__relocated__.py +++ /dev/null @@ -1,430 +0,0 @@ -from typing import Dict, Optional, Tuple - -# The following is a map of environments which have been relocated -# to a different namespace. This map is important when reporting -# new versions of an environment outside of Gym. -# This map should be removed eventually once users -# are sufficiently aware of the environment relocations. -# The value of the mapping is (namespace, package,). -internal_env_relocation_map: Dict[str, Tuple[Optional[str], str]] = { - "Adventure": ("ALE", "ale-py"), - "AdventureDeterministic": (None, "ale-py"), - "AdventureNoFrameskip": (None, "ale-py"), - "Adventure-ram": ("ALE", "ale-py"), - "Adventure-ramDeterministic": (None, "ale-py"), - "Adventure-ramNoFrameskip": (None, "ale-py"), - "AirRaid": ("ALE", "ale-py"), - "AirRaidDeterministic": (None, "ale-py"), - "AirRaidNoFrameskip": (None, "ale-py"), - "AirRaid-ram": ("ALE", "ale-py"), - "AirRaid-ramDeterministic": (None, "ale-py"), - "AirRaid-ramNoFrameskip": (None, "ale-py"), - "Alien": ("ALE", "ale-py"), - "AlienDeterministic": (None, "ale-py"), - "AlienNoFrameskip": (None, "ale-py"), - "Alien-ram": ("ALE", "ale-py"), - "Alien-ramDeterministic": (None, "ale-py"), - "Alien-ramNoFrameskip": (None, "ale-py"), - "Amidar": ("ALE", "ale-py"), - "AmidarDeterministic": (None, "ale-py"), - "AmidarNoFrameskip": (None, "ale-py"), - "Amidar-ram": ("ALE", "ale-py"), - "Amidar-ramDeterministic": (None, "ale-py"), - "Amidar-ramNoFrameskip": (None, "ale-py"), - "Assault": ("ALE", "ale-py"), - "AssaultDeterministic": (None, "ale-py"), - "AssaultNoFrameskip": (None, "ale-py"), - "Assault-ram": ("ALE", "ale-py"), - "Assault-ramDeterministic": (None, "ale-py"), - "Assault-ramNoFrameskip": (None, "ale-py"), - "Asterix": ("ALE", "ale-py"), - "AsterixDeterministic": (None, "ale-py"), - "AsterixNoFrameskip": (None, "ale-py"), - "Asterix-ram": ("ALE", "ale-py"), - "Asterix-ramDeterministic": (None, "ale-py"), - "Asterix-ramNoFrameskip": (None, "ale-py"), - "Asteroids": ("ALE", "ale-py"), - "AsteroidsDeterministic": (None, "ale-py"), - "AsteroidsNoFrameskip": (None, "ale-py"), - "Asteroids-ram": ("ALE", "ale-py"), - "Asteroids-ramDeterministic": (None, "ale-py"), - "Asteroids-ramNoFrameskip": (None, "ale-py"), - "Atlantis": ("ALE", "ale-py"), - "AtlantisDeterministic": (None, "ale-py"), - "AtlantisNoFrameskip": (None, "ale-py"), - "Atlantis-ram": ("ALE", "ale-py"), - "Atlantis-ramDeterministic": (None, "ale-py"), - "Atlantis-ramNoFrameskip": (None, "ale-py"), - "BankHeist": ("ALE", "ale-py"), - "BankHeistDeterministic": (None, "ale-py"), - "BankHeistNoFrameskip": (None, "ale-py"), - "BankHeist-ram": ("ALE", "ale-py"), - "BankHeist-ramDeterministic": (None, "ale-py"), - "BankHeist-ramNoFrameskip": (None, "ale-py"), - "BattleZone": ("ALE", "ale-py"), - "BattleZoneDeterministic": (None, "ale-py"), - "BattleZoneNoFrameskip": (None, "ale-py"), - "BattleZone-ram": ("ALE", "ale-py"), - "BattleZone-ramDeterministic": (None, "ale-py"), - "BattleZone-ramNoFrameskip": (None, "ale-py"), - "BeamRider": ("ALE", "ale-py"), - "BeamRiderDeterministic": (None, "ale-py"), - "BeamRiderNoFrameskip": (None, "ale-py"), - "BeamRider-ram": ("ALE", "ale-py"), - "BeamRider-ramDeterministic": (None, "ale-py"), - "BeamRider-ramNoFrameskip": (None, "ale-py"), - "Berzerk": ("ALE", "ale-py"), - "BerzerkDeterministic": (None, "ale-py"), - "BerzerkNoFrameskip": (None, "ale-py"), - "Berzerk-ram": ("ALE", "ale-py"), - "Berzerk-ramDeterministic": (None, "ale-py"), - "Berzerk-ramNoFrameskip": (None, "ale-py"), - "Bowling": ("ALE", "ale-py"), - "BowlingDeterministic": (None, "ale-py"), - "BowlingNoFrameskip": (None, "ale-py"), - "Bowling-ram": ("ALE", "ale-py"), - "Bowling-ramDeterministic": (None, "ale-py"), - "Bowling-ramNoFrameskip": (None, "ale-py"), - "Boxing": ("ALE", "ale-py"), - "BoxingDeterministic": (None, "ale-py"), - "BoxingNoFrameskip": (None, "ale-py"), - "Boxing-ram": ("ALE", "ale-py"), - "Boxing-ramDeterministic": (None, "ale-py"), - "Boxing-ramNoFrameskip": (None, "ale-py"), - "Breakout": ("ALE", "ale-py"), - "BreakoutDeterministic": (None, "ale-py"), - "BreakoutNoFrameskip": (None, "ale-py"), - "Breakout-ram": ("ALE", "ale-py"), - "Breakout-ramDeterministic": (None, "ale-py"), - "Breakout-ramNoFrameskip": (None, "ale-py"), - "Carnival": ("ALE", "ale-py"), - "CarnivalDeterministic": (None, "ale-py"), - "CarnivalNoFrameskip": (None, "ale-py"), - "Carnival-ram": ("ALE", "ale-py"), - "Carnival-ramDeterministic": (None, "ale-py"), - "Carnival-ramNoFrameskip": (None, "ale-py"), - "Centipede": ("ALE", "ale-py"), - "CentipedeDeterministic": (None, "ale-py"), - "CentipedeNoFrameskip": (None, "ale-py"), - "Centipede-ram": ("ALE", "ale-py"), - "Centipede-ramDeterministic": (None, "ale-py"), - "Centipede-ramNoFrameskip": (None, "ale-py"), - "ChopperCommand": ("ALE", "ale-py"), - "ChopperCommandDeterministic": (None, "ale-py"), - "ChopperCommandNoFrameskip": (None, "ale-py"), - "ChopperCommand-ram": ("ALE", "ale-py"), - "ChopperCommand-ramDeterministic": (None, "ale-py"), - "ChopperCommand-ramNoFrameskip": (None, "ale-py"), - "CrazyClimber": ("ALE", "ale-py"), - "CrazyClimberDeterministic": (None, "ale-py"), - "CrazyClimberNoFrameskip": (None, "ale-py"), - "CrazyClimber-ram": ("ALE", "ale-py"), - "CrazyClimber-ramDeterministic": (None, "ale-py"), - "CrazyClimber-ramNoFrameskip": (None, "ale-py"), - "Defender": ("ALE", "ale-py"), - "DefenderDeterministic": (None, "ale-py"), - "DefenderNoFrameskip": (None, "ale-py"), - "Defender-ram": ("ALE", "ale-py"), - "Defender-ramDeterministic": (None, "ale-py"), - "Defender-ramNoFrameskip": (None, "ale-py"), - "DemonAttack": ("ALE", "ale-py"), - "DemonAttackDeterministic": (None, "ale-py"), - "DemonAttackNoFrameskip": (None, "ale-py"), - "DemonAttack-ram": ("ALE", "ale-py"), - "DemonAttack-ramDeterministic": (None, "ale-py"), - "DemonAttack-ramNoFrameskip": (None, "ale-py"), - "DoubleDunk": ("ALE", "ale-py"), - "DoubleDunkDeterministic": (None, "ale-py"), - "DoubleDunkNoFrameskip": (None, "ale-py"), - "DoubleDunk-ram": ("ALE", "ale-py"), - "DoubleDunk-ramDeterministic": (None, "ale-py"), - "DoubleDunk-ramNoFrameskip": (None, "ale-py"), - "ElevatorAction": ("ALE", "ale-py"), - "ElevatorActionDeterministic": (None, "ale-py"), - "ElevatorActionNoFrameskip": (None, "ale-py"), - "ElevatorAction-ram": ("ALE", "ale-py"), - "ElevatorAction-ramDeterministic": (None, "ale-py"), - "ElevatorAction-ramNoFrameskip": (None, "ale-py"), - "Enduro": ("ALE", "ale-py"), - "EnduroDeterministic": (None, "ale-py"), - "EnduroNoFrameskip": (None, "ale-py"), - "Enduro-ram": ("ALE", "ale-py"), - "Enduro-ramDeterministic": (None, "ale-py"), - "Enduro-ramNoFrameskip": (None, "ale-py"), - "FishingDerby": ("ALE", "ale-py"), - "FishingDerbyDeterministic": (None, "ale-py"), - "FishingDerbyNoFrameskip": (None, "ale-py"), - "FishingDerby-ram": ("ALE", "ale-py"), - "FishingDerby-ramDeterministic": (None, "ale-py"), - "FishingDerby-ramNoFrameskip": (None, "ale-py"), - "Freeway": ("ALE", "ale-py"), - "FreewayDeterministic": (None, "ale-py"), - "FreewayNoFrameskip": (None, "ale-py"), - "Freeway-ram": ("ALE", "ale-py"), - "Freeway-ramDeterministic": (None, "ale-py"), - "Freeway-ramNoFrameskip": (None, "ale-py"), - "Frostbite": ("ALE", "ale-py"), - "FrostbiteDeterministic": (None, "ale-py"), - "FrostbiteNoFrameskip": (None, "ale-py"), - "Frostbite-ram": ("ALE", "ale-py"), - "Frostbite-ramDeterministic": (None, "ale-py"), - "Frostbite-ramNoFrameskip": (None, "ale-py"), - "Gopher": ("ALE", "ale-py"), - "GopherDeterministic": (None, "ale-py"), - "GopherNoFrameskip": (None, "ale-py"), - "Gopher-ram": ("ALE", "ale-py"), - "Gopher-ramDeterministic": (None, "ale-py"), - "Gopher-ramNoFrameskip": (None, "ale-py"), - "Gravitar": ("ALE", "ale-py"), - "GravitarDeterministic": (None, "ale-py"), - "GravitarNoFrameskip": (None, "ale-py"), - "Gravitar-ram": ("ALE", "ale-py"), - "Gravitar-ramDeterministic": (None, "ale-py"), - "Gravitar-ramNoFrameskip": (None, "ale-py"), - "Hero": ("ALE", "ale-py"), - "HeroDeterministic": (None, "ale-py"), - "HeroNoFrameskip": (None, "ale-py"), - "Hero-ram": ("ALE", "ale-py"), - "Hero-ramDeterministic": (None, "ale-py"), - "Hero-ramNoFrameskip": (None, "ale-py"), - "IceHockey": ("ALE", "ale-py"), - "IceHockeyDeterministic": (None, "ale-py"), - "IceHockeyNoFrameskip": (None, "ale-py"), - "IceHockey-ram": ("ALE", "ale-py"), - "IceHockey-ramDeterministic": (None, "ale-py"), - "IceHockey-ramNoFrameskip": (None, "ale-py"), - "Jamesbond": ("ALE", "ale-py"), - "JamesbondDeterministic": (None, "ale-py"), - "JamesbondNoFrameskip": (None, "ale-py"), - "Jamesbond-ram": ("ALE", "ale-py"), - "Jamesbond-ramDeterministic": (None, "ale-py"), - "Jamesbond-ramNoFrameskip": (None, "ale-py"), - "JourneyEscape": ("ALE", "ale-py"), - "JourneyEscapeDeterministic": (None, "ale-py"), - "JourneyEscapeNoFrameskip": (None, "ale-py"), - "JourneyEscape-ram": ("ALE", "ale-py"), - "JourneyEscape-ramDeterministic": (None, "ale-py"), - "JourneyEscape-ramNoFrameskip": (None, "ale-py"), - "Kangaroo": ("ALE", "ale-py"), - "KangarooDeterministic": (None, "ale-py"), - "KangarooNoFrameskip": (None, "ale-py"), - "Kangaroo-ram": ("ALE", "ale-py"), - "Kangaroo-ramDeterministic": (None, "ale-py"), - "Kangaroo-ramNoFrameskip": (None, "ale-py"), - "Krull": ("ALE", "ale-py"), - "KrullDeterministic": (None, "ale-py"), - "KrullNoFrameskip": (None, "ale-py"), - "Krull-ram": ("ALE", "ale-py"), - "Krull-ramDeterministic": (None, "ale-py"), - "Krull-ramNoFrameskip": (None, "ale-py"), - "KungFuMaster": ("ALE", "ale-py"), - "KungFuMasterDeterministic": (None, "ale-py"), - "KungFuMasterNoFrameskip": (None, "ale-py"), - "KungFuMaster-ram": ("ALE", "ale-py"), - "KungFuMaster-ramDeterministic": (None, "ale-py"), - "KungFuMaster-ramNoFrameskip": (None, "ale-py"), - "MontezumaRevenge": ("ALE", "ale-py"), - "MontezumaRevengeDeterministic": (None, "ale-py"), - "MontezumaRevengeNoFrameskip": (None, "ale-py"), - "MontezumaRevenge-ram": ("ALE", "ale-py"), - "MontezumaRevenge-ramDeterministic": (None, "ale-py"), - "MontezumaRevenge-ramNoFrameskip": (None, "ale-py"), - "MsPacman": ("ALE", "ale-py"), - "MsPacmanDeterministic": (None, "ale-py"), - "MsPacmanNoFrameskip": (None, "ale-py"), - "MsPacman-ram": ("ALE", "ale-py"), - "MsPacman-ramDeterministic": (None, "ale-py"), - "MsPacman-ramNoFrameskip": (None, "ale-py"), - "NameThisGame": ("ALE", "ale-py"), - "NameThisGameDeterministic": (None, "ale-py"), - "NameThisGameNoFrameskip": (None, "ale-py"), - "NameThisGame-ram": ("ALE", "ale-py"), - "NameThisGame-ramDeterministic": (None, "ale-py"), - "NameThisGame-ramNoFrameskip": (None, "ale-py"), - "Phoenix": ("ALE", "ale-py"), - "PhoenixDeterministic": (None, "ale-py"), - "PhoenixNoFrameskip": (None, "ale-py"), - "Phoenix-ram": ("ALE", "ale-py"), - "Phoenix-ramDeterministic": (None, "ale-py"), - "Phoenix-ramNoFrameskip": (None, "ale-py"), - "Pitfall": ("ALE", "ale-py"), - "PitfallDeterministic": (None, "ale-py"), - "PitfallNoFrameskip": (None, "ale-py"), - "Pitfall-ram": ("ALE", "ale-py"), - "Pitfall-ramDeterministic": (None, "ale-py"), - "Pitfall-ramNoFrameskip": (None, "ale-py"), - "Pong": ("ALE", "ale-py"), - "PongDeterministic": (None, "ale-py"), - "PongNoFrameskip": (None, "ale-py"), - "Pong-ram": ("ALE", "ale-py"), - "Pong-ramDeterministic": (None, "ale-py"), - "Pong-ramNoFrameskip": (None, "ale-py"), - "Pooyan": ("ALE", "ale-py"), - "PooyanDeterministic": (None, "ale-py"), - "PooyanNoFrameskip": (None, "ale-py"), - "Pooyan-ram": ("ALE", "ale-py"), - "Pooyan-ramDeterministic": (None, "ale-py"), - "Pooyan-ramNoFrameskip": (None, "ale-py"), - "PrivateEye": ("ALE", "ale-py"), - "PrivateEyeDeterministic": (None, "ale-py"), - "PrivateEyeNoFrameskip": (None, "ale-py"), - "PrivateEye-ram": ("ALE", "ale-py"), - "PrivateEye-ramDeterministic": (None, "ale-py"), - "PrivateEye-ramNoFrameskip": (None, "ale-py"), - "Qbert": ("ALE", "ale-py"), - "QbertDeterministic": (None, "ale-py"), - "QbertNoFrameskip": (None, "ale-py"), - "Qbert-ram": ("ALE", "ale-py"), - "Qbert-ramDeterministic": (None, "ale-py"), - "Qbert-ramNoFrameskip": (None, "ale-py"), - "Riverraid": ("ALE", "ale-py"), - "RiverraidDeterministic": (None, "ale-py"), - "RiverraidNoFrameskip": (None, "ale-py"), - "Riverraid-ram": ("ALE", "ale-py"), - "Riverraid-ramDeterministic": (None, "ale-py"), - "Riverraid-ramNoFrameskip": (None, "ale-py"), - "RoadRunner": ("ALE", "ale-py"), - "RoadRunnerDeterministic": (None, "ale-py"), - "RoadRunnerNoFrameskip": (None, "ale-py"), - "RoadRunner-ram": ("ALE", "ale-py"), - "RoadRunner-ramDeterministic": (None, "ale-py"), - "RoadRunner-ramNoFrameskip": (None, "ale-py"), - "Robotank": ("ALE", "ale-py"), - "RobotankDeterministic": (None, "ale-py"), - "RobotankNoFrameskip": (None, "ale-py"), - "Robotank-ram": ("ALE", "ale-py"), - "Robotank-ramDeterministic": (None, "ale-py"), - "Robotank-ramNoFrameskip": (None, "ale-py"), - "Seaquest": ("ALE", "ale-py"), - "SeaquestDeterministic": (None, "ale-py"), - "SeaquestNoFrameskip": (None, "ale-py"), - "Seaquest-ram": ("ALE", "ale-py"), - "Seaquest-ramDeterministic": (None, "ale-py"), - "Seaquest-ramNoFrameskip": (None, "ale-py"), - "Skiing": ("ALE", "ale-py"), - "SkiingDeterministic": (None, "ale-py"), - "SkiingNoFrameskip": (None, "ale-py"), - "Skiing-ram": ("ALE", "ale-py"), - "Skiing-ramDeterministic": (None, "ale-py"), - "Skiing-ramNoFrameskip": (None, "ale-py"), - "Solaris": ("ALE", "ale-py"), - "SolarisDeterministic": (None, "ale-py"), - "SolarisNoFrameskip": (None, "ale-py"), - "Solaris-ram": ("ALE", "ale-py"), - "Solaris-ramDeterministic": (None, "ale-py"), - "Solaris-ramNoFrameskip": (None, "ale-py"), - "SpaceInvaders": ("ALE", "ale-py"), - "SpaceInvadersDeterministic": (None, "ale-py"), - "SpaceInvadersNoFrameskip": (None, "ale-py"), - "SpaceInvaders-ram": ("ALE", "ale-py"), - "SpaceInvaders-ramDeterministic": (None, "ale-py"), - "SpaceInvaders-ramNoFrameskip": (None, "ale-py"), - "StarGunner": ("ALE", "ale-py"), - "StarGunnerDeterministic": (None, "ale-py"), - "StarGunnerNoFrameskip": (None, "ale-py"), - "StarGunner-ram": ("ALE", "ale-py"), - "StarGunner-ramDeterministic": (None, "ale-py"), - "StarGunner-ramNoFrameskip": (None, "ale-py"), - "Tennis": ("ALE", "ale-py"), - "TennisDeterministic": (None, "ale-py"), - "TennisNoFrameskip": (None, "ale-py"), - "Tennis-ram": ("ALE", "ale-py"), - "Tennis-ramDeterministic": (None, "ale-py"), - "Tennis-ramNoFrameskip": (None, "ale-py"), - "TimePilot": ("ALE", "ale-py"), - "TimePilotDeterministic": (None, "ale-py"), - "TimePilotNoFrameskip": (None, "ale-py"), - "TimePilot-ram": ("ALE", "ale-py"), - "TimePilot-ramDeterministic": (None, "ale-py"), - "TimePilot-ramNoFrameskip": (None, "ale-py"), - "Tutankham": ("ALE", "ale-py"), - "TutankhamDeterministic": (None, "ale-py"), - "TutankhamNoFrameskip": (None, "ale-py"), - "Tutankham-ram": ("ALE", "ale-py"), - "Tutankham-ramDeterministic": (None, "ale-py"), - "Tutankham-ramNoFrameskip": (None, "ale-py"), - "UpNDown": ("ALE", "ale-py"), - "UpNDownDeterministic": (None, "ale-py"), - "UpNDownNoFrameskip": (None, "ale-py"), - "UpNDown-ram": ("ALE", "ale-py"), - "UpNDown-ramDeterministic": (None, "ale-py"), - "UpNDown-ramNoFrameskip": (None, "ale-py"), - "Venture": ("ALE", "ale-py"), - "VentureDeterministic": (None, "ale-py"), - "VentureNoFrameskip": (None, "ale-py"), - "Venture-ram": ("ALE", "ale-py"), - "Venture-ramDeterministic": (None, "ale-py"), - "Venture-ramNoFrameskip": (None, "ale-py"), - "VideoPinball": ("ALE", "ale-py"), - "VideoPinballDeterministic": (None, "ale-py"), - "VideoPinballNoFrameskip": (None, "ale-py"), - "VideoPinball-ram": ("ALE", "ale-py"), - "VideoPinball-ramDeterministic": (None, "ale-py"), - "VideoPinball-ramNoFrameskip": (None, "ale-py"), - "WizardOfWor": ("ALE", "ale-py"), - "WizardOfWorDeterministic": (None, "ale-py"), - "WizardOfWorNoFrameskip": (None, "ale-py"), - "WizardOfWor-ram": ("ALE", "ale-py"), - "WizardOfWor-ramDeterministic": (None, "ale-py"), - "WizardOfWor-ramNoFrameskip": (None, "ale-py"), - "YarsRevenge": ("ALE", "ale-py"), - "YarsRevengeDeterministic": (None, "ale-py"), - "YarsRevengeNoFrameskip": (None, "ale-py"), - "YarsRevenge-ram": ("ALE", "ale-py"), - "YarsRevenge-ramDeterministic": (None, "ale-py"), - "YarsRevenge-ramNoFrameskip": (None, "ale-py"), - "Zaxxon": ("ALE", "ale-py"), - "ZaxxonDeterministic": (None, "ale-py"), - "ZaxxonNoFrameskip": (None, "ale-py"), - "Zaxxon-ram": ("ALE", "ale-py"), - "Zaxxon-ramDeterministic": (None, "ale-py"), - "Zaxxon-ramNoFrameskip": (None, "ale-py"), - "FetchSlide": (None, "gym-robotics"), - "FetchPickAndPlace": (None, "gym-robotics"), - "FetchReach": (None, "gym-robotics"), - "FetchPush": (None, "gym-robotics"), - "HandReach": (None, "gym-robotics"), - "HandManipulateBlockRotateZ": (None, "gym-robotics"), - "HandManipulateBlockRotateZTouchSensors": (None, "gym-robotics"), - "HandManipulateBlockRotateParallel": (None, "gym-robotics"), - "HandManipulateBlockRotateParallelTouchSensors": (None, "gym-robotics"), - "HandManipulateBlockRotateXYZ": (None, "gym-robotics"), - "HandManipulateBlockRotateXYZTouchSensors": (None, "gym-robotics"), - "HandManipulateBlockFull": (None, "gym-robotics"), - "HandManipulateBlock": (None, "gym-robotics"), - "HandManipulateBlockTouchSensors": (None, "gym-robotics"), - "HandManipulateEggRotate": (None, "gym-robotics"), - "HandManipulateEggRotateTouchSensors": (None, "gym-robotics"), - "HandManipulateEggFull": (None, "gym-robotics"), - "HandManipulateEgg": (None, "gym-robotics"), - "HandManipulateEggTouchSensors": (None, "gym-robotics"), - "HandManipulatePenRotate": (None, "gym-robotics"), - "HandManipulatePenRotateTouchSensors": (None, "gym-robotics"), - "HandManipulatePenFull": (None, "gym-robotics"), - "HandManipulatePen": (None, "gym-robotics"), - "HandManipulatePenTouchSensors": (None, "gym-robotics"), - "FetchSlideDense": (None, "gym-robotics"), - "FetchPickAndPlaceDense": (None, "gym-robotics"), - "FetchReachDense": (None, "gym-robotics"), - "FetchPushDense": (None, "gym-robotics"), - "HandReachDense": (None, "gym-robotics"), - "HandManipulateBlockRotateZDense": (None, "gym-robotics"), - "HandManipulateBlockRotateZTouchSensorsDense": (None, "gym-robotics"), - "HandManipulateBlockRotateParallelDense": (None, "gym-robotics"), - "HandManipulateBlockRotateParallelTouchSensorsDense": (None, "gym-robotics"), - "HandManipulateBlockRotateXYZDense": (None, "gym-robotics"), - "HandManipulateBlockRotateXYZTouchSensorsDense": (None, "gym-robotics"), - "HandManipulateBlockFullDense": (None, "gym-robotics"), - "HandManipulateBlockDense": (None, "gym-robotics"), - "HandManipulateBlockTouchSensorsDense": (None, "gym-robotics"), - "HandManipulateEggRotateDense": (None, "gym-robotics"), - "HandManipulateEggRotateTouchSensorsDense": (None, "gym-robotics"), - "HandManipulateEggFullDense": (None, "gym-robotics"), - "HandManipulateEggDense": (None, "gym-robotics"), - "HandManipulateEggTouchSensorsDense": (None, "gym-robotics"), - "HandManipulatePenRotateDense": (None, "gym-robotics"), - "HandManipulatePenRotateTouchSensorsDense": (None, "gym-robotics"), - "HandManipulatePenFullDense": (None, "gym-robotics"), - "HandManipulatePenDense": (None, "gym-robotics"), - "HandManipulatePenTouchSensorsDense": (None, "gym-robotics"), -} diff --git a/gym/envs/registration.py b/gym/envs/registration.py index 8e5f1d051..feeb08c90 100644 --- a/gym/envs/registration.py +++ b/gym/envs/registration.py @@ -10,7 +10,6 @@ from dataclasses import dataclass, field from typing import ( Callable, Dict, - Iterable, List, Optional, Sequence, @@ -22,7 +21,6 @@ from typing import ( import numpy as np -from gym.envs.__relocated__ import internal_env_relocation_map from gym.wrappers import ( AutoResetWrapper, HumanRendering, @@ -131,7 +129,9 @@ class EnvSpec: """ id: str - entry_point: Optional[Union[Callable, str]] = field(default=None) + entry_point: Union[Callable, str] + + # Environment attributes reward_threshold: Optional[float] = field(default=None) nondeterministic: bool = field(default=False) @@ -145,6 +145,7 @@ class EnvSpec: # Environment arguments kwargs: dict = field(default_factory=dict) + # post-init attributes namespace: Optional[str] = field(init=False) name: str = field(init=False) version: Optional[int] = field(init=False) @@ -188,23 +189,6 @@ def _check_name_exists(ns: Optional[str], name: str): if name in names: return - if namespace is None and name in internal_env_relocation_map: - relocated_namespace, relocated_package = internal_env_relocation_map[name] - message = f"The environment `{name}` has been moved out of Gym to the package `{relocated_package}`." - - # Check if the package is installed - # If not instruct the user to install the package and then how to instantiate the env - if importlib.util.find_spec(relocated_package) is None: - message += ( - f" Please install the package via `pip install {relocated_package}`." - ) - - # Otherwise the user should be able to instantiate the environment directly - if namespace != relocated_namespace: - message += f" You can instantiate the new namespaced environment as `{relocated_namespace}/{name}`." - - raise error.NameNotFound(message) - suggestion = difflib.get_close_matches(name, names, n=1) namespace_msg = f" in namespace {ns}" if ns else "" suggestion_msg = f"Did you mean: `{suggestion[0]}`?" if suggestion else "" @@ -313,8 +297,7 @@ def load_env_plugins(entry_point: str = "gym.envs") -> None: else: logger.warn( f"The environment namespace magic key `{plugin.name}` is unsupported. " - "To register an environment at the root namespace you should specify " - "the `__root__` namespace." + "To register an environment at the root namespace you should specify the `__root__` namespace." ) with context: @@ -326,10 +309,14 @@ def load_env_plugins(entry_point: str = "gym.envs") -> None: # fmt: off +@overload +def make(id: str, **kwargs) -> Env: ... +@overload +def make(id: EnvSpec, **kwargs) -> Env: ... + + # Classic control # ---------------------------------------- - - @overload def make(id: Literal["CartPole-v0", "CartPole-v1"], **kwargs) -> Env[np.ndarray, Union[np.ndarray, int]]: ... @overload @@ -341,21 +328,19 @@ def make(id: Literal["Pendulum-v1"], **kwargs) -> Env[np.ndarray, Union[np.ndarr @overload def make(id: Literal["Acrobot-v1"], **kwargs) -> Env[np.ndarray, Union[np.ndarray, int]]: ... + # Box2d # ---------------------------------------- - - @overload def make(id: Literal["LunarLander-v2", "LunarLanderContinuous-v2"], **kwargs) -> Env[np.ndarray, Union[np.ndarray, int]]: ... @overload def make(id: Literal["BipedalWalker-v3", "BipedalWalkerHardcore-v3"], **kwargs) -> Env[np.ndarray, Union[np.ndarray, Sequence[SupportsFloat]]]: ... @overload -def make(id: Literal["CarRacing-v1"], **kwargs) -> Env[np.ndarray, Union[np.ndarray, Sequence[SupportsFloat]]]: ... +def make(id: Literal["CarRacing-v2"], **kwargs) -> Env[np.ndarray, Union[np.ndarray, Sequence[SupportsFloat]]]: ... + # Toy Text # ---------------------------------------- - - @overload def make(id: Literal["Blackjack-v1"], **kwargs) -> Env[np.ndarray, Union[np.ndarray, int]]: ... @overload @@ -365,86 +350,28 @@ def make(id: Literal["CliffWalking-v0"], **kwargs) -> Env[np.ndarray, Union[np.n @overload def make(id: Literal["Taxi-v3"], **kwargs) -> Env[np.ndarray, Union[np.ndarray, int]]: ... + # Mujoco # ---------------------------------------- - - @overload def make(id: Literal[ - "Reacher-v2", - "Pusher-v2", - "Thrower-v2", - "Striker-v2", - "InvertedPendulum-v2", - "InvertedDoublePendulum-v2", - "HalfCheetah-v2", "HalfCheetah-v3", - "Hopper-v2", "Hopper-v3", - "Swimmer-v2", "Swimmer-v3", - "Walker2d-v2", "Walker2d-v3", - "Ant-v2" + "Reacher-v2", "Reacher-v4", + "Pusher-v2", "Pusher-v4", + "InvertedPendulum-v2", "InvertedPendulum-v4", + "InvertedDoublePendulum-v2", "InvertedDoublePendulum-v4", + "HalfCheetah-v2", "HalfCheetah-v3", "HalfCheetah-v4", + "Hopper-v2", "Hopper-v3", "Hopper-v4", + "Swimmer-v2", "Swimmer-v3", "Swimmer-v4", + "Walker2d-v2", "Walker2d-v3", "Walker2d-v4", + "Ant-v2", "Ant-v3", "Ant-v4", + "HumanoidStandup-v2", "HumanoidStandup-v4", + "Humanoid-v2", "Humanoid-v3", "Humanoid-v4", ], **kwargs) -> Env[np.ndarray, np.ndarray]: ... - - -@overload -def make(id: str, **kwargs) -> Env: ... -@overload -def make(id: EnvSpec, **kwargs) -> Env: ... - # fmt: on -class EnvRegistry(dict): - """A glorified dictionary for compatibility reasons. - - Turns out that some existing code directly used the old `EnvRegistry` code, - even though the intended API was just `register` and `make`. - This reimplements some old methods, so that e.g. pybullet environments will still work. - - Ideally, nobody should ever use these methods, and they will be removed soon. - """ - - # TODO: remove this at 1.0 - - def make(self, path: str, **kwargs) -> Env: - logger.warn( - "The `registry.make` method is deprecated. Please use `gym.make` instead." - ) - return make(path, **kwargs) - - def register(self, id: str, **kwargs) -> None: - logger.warn( - "The `registry.register` method is deprecated. Please use `gym.register` instead." - ) - return register(id, **kwargs) - - def all(self) -> Iterable[EnvSpec]: - logger.warn( - "The `registry.all` method is deprecated. Please use `registry.values` instead." - ) - return self.values() - - def spec(self, path: str) -> EnvSpec: - logger.warn( - "The `registry.spec` method is deprecated. Please use `gym.spec` instead." - ) - return spec(path) - - def namespace(self, ns: str): - logger.warn( - "The `registry.namespace` method is deprecated. Please use `gym.namespace` instead." - ) - return namespace(ns) - - @property - def env_specs(self): - logger.warn( - "The `registry.env_specs` property along with `EnvSpecTree` is deprecated. Please use `registry` directly as a dictionary instead." - ) - return self - - # Global registry of environments. Meant to be accessed through `register` and `make` -registry: Dict[str, EnvSpec] = EnvRegistry() +registry: Dict[str, EnvSpec] = {} current_namespace: Optional[str] = None @@ -503,7 +430,18 @@ def namespace(ns: str): current_namespace = old_namespace -def register(id: str, **kwargs): +def register( + id: str, + entry_point: Union[Callable, str], + reward_threshold: Optional[float] = None, + nondeterministic: bool = False, + max_episode_steps: Optional[int] = None, + order_enforce: bool = True, + autoreset: bool = False, + disable_env_checker: bool = False, + apply_step_compatibility: bool = False, + **kwargs, +): """Register an environment with gym. The `id` parameter corresponds to the name of the environment, with the syntax as follows: @@ -513,6 +451,14 @@ def register(id: str, **kwargs): Args: id: The environment id + entry_point: The entry point for creating the environment + reward_threshold: The reward threshold considered to have learnt an environment + nondeterministic: If the environment is nondeterministic (even with knowledge of the initial seed and all actions) + max_episode_steps: The maximum number of episodes steps before truncation. Used by the Time Limit wrapper. + order_enforce: If to enable the order enforcer wrapper to ensure users run functions in the correct order + autoreset: If to add the autoreset wrapper such that reset does not need to be called. + disable_env_checker: If to disable the environment checker for the environment. Recommended to False. + apply_step_compatibility: If to apply the `StepAPICompatibility` wrapper. **kwargs: arbitrary keyword arguments which are passed to the environment constructor """ global registry, current_namespace @@ -524,11 +470,9 @@ def register(id: str, **kwargs): and kwargs.get("namespace") != current_namespace ): logger.warn( - f"Custom namespace `{kwargs.get('namespace')}` is being overridden " - f"by namespace `{current_namespace}`. If you are developing a " - "plugin you shouldn't specify a namespace in `register` " - "calls. The namespace is specified through the " - "entry point package metadata." + f"Custom namespace `{kwargs.get('namespace')}` is being overridden by namespace `{current_namespace}`. " + f"If you are developing a plugin you shouldn't specify a namespace in `register` calls. " + "The namespace is specified through the entry point package metadata." ) ns_id = current_namespace else: @@ -536,28 +480,45 @@ def register(id: str, **kwargs): full_id = get_env_id(ns_id, name, version) - spec = EnvSpec(id=full_id, **kwargs) - _check_spec_register(spec) - if spec.id in registry: - logger.warn(f"Overriding environment {spec.id}") - registry[spec.id] = spec + new_spec = EnvSpec( + id=full_id, + entry_point=entry_point, + reward_threshold=reward_threshold, + nondeterministic=nondeterministic, + max_episode_steps=max_episode_steps, + order_enforce=order_enforce, + autoreset=autoreset, + disable_env_checker=disable_env_checker, + apply_step_compatibility=apply_step_compatibility, + **kwargs, + ) + _check_spec_register(new_spec) + if new_spec.id in registry: + logger.warn(f"Overriding environment {new_spec.id} already in registry.") + registry[new_spec.id] = new_spec def make( id: Union[str, EnvSpec], max_episode_steps: Optional[int] = None, autoreset: bool = False, - apply_step_compatibility: bool = False, + apply_step_compatibility: Optional[bool] = None, disable_env_checker: Optional[bool] = None, **kwargs, ) -> Env: """Create an environment according to the given ID. + To find all available environments use `gym.envs.registry.keys()` for all valid ids. + Args: id: Name of the environment. Optionally, a module to import can be included, eg. 'module:Env-v0' max_episode_steps: Maximum length of an episode (TimeLimit wrapper). autoreset: Whether to automatically reset the environment after each episode (AutoResetWrapper). - apply_step_compatibility: Whether to use apply compatibility wrapper that converts step method to return two bools (StepAPICompatibility wrapper) + apply_step_compatibility: Whether to wrap the environment with the `StepAPICompatibility` wrapper that + converts the environment step from a done bool to return termination and truncation bools. + By default, the argument is None to which the environment specification `apply_step_compatibility` is used + which defaults to False. Otherwise, the value of `apply_step_compatibility` is used. + If `True`, the wrapper is applied otherwise, the wrapper is not applied. disable_env_checker: If to run the env checker, None will default to the environment specification `disable_env_checker` (which is by default False, running the environment checker), otherwise will run according to this parameter (`True` = not run, `False` = run) @@ -684,6 +645,12 @@ def make( ): env = PassiveEnvChecker(env) + # Add step API wrapper + if apply_step_compatibility is True or ( + apply_step_compatibility is None and spec_.apply_step_compatibility is True + ): + env = StepAPICompatibility(env, output_truncation_bool=True) + # Add the order enforcing wrapper if spec_.order_enforce: env = OrderEnforcing(env) @@ -702,10 +669,6 @@ def make( if apply_human_rendering: env = HumanRendering(env) - # Add step API wrapper - if apply_step_compatibility: - env = StepAPICompatibility(env, True) - return env diff --git a/tests/envs/test_make.py b/tests/envs/test_make.py index cdba7b277..00b2bfa00 100644 --- a/tests/envs/test_make.py +++ b/tests/envs/test_make.py @@ -9,11 +9,18 @@ import pytest import gym from gym.envs.classic_control import cartpole -from gym.wrappers import AutoResetWrapper, HumanRendering, OrderEnforcing, TimeLimit +from gym.wrappers import ( + AutoResetWrapper, + HumanRendering, + OrderEnforcing, + StepAPICompatibility, + TimeLimit, +) from gym.wrappers.env_checker import PassiveEnvChecker from tests.envs.test_envs import PASSIVE_CHECK_IGNORE_WARNING from tests.envs.utils import all_testing_env_specs from tests.envs.utils_envs import ArgumentEnv, RegisterDuringMakeEnv +from tests.testing_env import GenericTestEnv, old_step_fn from tests.wrappers.utils import has_wrapper gym.register( @@ -131,6 +138,39 @@ def test_make_disable_env_checker(): env.close() +def test_apply_step_compatibility(): + gym.register( + "testing-old-env", + lambda: GenericTestEnv(step_fn=old_step_fn), + apply_step_compatibility=True, + max_episode_steps=3, + ) + env = gym.make("testing-old-env") + assert has_wrapper(env, StepAPICompatibility) + + env.reset() + assert len(env.step(env.action_space.sample())) == 5 + env.step(env.action_space.sample()) + _, _, termination, truncation, _ = env.step(env.action_space.sample()) + assert termination is False and truncation is True + + gym.spec("testing-old-env").apply_step_compatibility = False + env = gym.make("testing-old-env") + assert has_wrapper(env, StepAPICompatibility) is False + # Cannot run reset and step as will not work + + env = gym.make("testing-old-env", apply_step_compatibility=True) + assert has_wrapper(env, StepAPICompatibility) + + env.reset() + assert len(env.step(env.action_space.sample())) == 5 + env.step(env.action_space.sample()) + _, _, termination, truncation, _ = env.step(env.action_space.sample()) + assert termination is False and truncation is True + + gym.envs.registry.pop("testing-old-env") + + @pytest.mark.parametrize( "spec", all_testing_env_specs, ids=[spec.id for spec in all_testing_env_specs] ) @@ -201,8 +241,7 @@ def test_make_render_mode(): env.close() for warning in caught_warnings: - if not re.compile(".*step API.*").match(warning.message.args[0]): - raise gym.error.Error(f"Unexpected warning: {warning.message}") + raise gym.error.Error(f"Unexpected warning: {warning.message}") # Make sure that native rendering is used when possible env = gym.make("CartPole-v1", render_mode="human", disable_env_checker=True) diff --git a/tests/envs/test_register.py b/tests/envs/test_register.py index 0fd13efb7..ef96c6eba 100644 --- a/tests/envs/test_register.py +++ b/tests/envs/test_register.py @@ -1,4 +1,4 @@ -"""Tests that gym.register works as expected.""" +"""Tests that `gym.register` works as expected.""" import re from typing import Optional @@ -63,7 +63,7 @@ def register_testing_envs(): def test_register( env_id: str, namespace: Optional[str], name: str, version: Optional[int] ): - gym.register(env_id) + gym.register(env_id, "no-entry-point") assert gym.spec(env_id).id == env_id full_name = f"{name}" @@ -87,7 +87,7 @@ def test_register( ) def test_register_error(env_id): with pytest.raises(gym.error.Error, match=f"^Malformed environment ID: {env_id}"): - gym.register(env_id) + gym.register(env_id, "no-entry-point") @pytest.mark.parametrize( @@ -143,7 +143,7 @@ def test_env_version_suggestions( def test_register_versioned_unversioned(): # Register versioned then unversioned versioned_env = "Test/MyEnv-v0" - gym.register(versioned_env) + gym.register(versioned_env, "no-entry-point") assert gym.envs.spec(versioned_env).id == versioned_env unversioned_env = "Test/MyEnv" @@ -153,13 +153,13 @@ def test_register_versioned_unversioned(): "Can't register the unversioned environment `Test/MyEnv` when the versioned environment `Test/MyEnv-v0` of the same name already exists" ), ): - gym.register(unversioned_env) + gym.register(unversioned_env, "no-entry-point") # Clean everything del gym.envs.registry[versioned_env] # Register unversioned then versioned - gym.register(unversioned_env) + gym.register(unversioned_env, "no-entry-point") assert gym.envs.spec(unversioned_env).id == unversioned_env with pytest.raises( gym.error.RegistrationError, @@ -167,7 +167,7 @@ def test_register_versioned_unversioned(): "Can't register the versioned environment `Test/MyEnv-v0` when the unversioned environment `Test/MyEnv` of the same name already exists." ), ): - gym.register(versioned_env) + gym.register(versioned_env, "no-entry-point") # Clean everything del gym.envs.registry[unversioned_env] @@ -189,8 +189,8 @@ def test_make_latest_versioned_env(register_testing_envs): def test_namespace(): # Check if the namespace context manager works with gym.envs.registration.namespace("MyDefaultNamespace"): - gym.register("MyDefaultEnvironment-v0") - gym.register("MyDefaultEnvironment-v1") + gym.register("MyDefaultEnvironment-v0", "no-entry-point") + gym.register("MyDefaultEnvironment-v1", "no-entry-point") assert "MyDefaultNamespace/MyDefaultEnvironment-v0" in gym.envs.registry assert "MyDefaultEnvironment-v1" in gym.envs.registry diff --git a/tests/envs/test_spec.py b/tests/envs/test_spec.py index f01657f23..78e7d801e 100644 --- a/tests/envs/test_spec.py +++ b/tests/envs/test_spec.py @@ -20,10 +20,10 @@ def test_spec_kwargs(): def test_spec_missing_lookup(): - gym.register(id="Test1-v0", entry_point=None) - gym.register(id="Test1-v15", entry_point=None) - gym.register(id="Test1-v9", entry_point=None) - gym.register(id="Other1-v100", entry_point=None) + gym.register(id="Test1-v0", entry_point="no-entry-point") + gym.register(id="Test1-v15", entry_point="no-entry-point") + gym.register(id="Test1-v9", entry_point="no-entry-point") + gym.register(id="Other1-v100", entry_point="no-entry-point") with pytest.raises( gym.error.DeprecatedEnv, @@ -57,7 +57,7 @@ def test_spec_malformed_lookup(): def test_spec_versioned_lookups(): - gym.register("test/Test2-v5") + gym.register("test/Test2-v5", "no-entry-point") with pytest.raises( gym.error.VersionNotFound, @@ -79,7 +79,7 @@ def test_spec_versioned_lookups(): def test_spec_default_lookups(): - gym.register("test/Test3") + gym.register("test/Test3", "no-entry-point") with pytest.raises( gym.error.DeprecatedEnv, diff --git a/tests/testing_env.py b/tests/testing_env.py index 957f25fc8..64ab691ed 100644 --- a/tests/testing_env.py +++ b/tests/testing_env.py @@ -48,7 +48,7 @@ class GenericTestEnv(gym.Env): render_fn: callable = basic_render_fn, metadata: Optional[Dict[str, Any]] = None, render_mode: Optional[str] = None, - spec: EnvSpec = EnvSpec("TestingEnv-v0"), + spec: EnvSpec = EnvSpec("TestingEnv-v0", "testing-env-no-entry-point"), ): self.metadata = {} if metadata is None else metadata self.render_mode = render_mode