diff --git a/CPU_Container.dockerfile b/CPU_Container.dockerfile index fc0c36ed..78d21dd4 100644 --- a/CPU_Container.dockerfile +++ b/CPU_Container.dockerfile @@ -9,7 +9,7 @@ ARG DEBIAN_FRONTEND=noninteractive ENV TZ=America/New_York # --build-arg mcsversion=x.y.z to override default in docker build command -ARG mcsversion=0.7.2 +ARG mcsversion=0.7.3 ARG mcs_library_version=master WORKDIR /mcs diff --git a/Dockerfile b/Dockerfile index 792c4962..25e2bf94 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,7 +19,7 @@ ENV NVIDIA_DRIVER_CAPABILITIES ${NVIDIA_DRIVER_CAPABILITIES},display # ENV LANG C.UTF-8 # --build-arg mcsversion=x.y.z to override default in docker build command -ARG mcsversion=0.7.2 +ARG mcsversion=0.7.3 ARG mcs_library_version=master WORKDIR /mcs diff --git a/README.md b/README.md index f230e0a9..5d7f585d 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Publish to PyPI: [![Publish PyPI](https://github.com/NextCenturyCorporation/MCS/ # MCS Python Package -Python interface for interacting with MCS AI2Thor environment and running scenes. The latest release of the MCS Python library is `0.7.2`. You can find the latest documentation [here](https://nextcenturycorporation.github.io/MCS). +Python interface for interacting with MCS AI2Thor environment and running scenes. The latest release of the MCS Python library is `0.7.3`. You can find the latest documentation [here](https://nextcenturycorporation.github.io/MCS). - [Quickstart Installation](#quickstart-installation) - [Usage](#usage) diff --git a/docs/source/install.rst b/docs/source/install.rst index 1ef332e6..dfcb5133 100644 --- a/docs/source/install.rst +++ b/docs/source/install.rst @@ -2,8 +2,8 @@ Installation and Setup ======================= -.. _Download and unzip the Mac ZIP: https://github.com/NextCenturyCorporation/MCS/releases/download/0.7.2/MCS-AI2-THOR-Unity-App-v0.7.2-mac.zip -.. _Download and unzip the Linux ZIP: https://github.com/NextCenturyCorporation/MCS/releases/download/0.7.2/MCS-AI2-THOR-Unity-App-v0.7.2-linux.zip +.. _Download and unzip the Mac ZIP: https://github.com/NextCenturyCorporation/MCS/releases/download/0.7.3/MCS-AI2-THOR-Unity-App-v0.7.3-mac.zip +.. _Download and unzip the Linux ZIP: https://github.com/NextCenturyCorporation/MCS/releases/download/0.7.3/MCS-AI2-THOR-Unity-App-v0.7.3-linux.zip Virtual Environments ------------------------ @@ -240,7 +240,7 @@ controller_timeout (int, optional) -Sets the time (in seconds) to allow on controller initialization before timing out. Default 180 +Sets the time (in seconds) to allow on controller initialization before timing out. Default 600 terminal_output ^^^^^^^^^^^^^^^ diff --git a/integration_tests/additional_integration_tests.py b/integration_tests/additional_integration_tests.py index 12514d13..8940032f 100644 --- a/integration_tests/additional_integration_tests.py +++ b/integration_tests/additional_integration_tests.py @@ -86,13 +86,12 @@ def run_depth_and_segmentation_test(controller, metadata_tier): for row_idx, pixel_row in enumerate( output_depth_data[0]["depth_map_list"][0]): for col_idx, pixel_col in enumerate(pixel_row): - # Need to account for hardware differences if (not math.isclose( pixel_col, step_metadata_0.depth_map_list[0][row_idx][col_idx], - rel_tol=0.00009, - abs_tol=0.00009 + rel_tol=0.0009, + abs_tol=0.0009 )): return ( False, @@ -150,8 +149,8 @@ def run_depth_and_segmentation_test(controller, metadata_tier): if (not math.isclose( pixel_col, step_metadata_1.depth_map_list[0][row_idx][col_idx], - rel_tol=0.00009, - abs_tol=0.00009 + rel_tol=0.0009, + abs_tol=0.0009 )): return ( False, diff --git a/integration_tests/data/081.move_into_light_object_intuitive_reset.oracle.outputs.json b/integration_tests/data/081.move_into_light_object_intuitive_reset.oracle.outputs.json index 943293b1..535e8437 100644 --- a/integration_tests/data/081.move_into_light_object_intuitive_reset.oracle.outputs.json +++ b/integration_tests/data/081.move_into_light_object_intuitive_reset.oracle.outputs.json @@ -323,7 +323,7 @@ { "direction_x": 0.0, "direction_y": -0.734, - "direction_z": 0.69, + "direction_z": 0.68, "distance": 0.697, "held": false, "id": "testBall", @@ -353,7 +353,7 @@ "objects": [ { "direction_x": 0.0, - "direction_y": -0.72, + "direction_y": -0.73, "direction_z": 0.69, "distance": 0.71, "held": false, diff --git a/integration_tests/data/110.tool_cannot_walk_into.oracle.outputs.json b/integration_tests/data/110.tool_cannot_walk_into.oracle.outputs.json index f8fe158d..afb58f68 100644 --- a/integration_tests/data/110.tool_cannot_walk_into.oracle.outputs.json +++ b/integration_tests/data/110.tool_cannot_walk_into.oracle.outputs.json @@ -17,7 +17,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -48,7 +49,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -79,7 +81,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -110,7 +113,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -141,7 +145,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } diff --git a/integration_tests/data/111.tool_push.oracle.outputs.json b/integration_tests/data/111.tool_push.oracle.outputs.json index b1454949..d331e709 100644 --- a/integration_tests/data/111.tool_push.oracle.outputs.json +++ b/integration_tests/data/111.tool_push.oracle.outputs.json @@ -17,7 +17,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -48,7 +49,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -79,7 +81,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -110,7 +113,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -141,7 +145,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -172,7 +177,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -203,7 +209,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -234,7 +241,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -265,7 +273,8 @@ "rotation_y": 0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -296,7 +305,8 @@ "rotation_y": 0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -327,7 +337,8 @@ "rotation_y": 0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } diff --git a/integration_tests/data/112.tool_move.oracle.outputs.json b/integration_tests/data/112.tool_move.oracle.outputs.json index 3128f633..ee1975b3 100644 --- a/integration_tests/data/112.tool_move.oracle.outputs.json +++ b/integration_tests/data/112.tool_move.oracle.outputs.json @@ -17,7 +17,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -48,7 +49,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -79,7 +81,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -110,7 +113,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -141,7 +145,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -172,7 +177,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -203,7 +209,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } diff --git a/integration_tests/data/113.tool_torque.oracle.outputs.json b/integration_tests/data/113.tool_torque.oracle.outputs.json index f9188413..9dfa6506 100644 --- a/integration_tests/data/113.tool_torque.oracle.outputs.json +++ b/integration_tests/data/113.tool_torque.oracle.outputs.json @@ -17,7 +17,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -48,7 +49,8 @@ "rotation_y": 1, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -79,7 +81,8 @@ "rotation_y": 2, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -110,7 +113,8 @@ "rotation_y": 4, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -141,7 +145,8 @@ "rotation_y": 7, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -172,7 +177,8 @@ "rotation_y": 9, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -203,7 +209,8 @@ "rotation_y": 10, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -237,7 +244,8 @@ ], "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -271,7 +279,8 @@ ], "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } diff --git a/integration_tests/data/114.tool_rotate.oracle.outputs.json b/integration_tests/data/114.tool_rotate.oracle.outputs.json index dadfd109..fd94df1f 100644 --- a/integration_tests/data/114.tool_rotate.oracle.outputs.json +++ b/integration_tests/data/114.tool_rotate.oracle.outputs.json @@ -17,7 +17,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -48,7 +49,8 @@ "rotation_y": 5, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -79,7 +81,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -110,7 +113,8 @@ "rotation_y": 355, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -141,7 +145,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } diff --git a/integration_tests/data/115.tool_push_into_soccer_ball.oracle.outputs.json b/integration_tests/data/115.tool_push_into_soccer_ball.oracle.outputs.json index 641a20a6..5af5a2d6 100644 --- a/integration_tests/data/115.tool_push_into_soccer_ball.oracle.outputs.json +++ b/integration_tests/data/115.tool_push_into_soccer_ball.oracle.outputs.json @@ -37,7 +37,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -87,7 +88,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -137,7 +139,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -187,7 +190,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -237,7 +241,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -287,7 +292,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -337,7 +343,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -387,7 +394,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -437,7 +445,8 @@ "rotation_y": 0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -487,7 +496,8 @@ "rotation_y": 0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -537,7 +547,8 @@ "rotation_y": 0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -587,7 +598,8 @@ "rotation_y": 0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -637,7 +649,8 @@ "rotation_y": 0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -687,7 +700,8 @@ "rotation_y": 0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -737,7 +751,8 @@ "rotation_y": 0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -787,7 +802,8 @@ "rotation_y": 0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -837,7 +853,8 @@ "rotation_y": 0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } diff --git a/integration_tests/data/116.tool_move_into_soccer_ball.oracle.outputs.json b/integration_tests/data/116.tool_move_into_soccer_ball.oracle.outputs.json index 4220320b..4d70cd54 100644 --- a/integration_tests/data/116.tool_move_into_soccer_ball.oracle.outputs.json +++ b/integration_tests/data/116.tool_move_into_soccer_ball.oracle.outputs.json @@ -37,7 +37,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -88,7 +89,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -139,7 +141,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -190,7 +193,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -241,7 +245,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -292,7 +297,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -343,7 +349,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -394,7 +401,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -445,7 +453,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -496,7 +505,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -547,7 +557,8 @@ "rotation_y": 0.0, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } diff --git a/integration_tests/data/141.rotate_and_move_object_collide_with_performer.oracle.outputs.json b/integration_tests/data/141.rotate_and_move_object_collide_with_performer.oracle.outputs.json index 4489b887..23334211 100644 --- a/integration_tests/data/141.rotate_and_move_object_collide_with_performer.oracle.outputs.json +++ b/integration_tests/data/141.rotate_and_move_object_collide_with_performer.oracle.outputs.json @@ -17,7 +17,8 @@ "rotation_y": 90, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -48,7 +49,8 @@ "rotation_y": 95, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -79,7 +81,8 @@ "rotation_y": 95, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -110,7 +113,8 @@ "rotation_y": 95, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -141,7 +145,8 @@ "rotation_y": 95, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } @@ -172,7 +177,8 @@ "rotation_y": 95, "shape": "tool", "texture_color_list": [ - "grey" + "grey", + "black" ], "visible": true } diff --git a/integration_tests/run_handmade_tests.py b/integration_tests/run_handmade_tests.py index 6f022c2b..623f48ff 100644 --- a/integration_tests/run_handmade_tests.py +++ b/integration_tests/run_handmade_tests.py @@ -392,7 +392,7 @@ def start_handmade_tests( else: failed_test_list.append((test_name, metadata_tier, status)) - controller.stop_simulation() + controller.stop_simulation() successful_test_list.sort(key=lambda x: x[0]) failed_test_list.sort(key=lambda x: x[0]) diff --git a/machine_common_sense/__init__.py b/machine_common_sense/__init__.py index 1989cbc7..bb78c855 100644 --- a/machine_common_sense/__init__.py +++ b/machine_common_sense/__init__.py @@ -1,3 +1,5 @@ +from . import import_override # isort: skip + import concurrent.futures import json import logging diff --git a/machine_common_sense/_version.py b/machine_common_sense/_version.py index fb9b668f..1ef13195 100644 --- a/machine_common_sense/_version.py +++ b/machine_common_sense/_version.py @@ -1 +1 @@ -__version__ = '0.7.2' +__version__ = '0.7.3' diff --git a/machine_common_sense/config_manager.py b/machine_common_sense/config_manager.py index a1624726..0c07e57e 100644 --- a/machine_common_sense/config_manager.py +++ b/machine_common_sense/config_manager.py @@ -356,7 +356,7 @@ class ConfigManager: TIMEOUT_DEFAULT = 3600 # Default time for initalizing a controller. - CONTROLLER_TIMEOUT_DEFAULT = 180 + CONTROLLER_TIMEOUT_DEFAULT = 600 def __init__(self, config_file_or_dict=None): ''' diff --git a/machine_common_sense/controller.py b/machine_common_sense/controller.py index 2a3bc753..f714f7e3 100644 --- a/machine_common_sense/controller.py +++ b/machine_common_sense/controller.py @@ -7,12 +7,15 @@ import json import logging import os +import platform import threading import time from typing import Dict, List, Optional, Union import ai2thor.controller +import ai2thor.fifo_server import ai2thor.server +import ai2thor.wsgi_server import numpy as np import typeguard # can we replace with pydantic function validator? @@ -49,6 +52,16 @@ def __reset_override(self, scene): ai2thor.controller.Controller.reset = __reset_override +def __stop_unity_override(self): + if self.server and self.server.unity_proc: + self.killing_unity = True + # Cannot use os.kill on Windows due to permissions, so use Popen.kill. + self.server.unity_proc.kill() + + +ai2thor.controller.Controller.stop_unity = __stop_unity_override + + def __image_depth_override(self, image_depth_data, **kwargs): # From https://github.com/NextCenturyCorporation/ai2thor/blob/47a9d0802861ba8d7a2a7a6d943a46db28ddbaab/ai2thor/server.py#L232-L240 # noqa: E501 # The MCS depth shader in Unity is completely different now, so override @@ -93,6 +106,10 @@ class Controller(): @typeguard.typechecked def __init__(self, unity_app_file_path: str, config: ConfigManager): + server_class = ai2thor.fifo_server.FifoServer + if platform.system() == 'Windows': + # Cannot use os.mkfifo on Windows, so use ai2thor's WSGI server. + server_class = ai2thor.wsgi_server.WsgiServer # Suppress print statements from the AI2-THOR Controller's constructor. with contextlib.redirect_stdout(io.StringIO()) as _: self._controller = ai2thor.controller.Controller( @@ -103,6 +120,7 @@ def __init__(self, unity_app_file_path: str, config: ConfigManager): width=config.get_screen_width(), height=config.get_screen_height(), scene='MCS', # Unity scene name + server_class=server_class, logs=True, # This constructor always initializes a scene, so add a scene # config to ensure it doesn't error @@ -238,10 +256,11 @@ def start_scene( ai2thor_step = self.parameter_converter.wrap_step( output_folder=self.__output_folder, - action='Initialize', sceneConfig=sc, goal_object_ids=self.__goal_object_ids) - step_output = self._controller.step(ai2thor_step) + # Must call reset first, which automatically initializes the new scene. + self._controller.initialization_parameters = ai2thor_step + step_output = self._controller.reset(scene='MCS') self._output_handler.set_scene_config(scene_config) (pre_restrict_output, output) = self._output_handler.handle_output( diff --git a/machine_common_sense/import_override.py b/machine_common_sense/import_override.py new file mode 100644 index 00000000..36a647d4 --- /dev/null +++ b/machine_common_sense/import_override.py @@ -0,0 +1,51 @@ +import builtins +from types import ModuleType + +import portalocker + + +class MockFcntl(ModuleType): + """ + The fcntl module is not available on Windows; if it's not found, then + return this mock module which wraps calls to the portalocker library. + The ai2thor python library depends on its "lockf" function and some static + variables. + """ + + LOCK_SH = 1 + LOCK_EX = 2 + LOCK_NB = 4 + LOCK_UN = 8 + + def lockf(self, lock_file, lock_mode): + if lock_mode == self.LOCK_SH: + portalocker.lock(lock_file, portalocker.LockFlags.SHARED) + if lock_mode > self.LOCK_SH and lock_mode < self.LOCK_UN: + portalocker.lock(lock_file, portalocker.LockFlags.EXCLUSIVE) + if lock_mode == self.LOCK_UN: + portalocker.unlock(lock_file) + + +class MockModule(ModuleType): + def __getattr__(self, key): + return None + __all__ = [] + + +def mock_import(name, *args, **kwargs): + try: + real_module = real_import(name, *args, **kwargs) + return real_module + except (ImportError, NameError) as e: + # Return mocks for all modules required by the ai2thor python library + # but not available on Windows. + if name == 'fcntl': + return MockFcntl(name) + if name in ['termios', 'tty']: + return MockModule(name) + raise e + + +# Override the built-in import function with mock_import, but save the original +# import function as real_import. +real_import, builtins.__import__ = builtins.__import__, mock_import diff --git a/machine_common_sense/unity_executable_provider.py b/machine_common_sense/unity_executable_provider.py index 629a99cf..722ec196 100644 --- a/machine_common_sense/unity_executable_provider.py +++ b/machine_common_sense/unity_executable_provider.py @@ -17,8 +17,15 @@ LINUX_URL = "https://github.com/NextCenturyCorporation/MCS/releases/download/{ver}/MCS-AI2-THOR-Unity-App-v{ver}-linux.zip" # noqa MAC_URL = "https://github.com/NextCenturyCorporation/MCS/releases/download/{ver}/MCS-AI2-THOR-Unity-App-v{ver}-mac.zip" # noqa +WIN64_URL = "https://github.com/NextCenturyCorporation/MCS/releases/download/{ver}/MCS-AI2-THOR-Unity-App-v{ver}-win64.zip" # noqa LINUX_DEV_URL = "https://ai2thor-unity-releases.s3.amazonaws.com/MCS-AI2-THOR-Unity-App-vdevelop-linux.zip" # noqa MAC_DEV_URL = "https://ai2thor-unity-releases.s3.amazonaws.com/MCS-AI2-THOR-Unity-App-vdevelop-mac.zip" # noqa +WIN64_DEV_URL = "https://ai2thor-unity-releases.s3.amazonaws.com/MCS-AI2-THOR-Unity-App-vdevelop-win64.zip" # noqa + +PLATFORM_MAC = "Darwin" +PLATFORM_LINUX = "Linux" +PLATFORM_OTHER = "other" +PLATFORM_WINDOWS64 = "Windows" class UnityExecutableProvider(): @@ -26,9 +33,6 @@ class UnityExecutableProvider(): package. Will check a cache and download if necessary''' DOWNLOAD_FILE = "MCS-AI2-THOR-Unity-App-v{}.zip" - PLATFORM_MAC = "Darwin" - PLATFORM_LINUX = "Linux" - PLATFORM_OTHER = "other" def __init__(self): self._downloader = Downloader() @@ -36,12 +40,13 @@ def __init__(self): def _platform_init(self): self._switcher = { - self.PLATFORM_LINUX: self._linux_init, - self.PLATFORM_MAC: self._mac_init, - self.PLATFORM_OTHER: self._other_init + PLATFORM_LINUX: self._linux_init, + PLATFORM_MAC: self._mac_init, + PLATFORM_OTHER: self._other_init, + PLATFORM_WINDOWS64: self._windows64_init } sys = platform.system() - self._switcher.get(sys, self.PLATFORM_OTHER)() + self._switcher.get(sys, PLATFORM_OTHER)() def _mac_init(self): self._cache = MacExecutionCache() @@ -49,9 +54,12 @@ def _mac_init(self): def _linux_init(self): self._cache = LinuxExecutionCache() + def _windows64_init(self): + self._cache = Windows64ExecutionCache() + def _other_init(self): raise Exception( - "Ai2thorProvider only supports Linux and Mac. " + "Ai2thorProvider only supports Linux, Windows and Mac. " f"Platform={platform.system()}" ) @@ -151,10 +159,12 @@ def add_zip_to_cache(self, version, zip_file: Path): f"Unzipping {zip_file.name} to {ver_dir.as_posix()}") zip.extractall(ver_dir) logger.info(f"Deleting {zip_file.name}.") - zip_file.unlink() + if platform.system() in [PLATFORM_LINUX, PLATFORM_MAC]: + zip_file.unlink() ver_dir = self._get_version_dir(version) file = self._get_executable_file().format(version=version) - (ver_dir / file).chmod(755) + if platform.system() in [PLATFORM_LINUX, PLATFORM_MAC]: + (ver_dir / file).chmod(755) for file in self._get_gz_files(): file = file.format(version=version) @@ -246,13 +256,36 @@ def _get_required_files(self): return self.REQUIRED_FILES +class Windows64ExecutionCache(AbstractExecutionCache): + '''Handles Windows64 specific code for running a cache for MCS Unity + executables.''' + REQUIRED_FILES = [ + "MonoBleedingEdge", + "UnityPlayer.dll", + "UnityCrashHandler64.exe", + "MCS-AI2-THOR-Unity-App-v{version}-win64_Data", + "MCS-AI2-THOR-Unity-App-v{version}-win64.exe"] + EXECUTABLE_FILE = "MCS-AI2-THOR-Unity-App-v{version}-win64.exe" + GZ_FILES = ["MCS-AI2-THOR-Unity-App-v{version}-win64_Data.tar.gz"] + + def _get_executable_file(self): + return self.EXECUTABLE_FILE + + def _get_gz_files(self): + return self.GZ_FILES + + def _get_required_files(self): + return self.REQUIRED_FILES + + class Downloader(): '''Handles downloading MCS AI2THOR package''' def get_url(self, ver): sys = platform.system() if (sys == "Windows"): - raise Exception("Windows is not supported") + return WIN64_URL.format( + ver=ver) if ver != "develop" else WIN64_DEV_URL elif sys == "Linux": return LINUX_URL.format( ver=ver) if ver != "develop" else LINUX_DEV_URL diff --git a/requirements.txt b/requirements.txt index a5c9ce48..3c669b35 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,6 +19,7 @@ numpyencoder==0.3.0 opencv-python==4.4.0.46; python_version<="3.9" opencv-python==4.5.4.60; python_version>="3.10" pep8-naming==0.13.3 +portalocker pre-commit==2.21.0; python_version<"3.8" pre-commit==3.2.2; python_version>="3.8" pydantic==1.10.7 diff --git a/tests/mock_controller.py b/tests/mock_controller.py index bf57287e..ee68181d 100644 --- a/tests/mock_controller.py +++ b/tests/mock_controller.py @@ -38,6 +38,7 @@ class MockController(): '''Mock of the Controller class from the AI2-THOR library.''' def __init__(self): + self.initialization_parameters = None self.__last_step_data = None self.__last_metadata = MOCK_VARIABLES['metadata'].copy() self._subscribers = [] @@ -56,6 +57,10 @@ def step(self, data): 0, [event for _ in range(MOCK_VARIABLES['event_count'])] ) + def reset(self, scene): + self.initialization_parameters['action'] = 'Initialize' + return self.step(self.initialization_parameters) + def get_last_step_data(self): return self.__last_step_data diff --git a/tests/test_config_manager.py b/tests/test_config_manager.py index cce50bcf..79d7a14d 100644 --- a/tests/test_config_manager.py +++ b/tests/test_config_manager.py @@ -191,9 +191,9 @@ def test_get_metadata_tier(self): 'oracle') def test_controller_timeout(self): - self.assertEquals(self.config_mngr.get_controller_timeout(), 180) + self.assertEqual(self.config_mngr.get_controller_timeout(), 600) self.config_mngr.set_controller_timeout(str(90)) - self.assertEquals(self.config_mngr.get_controller_timeout(), 90) + self.assertEqual(self.config_mngr.get_controller_timeout(), 90) def test_get_size(self): self.assertEqual(self.config_mngr.get_size(), 600) diff --git a/tests/test_recorder.py b/tests/test_recorder.py index 5a00d319..20286f7d 100644 --- a/tests/test_recorder.py +++ b/tests/test_recorder.py @@ -249,7 +249,10 @@ def setUp(self): def tearDown(self): if self.test_video_file.exists(): - self.test_video_file.unlink() + try: + self.test_video_file.unlink() + except Exception: + pass def test_video_path(self): self.assertEqual(self.recorder.path, self.test_video_file)