androidviewclient 25.0.0__tar.gz → 25.1.0__tar.gz

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.
Files changed (53) hide show
  1. {androidviewclient-25.0.0/src/androidviewclient.egg-info → androidviewclient-25.1.0}/PKG-INFO +2 -3
  2. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/README.md +25 -14
  3. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/setup.py +4 -3
  4. {androidviewclient-25.0.0 → androidviewclient-25.1.0/src/androidviewclient.egg-info}/PKG-INFO +2 -3
  5. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/androidviewclient.egg-info/requires.txt +1 -2
  6. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/adb/adbclient.py +1 -1
  7. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/adb/dumpsys.py +1 -1
  8. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/code_generator.py +1 -1
  9. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/common.py +1 -1
  10. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/concertina.py +1 -1
  11. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/controlpanel.py +1 -1
  12. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/culebron.py +25 -5
  13. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/mcp/__init__.py +1 -1
  14. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/mcp/object_store.py +1 -1
  15. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/mcp/server.py +1 -1
  16. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/mcp/tools.py +22 -12
  17. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/plot.py +1 -1
  18. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/robotframework/viewclientwrapper.py +1 -1
  19. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/uiautomator/uiautomatorhelper.py +10 -3
  20. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/viewclient.py +17 -13
  21. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/tools/culebra +1 -1
  22. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/tools/dump +1 -1
  23. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/LICENSE +0 -0
  24. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/setup.cfg +0 -0
  25. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/androidviewclient.egg-info/SOURCES.txt +0 -0
  26. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/androidviewclient.egg-info/dependency_links.txt +0 -0
  27. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/androidviewclient.egg-info/entry_points.txt +0 -0
  28. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/androidviewclient.egg-info/top_level.txt +0 -0
  29. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/__init__.py +0 -0
  30. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/__init__.py +0 -0
  31. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/__init__.py +0 -0
  32. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/adb/__init__.py +0 -0
  33. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/adb/androidkeymap.py +0 -0
  34. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/distance.py +0 -0
  35. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/kato/__init__.py +0 -0
  36. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/kato/kato.py +0 -0
  37. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/keyevent.py +0 -0
  38. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/robotframework/__init__.py +0 -0
  39. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/uiautomator/__init__.py +0 -0
  40. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/uiautomator/utils.py +0 -0
  41. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/com/dtmilano/android/window.py +0 -0
  42. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/share/__init__.py +0 -0
  43. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/share/pixmaps/__init__.py +0 -0
  44. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/share/pixmaps/culebra.png +0 -0
  45. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/share/pixmaps/plugins/__init__.py +0 -0
  46. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/share/pixmaps/plugins/android/__init__.py +0 -0
  47. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/share/pixmaps/plugins/android/lib/__init__.py +0 -0
  48. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/share/pixmaps/plugins/android/lib/device-art-resources/__init__.py +0 -0
  49. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/share/pixmaps/plugins/android/lib/device-art-resources/samsung_s4/__init__.py +0 -0
  50. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/share/pixmaps/plugins/android/lib/device-art-resources/samsung_s4/port_back.png +0 -0
  51. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/share/pixmaps/plugins/android/lib/device-art-resources/samsung_s4/port_fore.png +0 -0
  52. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/src/share/pixmaps/plugins/android/lib/device-art-resources/samsung_s4/port_shadow.png +0 -0
  53. {androidviewclient-25.0.0 → androidviewclient-25.1.0}/tools/culebra-mcp +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: androidviewclient
3
- Version: 25.0.0
3
+ Version: 25.1.0
4
4
  Summary: AndroidViewClient is a 100% pure python library and tools
5
5
  Home-page: https://github.com/dtmilano/AndroidViewClient/
6
6
  Author: Diego Torres Milano
@@ -16,12 +16,11 @@ Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.12
17
17
  Requires-Python: >=3.9
18
18
  License-File: LICENSE
19
- Requires-Dist: setuptools
20
19
  Requires-Dist: requests
21
20
  Requires-Dist: numpy
22
21
  Requires-Dist: matplotlib
23
22
  Requires-Dist: culebratester-client>=2.0.73
24
- Requires-Dist: mcp>=0.9.0
23
+ Requires-Dist: mcp<2,>=0.9.0
25
24
  Provides-Extra: dev
26
25
  Requires-Dist: pytest>=7.0.0; extra == "dev"
27
26
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
@@ -41,7 +41,7 @@ Or check the wiki for more alternatives.
41
41
 
42
42
  # AI-Powered Testing with MCP
43
43
 
44
- **NEW!** AndroidViewClient now includes a Model Context Protocol (MCP) server that enables AI assistants like Kiro to interact with Android devices through natural language.
44
+ **NEW!** AndroidViewClient now includes a Model Context Protocol (MCP) server that enables AI assistants like Claude Code and Kiro to interact with Android devices through natural language.
45
45
 
46
46
  ## Quick Start with MCP
47
47
 
@@ -53,11 +53,15 @@ Or check the wiki for more alternatives.
53
53
  2. **Start CulebraTester2 on your device:**
54
54
 
55
55
  Check the details at [How to run CulebraTester2 ?](https://github.com/dtmilano/CulebraTester2-public?tab=readme-ov-file#how-to-run-culebratester2-)
56
-
57
56
 
58
- 4. **Configure your AI assistant:**
59
-
60
- Add to `.kiro/settings/mcp.json` or `~/.kiro/settings/mcp.json`:
57
+ 3. **Configure your AI assistant:**
58
+
59
+ **Claude Code** — register the server with one command:
60
+ ```bash
61
+ claude mcp add culebratester2 --env CULEBRATESTER2_URL=http://localhost:9987 -- culebra-mcp
62
+ ```
63
+
64
+ Or add it to `.mcp.json` in your project root, so everyone who clones the project gets it:
61
65
  ```json
62
66
  {
63
67
  "mcpServers": {
@@ -71,12 +75,14 @@ Or check the wiki for more alternatives.
71
75
  }
72
76
  ```
73
77
 
74
- 5. **Start testing with natural language:**
75
- - "Get the device screen size"
76
- - "Launch the Calculator app"
77
- - "Find the button with text Submit and click it"
78
- - "Take a screenshot"
79
- - "Swipe up to scroll"
78
+ **Kiro** — add the same entry to `.kiro/settings/mcp.json` or `~/.kiro/settings/mcp.json`.
79
+
80
+ 4. **Start testing with natural language:**
81
+ - "_Get the device screen size_"
82
+ - "_Launch the Calculator app_"
83
+ - "_Find the button with text Submit and click it_"
84
+ - "_Take a screenshot_"
85
+ - "_Swipe up to scroll_"
80
86
 
81
87
  ## MCP Tools Available
82
88
 
@@ -103,9 +109,14 @@ The MCP server provides 20 tools for Android automation:
103
109
  For detailed MCP configuration options, see the [MCP Configuration Guide](docs/MCP_CONFIGURATION.md).
104
110
 
105
111
  Quick reference:
106
- - **User-level config** (kiro-cli): `~/.kiro/settings/mcp.json`
107
- - **Workspace config** (Kiro IDE): `.kiro/settings/mcp.json`
108
- - **Examples:** `examples/mcp_config.json`
112
+
113
+ | | Claude Code | Kiro |
114
+ |---|---|---|
115
+ | **Project config** | `.mcp.json` (repository root) | `.kiro/settings/mcp.json` |
116
+ | **User config** | `~/.claude.json` (via `claude mcp add --scope user`) | `~/.kiro/settings/mcp.json` |
117
+ | **Tool pre-approval** | `permissions.allow` in `.claude/settings.json` | `autoApprove` in the server entry |
118
+ | **Example** | `examples/mcp_config.json` | `examples/mcp_config_kiro.json` |
119
+
109
120
  - **Usage examples:** `examples/test_calculator_mcp.py`
110
121
 
111
122
  ## Environment Variables
@@ -3,7 +3,7 @@
3
3
  from setuptools import setup, find_packages
4
4
 
5
5
  setup(name='androidviewclient',
6
- version='25.0.0',
6
+ version='25.1.0',
7
7
  description='''AndroidViewClient is a 100% pure python library and tools
8
8
  that simplifies test script creation providing higher level
9
9
  operations and the ability of obtaining the tree of Views present at
@@ -33,12 +33,13 @@ setup(name='androidviewclient',
33
33
  'Programming Language :: Python :: 3.11',
34
34
  'Programming Language :: Python :: 3.12'],
35
35
  install_requires=[
36
- 'setuptools',
37
36
  'requests',
38
37
  'numpy',
39
38
  'matplotlib',
40
39
  'culebratester-client >= 2.0.73',
41
- 'mcp >= 0.9.0',
40
+ # mcp 2.x renamed FastMCP to MCPServer and changed other APIs;
41
+ # com.dtmilano.android.mcp.server still uses the v1 API.
42
+ 'mcp >= 0.9.0, < 2',
42
43
  ],
43
44
  extras_require={
44
45
  'dev': [
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: androidviewclient
3
- Version: 25.0.0
3
+ Version: 25.1.0
4
4
  Summary: AndroidViewClient is a 100% pure python library and tools
5
5
  Home-page: https://github.com/dtmilano/AndroidViewClient/
6
6
  Author: Diego Torres Milano
@@ -16,12 +16,11 @@ Classifier: Programming Language :: Python :: 3.11
16
16
  Classifier: Programming Language :: Python :: 3.12
17
17
  Requires-Python: >=3.9
18
18
  License-File: LICENSE
19
- Requires-Dist: setuptools
20
19
  Requires-Dist: requests
21
20
  Requires-Dist: numpy
22
21
  Requires-Dist: matplotlib
23
22
  Requires-Dist: culebratester-client>=2.0.73
24
- Requires-Dist: mcp>=0.9.0
23
+ Requires-Dist: mcp<2,>=0.9.0
25
24
  Provides-Extra: dev
26
25
  Requires-Dist: pytest>=7.0.0; extra == "dev"
27
26
  Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
@@ -1,9 +1,8 @@
1
- setuptools
2
1
  requests
3
2
  numpy
4
3
  matplotlib
5
4
  culebratester-client>=2.0.73
6
- mcp>=0.9.0
5
+ mcp<2,>=0.9.0
7
6
 
8
7
  [dev]
9
8
  pytest>=7.0.0
@@ -27,7 +27,7 @@ from typing import Optional
27
27
 
28
28
  from com.dtmilano.android.adb.dumpsys import Dumpsys
29
29
 
30
- __version__ = '25.0.0'
30
+ __version__ = '25.1.0'
31
31
 
32
32
  import sys
33
33
  import warnings
@@ -23,7 +23,7 @@ import re
23
23
  import sys
24
24
  from _warnings import warn
25
25
 
26
- __version__ = '25.0.0'
26
+ __version__ = '25.1.0'
27
27
 
28
28
  DEBUG = False
29
29
 
@@ -3,7 +3,7 @@ import textwrap
3
3
  from abc import ABC
4
4
  from datetime import date
5
5
 
6
- __version__ = '25.0.0'
6
+ __version__ = '25.1.0'
7
7
 
8
8
  from typing import TextIO, Union, Dict, List
9
9
 
@@ -20,7 +20,7 @@ limitations under the License.
20
20
 
21
21
  from __future__ import print_function
22
22
 
23
- __version__ = '25.0.0'
23
+ __version__ = '25.1.0'
24
24
 
25
25
  import ast
26
26
  import os
@@ -22,7 +22,7 @@ import json
22
22
  import random
23
23
 
24
24
  __author__ = 'diego'
25
- __version__ = '25.0.0'
25
+ __version__ = '25.1.0'
26
26
 
27
27
  DEBUG = True
28
28
 
@@ -20,7 +20,7 @@
20
20
  '''
21
21
  import platform
22
22
 
23
- __version__ = '25.0.0'
23
+ __version__ = '25.1.0'
24
24
 
25
25
  import tkinter
26
26
  import tkinter.ttk
@@ -38,7 +38,7 @@ from com.dtmilano.android.keyevent import KEY_EVENT
38
38
  from com.dtmilano.android.uiautomator.uiautomatorhelper import UiAutomatorHelper
39
39
  from com.dtmilano.android.viewclient import ViewClient, View, VERSION_SDK_PROPERTY
40
40
 
41
- __version__ = '25.0.0'
41
+ __version__ = '25.1.0'
42
42
 
43
43
  import sys
44
44
  import threading
@@ -46,7 +46,28 @@ import warnings
46
46
  import copy
47
47
  import os
48
48
  import platform
49
- from pkg_resources import Requirement, resource_filename
49
+ from importlib.metadata import PackageNotFoundError, distribution
50
+
51
+
52
+ def _culebra_icon_path() -> Optional[str]:
53
+ """
54
+ Path to the culebra window icon, or None if it cannot be found.
55
+
56
+ Replaces pkg_resources.resource_filename(Requirement.parse("androidviewclient"), ...),
57
+ which resolved the file relative to the installed distribution's location. pkg_resources
58
+ has been removed from setuptools, so it is looked up with the standard library instead,
59
+ falling back to the source tree when running from a checkout.
60
+ """
61
+ relative = os.path.join('share', 'pixmaps', 'culebra.png')
62
+ try:
63
+ located = str(distribution('androidviewclient').locate_file(relative))
64
+ if os.path.isfile(located):
65
+ return located
66
+ except PackageNotFoundError:
67
+ pass
68
+ # src/com/dtmilano/android/culebron.py -> src/share/pixmaps/culebra.png
69
+ in_tree = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..', relative)
70
+ return os.path.normpath(in_tree) if os.path.isfile(in_tree) else None
50
71
 
51
72
  # noinspection PyBroadException
52
73
  try:
@@ -289,9 +310,8 @@ This is usually installed by python package. Check your distribution details.
289
310
  self.concertinaConfigFile = concertinaConfigFile
290
311
  self.window = tkinter.Tk()
291
312
  try:
292
- f = resource_filename(Requirement.parse("androidviewclient"),
293
- "share/pixmaps/culebra.png")
294
- icon = ImageTk.PhotoImage(file=f)
313
+ f = _culebra_icon_path()
314
+ icon = ImageTk.PhotoImage(file=f) if f else None
295
315
  except:
296
316
  icon = None
297
317
  if icon:
@@ -21,7 +21,7 @@ For more information, see:
21
21
  https://github.com/dtmilano/AndroidViewClient/
22
22
  """
23
23
 
24
- __version__ = '25.0.0'
24
+ __version__ = '25.1.0'
25
25
  __author__ = 'Diego Torres Milano'
26
26
  __email__ = 'dtmilano@gmail.com'
27
27
 
@@ -25,7 +25,7 @@ limitations under the License.
25
25
 
26
26
  from typing import Dict, Any, Optional
27
27
 
28
- __version__ = '25.0.0'
28
+ __version__ = '25.1.0'
29
29
 
30
30
 
31
31
  class ObjectStore:
@@ -31,7 +31,7 @@ from culebratester_client import ApiClient, Configuration
31
31
  from culebratester_client.api import DefaultApi
32
32
  from com.dtmilano.android.mcp.object_store import ObjectStore
33
33
 
34
- __version__ = '25.0.0'
34
+ __version__ = '25.1.0'
35
35
 
36
36
  # Configure logging
37
37
  DEBUG = os.environ.get('CULEBRATESTER2_DEBUG', '').lower() in ('1', 'true', 'yes')
@@ -65,10 +65,10 @@ def getDeviceInfo() -> str:
65
65
  @mcp.tool()
66
66
  def dumpUiHierarchy() -> str:
67
67
  """
68
- Dump the current UI hierarchy as XML.
69
-
68
+ Dump the current UI hierarchy.
69
+
70
70
  Returns:
71
- JSON string with UI hierarchy XML
71
+ JSON string whose "data" is the window hierarchy as a nested dict
72
72
  """
73
73
  try:
74
74
  hierarchy = client.ui_device_dump_window_hierarchy_get()
@@ -351,19 +351,29 @@ def startApp(packageName: str, activityName: str = None) -> str:
351
351
 
352
352
  Args:
353
353
  packageName: The package name of the app (e.g., "com.example.app")
354
- activityName: Optional activity name to start (e.g., ".MainActivity")
355
-
354
+ activityName: The activity to start, either fully qualified
355
+ ("com.example.app.MainActivity") or relative to the package
356
+ (".MainActivity"). Required: CulebraTester2's startActivity
357
+ endpoint takes an explicit class and cannot resolve a launcher
358
+ activity from the package name alone.
359
+
356
360
  Returns:
357
361
  JSON string with success status
358
362
  """
359
363
  try:
360
- # Build component string
361
- if activityName:
362
- component = "{}/{}".format(packageName, activityName)
363
- else:
364
- component = packageName
365
-
366
- result = client.target_context_start_activity_get(component=component)
364
+ if not activityName:
365
+ return json.dumps({
366
+ "success": False,
367
+ "error": "activityName is required (e.g. \".MainActivity\"): "
368
+ "CulebraTester2 starts activities by explicit class"
369
+ })
370
+
371
+ # The endpoint takes pkg and cls as separate required query params,
372
+ # and the server does not expand a relative class name -- ".Main"
373
+ # reaches the Intent verbatim and fails with ActivityNotFoundException.
374
+ cls = packageName + activityName if activityName.startswith('.') else activityName
375
+
376
+ result = client.target_context_start_activity_get(pkg=packageName, cls=cls)
367
377
  return json.dumps({
368
378
  "success": True,
369
379
  "data": str(result) if result else "OK"
@@ -31,7 +31,7 @@ from mpl_toolkits.axes_grid1 import host_subplot
31
31
 
32
32
  from com.dtmilano.android.adb.dumpsys import Dumpsys
33
33
 
34
- __version__ = '25.0.0'
34
+ __version__ = '25.1.0'
35
35
 
36
36
  DEBUG = False
37
37
 
@@ -18,7 +18,7 @@ limitations under the License.
18
18
  @author: Diego Torres Milano
19
19
  '''
20
20
 
21
- __version__ = '25.0.0'
21
+ __version__ = '25.1.0'
22
22
  __author__ = 'diego'
23
23
 
24
24
  import sys
@@ -20,7 +20,7 @@ limitations under the License.
20
20
 
21
21
  from __future__ import print_function
22
22
 
23
- __version__ = '25.0.0'
23
+ __version__ = '25.1.0'
24
24
 
25
25
  import math
26
26
  import os
@@ -500,8 +500,15 @@ class UiAutomatorHelper:
500
500
 
501
501
  :see https://github.com/dtmilano/CulebraTester2-public/blob/master/openapi.yaml
502
502
  :param _format: the format (e.g.: JSON, XML)
503
- :return: the window hierarchy
504
- """
503
+ :return: the window hierarchy: a WindowHierarchy for JSON, the XML document as a str for XML
504
+ """
505
+ if _format and _format.upper() == 'XML':
506
+ # The server answers XML as a text/plain document, but the generated client declares a
507
+ # single response type (WindowHierarchy) for this endpoint and tries to deserialize the
508
+ # XML into it, which fails. Take the body undeserialized and hand back the document.
509
+ response = self.uiAutomatorHelper.api_instance.ui_device_dump_window_hierarchy_get(
510
+ format=_format, _preload_content=False)
511
+ return response.data.decode('utf-8')
505
512
  return self.uiAutomatorHelper.api_instance.ui_device_dump_window_hierarchy_get(format=_format)
506
513
 
507
514
  @kato.kato
@@ -18,15 +18,15 @@ limitations under the License.
18
18
  @author: Diego Torres Milano
19
19
  """
20
20
 
21
- from __future__ import print_function
21
+ from __future__ import annotations, print_function
22
22
 
23
23
  import json
24
- from typing import Optional, Union, Dict, Tuple
24
+ from typing import Literal, Optional, Union, Dict, Tuple
25
25
 
26
26
  import culebratester_client
27
27
  from culebratester_client import WindowHierarchyChild, WindowHierarchy
28
28
 
29
- __version__ = '25.0.0'
29
+ __version__ = '25.1.0'
30
30
 
31
31
  import sys
32
32
  import warnings
@@ -3738,15 +3738,15 @@ class ViewClient:
3738
3738
  self.windows[int('0x' + wid, 16)] = package
3739
3739
  return self.windows
3740
3740
 
3741
- def findViewById(self, viewId, root="ROOT", viewFilter=None):
3741
+ def findViewById(self, viewId: str, root: View | Literal["ROOT"] = "ROOT", viewFilter=None) -> View | None:
3742
3742
  """
3743
3743
  Finds the View with the specified viewId.
3744
3744
 
3745
3745
  @type viewId: str
3746
3746
  @param viewId: the ID of the view to find
3747
- @type root: str
3748
- @type root: View
3749
- @param root: the root node of the tree where the View will be searched
3747
+ @type root: View or str
3748
+ @param root: the root node of the tree where the View will be searched, or the
3749
+ string C{"ROOT"} to search the whole tree
3750
3750
  @type: viewFilter: function
3751
3751
  @param viewFilter: a function that will be invoked providing the candidate View as a parameter
3752
3752
  and depending on the return value (C{True} or C{False}) the View will be
@@ -3754,6 +3754,7 @@ class ViewClient:
3754
3754
  This can be C{None} and no extra filtering is applied.
3755
3755
 
3756
3756
  @return: the C{View} found or C{None}
3757
+ @raise ValueError: if C{root} is a str other than C{"ROOT"}
3757
3758
  """
3758
3759
 
3759
3760
  if self.uiAutomatorHelper:
@@ -3763,8 +3764,10 @@ class ViewClient:
3763
3764
  if not root:
3764
3765
  return None
3765
3766
 
3766
- if root == "ROOT":
3767
- return self.findViewById(viewId, self.root, viewFilter)
3767
+ if isinstance(root, str):
3768
+ if root == "ROOT":
3769
+ return self.findViewById(viewId, self.root, viewFilter)
3770
+ raise ValueError("Invalid root: '%s', the only str accepted is 'ROOT'" % root)
3768
3771
 
3769
3772
  try:
3770
3773
  rootId = root.getId()
@@ -3806,15 +3809,15 @@ class ViewClient:
3806
3809
  else:
3807
3810
  return foundView
3808
3811
 
3809
- def findViewByIdOrRaise(self, viewId, root="ROOT", viewFilter=None):
3812
+ def findViewByIdOrRaise(self, viewId: str, root: View | Literal["ROOT"] = "ROOT", viewFilter=None) -> View:
3810
3813
  """
3811
3814
  Finds the View or raise a ViewNotFoundException.
3812
3815
 
3813
3816
  @type viewId: str
3814
3817
  @param viewId: the ID of the view to find
3815
- @type root: str
3816
- @type root: View
3817
- @param root: the root node of the tree where the View will be searched
3818
+ @type root: View or str
3819
+ @param root: the root node of the tree where the View will be searched, or the
3820
+ string C{"ROOT"} to search the whole tree
3818
3821
  @type: viewFilter: function
3819
3822
  @param viewFilter: a function that will be invoked providing the candidate View as a parameter
3820
3823
  and depending on the return value (C{True} or C{False}) the View will be
@@ -3822,6 +3825,7 @@ class ViewClient:
3822
3825
  This can be C{None} and no extra filtering is applied.
3823
3826
  @return: the View found
3824
3827
  @raise ViewNotFoundException: raise the exception if View not found
3828
+ @raise ValueError: if C{root} is a str other than C{"ROOT"}
3825
3829
  """
3826
3830
 
3827
3831
  view = self.findViewById(viewId, root, viewFilter)
@@ -28,7 +28,7 @@ from typing import Pattern
28
28
  import culebratester_client
29
29
  from culebratester_client import WindowHierarchy, Selector
30
30
 
31
- __version__ = '25.0.0'
31
+ __version__ = '25.1.0'
32
32
 
33
33
  import calendar
34
34
  import codecs
@@ -8,7 +8,7 @@ Created on Feb 3, 2012
8
8
 
9
9
  from __future__ import print_function
10
10
 
11
- __version__ = '25.0.0'
11
+ __version__ = '25.1.0'
12
12
 
13
13
  import getopt
14
14
  import os