From 5e668e29c6c79edbfce9f0aef7f635d637491819 Mon Sep 17 00:00:00 2001 From: ACButcher Date: Mon, 9 Dec 2024 12:53:14 -0500 Subject: [PATCH 01/23] Added directory pull --- .gitignore | 1 + ppadb/device.py | 26 +++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f7d021e..18d8382 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,6 @@ dist .pytest_cache *.pyc venv +.venv test_result.xml .python-version \ No newline at end of file diff --git a/ppadb/device.py b/ppadb/device.py index ca0cb1a..e4b16c3 100644 --- a/ppadb/device.py +++ b/ppadb/device.py @@ -73,12 +73,36 @@ def push(self, src, dest, mode=0o644, progress=None): for item in files: self._push(root / item, destdir / item, mode, progress) - def pull(self, src, dest): + def _pull(self, src, dest): sync_conn = self.sync() sync = Sync(sync_conn) with sync_conn: return sync.pull(src, dest) + + def pull(self, src, dest): + #Currently will override dest-- desired? + src = PurePosixPath(src) + dest = Path(dest) + + dir_string = "IS_DIR" + res = self.shell(f"[ -d {src} ] && echo {dir_string}") + if dir_string in res: + #Get all files in the dir + #Pull each + dest.mkdir(exist_ok=True) + cmd = f"ls -1a {src}" + res = self.shell(cmd) + contents_list = res.split("\n") + contents_list = [ + x for x in contents_list if x != "." and x != ".." and x != "" + ] + for element in contents_list: + element_src = src / element + element_dest = dest / element + self.pull(element_src, element_dest) + else: + self._pull(str(src), str(dest)) def install( self, From bf79e6da68db61547914ca9e8ad969612357eddb Mon Sep 17 00:00:00 2001 From: ACButcher Date: Mon, 9 Dec 2024 12:53:32 -0500 Subject: [PATCH 02/23] Directory pull tests --- test/test_device.py | 65 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/test_device.py b/test/test_device.py index 78d10be..ff1fd12 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -1,5 +1,7 @@ import os import time +import tempfile +import pathlib import pytest import socket @@ -180,6 +182,69 @@ def progress(file_name, total_size, sent_size): assert result assert result[-1]["total_size"] == result[-1]["sent_size"] +@pytest.fixture(scope="function") +def test_filepaths(): + filepaths = [ + "toplevel/test1.txt", + "toplevel/test2.txt", + "toplevel/subdir1/test3.txt", + "toplevel/subdir1/test4.txt", + "toplevel/subdir1/subdir2/test5.txt", + "toplevel/subdir1/subdir2/test6.txt", + ] + yield filepaths + +@pytest.fixture(scope="function") +def populated_device(device, filepaths): + dirpath = "toplevel/subdir1/subdir2" + + device.shell(f"mkdir -p {dirpath}") + for path in filepaths: + device.shell(f"echo {path} > /data/local/tmp/{path}") + + yield device + + device.shell("rm -rf /data/local/tmp/toplevel") + +@pytest.fixture(scope="function") +def working_dir(): + with tempfile.TemporaryDirectory() as f: + yield pathlib.Path(f) + +def test_pull_file(populated_device, working_dir): + populated_device.pull( + "/data/local/tmp/toplevel/test1.txt", + working_dir + ) + dest_path = working_dir / "test1.txt" + assert dest_path.is_file() + assert dest_path.read_text() == "toplevel/test1.txt" + +def test_pull_dir(populated_device, working_dir): + populated_device.pull( + "/data/local/tmp/toplevel/subdir1/subdir2", + working_dir + ) + dest_path = working_dir / "subdir2" + filepath1 = dest_path / "test5.txt" + filepath2 = dest_path / "test6.txt" + assert dest_path.is_dir() + assert filepath1.is_file() + assert filepath2.read_text() == "toplevel/subdir1/subdir2/test5.txt" + assert filepath2.is_file() + assert filepath2.read_text() == "toplevel/subdir1/subdir2/test5.txt" + +def test_pull_recursive_dir(populated_device, working_dir, filepaths): + populated_device.pull( + "data/local/tmp/toplevel", + working_dir + ) + assert (working_dir / "toplevel").is_dir() + assert (working_dir / "toplevel" / "subdir1").is_dir() + for path in filepaths: + to_check = working_dir / path + assert to_check.is_file() + assert to_check.read_text() == path def test_forward(device): device.killforward_all() From aa9fe870c05fb5554e108aacab2d961988b6ed9e Mon Sep 17 00:00:00 2001 From: ACButcher Date: Mon, 9 Dec 2024 12:54:06 -0500 Subject: [PATCH 03/23] Refactored build to use pyproject --- pyproject.toml | 37 +++++++++++++++++++++++++++++++++++++ requirements.txt | 2 -- 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 pyproject.toml delete mode 100644 requirements.txt diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..bfe4ff8 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,37 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +exclude = ["*.test", "*.test.*", "test.*", "test"] + +[project] +name = "pure-python-adb-reborn" +description = "Pure python implementation of the adb client" +version = "0.1.0" +dependencies = ["Exscript"] +#requires-python = ">= ???" +license = {text = "MIT License"} +readme = "README.rst" +classifiers = [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python :: 3', + 'Topic :: Software Development :: Testing', +] + +[project.urls] +Repository = "https://github.com/spm5065/pure-python-adb.git" + +[project.optional-dependencies] + +async = [ + "aiofiles>=0.4.0" +] + +dev = [ + "pytest", + "black", + "ruff" +] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 274fbc7..0000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pytest -Exscript From 4f15899b555dea5655f4b38e3e79c030bf7e9bfc Mon Sep 17 00:00:00 2001 From: ACButcher Date: Thu, 26 Dec 2024 15:25:53 -0500 Subject: [PATCH 04/23] This testing setup sucks --- test/conftest.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/conftest.py b/test/conftest.py index 6644206..99bf05b 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -9,8 +9,6 @@ logger = logging.getLogger(__name__) -# adb_host = "emulator" -# adb_host = "172.20.0.2" adb_host = os.environ.get("ADB_HOST", "127.0.0.1") adb_port = int(os.environ.get("ADB_PORT", "5037")) device_serial = os.environ.get("DEVICE_SERIAL", "emulator-5554") From 00ac1edca5f521720664ab9f016a92bc12e65847 Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Wed, 15 Jan 2025 23:12:42 -0500 Subject: [PATCH 05/23] Fix exception when running tests, they still fail though --- test/test_device.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_device.py b/test/test_device.py index ff1fd12..aff7c2b 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -195,11 +195,11 @@ def test_filepaths(): yield filepaths @pytest.fixture(scope="function") -def populated_device(device, filepaths): +def populated_device(device, test_filepaths): dirpath = "toplevel/subdir1/subdir2" device.shell(f"mkdir -p {dirpath}") - for path in filepaths: + for path in test_filepaths: device.shell(f"echo {path} > /data/local/tmp/{path}") yield device @@ -234,14 +234,14 @@ def test_pull_dir(populated_device, working_dir): assert filepath2.is_file() assert filepath2.read_text() == "toplevel/subdir1/subdir2/test5.txt" -def test_pull_recursive_dir(populated_device, working_dir, filepaths): +def test_pull_recursive_dir(populated_device, working_dir, test_filepaths): populated_device.pull( "data/local/tmp/toplevel", working_dir ) assert (working_dir / "toplevel").is_dir() assert (working_dir / "toplevel" / "subdir1").is_dir() - for path in filepaths: + for path in test_filepaths: to_check = working_dir / path assert to_check.is_file() assert to_check.read_text() == path From 8e5866aeb28bc39d41173ac82ab0938a059267c6 Mon Sep 17 00:00:00 2001 From: Andrew Butcher Date: Mon, 17 Feb 2025 19:35:14 -0500 Subject: [PATCH 06/23] updated docker compose for pyproject.toml --- .gitignore | 3 ++- docker-compose.yaml | 2 +- ppadb/device.py | 8 ++++---- test/conftest.py | 2 +- test/test_device.py | 22 ++++++++++------------ test_async/test_client_async.py | 5 +---- test_async/test_connection_async.py | 4 +--- test_async/test_device_async.py | 9 ++------- 8 files changed, 22 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index 18d8382..88b32b4 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ dist venv .venv test_result.xml -.python-version \ No newline at end of file +.python-version +build/ diff --git a/docker-compose.yaml b/docker-compose.yaml index 46b89f2..8c6dc67 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -10,7 +10,7 @@ services: environment: - PYTHONPATH=/code - PYTHONUNBUFFERED=0 - command: sh -c "pip install -r requirements.txt;pip install 'Exscript';py.test test -s -v --junit-xml test_result.xml;pip install 'aiofiles>=0.4.0';py.test test_async -s -v --junit-xml test_result_async.xml;" + command: sh -c "pip install .;pip install 'Exscript';py.test test -s -v --junit-xml test_result.xml;pip install 'aiofiles>=0.4.0';py.test test_async -s -v --junit-xml test_result_async.xml;" emulator: image: swind/android-emulator:android_28 diff --git a/ppadb/device.py b/ppadb/device.py index e4b16c3..4725e3b 100644 --- a/ppadb/device.py +++ b/ppadb/device.py @@ -79,17 +79,17 @@ def _pull(self, src, dest): with sync_conn: return sync.pull(src, dest) - + def pull(self, src, dest): - #Currently will override dest-- desired? + # Currently will override dest-- desired? src = PurePosixPath(src) dest = Path(dest) dir_string = "IS_DIR" res = self.shell(f"[ -d {src} ] && echo {dir_string}") if dir_string in res: - #Get all files in the dir - #Pull each + # Get all files in the dir + # Pull each dest.mkdir(exist_ok=True) cmd = f"ls -1a {src}" res = self.shell(cmd) diff --git a/test/conftest.py b/test/conftest.py index 99bf05b..cc0f209 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -97,7 +97,7 @@ def emulator_console_is_connectable(): try: console = EmulatorConsole(host=adb_host, port=emulator_port) return console - except Exception as e: + except Exception: return None def is_boot_completed(): diff --git a/test/test_device.py b/test/test_device.py index aff7c2b..209834f 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -182,6 +182,7 @@ def progress(file_name, total_size, sent_size): assert result assert result[-1]["total_size"] == result[-1]["sent_size"] + @pytest.fixture(scope="function") def test_filepaths(): filepaths = [ @@ -194,6 +195,7 @@ def test_filepaths(): ] yield filepaths + @pytest.fixture(scope="function") def populated_device(device, test_filepaths): dirpath = "toplevel/subdir1/subdir2" @@ -206,25 +208,22 @@ def populated_device(device, test_filepaths): device.shell("rm -rf /data/local/tmp/toplevel") + @pytest.fixture(scope="function") def working_dir(): with tempfile.TemporaryDirectory() as f: yield pathlib.Path(f) + def test_pull_file(populated_device, working_dir): - populated_device.pull( - "/data/local/tmp/toplevel/test1.txt", - working_dir - ) + populated_device.pull("/data/local/tmp/toplevel/test1.txt", working_dir) dest_path = working_dir / "test1.txt" assert dest_path.is_file() assert dest_path.read_text() == "toplevel/test1.txt" + def test_pull_dir(populated_device, working_dir): - populated_device.pull( - "/data/local/tmp/toplevel/subdir1/subdir2", - working_dir - ) + populated_device.pull("/data/local/tmp/toplevel/subdir1/subdir2", working_dir) dest_path = working_dir / "subdir2" filepath1 = dest_path / "test5.txt" filepath2 = dest_path / "test6.txt" @@ -234,11 +233,9 @@ def test_pull_dir(populated_device, working_dir): assert filepath2.is_file() assert filepath2.read_text() == "toplevel/subdir1/subdir2/test5.txt" + def test_pull_recursive_dir(populated_device, working_dir, test_filepaths): - populated_device.pull( - "data/local/tmp/toplevel", - working_dir - ) + populated_device.pull("data/local/tmp/toplevel", working_dir) assert (working_dir / "toplevel").is_dir() assert (working_dir / "toplevel" / "subdir1").is_dir() for path in test_filepaths: @@ -246,6 +243,7 @@ def test_pull_recursive_dir(populated_device, working_dir, test_filepaths): assert to_check.is_file() assert to_check.read_text() == path + def test_forward(device): device.killforward_all() forward_map = device.list_forward() diff --git a/test_async/test_client_async.py b/test_async/test_client_async.py index f200909..3ce01c8 100644 --- a/test_async/test_client_async.py +++ b/test_async/test_client_async.py @@ -1,8 +1,5 @@ -"""Unit tests for the `ClientAsync` class. +"""Unit tests for the `ClientAsync` class.""" -""" - -import asyncio import sys import unittest diff --git a/test_async/test_connection_async.py b/test_async/test_connection_async.py index 87a1ed4..ffc5ab1 100644 --- a/test_async/test_connection_async.py +++ b/test_async/test_connection_async.py @@ -1,6 +1,4 @@ -"""Unit tests for `ConnectionAsync` class. - -""" +"""Unit tests for `ConnectionAsync` class.""" import asyncio import sys diff --git a/test_async/test_device_async.py b/test_async/test_device_async.py index 9cfc8b7..aa8d35e 100644 --- a/test_async/test_device_async.py +++ b/test_async/test_device_async.py @@ -1,14 +1,9 @@ -"""Unit tests for the `DeviceAsync` class. +"""Unit tests for the `DeviceAsync` class.""" -""" - -import asyncio -from contextlib import asynccontextmanager import os -import pathlib import sys import unittest -from unittest.mock import mock_open, patch +from unittest.mock import patch sys.path.insert(0, "..") From b912888c3883619ea524d8f2aec88cf86c76c485 Mon Sep 17 00:00:00 2001 From: Andrew Butcher Date: Mon, 17 Feb 2025 19:42:36 -0500 Subject: [PATCH 07/23] Updated workflow --- .github/workflows/test.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8dbc5e0..c27e347 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,8 +35,6 @@ jobs: #emulator-options: -no-boot-anim script: | pip install '.[async,dev]' - pip install -r requirements.txt - pip install pytest python3 -m pytest test -s -v --junitxml=junit/test-results.xml python3 -m pytest test_async -s -v --junitxml=junit/test-async-results.xml From f630a43463c3ed69336e2ebc93fe6720dba95220 Mon Sep 17 00:00:00 2001 From: Andrew Butcher Date: Mon, 17 Feb 2025 19:47:52 -0500 Subject: [PATCH 08/23] Fixes tests --- test/test_device.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_device.py b/test/test_device.py index 209834f..2b6ad71 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -216,14 +216,14 @@ def working_dir(): def test_pull_file(populated_device, working_dir): - populated_device.pull("/data/local/tmp/toplevel/test1.txt", working_dir) + populated_device.pull("/data/local/tmp/toplevel/test1.txt", working_dir / "test1.txt") dest_path = working_dir / "test1.txt" assert dest_path.is_file() assert dest_path.read_text() == "toplevel/test1.txt" def test_pull_dir(populated_device, working_dir): - populated_device.pull("/data/local/tmp/toplevel/subdir1/subdir2", working_dir) + populated_device.pull("/data/local/tmp/toplevel/subdir1/subdir2", working_dir / "subdir2") dest_path = working_dir / "subdir2" filepath1 = dest_path / "test5.txt" filepath2 = dest_path / "test6.txt" @@ -235,7 +235,7 @@ def test_pull_dir(populated_device, working_dir): def test_pull_recursive_dir(populated_device, working_dir, test_filepaths): - populated_device.pull("data/local/tmp/toplevel", working_dir) + populated_device.pull("data/local/tmp/toplevel", working_dir / "toplevel") assert (working_dir / "toplevel").is_dir() assert (working_dir / "toplevel" / "subdir1").is_dir() for path in test_filepaths: From ef5d148dafce17b36769d8a349383bec16136842 Mon Sep 17 00:00:00 2001 From: Andrew Butcher Date: Mon, 17 Feb 2025 19:49:37 -0500 Subject: [PATCH 09/23] Formatted --- test/test_device.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/test_device.py b/test/test_device.py index 2b6ad71..fc3782e 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -216,14 +216,18 @@ def working_dir(): def test_pull_file(populated_device, working_dir): - populated_device.pull("/data/local/tmp/toplevel/test1.txt", working_dir / "test1.txt") + populated_device.pull( + "/data/local/tmp/toplevel/test1.txt", working_dir / "test1.txt" + ) dest_path = working_dir / "test1.txt" assert dest_path.is_file() assert dest_path.read_text() == "toplevel/test1.txt" def test_pull_dir(populated_device, working_dir): - populated_device.pull("/data/local/tmp/toplevel/subdir1/subdir2", working_dir / "subdir2") + populated_device.pull( + "/data/local/tmp/toplevel/subdir1/subdir2", working_dir / "subdir2" + ) dest_path = working_dir / "subdir2" filepath1 = dest_path / "test5.txt" filepath2 = dest_path / "test6.txt" From 6cb110ddaf8e50ca9d5a6620eea2a1c9ec6cf364 Mon Sep 17 00:00:00 2001 From: Andrew Butcher Date: Mon, 17 Feb 2025 19:56:05 -0500 Subject: [PATCH 10/23] maybe this will shed some light --- test/test_device.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_device.py b/test/test_device.py index fc3782e..f87dcea 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -203,6 +203,7 @@ def populated_device(device, test_filepaths): device.shell(f"mkdir -p {dirpath}") for path in test_filepaths: device.shell(f"echo {path} > /data/local/tmp/{path}") + print(device.shell(f"cat /data/local/tmp/{path}")) yield device From c5d20931746dd5d5c217862ac8054d893e39d2e7 Mon Sep 17 00:00:00 2001 From: Andrew Butcher Date: Mon, 17 Feb 2025 20:02:59 -0500 Subject: [PATCH 11/23] Does this directory get made --- test/test_device.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_device.py b/test/test_device.py index f87dcea..4b6b1cb 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -201,6 +201,7 @@ def populated_device(device, test_filepaths): dirpath = "toplevel/subdir1/subdir2" device.shell(f"mkdir -p {dirpath}") + print(device.shell(f"ls /data/local/tmp")) for path in test_filepaths: device.shell(f"echo {path} > /data/local/tmp/{path}") print(device.shell(f"cat /data/local/tmp/{path}")) From 8b61660ded2310eaa771b3f0fb8fed66f253169d Mon Sep 17 00:00:00 2001 From: Andrew Butcher Date: Mon, 17 Feb 2025 20:08:34 -0500 Subject: [PATCH 12/23] Actually make it in tmp --- test/test_device.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_device.py b/test/test_device.py index 4b6b1cb..b9de74d 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -200,7 +200,7 @@ def test_filepaths(): def populated_device(device, test_filepaths): dirpath = "toplevel/subdir1/subdir2" - device.shell(f"mkdir -p {dirpath}") + device.shell(f"mkdir -p /data/local/tmp/{dirpath}") print(device.shell(f"ls /data/local/tmp")) for path in test_filepaths: device.shell(f"echo {path} > /data/local/tmp/{path}") From 805d099c5ffb5bbbe38be24a16b9765cb9558a65 Mon Sep 17 00:00:00 2001 From: Andrew Butcher Date: Mon, 17 Feb 2025 20:13:48 -0500 Subject: [PATCH 13/23] Fixes outputs --- test/test_device.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/test/test_device.py b/test/test_device.py index b9de74d..8f6bac9 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -201,10 +201,8 @@ def populated_device(device, test_filepaths): dirpath = "toplevel/subdir1/subdir2" device.shell(f"mkdir -p /data/local/tmp/{dirpath}") - print(device.shell(f"ls /data/local/tmp")) for path in test_filepaths: device.shell(f"echo {path} > /data/local/tmp/{path}") - print(device.shell(f"cat /data/local/tmp/{path}")) yield device @@ -223,7 +221,7 @@ def test_pull_file(populated_device, working_dir): ) dest_path = working_dir / "test1.txt" assert dest_path.is_file() - assert dest_path.read_text() == "toplevel/test1.txt" + assert dest_path.read_text() == "toplevel/test1.txt\n" def test_pull_dir(populated_device, working_dir): @@ -235,9 +233,9 @@ def test_pull_dir(populated_device, working_dir): filepath2 = dest_path / "test6.txt" assert dest_path.is_dir() assert filepath1.is_file() - assert filepath2.read_text() == "toplevel/subdir1/subdir2/test5.txt" + assert filepath2.read_text() == "toplevel/subdir1/subdir2/test5.txt\n" assert filepath2.is_file() - assert filepath2.read_text() == "toplevel/subdir1/subdir2/test5.txt" + assert filepath2.read_text() == "toplevel/subdir1/subdir2/test5.txt\n" def test_pull_recursive_dir(populated_device, working_dir, test_filepaths): @@ -247,7 +245,7 @@ def test_pull_recursive_dir(populated_device, working_dir, test_filepaths): for path in test_filepaths: to_check = working_dir / path assert to_check.is_file() - assert to_check.read_text() == path + assert to_check.read_text() == f"{path}\n" def test_forward(device): From 0d07b6df1f120bed9579220efeca5096ae98d4ce Mon Sep 17 00:00:00 2001 From: Andrew Butcher Date: Mon, 17 Feb 2025 20:18:19 -0500 Subject: [PATCH 14/23] Fixed test --- test/test_device.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_device.py b/test/test_device.py index 8f6bac9..f3abcd1 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -235,7 +235,7 @@ def test_pull_dir(populated_device, working_dir): assert filepath1.is_file() assert filepath2.read_text() == "toplevel/subdir1/subdir2/test5.txt\n" assert filepath2.is_file() - assert filepath2.read_text() == "toplevel/subdir1/subdir2/test5.txt\n" + assert filepath2.read_text() == "toplevel/subdir1/subdir2/test6.txt\n" def test_pull_recursive_dir(populated_device, working_dir, test_filepaths): From 5c4932f6e8a5efec6ff5e16c015a91db0c185dc5 Mon Sep 17 00:00:00 2001 From: Andrew Butcher Date: Mon, 17 Feb 2025 20:22:21 -0500 Subject: [PATCH 15/23] Fixed test --- test/test_device.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_device.py b/test/test_device.py index f3abcd1..b14522e 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -233,7 +233,7 @@ def test_pull_dir(populated_device, working_dir): filepath2 = dest_path / "test6.txt" assert dest_path.is_dir() assert filepath1.is_file() - assert filepath2.read_text() == "toplevel/subdir1/subdir2/test5.txt\n" + assert filepath1.read_text() == "toplevel/subdir1/subdir2/test5.txt\n" assert filepath2.is_file() assert filepath2.read_text() == "toplevel/subdir1/subdir2/test6.txt\n" From 5ba23031638c6ccd7d8cea90a2dc9fb087293553 Mon Sep 17 00:00:00 2001 From: Andrew Butcher Date: Sun, 23 Feb 2025 17:10:54 -0500 Subject: [PATCH 16/23] Added async pull directory (no tests) --- ppadb/device.py | 5 ++++- ppadb/device_async.py | 29 ++++++++++++++++++++++++++++- test/test_device.py | 7 +++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/ppadb/device.py b/ppadb/device.py index 4725e3b..a7d7dd4 100644 --- a/ppadb/device.py +++ b/ppadb/device.py @@ -81,7 +81,6 @@ def _pull(self, src, dest): return sync.pull(src, dest) def pull(self, src, dest): - # Currently will override dest-- desired? src = PurePosixPath(src) dest = Path(dest) @@ -102,6 +101,10 @@ def pull(self, src, dest): element_dest = dest / element self.pull(element_src, element_dest) else: + file_string = "IS_FILE" + res = self.shell(f"[ -f {src} ] && echo {file_string}") + if file_string not in res: + raise FileNotFoundError(f"Cannot find {src} on device") self._pull(str(src), str(dest)) def install( diff --git a/ppadb/device_async.py b/ppadb/device_async.py index 41b517c..26c23de 100644 --- a/ppadb/device_async.py +++ b/ppadb/device_async.py @@ -58,13 +58,40 @@ async def push(self, src, dest, mode=0o644, progress=None): for item in files: await self._push(root / item, destdir / item, mode, progress) - async def pull(self, src, dest): + async def _pull(self, src, dest): sync_conn = await self.sync() sync = SyncAsync(sync_conn) async with sync_conn: return await sync.pull(src, dest) + async def pull(self, src, dest): + src = PurePosixPath(src) + dest = Path(dest) + + dir_string = "IS_DIR" + res = await self.shell(f"[ -d {src} ] && echo {dir_string}") + if dir_string in res: + # Get all files in the dir + # Pull each + dest.mkdir(exist_ok=True) + cmd = f"ls -1a {src}" + res = await self.shell(cmd) + contents_list = res.split("\n") + contents_list = [ + x for x in contents_list if x != "." and x != ".." and x != "" + ] + for element in contents_list: + element_src = src / element + element_dest = dest / element + await self.pull(element_src, element_dest) + else: + file_string = "IS_FILE" + res = await self.shell(f"[ -f {src} ] && echo {file_string}") + if file_string not in res: + raise FileNotFoundError(f"Cannot find {src} on device") + await self._pull(str(src), str(dest)) + async def install( self, path, diff --git a/test/test_device.py b/test/test_device.py index b14522e..ba7f7cc 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -247,6 +247,13 @@ def test_pull_recursive_dir(populated_device, working_dir, test_filepaths): assert to_check.is_file() assert to_check.read_text() == f"{path}\n" +def test_pull_nonexisting(device, working_dir): + src = "data/local/tmp/dklsfalkjhvcnsdfalvfds" + with pytest.raises(Exception) as excinfo: + device.pull(src, working_dir / "non_existent") + + assert str(excinfo.value) == f"Cannot find {src} on device" + def test_forward(device): device.killforward_all() From ea21a94d5b8aa6782c6e5995844424db9bd5fae7 Mon Sep 17 00:00:00 2001 From: ACButcher Date: Fri, 7 Mar 2025 21:49:23 -0500 Subject: [PATCH 17/23] back to setup --- pyproject.toml | 37 ------------------------------------- requirements.txt | 2 ++ 2 files changed, 2 insertions(+), 37 deletions(-) delete mode 100644 pyproject.toml create mode 100644 requirements.txt diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index bfe4ff8..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,37 +0,0 @@ -[build-system] -requires = ["setuptools"] -build-backend = "setuptools.build_meta" - -[tool.setuptools.packages.find] -exclude = ["*.test", "*.test.*", "test.*", "test"] - -[project] -name = "pure-python-adb-reborn" -description = "Pure python implementation of the adb client" -version = "0.1.0" -dependencies = ["Exscript"] -#requires-python = ">= ???" -license = {text = "MIT License"} -readme = "README.rst" -classifiers = [ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 3', - 'Topic :: Software Development :: Testing', -] - -[project.urls] -Repository = "https://github.com/spm5065/pure-python-adb.git" - -[project.optional-dependencies] - -async = [ - "aiofiles>=0.4.0" -] - -dev = [ - "pytest", - "black", - "ruff" -] \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..274fbc7 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +pytest +Exscript From dea39bc151dc6c412858c6f742d324609e777ea3 Mon Sep 17 00:00:00 2001 From: ACButcher Date: Fri, 7 Mar 2025 21:50:32 -0500 Subject: [PATCH 18/23] formatted --- test/test_device.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_device.py b/test/test_device.py index ba7f7cc..0839c0d 100644 --- a/test/test_device.py +++ b/test/test_device.py @@ -247,11 +247,12 @@ def test_pull_recursive_dir(populated_device, working_dir, test_filepaths): assert to_check.is_file() assert to_check.read_text() == f"{path}\n" + def test_pull_nonexisting(device, working_dir): src = "data/local/tmp/dklsfalkjhvcnsdfalvfds" with pytest.raises(Exception) as excinfo: device.pull(src, working_dir / "non_existent") - + assert str(excinfo.value) == f"Cannot find {src} on device" From b4dd804d7020b259fa3749c46212c4bd925c4e30 Mon Sep 17 00:00:00 2001 From: Andrew Butcher <32207305+ACButcher@users.noreply.github.com> Date: Fri, 7 Mar 2025 21:54:00 -0500 Subject: [PATCH 19/23] Update test.yml --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c27e347..8dbc5e0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,6 +35,8 @@ jobs: #emulator-options: -no-boot-anim script: | pip install '.[async,dev]' + pip install -r requirements.txt + pip install pytest python3 -m pytest test -s -v --junitxml=junit/test-results.xml python3 -m pytest test_async -s -v --junitxml=junit/test-async-results.xml From 6d8b74947ef8f67f8c24a036464c4a4c05eb9a7a Mon Sep 17 00:00:00 2001 From: Andrew Butcher <32207305+ACButcher@users.noreply.github.com> Date: Fri, 7 Mar 2025 21:54:26 -0500 Subject: [PATCH 20/23] Update docker-compose.yaml --- docker-compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yaml b/docker-compose.yaml index 8c6dc67..46b89f2 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -10,7 +10,7 @@ services: environment: - PYTHONPATH=/code - PYTHONUNBUFFERED=0 - command: sh -c "pip install .;pip install 'Exscript';py.test test -s -v --junit-xml test_result.xml;pip install 'aiofiles>=0.4.0';py.test test_async -s -v --junit-xml test_result_async.xml;" + command: sh -c "pip install -r requirements.txt;pip install 'Exscript';py.test test -s -v --junit-xml test_result.xml;pip install 'aiofiles>=0.4.0';py.test test_async -s -v --junit-xml test_result_async.xml;" emulator: image: swind/android-emulator:android_28 From e8a82387daf4390d2ead310a9922e0f22d750446 Mon Sep 17 00:00:00 2001 From: Andrew Butcher <32207305+ACButcher@users.noreply.github.com> Date: Fri, 7 Mar 2025 21:54:54 -0500 Subject: [PATCH 21/23] Update test_client_async.py --- test_async/test_client_async.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test_async/test_client_async.py b/test_async/test_client_async.py index 3ce01c8..5980b10 100644 --- a/test_async/test_client_async.py +++ b/test_async/test_client_async.py @@ -1,5 +1,6 @@ """Unit tests for the `ClientAsync` class.""" +import asyncio import sys import unittest From 31c6e87af20f254ab5ef7743348ada7aa14cd27f Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Sat, 8 Mar 2025 14:31:18 -0500 Subject: [PATCH 22/23] Fix unit tests for DeviceAsync.pull() --- test_async/test_device_async.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test_async/test_device_async.py b/test_async/test_device_async.py index aa8d35e..a86f30f 100644 --- a/test_async/test_device_async.py +++ b/test_async/test_device_async.py @@ -139,6 +139,9 @@ async def test_pull(self): with async_patch( "asyncio.open_connection", return_value=(FakeStreamReader(), FakeStreamWriter()), + ), async_patch( + "ppadb.device_async.DeviceAsync.shell", + return_value=["", "IS_FILE"] ): with async_patch( "{}.FakeStreamReader.read".format(__name__), @@ -160,6 +163,9 @@ async def test_pull_fail(self): with async_patch( "asyncio.open_connection", return_value=(FakeStreamReader(), FakeStreamWriter()), + ), async_patch( + "ppadb.device_async.DeviceAsync.shell", + return_value=["", "IS_FILE"] ): with async_patch( "{}.FakeStreamReader.read".format(__name__), From e7398f2eaaa92e094b6a5684db572b306a3dbb6a Mon Sep 17 00:00:00 2001 From: Sergio Martins Date: Sat, 8 Mar 2025 14:36:35 -0500 Subject: [PATCH 23/23] Format... --- test_async/test_device_async.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test_async/test_device_async.py b/test_async/test_device_async.py index a86f30f..226f38a 100644 --- a/test_async/test_device_async.py +++ b/test_async/test_device_async.py @@ -140,8 +140,7 @@ async def test_pull(self): "asyncio.open_connection", return_value=(FakeStreamReader(), FakeStreamWriter()), ), async_patch( - "ppadb.device_async.DeviceAsync.shell", - return_value=["", "IS_FILE"] + "ppadb.device_async.DeviceAsync.shell", return_value=["", "IS_FILE"] ): with async_patch( "{}.FakeStreamReader.read".format(__name__), @@ -164,8 +163,7 @@ async def test_pull_fail(self): "asyncio.open_connection", return_value=(FakeStreamReader(), FakeStreamWriter()), ), async_patch( - "ppadb.device_async.DeviceAsync.shell", - return_value=["", "IS_FILE"] + "ppadb.device_async.DeviceAsync.shell", return_value=["", "IS_FILE"] ): with async_patch( "{}.FakeStreamReader.read".format(__name__),