Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remove atx-agent #959

Merged
merged 6 commits into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions QUICK_REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
import uiautomator2 as u2

d = u2.connect("--serial-here--") # 只有一个设备也可以省略参数
d = u2.connect() # 一个设备时
d = u2.connect("10.1.2.3") # 通过设备的IP连接(需要在同一局域网且设备上的atx-agent已经安装并启动)
d = u2.connect() # 一个设备时, read env-var ANDROID_SERIAL

d.app_current() # 获取前台应用 packageName, activity
d.app_start("com.example.app") # 启动应用
d.app_start("com.example.app", stop=True) # 启动应用前停止应用
d.app_stop("com.example.app") # 停止应用
d.app_start("io.appium.android.apis") # 启动应用
d.app_start("io.appium.android.apis", stop=True) # 启动应用前停止应用
d.app_stop("io.appium.android.apis") # 停止应用

app = d.session("com.example.app") # 启动应用并获取session
app = d.session("io.appium.android.apis") # 启动应用并获取session

# session的用途是操作的同时监控应用是否闪退,当闪退时操作,会抛出SessionBrokenError
app.click(10, 20) # 坐标点击
Expand Down
237 changes: 70 additions & 167 deletions README.md

Large diffs are not rendered by default.

133 changes: 105 additions & 28 deletions docs/2to3.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,117 @@
# 2.x到3.x升级说明

## 变更内容
## 变更内容简介

- 移除atx-agent,常驻服务移除,改为运行时启动手机内的uiautomator服务
- 直接通过atx-agent地址连接的方法不再支持,connect函数目前只支持本地的USB设备或adb connect状态的设备
- 环境变量 ANDROID_DEVICE_IP 不再支持,如果需要使用环境变量传递序列号可以使用 ANDROID_SERIAL
- 版本管理从pbr改为poetry,同时降低依赖库的数量
- Python依赖调整为最低3.8
- 增加更多的单测
- 日志使用标准库logging, 默认不输出任何内容,除非手动开启
- minicap,minitouch不再默认安装
- atx-agent[armeabi]直接打包到lib里面去,避免外网下载依赖

## 移除的功能
- current_app函数移除
- `d.xpath("...").wait()`从原有的返回 XMLElement|None,改为返回 bool
- 日志库清理
- 移除 logzero依赖
- 移除 property u2.logger
- 移除 property u2.xpath.XPath.logger
- 移除 property d.watcher.debug
- 移除 d.settings["xpath_debug"]

- 移除 class AdbUI
- 移除 function XPath.apply_watch_from_yaml
- 移除 module uiautomator2.ext.xpath
- 移除 connect_usb函数中的init参数移除,这个参数目前没什么用了

# 手动开启日志方法
开启Lib库日志的方法

```python
from uiautomator2 import enable_pretty_logging
enable_pretty_logging()
```
- ~~atx-agent[armeabi]直接打包到lib里面去,避免外网下载依赖~~


## New
- Add function enable_pretty_logging
- Add class AdbShellError, HierarchyEmptyError, HTTPError

## Breaking changes (移除的功能)

### Lib removes
- Remove logzero
- Remove filelocks
- Remove progress
- Remove packaging
- Remove Pillow

### Module removes
- Remove module uiautomator2.ext.xpath

### Class removes
- Remove class AdbUI
- Remove class Session, 这个本来就是个傀儡类型
- Remove class GatewayError
- Remove class ServerError, UiautomatorQuitError, RequestError, UiaError, JsonRpcError, NullObjectExceptionError, NullPointerExceptionError, StaleObjectExceptionError

### Property removes
- Remove property u2.logger
- Remove property u2.xpath.XPath.logger
- Remove property d.watcher.debug
- Remove property: address, 原来是用于获取atx-agent的URL地址
- Remove property: alive, 原来用于检测atx-agent的存活状态
- Remove property: uiautomator, 原来用法是d.uiautomator.stop()
- Remove property: widget, 原来也不怎么用
- Remove property: http, 原来是这样用的d.http.get("/device_info")
- Remove d.settings["xpath_debug"]

### Function removes
- Remove function current_app, use app_current instead
- Remove function XPath.apply_watch_from_yaml
- Remove function healcheck, 原来是未来恢复uiautomator服务用的
- Remove function service(name: str) -> Service, 原本是用于做atx-agent的服务管理
- Remove function session, 该函数依赖atx-agent,这个函数本来就是为了兼顾appium的用法,后来发现也用不到
- Remove function app_icon() -> Image, 该函数依赖atx-agent
- Remove function connect_wifi() -> Device, 该函数依赖atx-agent
- Remove function connect_adb_wifi(str) -> Device, 直接用connect就行了
- Remove function set_new_command_timeout(timeout: int), 用不着了
- Remove function device_info(), 函数依赖atx-agent
- Remove function open_identify(), 打开一个比较明显的界面,这个函数出了点毛病,先下掉了

### Command remove
- Remove "uiautomator2 healthcheck"
- Remove "uiautomator2 identify"

或者
## Function changes
### connect_usb
- 2.x connect_usb(serial, init: bool)
- 3.x connect_usb(serial)

### shell
- 2.x shell(cmdargs, stream: bool, timeout)
- 3.x shell(cmdargs, timeout)

### push
- 2.x push(src, dst, mode, show_process: bool)
- 3.x push(src, dst, mode)

### xpath
- 2.x `d.xpath("...").wait() -> XMLElement|None`
- 3.x `d.xpath("...").wait() -> bool`

### reset_uiautomator
- 2.x reset_uiautomator(self, reason="unknown", depth=0)
- 3.x reset_uiautomator()

### app_info
2.x Response

```json
{
"mainActivity": "com.github.uiautomator.MainActivity",
"label": "ATX",
"versionName": "1.1.7",
"versionCode": 1001007,
"size":1760809
}
```
logger = logging.getLogger("uiautomator2")
# 修改logger

3.x Response

```json
{
"versionName": "1.1.7",
"versionCode": 1001007,
}
```

### session
- 2.x sess = d.session("com.netease.cloudmusic", attach=True, strict=True)
- 3.x sess = d.session("com.netease.cloudmusic", attach=True)

It seems the strict is useless, so I delete it.

### push
- 2.x push(src, dst, mode, show_process:bool=False)
- 3.x push(src, dst, mode)
2 changes: 1 addition & 1 deletion examples/runyaml/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def read_file_content(path: str, mode:str = "r") -> str:
with open(path, mode) as f:
return f.read()

def run_step(cf: bunch.Bunch, app: u2.Session, step: str):
def run_step(cf: bunch.Bunch, app: u2.Device, step: str):
logger.info("Step: %s", step)
oper, body = split_step(step)
logger
Expand Down
2 changes: 1 addition & 1 deletion mobile_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def package_name():


@pytest.fixture(scope="function")
def sess(d, package_name) -> u2.Device: # type: ignore
def dev(d: u2.Device, package_name) -> u2.Device: # type: ignore
d.watcher.reset()

d.app_start(package_name, stop=True)
Expand Down
76 changes: 52 additions & 24 deletions mobile_tests/test_session.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,56 @@
# coding: utf-8
#


def test_session(sess):
sess.wlan_ip
sess.watcher
sess.jsonrpc
sess.open_identify
sess.shell
sess.set_new_command_timeout
sess.settings
sess.xpath


def test_session_app(sess, package_name):
sess.app_start(package_name)
assert sess.app_current()['package'] == package_name

sess.app_wait(package_name)
assert package_name in sess.app_list()
assert package_name in sess.app_list_running()

assert sess.app_info(package_name)['packageName'] == package_name

def test_session_window_size(sess):
assert isinstance(sess.window_size(), tuple)
import pytest
import uiautomator2 as u2
from uiautomator2.exceptions import SessionBrokenError

def test_session_function_exists(dev: u2.Device):
dev.wlan_ip
dev.watcher
dev.jsonrpc
dev.shell
dev.settings
dev.xpath


def test_app_mixin(dev: u2.Device, package_name: str):
assert package_name in dev.app_list()
dev.app_stop(package_name)
assert package_name not in dev.app_list_running()
dev.app_start(package_name)
assert package_name in dev.app_list_running()

demo_pid = dev.app_wait(package_name)
current_info = dev.app_current()
assert demo_pid == current_info['pid']
assert current_info['package'] == package_name

dev.app_start(package_name, stop=True)
assert demo_pid != dev.app_wait(package_name)


def test_session_app(dev: u2.Device, package_name):
dev.app_start(package_name)
assert dev.app_current()['package'] == package_name

dev.app_wait(package_name)
assert package_name in dev.app_list()
assert package_name in dev.app_list_running()

with dev.session("io.appium.android.apis") as sess:
sess(text="App").click()
assert sess.running() is True
dev.app_stop("io.appium.android.apis")
assert sess.running() is False
with pytest.raises(SessionBrokenError):
sess(text="App").click()

with dev.session("io.appium.android.apis") as sess:
sess(text="App").click()
assert sess.running() is True


def test_session_window_size(dev: u2.Device):
assert isinstance(dev.window_size(), tuple)

16 changes: 7 additions & 9 deletions mobile_tests/test_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,18 @@
import uiautomator2 as u2


def test_set_xpath_debug(sess):
def test_set_xpath_debug(dev: u2.Device):
with pytest.raises(TypeError):
sess.settings['xpath_debug'] = 1
dev.settings['xpath_debug'] = 1

sess.settings['xpath_debug'] = True
assert sess.settings['xpath_debug'] == True
assert sess.xpath.logger.level == logging.DEBUG
dev.settings['xpath_debug'] = True
assert dev.settings['xpath_debug'] == True

sess.settings['xpath_debug'] = False
assert sess.settings['xpath_debug'] == False
assert sess.xpath.logger.level == logging.INFO
dev.settings['xpath_debug'] = False
assert dev.settings['xpath_debug'] == False


def test_wait_timeout(d):
def test_wait_timeout(d: u2.Device):
d.settings['wait_timeout'] = 19.0
assert d.wait_timeout == 19.0

Expand Down
24 changes: 12 additions & 12 deletions mobile_tests/test_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@


@pytest.mark.skip("not working")
def test_toast_get_message(sess: u2.Device):
d = sess
def test_toast_get_message(dev: u2.Device):
d = dev
assert d.toast.get_message(0) is None
assert d.toast.get_message(0, default="d") == "d"
d(text="App").click()
Expand All @@ -29,8 +29,8 @@ def test_toast_get_message(sess: u2.Device):
assert d.toast.get_message(0, 0.4)


def test_scroll(sess: u2.Device):
d = sess
def test_scroll(dev: u2.Device):
d = dev
d(text="App").click()
if not d(scrollable=True).exists:
pytest.skip("screen to large, no need to scroll")
Expand Down Expand Up @@ -83,15 +83,15 @@ def test_count(self):
className="android.widget.TextView", instance=0).count
self.assertEqual(count, 1)

def test_get_text(sess):
d = sess
def test_get_text(dev):
d = dev
text = d(resourceId="android:id/list").child(
className="android.widget.TextView", instance=2).get_text()
assert text == "Animation"
className="android.widget.TextView", text="App").get_text()
assert text == "App"


def test_xpath(sess):
d = sess
def test_xpath(dev):
d = dev
d.xpath("//*[@text='Media']").wait()
assert len(d.xpath("//*[@text='Media']").all()) == 1
assert len(d.xpath("//*[@text='MediaNotExists']").all()) == 0
Expand Down Expand Up @@ -136,8 +136,8 @@ def _inner():
u2.plugin_register('my', _my_plugin, 'pp')
self.assertEqual(self.d.ext_my(), 'pp')

def test_send_keys(sess):
d = sess
def test_send_keys(dev):
d = dev
d.xpath("App").click()
d.xpath("Search").click()
d.xpath('//*[@text="Invoke Search"]').click()
Expand Down
8 changes: 4 additions & 4 deletions mobile_tests/test_watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
import uiautomator2 as u2


def test_watch_context(sess: u2.Device):
with sess.watch_context(builtin=True) as ctx:
def test_watch_context(dev: u2.Device):
with dev.watch_context(builtin=True) as ctx:
ctx.when("App").click()

sess(text='Menu').click()
assert sess(text='Inflate from XML').wait()
dev(text='Menu').click()
assert dev(text='Inflate from XML').wait()


def teardown_function(d: u2.Device):
Expand Down
Loading