Skip to content

Commit

Permalink
update usbmux, remove deps requests,logzero,cached-property,simplejson
Browse files Browse the repository at this point in the history
  • Loading branch information
codeskyblue committed May 29, 2024
1 parent 3972b36 commit a5e477b
Show file tree
Hide file tree
Showing 12 changed files with 634 additions and 409 deletions.
30 changes: 30 additions & 0 deletions examples/swipe.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import random
import wdapy

c = wdapy.AppiumUSBClient()
w, h = c.window_size()
# print(w, h)
x = w//10 * random.randint(1, 9)
print(x)
sy = h//10*7
ey = h//10*2

steps = 10
step_size = (ey - sy) // steps
ys = list(range(sy+step_size, ey, step_size)) + [ey]

gestures = []
gestures.append(wdapy.Gesture("press", options={"x": x, "y": sy}))
for y in ys:
gestures.append(wdapy.Gesture("wait", options={"ms": 100}))
gestures.append(wdapy.Gesture("moveTo", options={"x": x, "y": y}))
gestures.append(wdapy.Gesture("wait", options={"ms": 100}))
gestures.append(wdapy.Gesture("release"))


for g in gestures:
print(g.action, g.options)

# c.debug = True
c.appium_settings({"snapshotMaxDepth": 3})
c.touch_perform(gestures)
5 changes: 1 addition & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
requests>=2.9.1
Deprecated>=1.2.6
Pillow
logzero
cached-property
simplejson
retry
construct>=2
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
#

import setuptools
setuptools.setup(setup_requires=['pbr'], pbr=True)
setuptools.setup(setup_requires=['pbr'], pbr=True, python_requires='>=3.8')
3 changes: 2 additions & 1 deletion wdapy/_alert.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
"""Created on Tue Sep 14 2021 15:24:46 by codeskyblue
"""

import logging
import typing
from wdapy.exceptions import RequestError
from wdapy._proto import *
from wdapy._base import BaseClient
from wdapy._logger import logger

logger = logging.getLogger(__name__)

class Alert:
def __init__(self, client: BaseClient):
Expand Down
73 changes: 57 additions & 16 deletions wdapy/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,52 @@
"""Created on Tue Sep 14 2021 15:26:27 by codeskyblue
"""

import functools
from http.client import HTTPConnection, HTTPSConnection
import logging
import typing

import requests
import simplejson as json
import json
from retry import retry
from urllib.parse import urlparse

from wdapy._logger import logger
from wdapy._proto import *
from wdapy._types import Recover, StatusInfo
from wdapy.exceptions import *
from wdapy.usbmux import MuxError, requests_usbmux
from wdapy.usbmux.exceptions import MuxConnectError
from wdapy.usbmux.pyusbmux import select_device


logger = logging.getLogger(__name__)

class HTTPResponseWrapper:
def __init__(self, content: bytes, status_code: int):
self.content = content
self.status_code = status_code

def json(self):
return json.loads(self.content)

@property
def text(self) -> str:
return self.content.decode("utf-8")

def getcode(self) -> int:
return self.status_code


def http_create(url: str) -> typing.Union[HTTPConnection, HTTPSConnection]:
u = urlparse(url)
if u.scheme == "http+usbmux":
udid, device_wda_port = u.netloc.split(":")
device = select_device(udid)
return device.make_http_connection(int(device_wda_port))
elif u.scheme == "http":
return HTTPConnection(u.netloc)
elif u.scheme == "https":
return HTTPSConnection(u.netloc)
else:
raise ValueError(f"unknown scheme: {u.scheme}")


class BaseClient:
Expand Down Expand Up @@ -126,26 +159,34 @@ def _request_http(self, method: RequestMethod, url: str, payload: dict, **kwargs
RequestError, WDAFatalError
WDASessionDoesNotExist
"""
session = self._requests_session_pool_get()
if "timeout" not in kwargs:
kwargs["timeout"] = self.request_timeout
logger.info("request: %s %s %s", method, url, payload)
try:
resp = session.request(method, url, json=payload, timeout=self.request_timeout)
if resp.status_code == 200:
conn = http_create(url)
conn.timeout = kwargs.get("timeout", self.request_timeout)
u = urlparse(url)
urlpath = url[len(u.scheme) + len(u.netloc) + 3:]

if not payload:
conn.request(method.value, urlpath)
else:
conn.request(method.value, urlpath, json.dumps(payload), headers={"Content-Type": "application/json"})
response = conn.getresponse()
content = bytearray()
while chunk := response.read(4096):
content.extend(chunk)
resp = HTTPResponseWrapper(content, response.status)

if response.getcode() == 200:
return resp
else:
# handle unexpected response
if "Session does not exist" in resp.text:
raise WDASessionDoesNotExist(resp.text)
else:
raise RequestError(resp.text)
except (requests.RequestException, MuxError) as err:
raise RequestError(f"response code: {response.getcode()}", resp.text)
except MuxConnectError as err:
if self._recover:
if not self._recover.recover():
raise WDAFatalError("recover failed", err)
raise WDAFatalError("recover failed")
raise RequestError("ConnectionBroken", err)

@functools.lru_cache(1024)
def _requests_session_pool_get(self) -> requests.Session:
return requests_usbmux.Session()

11 changes: 0 additions & 11 deletions wdapy/_logger.py

This file was deleted.

29 changes: 19 additions & 10 deletions wdapy/_wdapy.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,17 @@
import typing

import requests
from cached_property import cached_property
from functools import cached_property
from logzero import setup_logger
from PIL import Image

from wdapy._alert import Alert
from wdapy._base import BaseClient
from wdapy._logger import logger
from wdapy._proto import *
from wdapy._types import *
from wdapy.exceptions import *
from wdapy._utils import omit_empty
from wdapy.usbmux import requests_usbmux, usbmux
from wdapy.usbmux.pyusbmux import list_devices, select_device


class HTTPResponse:
Expand Down Expand Up @@ -193,7 +192,10 @@ def send_keys(self, value: str):
self.session_request(POST, "/wda/keys", {"value": list(value)})

def tap(self, x: int, y: int):
self.session_request(POST, "/wda/tap/0", {"x": x, "y": y})
try:
self.session_request(POST, "/wda/tap", {"x": x, "y": y})
except RequestError:
self.session_request(POST, "/wda/tap/0", {"x": x, "y": y})

def touch_and_hold(self, x: int, y: int, duration: float):
""" touch and hold
Expand Down Expand Up @@ -361,12 +363,20 @@ def __init__(self, wda_url: str = DEFAULT_WDA_URL):
super().__init__(wda_url)


def get_single_device_udid() -> str:
devices = list_devices()
if len(devices) == 0:
raise WDAException("No device connected")
if len(devices) > 1:
raise WDAException("More than one device connected")
return devices[0].serial


class AppiumUSBClient(AppiumClient):
def __init__(self, udid: str = None, port: int = 8100):
if udid is None:
_usbmux = usbmux.Usbmux()
udid = _usbmux.get_single_device_udid()
super().__init__(requests_usbmux.DEFAULT_SCHEME+udid+f":{port}")
udid = get_single_device_udid()
super().__init__(f"http+usbmux://{udid}:{port}")
self.set_recover_handler(XCUITestRecover(udid))


Expand Down Expand Up @@ -404,7 +414,6 @@ def fast_swipe(self,
class NanoUSBClient(NanoClient):
def __init__(self, udid: str = None, port: int = 8100):
if udid is None:
_usbmux = usbmux.Usbmux()
udid = _usbmux.get_single_device_udid()
super().__init__(requests_usbmux.DEFAULT_SCHEME+udid+f":{port}")
udid = get_single_device_udid()
super().__init__(f"http+usbmux://{udid}:{port}")
self.set_recover_handler(XCUITestRecover(udid))
2 changes: 1 addition & 1 deletion wdapy/usbmux/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
"""Created on Thu Dec 09 2021 09:56:30 by codeskyblue
"""

from wdapy.usbmux.usbmux import MuxError, MuxConnectError
from wdapy.usbmux.exceptions import MuxError, MuxConnectError
38 changes: 38 additions & 0 deletions wdapy/usbmux/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""Created on Tue Mar 05 2024 10:18:09 by codeskyblue
Copy from https://github.com/doronz88/pymobiledevice3
"""

class NotPairedError(Exception):
pass


class MuxError(Exception):
pass


class MuxVersionError(MuxError):
pass


class BadCommandError(MuxError):
pass


class BadDevError(MuxError):
pass


class MuxConnectError(MuxError):
pass


class MuxConnectToUsbmuxdError(MuxConnectError):
pass


class ArgumentError(Exception):
pass
Loading

0 comments on commit a5e477b

Please sign in to comment.