uiautodev 0.10.0__py3-none-any.whl → 0.11.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of uiautodev might be problematic. Click here for more details.

uiautodev/__init__.py CHANGED
@@ -5,4 +5,4 @@
5
5
  """
6
6
 
7
7
  # version is auto managed by poetry
8
- __version__ = "0.10.0"
8
+ __version__ = "0.11.1"
@@ -13,7 +13,7 @@ from typing import Callable, Dict, List, Optional, Union
13
13
  from pydantic import BaseModel
14
14
 
15
15
  from uiautodev.command_types import AppLaunchRequest, AppTerminateRequest, By, Command, CurrentAppResponse, \
16
- DumpResponse, FindElementRequest, FindElementResponse, InstallAppRequest, InstallAppResponse, TapRequest, \
16
+ DumpResponse, FindElementRequest, FindElementResponse, InstallAppRequest, InstallAppResponse, SendKeysRequest, TapRequest, \
17
17
  WindowSizeResponse
18
18
  from uiautodev.driver.base_driver import BaseDriver
19
19
  from uiautodev.exceptions import ElementNotFoundError
@@ -39,7 +39,7 @@ def get_command_params_type(command: Command) -> Optional[BaseModel]:
39
39
  return type_hints.get("params")
40
40
 
41
41
 
42
- def send_command(driver: BaseDriver, command: Union[str, Command], params=None):
42
+ def send_command(driver: BaseDriver, command: Command, params=None):
43
43
  if command not in COMMANDS:
44
44
  raise NotImplementedError(f"command {command} not implemented")
45
45
  func = COMMANDS[command]
@@ -142,6 +142,14 @@ def dump(driver: BaseDriver) -> DumpResponse:
142
142
  def wake_up(driver: BaseDriver):
143
143
  driver.wake_up()
144
144
 
145
+ @register(Command.SEND_KEYS)
146
+ def send_keys(driver: BaseDriver, params: SendKeysRequest):
147
+ driver.send_keys(params.text)
148
+
149
+ @register(Command.CLEAR_TEXT)
150
+ def clear_text(driver: BaseDriver):
151
+ driver.clear_text()
152
+
145
153
 
146
154
  def node_match(node: Node, by: By, value: str) -> bool:
147
155
  if by == By.ID:
@@ -39,6 +39,8 @@ class Command(str, enum.Enum):
39
39
  VOLUME_UP = "volumeUp"
40
40
  VOLUME_DOWN = "volumeDown"
41
41
  VOLUME_MUTE = "volumeMute"
42
+ SEND_KEYS = "sendKeys"
43
+ CLEAR_TEXT = "clearText"
42
44
 
43
45
 
44
46
  class TapRequest(BaseModel):
@@ -94,4 +96,8 @@ class FindElementRequest(BaseModel):
94
96
 
95
97
  class FindElementResponse(BaseModel):
96
98
  count: int
97
- value: List[Node]
99
+ value: List[Node]
100
+
101
+
102
+ class SendKeysRequest(BaseModel):
103
+ text: str
@@ -127,7 +127,7 @@ class AndroidDriver(BaseDriver):
127
127
  def volume_mute(self):
128
128
  self.adb_device.keyevent("VOLUME_MUTE")
129
129
 
130
- def get_app_version(self, package_name: str) -> Optional[dict]:
130
+ def get_app_version(self, package_name: str) -> dict:
131
131
  """
132
132
  Get the version information of an app, including mainVersion and subVersion.
133
133
 
@@ -172,11 +172,17 @@ class AndroidDriver(BaseDriver):
172
172
 
173
173
  def open_app_file(self, package: str) -> Iterator[bytes]:
174
174
  line = self.adb_device.shell(f"pm path {package}")
175
+ assert isinstance(line, str)
175
176
  if not line.startswith("package:"):
176
177
  raise AndroidDriverException(f"Failed to get package path: {line}")
177
178
  remote_path = line.split(':', 1)[1]
178
179
  yield from self.adb_device.sync.iter_content(remote_path)
179
-
180
+
181
+ def send_keys(self, text: str):
182
+ self.ud.send_keys(text)
183
+
184
+ def clear_text(self):
185
+ self.ud.clear_text()
180
186
 
181
187
 
182
188
  def parse_xml(xml_data: str, wsize: WindowSize, display_id: Optional[int] = None) -> Node:
@@ -102,4 +102,11 @@ class BaseDriver(abc.ABC):
102
102
  def open_app_file(self, package: str) -> Iterator[bytes]:
103
103
  """ open app file """
104
104
  raise NotImplementedError()
105
-
105
+
106
+ def send_keys(self, text: str):
107
+ """ send keys to device """
108
+ raise NotImplementedError()
109
+
110
+ def clear_text(self):
111
+ """ clear text input on device """
112
+ raise NotImplementedError()
@@ -10,7 +10,7 @@ import tempfile
10
10
  import time
11
11
  import uuid
12
12
  from pathlib import Path
13
- from typing import List, Optional, Tuple, Union, final
13
+ from typing import List, Optional, Tuple, Union, final, Dict
14
14
 
15
15
  from PIL import Image
16
16
 
@@ -31,6 +31,7 @@ def run_command(command: str, timeout: int = 60) -> str:
31
31
  capture_output=True,
32
32
  timeout=timeout,
33
33
  text=True,
34
+ errors='ignore',
34
35
  input='' # this avoid stdout: "FreeChannelContinue handle->data is nullptr"
35
36
  )
36
37
  # the hdc shell stderr is (不仅没啥用,还没办法去掉)
@@ -50,10 +51,10 @@ class HDC:
50
51
  def __init__(self):
51
52
  self.hdc = 'hdc'
52
53
  self.tmpdir = tempfile.TemporaryDirectory()
53
-
54
+
54
55
  def __del__(self):
55
56
  self.tmpdir.cleanup()
56
-
57
+
57
58
  def list_device(self) -> List[str]:
58
59
  command = f"{self.hdc} list targets"
59
60
  result = run_command(command)
@@ -65,15 +66,48 @@ class HDC:
65
66
  return devices
66
67
  else:
67
68
  return []
68
-
69
+
69
70
  def shell(self, serial: str, command: str) -> str:
70
71
  command = f"{self.hdc} -t {serial} shell \"{command}\""
71
72
  result = run_command(command)
72
73
  return result.strip()
73
-
74
+
75
+ def __split_text(self, text: str) -> str:
76
+ return text.split("\n")[0].strip() if text else ""
77
+
74
78
  def get_model(self, serial: str) -> str:
75
79
  return self.shell(serial, "param get const.product.model")
76
-
80
+
81
+ def get_name(self, serial: str) -> str:
82
+ data = self.shell(serial, "param get const.product.name")
83
+ return self.__split_text(data)
84
+
85
+ def wlan_ip(self, serial: str) -> str:
86
+ data = self.shell(serial, "ifconfig")
87
+ if not data or "not found" in data.lower() or "error" in data.lower():
88
+ logger.warning(f"ifconfig command failed or returned error for serial {serial}: {data!r}")
89
+ return ""
90
+ # Try multiple patterns for IP address
91
+ matches = re.findall(r'inet addr:(?!127)(\d+\.\d+\.\d+\.\d+)', data)
92
+ if not matches:
93
+ matches = re.findall(r'inet (?!127)(\d+\.\d+\.\d+\.\d+)', data)
94
+ if matches:
95
+ return matches[0]
96
+ logger.warning(f"No valid IP address found in ifconfig output for serial {serial}: {data!r}")
97
+ return ""
98
+
99
+ def sdk_version(self, serial: str) -> str:
100
+ data = self.shell(serial, "param get const.ohos.apiversion")
101
+ return self.__split_text(data)
102
+
103
+ def sys_version(self, serial: str) -> str:
104
+ data = self.shell(serial, "param get const.product.software.version")
105
+ return self.__split_text(data)
106
+
107
+ def brand(self, serial: str) -> str:
108
+ data = self.shell(serial, "param get const.product.brand")
109
+ return self.__split_text(data)
110
+
77
111
  def pull(self, serial: str, remote: StrOrPath, local: StrOrPath):
78
112
  if isinstance(remote, Path):
79
113
  remote = remote.as_posix()
@@ -81,13 +115,13 @@ class HDC:
81
115
  output = run_command(command)
82
116
  if not os.path.exists(local):
83
117
  raise HDCError(f"device file: {remote} not found", output)
84
-
118
+
85
119
  def push(self, serial: str, local: StrOrPath, remote: StrOrPath) -> str:
86
120
  if isinstance(remote, Path):
87
121
  remote = remote.as_posix()
88
122
  command = f"{self.hdc} -t {serial} file send {local} {remote}"
89
123
  return run_command(command)
90
-
124
+
91
125
  def screenshot(self, serial: str) -> Image.Image:
92
126
  device_path = f'/data/local/tmp/screenshot-{int(time.time()*1000)}.png'
93
127
  self.shell(serial, f"uitest screenCap -p {device_path}")
@@ -116,7 +150,7 @@ class HDC:
116
150
  raise HDCError(f"failed to dump layout: {output}")
117
151
  finally:
118
152
  self.shell(serial, f"rm {remote_path}")
119
-
153
+
120
154
 
121
155
  class HarmonyDriver(BaseDriver):
122
156
  def __init__(self, hdc: HDC, serial: str):
@@ -164,6 +198,112 @@ class HarmonyDriver(BaseDriver):
164
198
  else:
165
199
  return None
166
200
 
201
+ def get_app_info(self, package_name: str) -> Dict:
202
+ """
203
+ Get detailed information about a specific application.
204
+
205
+ Args:
206
+ package_name (str): The package name of the application to retrieve information for.
207
+
208
+ Returns:
209
+ Dict: A dictionary containing the application information. If an error occurs during parsing,
210
+ an empty dictionary is returned.
211
+ """
212
+ app_info = {}
213
+ data = self.hdc.shell(self.serial, f"bm dump -n {package_name}")
214
+ output = data
215
+ try:
216
+ json_start = output.find("{")
217
+ json_end = output.rfind("}") + 1
218
+ json_output = output[json_start:json_end]
219
+
220
+ app_info = json.loads(json_output)
221
+ except Exception as e:
222
+ logger.error(f"An error occurred: {e}")
223
+ return app_info
224
+
225
+ def get_app_abilities(self, package_name: str) -> List[Dict]:
226
+ """
227
+ Get the abilities of an application.
228
+
229
+ Args:
230
+ package_name (str): The package name of the application.
231
+
232
+ Returns:
233
+ List[Dict]: A list of dictionaries containing the abilities of the application.
234
+ """
235
+ result = []
236
+ app_info = self.get_app_info(package_name)
237
+ hap_module_infos = app_info.get("hapModuleInfos")
238
+ main_entry = app_info.get("mainEntry")
239
+ for hap_module_info in hap_module_infos:
240
+ # 尝试读取moduleInfo
241
+ try:
242
+ ability_infos = hap_module_info.get("abilityInfos")
243
+ module_main = hap_module_info["mainAbility"]
244
+ except Exception as e:
245
+ logger.warning(f"Fail to parse moduleInfo item, {repr(e)}")
246
+ continue
247
+ # 尝试读取abilityInfo
248
+ for ability_info in ability_infos:
249
+ try:
250
+ is_launcher_ability = False
251
+ skills = ability_info['skills']
252
+ if len(skills) > 0 and "action.system.home" in skills[0]["actions"]:
253
+ is_launcher_ability = True
254
+ icon_ability_info = {
255
+ "name": ability_info["name"],
256
+ "moduleName": ability_info["moduleName"],
257
+ "moduleMainAbility": module_main,
258
+ "mainModule": main_entry,
259
+ "isLauncherAbility": is_launcher_ability
260
+ }
261
+ result.append(icon_ability_info)
262
+ except Exception as e:
263
+ logger.warning(f"Fail to parse ability_info item, {repr(e)}")
264
+ continue
265
+ logger.debug(f"all abilities: {result}")
266
+ return result
267
+
268
+ def get_app_main_ability(self, package_name: str) -> Dict:
269
+ """
270
+ Get the main ability of an application.
271
+
272
+ Args:
273
+ package_name (str): The package name of the application to retrieve information for.
274
+
275
+ Returns:
276
+ Dict: A dictionary containing the main ability of the application.
277
+
278
+ """
279
+ if not (abilities := self.get_app_abilities(package_name)):
280
+ return {}
281
+ for item in abilities:
282
+ score = 0
283
+ if (name := item["name"]) and name == item["moduleMainAbility"]:
284
+ score += 1
285
+ if (module_name := item["moduleName"]) and module_name == item["mainModule"]:
286
+ score += 1
287
+ item["score"] = score
288
+ abilities.sort(key=lambda x: (not x["isLauncherAbility"], -x["score"]))
289
+ logger.debug(f"main ability: {abilities[0]}")
290
+ return abilities[0]
291
+
292
+ def app_launch(self, package: str, page_name: Optional[str] = None):
293
+ """
294
+ Start an application on the device.
295
+ If the `page_name` is empty, it will retrieve the main ability using `get_app_main_ability`.
296
+ Args:
297
+ package (str): The package name of the application.
298
+ page_name (Optional[str]): Ability Name within the application to start. If not provided, the main ability will be used.
299
+ """
300
+ if not page_name:
301
+ page_name = self.get_app_main_ability(package).get('name', 'MainAbility')
302
+ self.shell(f"aa start -a {page_name} -b {package}")
303
+
304
+ def app_terminate(self, package: str):
305
+ self.shell(f"aa force-stop {package}")
306
+
167
307
  def shell(self, command: str) -> ShellResponse:
168
308
  result = self.hdc.shell(self.serial, command)
169
309
  return ShellResponse(output=result)
uiautodev/model.py CHANGED
@@ -14,6 +14,7 @@ from pydantic import BaseModel
14
14
  class DeviceInfo(BaseModel):
15
15
  serial: str
16
16
  model: str = ""
17
+ product: str = ""
17
18
  name: str = ""
18
19
  status: str = ""
19
20
  enabled: bool = True
uiautodev/provider.py CHANGED
@@ -46,12 +46,18 @@ class AndroidProvider(BaseProvider):
46
46
  def list_devices(self) -> list[DeviceInfo]:
47
47
  adb = adbutils.AdbClient()
48
48
  ret: list[DeviceInfo] = []
49
- for d in adb.list():
49
+ for d in adb.list(extended=True):
50
50
  if d.state != "device":
51
51
  ret.append(DeviceInfo(serial=d.serial, status=d.state, enabled=False))
52
52
  else:
53
- dev = adb.device(d.serial)
54
- ret.append(DeviceInfo(serial=d.serial, model=dev.prop.model, name=dev.prop.name))
53
+ ret.append(DeviceInfo(
54
+ serial=d.serial,
55
+ status=d.state,
56
+ name=d.tags.get('device', ''),
57
+ model=d.tags.get('model', ''),
58
+ product=d.tags.get('product', ''),
59
+ enabled=True
60
+ ))
55
61
  return ret
56
62
 
57
63
  @lru_cache
@@ -76,7 +82,7 @@ class HarmonyProvider(BaseProvider):
76
82
 
77
83
  def list_devices(self) -> list[DeviceInfo]:
78
84
  devices = self.hdc.list_device()
79
- return [DeviceInfo(serial=d, model=self.hdc.get_model(d), name=self.hdc.get_model(d)) for d in devices]
85
+ return [DeviceInfo(serial=d, model=self.hdc.get_model(d), name=self.hdc.get_name(d)) for d in devices]
80
86
 
81
87
  @lru_cache
82
88
  def get_device_driver(self, serial: str) -> HarmonyDriver:
uiautodev/router/proxy.py CHANGED
@@ -1,11 +1,10 @@
1
1
  import asyncio
2
+ import logging
2
3
 
3
4
  import httpx
4
5
  import websockets
5
6
  from fastapi import APIRouter, HTTPException, Request, WebSocket, WebSocketDisconnect
6
7
  from fastapi.responses import Response
7
- import logging
8
-
9
8
 
10
9
  logger = logging.getLogger(__name__)
11
10
  router = APIRouter()
@@ -1,8 +1,9 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: uiautodev
3
- Version: 0.10.0
3
+ Version: 0.11.1
4
4
  Summary: Mobile UI Automation, include UI hierarchy inspector, script recorder
5
5
  License: MIT
6
+ License-File: LICENSE
6
7
  Author: codeskyblue
7
8
  Author-email: codeskyblue@gmail.com
8
9
  Requires-Python: >=3.8,<4.0
@@ -14,6 +15,7 @@ Classifier: Programming Language :: Python :: 3.10
14
15
  Classifier: Programming Language :: Python :: 3.11
15
16
  Classifier: Programming Language :: Python :: 3.12
16
17
  Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
17
19
  Requires-Dist: Pillow
18
20
  Requires-Dist: adbutils (>=2.8.10,<3)
19
21
  Requires-Dist: click (>=8.1.7,<9.0.0)
@@ -1,25 +1,25 @@
1
- uiautodev/__init__.py,sha256=TXoecsIhto8S54V7jn6x4PdNIlhxaTPTQgtpSKQWcq0,165
1
+ uiautodev/__init__.py,sha256=Ya4pFQpAHk2du5GJjKUOuuJd0dK2UYSmEaajmyAkLDU,165
2
2
  uiautodev/__main__.py,sha256=0WZHyHW-M7FG5RexANNoIB5pkCX8xwQbTnmaOA9Y1kg,176
3
3
  uiautodev/app.py,sha256=K3u6WCobH3Q5HmXvrZff0Cq44L0j1J4eBVhSxnSNKiE,6600
4
4
  uiautodev/appium_proxy.py,sha256=yMzPnIDo50hYSaq0g5bXUpgRrFa_849wNa2o7ZpxGNY,1773
5
5
  uiautodev/binaries/scrcpy_server.jar,sha256=ojxWWfNsJg8QXAItJ7yz6v_6JgcOe6qe2mbQE3ehrbo,71200
6
6
  uiautodev/case.py,sha256=Jk2_5X2F-XIPnGuYTCqOVQiwwchwOhF7uKK5oKv5shg,3919
7
7
  uiautodev/cli.py,sha256=FL9PBGo0UTttRhGW7THrWqNn2ujsA-728y0O46h2Qjk,6240
8
- uiautodev/command_proxy.py,sha256=C9z-dITMED4k5na45NMdEWAXlLh3Ll921mKuefFyk78,5226
9
- uiautodev/command_types.py,sha256=pWdnCS4FRnEIiR1ynd4cjXX8zeFndjPztacBlukt61E,1761
8
+ uiautodev/command_proxy.py,sha256=Od8jSVDOUJWWcni-Jq8_IHd34VbfWECi0mL1wl86lIo,5446
9
+ uiautodev/command_types.py,sha256=wZa-yQpxzQO79iFMHShJELuZgYJm-yweG-TeSBvzBvs,1867
10
10
  uiautodev/common.py,sha256=1A0kXfxVrp_i5mc_aRjuqSDWFFZ7DwZR9qpRLu2GMMg,1488
11
- uiautodev/driver/android.py,sha256=j7M2yqelWnfErGNF0JGTrth9unwBlRI6-gi71v1suu4,8022
11
+ uiautodev/driver/android.py,sha256=k4Mjq2gmsokwCUN68VGCuhbl7HHEEyeowuTzQFXjg30,8181
12
12
  uiautodev/driver/appium.py,sha256=U3TGpOXmu3tEa3E1ttTFoXehOfFyjavJQ3XA4CtqeBE,5308
13
- uiautodev/driver/base_driver.py,sha256=neoVS9T8MN5RXvW6vvqXSc6pcBW_fqujJurjUrlt0OA,2816
14
- uiautodev/driver/harmony.py,sha256=93pwlg04wazey8MQM6DEvcBkr52REYVw4bwz321fK38,8031
13
+ uiautodev/driver/base_driver.py,sha256=6MBNfEg_CtS4ed90SaSGbdqmf-JNaypqiBNaZBRKeAo,3027
14
+ uiautodev/driver/harmony.py,sha256=L3Ggd1PNlv6cPDbaaf8BA7OqtUp-G5g4Tk9cvhpnakw,13777
15
15
  uiautodev/driver/ios.py,sha256=EOi9k-Y4qQS6Htdz_ycBf5jYCnOkruB-mR0Sc8J-coo,4204
16
16
  uiautodev/driver/mock.py,sha256=0VtxBkZRMbHiQGHjqm8Ih2Ld6baXiVxX8yUTwWJQlnE,2422
17
17
  uiautodev/driver/testdata/layout.json,sha256=0z9jGJteXuGwkOhO_iINYPoDp1kCq-EaQds_iZkmiPQ,276538
18
18
  uiautodev/driver/udt/appium-uiautomator2-v5.12.4-light.apk,sha256=cKUVKpqEiGRXODeqpwzVWllyjdSLyowFm94a6jDTvhI,3675062
19
19
  uiautodev/driver/udt/udt.py,sha256=p6opbUtYxEGTINIX83F6m2CtzB42iSSBYRv1SjXCEFg,8351
20
20
  uiautodev/exceptions.py,sha256=lQI14vshN5qExVE23g2aw5i2fkdQFfLCJj2dO6kVLZw,591
21
- uiautodev/model.py,sha256=lCe1bAoY6-mx67dLYVR-xR-trGT81sCw93Aih0Yfi-M,1049
22
- uiautodev/provider.py,sha256=EnBI8PD2eoBjqugGS5cmy8GZ1Z7EaEF6YEQSfpOMN6s,2862
21
+ uiautodev/model.py,sha256=hrqezVn1XFXHyajFxxmoiuGDZoYAodfitWMBzrYgziA,1071
22
+ uiautodev/provider.py,sha256=f3fh9IbgTRlJmxZXXTNNZbHgHBIqfQCIBKIPz_BOOng,3054
23
23
  uiautodev/remote/android_input.py,sha256=r9y2SxnDw0GhN44emL-2Nz0UasaVaVtzh53hd-LJ710,2445
24
24
  uiautodev/remote/harmony_mjpeg.py,sha256=-J2sVfPSTuqN80BelisvwaZAimWxIk9SIzD010q3h7c,8287
25
25
  uiautodev/remote/keycode.py,sha256=RHSJVfcNY2pelQd7_tcE6T0j3n8CKBkiku7A2AJZUpk,8097
@@ -27,15 +27,15 @@ uiautodev/remote/scrcpy.py,sha256=JNSwC35f4os-IQW4ixx7ky9clpqRWvA8X_obUkwuOh8,74
27
27
  uiautodev/remote/touch_controller.py,sha256=dYl5XTLaYEyZiNJmKwHQpw9QhPSkN3iUetJSaiQJBHg,4255
28
28
  uiautodev/router/android.py,sha256=xwzaZduMRJsyml-7eZjNtQMg_c22ZpFAq6TErc_-tlA,1358
29
29
  uiautodev/router/device.py,sha256=iNJUexRLUmgGT_n1UgWybX8PvRSDinpoUpvKX-NZi10,4298
30
- uiautodev/router/proxy.py,sha256=Jn9emYCWJCl5nxI6f4lwXNaaZy4kAmfWL-nj9hSKGnA,2007
30
+ uiautodev/router/proxy.py,sha256=Kp_w1KfbKMp9RTERtLAQjn1_U3tUSC4ZWAliHeaJuug,2006
31
31
  uiautodev/router/xml.py,sha256=MKVLhjMBqE4qbEraQxvdrVp_OBnylEL9Wti5lnmBDk4,891
32
32
  uiautodev/static/demo.html,sha256=qC7qUZP5Af9T3V5EuFGbovzv8mArwiGMWsX_vcs_Bt0,1240
33
33
  uiautodev/utils/common.py,sha256=L1qBBBS6jRgkXlGy5o6Xafo49auLXKRWyX9x8U_IKjc,4821
34
34
  uiautodev/utils/envutils.py,sha256=Clyt2Hz9PXpK_fT0yWbMmixXyGvCaJO3LAgamM7aUVc,197
35
35
  uiautodev/utils/exceptions.py,sha256=lL_G_E41KWvfXnl32-E4Vgr3_HyTboxq_EwzdQMuvK4,637
36
36
  uiautodev/utils/usbmux.py,sha256=LYupLDn7U4KFKhYQJrmIroS-3040gqZQVDRDB_FNDJM,17386
37
- uiautodev-0.10.0.dist-info/LICENSE,sha256=RyeW676gBYO7AVVP2zQgfEx5rPSt46vR47xXZe7TlX4,1068
38
- uiautodev-0.10.0.dist-info/METADATA,sha256=w48FCoinwhnidWaoG5UPjAA8IplnMFGcCjFb1uIM384,2555
39
- uiautodev-0.10.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
40
- uiautodev-0.10.0.dist-info/entry_points.txt,sha256=zBY8GgseYAAzPFA5Cf4rCCS9ivdyWsNxMVVYIaGAHJU,88
41
- uiautodev-0.10.0.dist-info/RECORD,,
37
+ uiautodev-0.11.1.dist-info/METADATA,sha256=omxcGuHP5rjLAtT0JbnhdkCq58majJ3m726u4p25t9U,2628
38
+ uiautodev-0.11.1.dist-info/WHEEL,sha256=M5asmiAlL6HEcOq52Yi5mmk9KmTVjY2RDPtO4p9DMrc,88
39
+ uiautodev-0.11.1.dist-info/entry_points.txt,sha256=zBY8GgseYAAzPFA5Cf4rCCS9ivdyWsNxMVVYIaGAHJU,88
40
+ uiautodev-0.11.1.dist-info/licenses/LICENSE,sha256=RyeW676gBYO7AVVP2zQgfEx5rPSt46vR47xXZe7TlX4,1068
41
+ uiautodev-0.11.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 2.1.3
2
+ Generator: poetry-core 2.2.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any