diff --git a/android_world/env/adb_utils.py b/android_world/env/adb_utils.py index 799f2144..3653af62 100644 --- a/android_world/env/adb_utils.py +++ b/android_world/env/adb_utils.py @@ -1015,7 +1015,7 @@ def extract_broadcast_data(raw_output: str) -> Optional[str]: Extracted data as a string, or None if the result is 0. """ if 'Broadcast completed: result=-1, data=' in raw_output: - return raw_output.split('data=')[1].strip('"\n') + return raw_output.split('data=')[1].strip('"\r\n') elif 'Broadcast completed: result=0' in raw_output: return None else: diff --git a/android_world/env/android_world_controller.py b/android_world/env/android_world_controller.py index 62e38180..91eefebc 100644 --- a/android_world/env/android_world_controller.py +++ b/android_world/env/android_world_controller.py @@ -103,7 +103,7 @@ def get_a11y_tree( return forest -_TASK_PATH = '/tmp/default.textproto' +_TASK_PATH = file_utils.convert_to_posix_path(file_utils.get_local_tmp_directory(), 'default.textproto') DEFAULT_ADB_PATH = '~/Android/Sdk/platform-tools/adb' diff --git a/android_world/env/android_world_controller_test.py b/android_world/env/android_world_controller_test.py index c01f3f18..cf4bae09 100644 --- a/android_world/env/android_world_controller_test.py +++ b/android_world/env/android_world_controller_test.py @@ -30,7 +30,7 @@ def create_file_with_contents(contents: str) -> str: temp_dir = tempfile.mkdtemp() - file_path = os.path.join(temp_dir, 'file.txt') + file_path = file_utils.convert_to_posix_path(temp_dir, 'file.txt') with open(file_path, 'w') as f: f.write(contents) return file_path @@ -169,7 +169,7 @@ def test_pull_file(self): with env.pull_file(remote_file_path) as local_dir: local_path = os.path.split(remote_file_path)[1] - local_file = open(os.path.join(local_dir, local_path), 'r') + local_file = open(file_utils.convert_to_posix_path(local_dir, local_path), 'r') self.assertEqual(open(remote_file_path, 'r').read(), local_file.read()) self.mock_copy_db.assert_called_once_with( diff --git a/android_world/env/setup_device/apps.py b/android_world/env/setup_device/apps.py index a219c01a..63c56473 100644 --- a/android_world/env/setup_device/apps.py +++ b/android_world/env/setup_device/apps.py @@ -32,16 +32,16 @@ import requests -APP_DATA = os.path.join(os.path.dirname(__file__), 'app_data') +APP_DATA = file_utils.convert_to_posix_path(os.path.dirname(__file__), 'app_data') def download_app_data(file_name: str) -> str: """Downloads file from a GCS bucket, if not cached, and installs it.""" - cache_dir = "/tmp/android_world/app_data" + cache_dir = file_utils.convert_to_posix_path(file_utils.get_local_tmp_directory(), 'android_world', 'app_data') remote_url = ( f"https://storage.googleapis.com/gresearch/android_world/{file_name}" ) - full_path = os.path.join(cache_dir, file_name) + full_path = file_utils.convert_to_posix_path(cache_dir, file_name) os.makedirs(cache_dir, exist_ok=True) if not os.path.isfile(full_path): logging.info("Downloading file_name %s to cache %s", file_name, cache_dir) @@ -580,7 +580,7 @@ def setup(cls, env: interface.AsyncEnv) -> None: "shell", "chcon", "u:object_r:media_rw_data_file:s0", - os.path.join(cls.DEVICE_MAPS_PATH, map_file), + file_utils.convert_to_posix_path(cls.DEVICE_MAPS_PATH, map_file), ], env.controller, ) diff --git a/android_world/task_evals/common_validators/file_validators.py b/android_world/task_evals/common_validators/file_validators.py index a5d4eab4..145deb8c 100644 --- a/android_world/task_evals/common_validators/file_validators.py +++ b/android_world/task_evals/common_validators/file_validators.py @@ -44,10 +44,10 @@ class MoveFile(task_eval.TaskEval): def __init__(self, params: dict[str, Any], data_directory: str): """Initialize the task.""" super().__init__(params) - self.source_directory = os.path.join( + self.source_directory = file_utils.convert_to_posix_path( data_directory, self.params["source_folder"] ) - self.dest_directory = os.path.join( + self.dest_directory = file_utils.convert_to_posix_path( data_directory, self.params["destination_folder"] ) @@ -123,7 +123,7 @@ def __init__(self, params: dict[str, Any], data_directory: str): """ super().__init__(params) if "subfolder" in self.params: - self.data_directory = os.path.join( + self.data_directory = file_utils.convert_to_posix_path( data_directory, self.params["subfolder"] ) else: @@ -214,7 +214,7 @@ def is_successful(self, env: interface.AsyncEnv) -> float: [ "shell", "cat", - os.path.join(self.data_directory, file_name), + file_utils.convert_to_posix_path(self.data_directory, file_name), ], env.controller, ) diff --git a/android_world/task_evals/common_validators/sms_validators.py b/android_world/task_evals/common_validators/sms_validators.py index fc47048b..7e4f7da4 100644 --- a/android_world/task_evals/common_validators/sms_validators.py +++ b/android_world/task_evals/common_validators/sms_validators.py @@ -48,6 +48,7 @@ def parse_message(row: str) -> dict[str, str]: """ parsed_dict = {} + row = row.strip() body_start = row.find("body=") if body_start != -1: diff --git a/android_world/task_evals/information_retrieval/information_retrieval_registry.py b/android_world/task_evals/information_retrieval/information_retrieval_registry.py index 16d4c6cb..a9dbfb58 100644 --- a/android_world/task_evals/information_retrieval/information_retrieval_registry.py +++ b/android_world/task_evals/information_retrieval/information_retrieval_registry.py @@ -24,6 +24,7 @@ from typing import Any, Generic, Type, TypeVar from android_world.task_evals.information_retrieval import information_retrieval from android_world.task_evals.information_retrieval.proto import task_pb2 +from android_world.utils import file_utils from google.protobuf import text_format TaskType = TypeVar('TaskType', bound=information_retrieval.InformationRetrieval) @@ -50,7 +51,7 @@ def registry( def _read_tasks(self) -> task_pb2.Tasks: proto = task_pb2.Tasks() script_dir = os.path.dirname(os.path.abspath(__file__)) - local_path = os.path.join(script_dir, 'proto', 'tasks.textproto') + local_path = file_utils.convert_to_posix_path(script_dir, 'proto', 'tasks.textproto') with open(local_path, 'r') as f: textproto_content = f.read() text_format.Merge(textproto_content, proto) diff --git a/android_world/task_evals/information_retrieval/joplin_app_utils.py b/android_world/task_evals/information_retrieval/joplin_app_utils.py index 541f59d8..8e11d951 100644 --- a/android_world/task_evals/information_retrieval/joplin_app_utils.py +++ b/android_world/task_evals/information_retrieval/joplin_app_utils.py @@ -24,6 +24,7 @@ from android_world.task_evals.information_retrieval.proto import task_pb2 from android_world.task_evals.utils import sqlite_schema_utils from android_world.task_evals.utils import sqlite_utils +from android_world.utils import file_utils _NOTES_TABLE = "notes" _NOTES_NORMALIZED_TABLE = "notes_normalized" @@ -84,7 +85,7 @@ def _get_folder_to_id( ) -> dict[str, str]: """Gets a mapping from folder title to ID as represented in Folder table.""" with env.controller.pull_file(_DB_PATH) as local_db_directory: - local_db_path = os.path.join(local_db_directory, os.path.split(_DB_PATH)[1]) + local_db_path = file_utils.convert_to_posix_path(local_db_directory, os.path.split(_DB_PATH)[1]) folder_info = sqlite_utils.execute_query( f"select * from {_FOLDER_TABLE};", local_db_path, diff --git a/android_world/task_evals/single/browser.py b/android_world/task_evals/single/browser.py index 201edde5..a5b8b8bc 100644 --- a/android_world/task_evals/single/browser.py +++ b/android_world/task_evals/single/browser.py @@ -72,11 +72,12 @@ def initialize_task(self, env: interface.AsyncEnv): ) html = self.HTML.replace('%%SEED%%', str(self.params['browser_task_seed'])) - with open('/tmp/task.html', 'w') as f: + task_html_path = file_utils.convert_to_posix_path(file_utils.get_local_tmp_directory(), 'task.html') + with open(task_html_path, 'w') as f: f.write(html) file_utils.copy_data_to_device( - '/tmp/task.html', - os.path.join(device_constants.DOWNLOAD_DATA, 'task.html'), + task_html_path, + file_utils.convert_to_posix_path(device_constants.DOWNLOAD_DATA, 'task.html'), env.controller, ) diff --git a/android_world/task_evals/single/markor.py b/android_world/task_evals/single/markor.py index db30dd3e..f24962dc 100644 --- a/android_world/task_evals/single/markor.py +++ b/android_world/task_evals/single/markor.py @@ -228,7 +228,7 @@ def is_successful(self, env: interface.AsyncEnv) -> float: [ "shell", "cat", - os.path.join( + file_utils.convert_to_posix_path( device_constants.MARKOR_DATA, self.params["file_name"] ), ], @@ -614,7 +614,7 @@ def is_successful(self, env: interface.AsyncEnv) -> float: [ "shell", "cat", - os.path.join( + file_utils.convert_to_posix_path( device_constants.MARKOR_DATA, self.params["new_file_name"] ), ], @@ -711,7 +711,7 @@ def is_successful(self, env: interface.AsyncEnv) -> float: ): return 0.0 content_updated = file_utils.check_file_content( - os.path.join(device_constants.MARKOR_DATA, self.params["new_name"]), + file_utils.convert_to_posix_path(device_constants.MARKOR_DATA, self.params["new_name"]), self.params["updated_content"], env.controller, ) @@ -793,7 +793,7 @@ def is_successful(self, env: interface.AsyncEnv) -> float: ): return 0.0 correct = file_utils.check_file_content( - os.path.join(device_constants.MARKOR_DATA, self.params["new_name"]), + file_utils.convert_to_posix_path(device_constants.MARKOR_DATA, self.params["new_name"]), self.params["header"] + "\n\n" + self.params["original_content"] + "\n", env.controller, exact_match=True, @@ -840,9 +840,10 @@ def initialize_task(self, env: interface.AsyncEnv) -> None: """Initializes the task for creating a receipt markdown file.""" super().initialize_task(env) self.create_file_task.initialize_task(env) - self.img.save("/tmp/receipt.png") + receipt_img_path = file_utils.convert_to_posix_path(file_utils.get_local_tmp_directory(), 'receipt.png') + self.img.save(receipt_img_path) file_utils.copy_data_to_device( - "/tmp/receipt.png", + receipt_img_path, device_constants.GALLERY_DATA, env.controller, ) diff --git a/android_world/task_evals/single/markor_test.py b/android_world/task_evals/single/markor_test.py index 26081ae9..f59f06b3 100644 --- a/android_world/task_evals/single/markor_test.py +++ b/android_world/task_evals/single/markor_test.py @@ -346,9 +346,10 @@ def test_initialize_task(self, mock_copy_data_to_device): task.initialize_task(mock_env) - task.img.save.assert_called_once_with('/tmp/receipt.png') + receipt_img_path = file_utils.convert_to_posix_path(file_utils.get_local_tmp_directory(), 'receipt.png') + task.img.save.assert_called_once_with(receipt_img_path) mock_copy_data_to_device.assert_called_once_with( - '/tmp/receipt.png', + receipt_img_path, device_constants.GALLERY_DATA, mock_env.controller, ) diff --git a/android_world/task_evals/single/osmand.py b/android_world/task_evals/single/osmand.py index 4d8f0d59..6a171256 100644 --- a/android_world/task_evals/single/osmand.py +++ b/android_world/task_evals/single/osmand.py @@ -31,9 +31,9 @@ _DEVICE_FILES = '/data/media/0/Android/data/net.osmand/files' _LEGACY_FILES = '/data/data/net.osmand/files' -_FAVORITES_PATH = os.path.join(_DEVICE_FILES, 'favorites/favorites.gpx') -_LEGACY_FAVORITES_PATH = os.path.join(_LEGACY_FILES, 'favourites_bak.gpx') -_BACKUP_DIR_PATH = os.path.join(_LEGACY_FILES, 'backup') +_FAVORITES_PATH = file_utils.convert_to_posix_path(_DEVICE_FILES, 'favorites/favorites.gpx') +_LEGACY_FAVORITES_PATH = file_utils.convert_to_posix_path(_LEGACY_FILES, 'favourites_bak.gpx') +_BACKUP_DIR_PATH = file_utils.convert_to_posix_path(_LEGACY_FILES, 'backup') # Random location names and coords present in the pre-loaded Liechtenstein map. _PRELOADED_MAP_LOCATIONS = { @@ -312,7 +312,7 @@ def _clear_tracks(env: env_interface.AndroidEnvInterface): Raises: RuntimeError: If there is an adb communication issue. """ - adb_args = ['shell', 'rm -rf', os.path.join(_DEVICE_FILES, 'tracks', '*')] + adb_args = ['shell', 'rm -rf', file_utils.convert_to_posix_path(_DEVICE_FILES, 'tracks', '*')] # Issue ADB pull command to copy the directory response = adb_utils.issue_generic_request(adb_args, env) if response.status != adb_pb2.AdbResponse.OK: @@ -417,13 +417,13 @@ def initialize_task(self, env: interface.AsyncEnv) -> None: def is_successful(self, env: interface.AsyncEnv) -> float: with file_utils.tmp_directory_from_device( - os.path.join(_DEVICE_FILES, 'tracks'), env.controller + file_utils.convert_to_posix_path(_DEVICE_FILES, 'tracks'), env.controller ) as tracks_directory: for track_file in os.listdir(tracks_directory): if _track_matches( _track_points( ElementTree.parse( - os.path.join(tracks_directory, track_file) + file_utils.convert_to_posix_path(tracks_directory, track_file) ).getroot() ), self._target_waypoint_coords, diff --git a/android_world/task_evals/single/retro_music.py b/android_world/task_evals/single/retro_music.py index 97b61358..235ef233 100644 --- a/android_world/task_evals/single/retro_music.py +++ b/android_world/task_evals/single/retro_music.py @@ -66,7 +66,7 @@ def _get_playlist_data( with env.controller.pull_file( _PLAYLIST_DB_PATH, timeout_sec=3 ) as local_db_directory: - local_db_path = os.path.join( + local_db_path = file_utils.convert_to_posix_path( local_db_directory, os.path.split(_PLAYLIST_DB_PATH)[1] ) return sqlite_utils.execute_query( @@ -86,7 +86,7 @@ class Queue(sqlite_schema_utils.SQLiteRow): with env.controller.pull_file( _PLAYBACK_DB_PATH, timeout_sec=3 ) as local_db_directory: - local_db_path = os.path.join( + local_db_path = file_utils.convert_to_posix_path( local_db_directory, os.path.split(_PLAYBACK_DB_PATH)[1] ) result = sqlite_utils.execute_query( @@ -151,7 +151,7 @@ def initialize_task(self, env: interface.AsyncEnv): for file in self.params['files'] + self.params['noise_files']: user_data_generation.write_mp3_file_to_device( - os.path.join(device_constants.MUSIC_DATA, file), + file_utils.convert_to_posix_path(device_constants.MUSIC_DATA, file), env, title=file.split('.')[0], artist=random.choice(user_data_generation.COMMON_GIVEN_NAMES), @@ -223,7 +223,7 @@ def goal(self) -> str: def is_successful(self, env: interface.AsyncEnv) -> float: playlist_exists = file_utils.check_file_exists( - os.path.join( + file_utils.convert_to_posix_path( device_constants.DOWNLOAD_DATA, self.params['playlist_name'] + '.m3u', ), @@ -266,7 +266,7 @@ def initialize_task(self, env: interface.AsyncEnv): ) for file, duration in zip(self.params['files'], durations): user_data_generation.write_mp3_file_to_device( - os.path.join(device_constants.MUSIC_DATA, file), + file_utils.convert_to_posix_path(device_constants.MUSIC_DATA, file), env, title=file.split('.')[0], artist=random.choice(user_data_generation.COMMON_GIVEN_NAMES), @@ -275,7 +275,7 @@ def initialize_task(self, env: interface.AsyncEnv): for file in self.params['noise_files']: user_data_generation.write_mp3_file_to_device( - os.path.join(device_constants.MUSIC_DATA, file), + file_utils.convert_to_posix_path(device_constants.MUSIC_DATA, file), env, title=file.split('.')[0], artist=random.choice(user_data_generation.COMMON_GIVEN_NAMES), diff --git a/android_world/task_evals/single/simple_draw_pro.py b/android_world/task_evals/single/simple_draw_pro.py index de2df627..a5533d9d 100644 --- a/android_world/task_evals/single/simple_draw_pro.py +++ b/android_world/task_evals/single/simple_draw_pro.py @@ -40,7 +40,7 @@ def __init__(self, params: dict[str, Any]): super().__init__(params) self.initialized = False self.create_file_task = file_validators.CreateFile( - params, os.path.join(device_constants.EMULATOR_DATA, "Pictures") + params, file_utils.convert_to_posix_path(device_constants.EMULATOR_DATA, "Pictures") ) def initialize_task(self, env: interface.AsyncEnv) -> None: diff --git a/android_world/task_evals/single/simple_gallery_pro.py b/android_world/task_evals/single/simple_gallery_pro.py index 9461c56f..2fcee2ae 100644 --- a/android_world/task_evals/single/simple_gallery_pro.py +++ b/android_world/task_evals/single/simple_gallery_pro.py @@ -43,7 +43,7 @@ def initialize_task(self, env: interface.AsyncEnv) -> None: super().initialize_task(env) user_data_generation.clear_device_storage(env) receipt_image = self.params["receipt_image"] - temp_storage_location = os.path.join("/tmp/", self.params["file_name"]) + temp_storage_location = file_utils.convert_to_posix_path(file_utils.get_local_tmp_directory(), self.params["file_name"]) receipt_image.save(temp_storage_location) file_utils.copy_data_to_device( temp_storage_location, diff --git a/android_world/task_evals/single/simple_gallery_pro_test.py b/android_world/task_evals/single/simple_gallery_pro_test.py index a07d00fd..fabc5398 100644 --- a/android_world/task_evals/single/simple_gallery_pro_test.py +++ b/android_world/task_evals/single/simple_gallery_pro_test.py @@ -26,6 +26,7 @@ from android_world.utils import app_snapshot from android_world.utils import datetime_utils from android_world.utils import fake_adb_responses +from android_world.utils import file_utils from PIL import Image @@ -35,7 +36,7 @@ def _touch_temp_file(file_name): Args: file_name: The name of the file. """ - path = os.path.join(tempfile.gettempdir(), file_name) + path = file_utils.convert_to_posix_path(tempfile.gettempdir(), file_name) with open(path, "w") as f: f.write("") diff --git a/android_world/task_evals/single/vlc.py b/android_world/task_evals/single/vlc.py index 545194d8..3b8d00f2 100644 --- a/android_world/task_evals/single/vlc.py +++ b/android_world/task_evals/single/vlc.py @@ -61,7 +61,7 @@ def _get_playlist_file_info( ) -> list[sqlite_schema_utils.PlaylistInfo]: """Executes join query to fetch playlist file info.""" with env.controller.pull_file(_DB_PATH, timeout_sec=3) as local_db_directory: - local_db_path = os.path.join(local_db_directory, os.path.split(_DB_PATH)[1]) + local_db_path = file_utils.convert_to_posix_path(local_db_directory, os.path.split(_DB_PATH)[1]) return sqlite_utils.execute_query( _get_playlist_info_query(), local_db_path, diff --git a/android_world/task_evals/single/vlc_test.py b/android_world/task_evals/single/vlc_test.py index 804efd1a..892b61be 100644 --- a/android_world/task_evals/single/vlc_test.py +++ b/android_world/task_evals/single/vlc_test.py @@ -101,9 +101,9 @@ def setUp(self): self.env_mock.controller = self.controller temp_dir = tempfile.mkdtemp() - self.test_db_path = os.path.join(temp_dir, 'app_db/vlc_media.db') + self.test_db_path = file_utils.convert_to_posix_path(temp_dir, 'app_db/vlc_media.db') os.makedirs( - os.path.join(os.path.dirname(self.test_db_path), 'app_db'), + file_utils.convert_to_posix_path(os.path.dirname(self.test_db_path), 'app_db'), exist_ok=True, ) diff --git a/android_world/task_evals/utils/sqlite_test_utils.py b/android_world/task_evals/utils/sqlite_test_utils.py index 86cc43d8..87a2c6bd 100644 --- a/android_world/task_evals/utils/sqlite_test_utils.py +++ b/android_world/task_evals/utils/sqlite_test_utils.py @@ -20,6 +20,7 @@ from android_world.env import device_constants from android_world.task_evals.utils import sqlite_schema_utils +from android_world.utils import file_utils def setup_test_db() -> str: @@ -28,7 +29,7 @@ def setup_test_db() -> str: temp_dir = tempfile.mkdtemp() # Path for the new database - db_path = os.path.join(temp_dir, 'events.db') + db_path = file_utils.convert_to_posix_path(temp_dir, 'events.db') conn = sqlite3.connect(db_path) cursor = conn.cursor() diff --git a/android_world/task_evals/utils/sqlite_utils.py b/android_world/task_evals/utils/sqlite_utils.py index 9dfd42c0..736596bf 100644 --- a/android_world/task_evals/utils/sqlite_utils.py +++ b/android_world/task_evals/utils/sqlite_utils.py @@ -21,6 +21,7 @@ from android_world.env import adb_utils from android_world.env import interface from android_world.task_evals.utils import sqlite_schema_utils +from android_world.utils import file_utils def execute_query( @@ -83,7 +84,7 @@ def get_rows_from_remote_device( with env.controller.pull_file( remote_db_file_path, timeout_sec ) as local_db_directory: - local_db_path = os.path.join( + local_db_path = file_utils.convert_to_posix_path( local_db_directory, os.path.split(remote_db_file_path)[1] ) for _ in range(n_retries): @@ -153,7 +154,7 @@ def delete_all_rows_from_table( with env.controller.pull_file( remote_db_file_path, timeout_sec ) as local_db_directory: - local_db_path = os.path.join( + local_db_path = file_utils.convert_to_posix_path( local_db_directory, os.path.split(remote_db_file_path)[1] ) @@ -193,7 +194,7 @@ def insert_rows_to_remote_db( with env.controller.pull_file( remote_db_file_path, timeout_sec ) as local_db_directory: - local_db_path = os.path.join( + local_db_path = file_utils.convert_to_posix_path( local_db_directory, os.path.split(remote_db_file_path)[1] ) diff --git a/android_world/task_evals/utils/user_data_generation.py b/android_world/task_evals/utils/user_data_generation.py index 9a989254..25aa4022 100644 --- a/android_world/task_evals/utils/user_data_generation.py +++ b/android_world/task_evals/utils/user_data_generation.py @@ -54,7 +54,7 @@ def get_font_path() -> str: raise RuntimeError("No suitable font found.") from exc -_TMP = "/tmp" +_TMP = file_utils.get_local_tmp_directory() def generate_random_string(length: int) -> str: @@ -164,7 +164,7 @@ def write_to_gallery( """ image = _draw_text(data) - temp_storage_location = os.path.join(_TMP, file_name) + temp_storage_location = file_utils.convert_to_posix_path(_TMP, file_name) image.save(temp_storage_location) file_utils.copy_data_to_device( temp_storage_location, @@ -179,7 +179,7 @@ def _copy_data_to_device( data: str, file_name: str, location: str, env: interface.AsyncEnv ): """Copies data to device by first writing locally, then copying..""" - temp_storage_location = os.path.join(_TMP, file_name) + temp_storage_location = file_utils.convert_to_posix_path(_TMP, file_name) with open(temp_storage_location, "w") as temp_file: temp_file.write(data) @@ -280,7 +280,7 @@ def write_video_file_to_device( messages = ["test" + str(random.randint(0, 1_000_000))] _create_mpeg_with_messages( - os.path.join(_TMP, file_name), + file_utils.convert_to_posix_path(_TMP, file_name), messages, display_time=message_display_time, width=width, @@ -289,7 +289,7 @@ def write_video_file_to_device( ) file_utils.copy_data_to_device( - os.path.join(_TMP, file_name), + file_utils.convert_to_posix_path(_TMP, file_name), location, env.controller, ) @@ -332,7 +332,7 @@ def write_mp3_file_to_device( title: The title of the song. duration_milliseconds: The duration of the MP3 file in milliseconds. """ - local = os.path.join(_TMP, os.path.basename(remote_path)) + local = file_utils.convert_to_posix_path(_TMP, os.path.basename(remote_path)) _create_test_mp3( local, artist=artist, @@ -447,7 +447,7 @@ def clear_internal_storage(env: interface.AsyncEnv) -> None: """Clears all internal storage directories on device.""" for directory in EMULATOR_DIRECTORIES: file_utils.clear_directory( - os.path.join(device_constants.EMULATOR_DATA, directory), env.controller + file_utils.convert_to_posix_path(device_constants.EMULATOR_DATA, directory), env.controller ) diff --git a/android_world/task_evals/utils/user_data_generation_test.py b/android_world/task_evals/utils/user_data_generation_test.py index 775828e1..04e94bcd 100644 --- a/android_world/task_evals/utils/user_data_generation_test.py +++ b/android_world/task_evals/utils/user_data_generation_test.py @@ -16,6 +16,7 @@ import tempfile from absl.testing import absltest from android_world.task_evals.utils import user_data_generation +from android_world.utils import file_utils import cv2 @@ -42,7 +43,7 @@ def get_video_properties(file_path: str) -> tuple[int, float]: class TestCreateMpegWithMessages(absltest.TestCase): def test_video_properties(self): - file_path = os.path.join(tempfile.mkdtemp(), "test_video.mp4") + file_path = file_utils.convert_to_posix_path(tempfile.mkdtemp(), "test_video.mp4") messages = ["Hello", "World"] width = 10 height = 12 diff --git a/android_world/utils/app_snapshot.py b/android_world/utils/app_snapshot.py index 55c4d256..11129eeb 100644 --- a/android_world/utils/app_snapshot.py +++ b/android_world/utils/app_snapshot.py @@ -27,14 +27,14 @@ def _app_data_path(app_name: str) -> str: package_name = adb_utils.extract_package_name( adb_utils.get_adb_activity(app_name) ) - return os.path.join("/data/data/", package_name) + return file_utils.convert_to_posix_path("/data/data/", package_name) def _snapshot_path(app_name: str) -> str: package_name = adb_utils.extract_package_name( adb_utils.get_adb_activity(app_name) ) - return os.path.join(device_constants.SNAPSHOT_DATA, package_name) + return file_utils.convert_to_posix_path(device_constants.SNAPSHOT_DATA, package_name) def clear_snapshot( diff --git a/android_world/utils/fake_adb_responses.py b/android_world/utils/fake_adb_responses.py index b933abf5..8f69a2fa 100644 --- a/android_world/utils/fake_adb_responses.py +++ b/android_world/utils/fake_adb_responses.py @@ -22,6 +22,7 @@ import os from android_env.proto import adb_pb2 +from android_world.utils import file_utils def create_successful_generic_response(output: str) -> adb_pb2.AdbResponse: @@ -93,7 +94,7 @@ def create_check_file_or_folder_exists_responses( return [ create_check_directory_exists_response(exists=True), create_successful_generic_response( - os.path.join(base_path, file_name) + "\n" + file_utils.convert_to_posix_path(base_path, file_name) + "\n" ), ] diff --git a/android_world/utils/file_test_utils.py b/android_world/utils/file_test_utils.py index 462413af..20944e37 100644 --- a/android_world/utils/file_test_utils.py +++ b/android_world/utils/file_test_utils.py @@ -20,6 +20,7 @@ import tempfile from android_env import env_interface +from android_world.utils import file_utils @contextlib.contextmanager @@ -31,7 +32,7 @@ def mock_tmp_directory_from_device( """Mocks `file_utils.tmp_directory_from_device` for unit testing.""" del env, timeout_sec with tempfile.TemporaryDirectory() as tmp_dir: - parent_dir = os.path.join( + parent_dir = file_utils.convert_to_posix_path( tmp_dir, os.path.split(os.path.split(device_path)[0])[1] ) try: @@ -75,7 +76,7 @@ def mock_remove_files(directory: str, env: env_interface.AndroidEnvInterface): """ del env for filename in os.listdir(directory): - file_path = os.path.join(directory, filename) + file_path = file_utils.convert_to_posix_path(directory, filename) if os.path.isfile(file_path) or os.path.islink(file_path): os.unlink(file_path) elif os.path.isdir(file_path): diff --git a/android_world/utils/file_utils.py b/android_world/utils/file_utils.py index d442fc01..b99476e5 100644 --- a/android_world/utils/file_utils.py +++ b/android_world/utils/file_utils.py @@ -24,6 +24,7 @@ import tempfile from typing import Iterator from typing import Optional +from pathlib import Path from absl import logging from android_env import env_interface @@ -32,9 +33,25 @@ from android_world.env import adb_utils from android_world.utils import fuzzy_match_lib +def get_local_tmp_directory() -> str: + """Returns the local temporary directory path. + + Returns: + str: The local temporary directory path. + """ + return tempfile.gettempdir() + +def convert_to_posix_path(*args): + """Converts the given path to a posix path. + It can also be used to join paths. + + Returns: + str: The path in posix format. + """ + return str(Path(*args).as_posix()) # Local temporary location for files copied to or from the device. -TMP_LOCAL_LOCATION = "/tmp/android_world" +TMP_LOCAL_LOCATION = convert_to_posix_path(get_local_tmp_directory(), "android_world") @dataclasses.dataclass(frozen=True) @@ -70,7 +87,7 @@ def remove_single_file( file_list = get_file_list_with_metadata(base_path, env) if target in [file_info.file_name for file_info in file_list]: adb_utils.issue_generic_request( - ["shell", "rm", "-r", os.path.join(base_path, target)], + ["shell", "rm", "-r", convert_to_posix_path(base_path, target)], env, ) else: @@ -234,7 +251,7 @@ def check_file_or_folder_exists( all_paths = set(res.generic.output.decode().split("\n")) - full_target_path = os.path.join(base_path, target) + full_target_path = convert_to_posix_path(base_path, target) return full_target_path in all_paths @@ -327,7 +344,7 @@ def tmp_directory_from_device( ) ) adb_utils.check_ok(pull_response) - with open(os.path.join(tmp_directory, file.file_name), "wb") as f: + with open(convert_to_posix_path(tmp_directory, file.file_name), "wb") as f: f.write(pull_response.pull.content) yield tmp_directory @@ -357,8 +374,8 @@ def tmp_file_from_device( RuntimeError: If there is an adb communication error. """ head, tail = os.path.split(device_file) - dir_and_file_name = os.path.join(os.path.basename(head), tail) - local_file = os.path.join(TMP_LOCAL_LOCATION, dir_and_file_name) + dir_and_file_name = convert_to_posix_path(os.path.basename(head), tail) + local_file = convert_to_posix_path(TMP_LOCAL_LOCATION, dir_and_file_name) try: # Need root access to access many directories. adb_utils.set_root_if_needed(env, timeout_sec) @@ -437,14 +454,14 @@ def copy_data_to_device( if os.path.isfile(local_path): # If the file extension is different, remote_path is likely a directory. if os.path.splitext(local_path)[1] != os.path.splitext(remote_path)[1]: - remote_path = os.path.join(remote_path, os.path.basename(local_path)) + remote_path = convert_to_posix_path(remote_path, os.path.basename(local_path)) return copy_file_to_device(local_path, remote_path, env, timeout_sec) # Copying a directory over, push every file separately. for file_path in os.listdir(local_path): current_response = copy_file_to_device( - os.path.join(local_path, file_path), - os.path.join(remote_path, os.path.basename(file_path)), + convert_to_posix_path(local_path, file_path), + convert_to_posix_path(remote_path, os.path.basename(file_path)), env, timeout_sec, ) @@ -496,11 +513,11 @@ def get_file_list_with_metadata( if len(parts) < 9: raise RuntimeError(f"Failed to parse file details: {file_details}") - file_name = parts[8] # This will preserve spaces in the filename + file_name = parts[8].strip() # This will preserve spaces in the filename files.append( FileWithMetadata( file_name=file_name, - full_path=os.path.join(directory_path, file_name), + full_path=convert_to_posix_path(directory_path, file_name), file_size=int(parts[4]), change_time=datetime.datetime.fromisoformat( " ".join(parts[5:7])[:-3] diff --git a/android_world/utils/file_utils_test.py b/android_world/utils/file_utils_test.py index 06ddacc2..a2a13ccc 100644 --- a/android_world/utils/file_utils_test.py +++ b/android_world/utils/file_utils_test.py @@ -89,7 +89,7 @@ def test_tmp_directory_from_device( ), ) - tmp_local_directory = '/tmp/random/dir' + tmp_local_directory = file_utils.convert_to_posix_path(file_utils.get_local_tmp_directory(), 'random', 'dir') mock_mkdtemp.return_value = tmp_local_directory with file_utils.tmp_directory_from_device( '/remotedir', self.mock_env @@ -99,7 +99,7 @@ def test_tmp_directory_from_device( mock.call( adb_pb2.AdbRequest( pull=adb_pb2.AdbRequest.Pull( - path=os.path.join('/remotedir/', file_name) + path=file_utils.convert_to_posix_path('/remotedir/', file_name) ), timeout_sec=None, ) @@ -138,7 +138,7 @@ def test_copy_data_to_device_copies_file(self): self.mock_env.execute_adb_call.return_value = mock_response temp_dir = tempfile.mkdtemp() file_name = 'file1.txt' - create_file_with_contents(os.path.join(temp_dir, file_name), file_contents) + create_file_with_contents(file_utils.convert_to_posix_path(temp_dir, file_name), file_contents) response = file_utils.copy_data_to_device( temp_dir, '/remote/dir', self.mock_env @@ -149,7 +149,7 @@ def test_copy_data_to_device_copies_file(self): adb_pb2.AdbRequest( push=adb_pb2.AdbRequest.Push( content=file_contents, - path=os.path.join('/remote/dir/', file_name), + path=file_utils.convert_to_posix_path('/remote/dir/', file_name), ), timeout_sec=None, ) @@ -169,7 +169,7 @@ def test_copy_data_to_device_copies_full_dir(self): file_names = ['file1.txt', 'file2.txt'] for file_name in file_names: create_file_with_contents( - os.path.join(temp_dir, file_name), file_contents + file_utils.convert_to_posix_path(temp_dir, file_name), file_contents ) response = file_utils.copy_data_to_device( @@ -182,7 +182,7 @@ def test_copy_data_to_device_copies_full_dir(self): adb_pb2.AdbRequest( push=adb_pb2.AdbRequest.Push( content=file_contents, - path=os.path.join('/remote/dir/', file_name), + path=file_utils.convert_to_posix_path('/remote/dir/', file_name), ), timeout_sec=None, )