pymobiledevice3 5.3.2__py3-none-any.whl → 6.0.0__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.
@@ -1,4 +1,5 @@
1
1
  from dataclasses import asdict, dataclass
2
+ from typing import Optional
2
3
 
3
4
  from pymobiledevice3.services.web_protocol.automation_session import RESOURCES, Point, Rect, Size
4
5
  from pymobiledevice3.services.web_protocol.element import WebElement
@@ -34,106 +35,106 @@ class WebDriver(SeleniumApi):
34
35
  self.session = session
35
36
  self.switch_to = SwitchTo(session)
36
37
 
37
- def add_cookie(self, cookie: Cookie):
38
+ async def add_cookie(self, cookie: Cookie):
38
39
  """Adds a cookie to your current session."""
39
40
  if isinstance(cookie, Cookie):
40
41
  cookie = asdict(cookie)
41
- self.session.add_single_cookie(cookie)
42
+ await self.session.add_single_cookie(cookie)
42
43
 
43
- def back(self):
44
+ async def back(self):
44
45
  """Goes one step backward in the browser history."""
45
- self.session.wait_for_navigation_to_complete()
46
- self.session.go_back_in_browsing_context()
47
- self.session.switch_to_browsing_context("")
46
+ await self.session.wait_for_navigation_to_complete()
47
+ await self.session.go_back_in_browsing_context()
48
+ await self.session.switch_to_browsing_context("")
48
49
 
49
- def close(self):
50
+ async def close(self):
50
51
  """Closes the current window."""
51
- self.session.close_window()
52
+ await self.session.close_window()
52
53
 
53
54
  @property
54
- def current_url(self):
55
+ async def current_url(self):
55
56
  """Gets the URL of the current page."""
56
- self.session.wait_for_navigation_to_complete()
57
- return self.session.get_browsing_context()["url"]
57
+ await self.session.wait_for_navigation_to_complete()
58
+ return (await self.session.get_browsing_context())["url"]
58
59
 
59
60
  @property
60
- def current_window_handle(self):
61
+ async def current_window_handle(self):
61
62
  """Returns the handle of the current window."""
62
- return self.session.get_browsing_context()["handle"]
63
+ return (await self.session.get_browsing_context())["handle"]
63
64
 
64
- def delete_all_cookies(self):
65
+ async def delete_all_cookies(self):
65
66
  """Delete all cookies in the scope of the session."""
66
- self.session.delete_all_cookies()
67
+ await self.session.delete_all_cookies()
67
68
 
68
- def delete_cookie(self, name: str):
69
+ async def delete_cookie(self, name: str):
69
70
  """Deletes a single cookie with the given name."""
70
- self.session.delete_single_cookie(name)
71
+ await self.session.delete_single_cookie(name)
71
72
 
72
- def execute_async_script(self, script: str, *args):
73
+ async def execute_async_script(self, script: str, *args):
73
74
  """
74
75
  Asynchronously Executes JavaScript in the current window/frame.
75
76
  :param script: The JavaScript to execute.
76
77
  :param args: Any applicable arguments for your JavaScript.
77
78
  """
78
- return self.session.execute_script(script, args, async_=True)
79
+ return await self.session.execute_script(script, args, async_=True)
79
80
 
80
- def execute_script(self, script: str, *args):
81
+ async def execute_script(self, script: str, *args):
81
82
  """
82
83
  Synchronously Executes JavaScript in the current window/frame.
83
84
  :param script: The JavaScript to execute.
84
85
  :param args: Any applicable arguments for your JavaScript.
85
86
  """
86
- return self.session.execute_script(script, args)
87
+ return await self.session.execute_script(script, args)
87
88
 
88
- def find_element(self, by=By.ID, value=None) -> WebElement:
89
+ async def find_element(self, by=By.ID, value=None) -> Optional[WebElement]:
89
90
  """Find an element given a By strategy and locator."""
90
- elem = self.session.find_elements(by, value)
91
+ elem = await self.session.find_elements(by, value)
91
92
  return None if elem is None else WebElement(self.session, elem)
92
93
 
93
- def find_elements(self, by=By.ID, value=None) -> list[WebElement]:
94
+ async def find_elements(self, by=By.ID, value=None) -> list[WebElement]:
94
95
  """Find elements given a By strategy and locator."""
95
- elements = self.session.find_elements(by, value, single=False)
96
+ elements = await self.session.find_elements(by, value, single=False)
96
97
  return [WebElement(self.session, elem) for elem in elements]
97
98
 
98
- def forward(self):
99
+ async def forward(self):
99
100
  """Goes one step forward in the browser history."""
100
- self.session.wait_for_navigation_to_complete()
101
- self.session.go_forward_in_browsing_context()
102
- self.session.switch_to_browsing_context("")
101
+ await self.session.wait_for_navigation_to_complete()
102
+ await self.session.go_forward_in_browsing_context()
103
+ await self.session.switch_to_browsing_context("")
103
104
 
104
- def fullscreen_window(self):
105
+ async def fullscreen_window(self):
105
106
  """Invokes the window manager-specific 'full screen' operation."""
106
- self.session.evaluate_js_function(ENTER_FULLSCREEN, implicit_callback=True)
107
+ await self.session.evaluate_js_function(ENTER_FULLSCREEN, implicit_callback=True)
107
108
 
108
- def get(self, url: str):
109
+ async def get(self, url: str):
109
110
  """Loads a web page in the current browser session."""
110
- self.session.wait_for_navigation_to_complete()
111
- self.session.navigate_broswing_context(url)
112
- self.session.switch_to_browsing_context("")
111
+ await self.session.wait_for_navigation_to_complete()
112
+ await self.session.navigate_broswing_context(url)
113
+ await self.session.switch_to_browsing_context("")
113
114
 
114
- def get_cookie(self, name: str) -> Cookie:
115
+ async def get_cookie(self, name: str) -> Cookie:
115
116
  """Get a single cookie by name. Returns the cookie if found, None if not."""
116
- for cookie in self.get_cookies():
117
+ for cookie in await self.get_cookies():
117
118
  if cookie.name == name:
118
119
  return cookie
119
120
 
120
- def get_cookies(self) -> list[Cookie]:
121
+ async def get_cookies(self) -> list[Cookie]:
121
122
  """Returns cookies visible in the current session."""
122
- return list(map(Cookie.from_automation, self.session.get_all_cookies()))
123
+ return list(map(Cookie.from_automation, await self.session.get_all_cookies()))
123
124
 
124
125
  @property
125
- def screenshot_as_base64(self) -> str:
126
+ async def screenshot_as_base64(self) -> str:
126
127
  """Gets the screenshot of the current window as a base64 encoded string."""
127
- return self.session.screenshot_as_base64()
128
+ return await self.session.screenshot_as_base64()
128
129
 
129
130
  def get_window_position(self) -> Point:
130
131
  """Gets the x,y position of the current window."""
131
132
  rect = self.get_window_rect()
132
133
  return Point(x=rect.x, y=rect.y)
133
134
 
134
- def get_window_rect(self) -> Rect:
135
+ async def get_window_rect(self) -> Rect:
135
136
  """Gets the x, y coordinates of the window as well as height and width of the current window."""
136
- context = self.session.get_browsing_context()
137
+ context = await self.session.get_browsing_context()
137
138
  return Rect(
138
139
  context["windowOrigin"]["x"],
139
140
  context["windowOrigin"]["y"],
@@ -141,57 +142,57 @@ class WebDriver(SeleniumApi):
141
142
  context["windowSize"]["height"],
142
143
  )
143
144
 
144
- def get_window_size(self) -> Size:
145
+ async def get_window_size(self) -> Size:
145
146
  """Gets the width and height of the current window."""
146
- rect = self.get_window_rect()
147
+ rect = await self.get_window_rect()
147
148
  return Size(height=rect.height, width=rect.width)
148
149
 
149
150
  def implicitly_wait(self, time_to_wait):
150
151
  """Sets a sticky timeout to implicitly wait for an element to be found, or a command to complete."""
151
152
  self.session.implicit_wait_timeout = time_to_wait * 1000
152
153
 
153
- def maximize_window(self):
154
+ async def maximize_window(self):
154
155
  """Maximizes the current window."""
155
- self.session.maximize_window()
156
+ await self.session.maximize_window()
156
157
 
157
- def minimize_window(self):
158
+ async def minimize_window(self):
158
159
  """Invokes the window manager-specific 'minimize' operation."""
159
- self.session.hide_window()
160
+ await self.session.hide_window()
160
161
 
161
162
  @property
162
- def page_source(self) -> str:
163
+ async def page_source(self) -> str:
163
164
  """Gets the source of the current page."""
164
- return self.session.evaluate_js_function("function() { return document.documentElement.outerHTML; }")
165
+ return await self.session.evaluate_js_function("function() { return document.documentElement.outerHTML; }")
165
166
 
166
- def refresh(self):
167
+ async def refresh(self):
167
168
  """Refreshes the current page."""
168
- self.session.wait_for_navigation_to_complete()
169
- self.session.reload_browsing_context()
170
- self.session.switch_to_browsing_context("")
169
+ await self.session.wait_for_navigation_to_complete()
170
+ await self.session.reload_browsing_context()
171
+ await self.session.switch_to_browsing_context("")
171
172
 
172
- def set_window_position(self, x, y):
173
+ async def set_window_position(self, x, y):
173
174
  """Sets the x,y position of the current window."""
174
- self.set_window_rect(x=int(x, 0), y=int(y, 0))
175
+ await self.set_window_rect(x=int(x, 0), y=int(y, 0))
175
176
 
176
- def set_window_rect(self, x=None, y=None, width=None, height=None):
177
+ async def set_window_rect(self, x=None, y=None, width=None, height=None):
177
178
  """Sets the x, y coordinates of the window as well as height and width of the current window."""
178
- self.session.set_window_frame(x, y, width, height)
179
+ await self.session.set_window_frame(x, y, width, height)
179
180
 
180
- def set_window_size(self, width, height):
181
+ async def set_window_size(self, width, height):
181
182
  """Sets the width and height of the current window."""
182
- self.set_window_rect(width=int(width, 0), height=int(height, 0))
183
+ await self.set_window_rect(width=int(width, 0), height=int(height, 0))
183
184
 
184
- def start_session(self):
185
+ async def start_session(self):
185
186
  """Creates a new session."""
186
- self.session.start_session()
187
+ await self.session.start_session()
187
188
 
188
189
  @property
189
- def title(self) -> str:
190
+ async def title(self) -> str:
190
191
  """Returns the title of the current page."""
191
- self.session.wait_for_navigation_to_complete()
192
- return self.session.evaluate_js_function("function() { return document.title; }")
192
+ await self.session.wait_for_navigation_to_complete()
193
+ return await self.session.evaluate_js_function("function() { return document.title; }")
193
194
 
194
195
  @property
195
- def window_handles(self) -> list[str]:
196
+ async def window_handles(self) -> list[str]:
196
197
  """Returns the handles of all windows within the current session."""
197
- return self.session.get_window_handles()
198
+ return await self.session.get_window_handles()
@@ -31,89 +31,91 @@ class WebElement(SeleniumApi):
31
31
  self.id_ = id_
32
32
  self.node_id = id_[f"session-node-{self.session.id_}"]
33
33
 
34
- def clear(self):
34
+ async def clear(self):
35
35
  """Clears the text if it's a text entry element."""
36
36
  if not self.is_editable():
37
37
  return
38
- rect, center, _is_obscured = self._compute_layout()
38
+ rect, center, _is_obscured = await self._compute_layout()
39
39
  if rect is None or center is None:
40
40
  return
41
- self._evaluate_js_function(ELEMENT_CLEAR)
41
+ await self._evaluate_js_function(ELEMENT_CLEAR)
42
42
 
43
- def click(self):
43
+ async def click(self):
44
44
  """Clicks the element."""
45
- rect, center, is_obscured = self._compute_layout(use_viewport=True)
45
+ rect, center, is_obscured = await self._compute_layout(use_viewport=True)
46
46
  if rect is None or is_obscured or center is None:
47
47
  return
48
48
  if self.tag_name == "option":
49
- self._select_option_element()
49
+ await self._select_option_element()
50
50
  else:
51
- self.session.perform_mouse_interaction(center.x, center.y, MouseButton.LEFT, MouseInteraction.SINGLE_CLICK)
51
+ await self.session.perform_mouse_interaction(
52
+ center.x, center.y, MouseButton.LEFT, MouseInteraction.SINGLE_CLICK
53
+ )
52
54
 
53
- def find_element(self, by=By.ID, value=None):
55
+ async def find_element(self, by=By.ID, value=None):
54
56
  """Find an element given a By strategy and locator."""
55
57
  elem = self.session.find_elements(by, value, root=self.id_)
56
58
  return None if elem is None else WebElement(self.session, elem)
57
59
 
58
- def find_elements(self, by=By.ID, value=None):
60
+ async def find_elements(self, by=By.ID, value=None):
59
61
  """Find elements given a By strategy and locator."""
60
- elements = self.session.find_elements(by, value, single=False, root=self.id_)
62
+ elements = await self.session.find_elements(by, value, single=False, root=self.id_)
61
63
  return [WebElement(self.session, elem) for elem in elements]
62
64
 
63
- def get_attribute(self, name: str) -> str:
65
+ async def get_attribute(self, name: str) -> str:
64
66
  """Gets the given attribute or property of the element."""
65
- return self.session.execute_script(f"return ({GET_ATTRIBUTE}).apply(null, arguments);", self.id_, name)
67
+ return await self.session.execute_script(f"return ({GET_ATTRIBUTE}).apply(null, arguments);", self.id_, name)
66
68
 
67
- def get_dom_attribute(self, name: str) -> str:
69
+ async def get_dom_attribute(self, name: str) -> str:
68
70
  """Gets the given attribute of the element."""
69
- return self._evaluate_js_function(ELEMENT_ATTRIBUTE, name)
71
+ return await self._evaluate_js_function(ELEMENT_ATTRIBUTE, name)
70
72
 
71
- def get_property(self, name: str) -> str:
73
+ async def get_property(self, name: str) -> str:
72
74
  """Gets the given property of the element."""
73
- return self._evaluate_js_function(f"function(element) {{ return element.{name}; }}")
75
+ return await self._evaluate_js_function(f"function(element) {{ return element.{name}; }}")
74
76
 
75
- def is_displayed(self) -> bool:
77
+ async def is_displayed(self) -> bool:
76
78
  """Whether the element is visible to a user."""
77
- return self.session.execute_script(f"return ({IS_DISPLAYED}).apply(null, arguments);", self.id_)
79
+ return await self.session.execute_script(f"return ({IS_DISPLAYED}).apply(null, arguments);", self.id_)
78
80
 
79
- def is_enabled(self) -> bool:
81
+ async def is_enabled(self) -> bool:
80
82
  """Returns whether the element is enabled."""
81
- return self._evaluate_js_function(IS_ENABLED)
83
+ return await self._evaluate_js_function(IS_ENABLED)
82
84
 
83
- def is_selected(self) -> bool:
85
+ async def is_selected(self) -> bool:
84
86
  """Returns whether the element is selected. Can be used to check if a checkbox or radio button is selected."""
85
- return bool(self.get_dom_attribute("selected"))
87
+ return bool(await self.get_dom_attribute("selected"))
86
88
 
87
89
  @property
88
- def location(self) -> Point:
90
+ async def location(self) -> Point:
89
91
  """The location of the element in the renderable canvas."""
90
- rect = self.rect
92
+ rect = await self.rect
91
93
  return Point(x=rect.x, y=rect.y)
92
94
 
93
95
  @property
94
- def location_once_scrolled_into_view(self) -> Point:
96
+ async def location_once_scrolled_into_view(self) -> Point:
95
97
  """Returns the top lefthand corner location on the screen, or ``None`` if the element is not visible."""
96
- rect = self.session.execute_script(
98
+ rect = await self.session.execute_script(
97
99
  "arguments[0].scrollIntoView(true); return arguments[0].getBoundingClientRect(); ", self.id_
98
100
  )
99
101
  return Point(x=round(rect["x"]), y=round(rect["y"]))
100
102
 
101
103
  @property
102
- def rect(self) -> Rect:
104
+ async def rect(self) -> Rect:
103
105
  """The size and location of the element."""
104
- return self._compute_layout(scroll_if_needed=False)[0]
106
+ return await self._compute_layout(scroll_if_needed=False)[0]
105
107
 
106
108
  @property
107
- def screenshot_as_base64(self) -> str:
109
+ async def screenshot_as_base64(self) -> str:
108
110
  """Gets the screenshot of the current element as a base64 encoded string."""
109
- return self.session.screenshot_as_base64(scroll=True, node_id=self.node_id)
111
+ return await self.session.screenshot_as_base64(scroll=True, node_id=self.node_id)
110
112
 
111
- def send_keys(self, value):
113
+ async def send_keys(self, value):
112
114
  """
113
115
  Simulates typing into the element.
114
116
  :param value: A string for typing, or setting form fields.
115
117
  """
116
- self._evaluate_js_function(FOCUS)
118
+ await self._evaluate_js_function(FOCUS)
117
119
  interactions = []
118
120
  sticky_modifier = set()
119
121
  for key in value:
@@ -132,15 +134,15 @@ class WebElement(SeleniumApi):
132
134
  interactions.append({"type": KeyboardInteractionType.INSERT_BY_KEY, "text": key})
133
135
  for modifier in sticky_modifier:
134
136
  interactions.append({"type": KeyboardInteractionType.KEY_RELEASE, "key": MODIFIER_TO_KEY[modifier]})
135
- self.session.perform_keyboard_interactions(interactions)
137
+ await self.session.perform_keyboard_interactions(interactions)
136
138
 
137
139
  @property
138
- def size(self) -> Size:
140
+ async def size(self) -> Size:
139
141
  """The size of the element."""
140
- rect = self.rect
142
+ rect = await self.rect
141
143
  return Size(height=rect.height, width=rect.width)
142
144
 
143
- def submit(self):
145
+ async def submit(self):
144
146
  """Submits a form."""
145
147
  form = self.find_element(By.XPATH, "./ancestor-or-self::form")
146
148
  submit_code = (
@@ -148,31 +150,31 @@ class WebElement(SeleniumApi):
148
150
  "e.initEvent('submit', true, true);"
149
151
  "if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }"
150
152
  )
151
- self.session.execute_script(submit_code, form.id_)
153
+ await self.session.execute_script(submit_code, form.id_)
152
154
 
153
155
  @property
154
- def tag_name(self) -> str:
156
+ async def tag_name(self) -> str:
155
157
  """This element's ``tagName`` property."""
156
- return self._evaluate_js_function("function(element) { return element.tagName.toLowerCase() }")
158
+ return await self._evaluate_js_function("function(element) { return element.tagName.toLowerCase() }")
157
159
 
158
160
  @property
159
- def text(self) -> str:
161
+ async def text(self) -> str:
160
162
  """The text of the element."""
161
- return self._evaluate_js_function(
163
+ return await self._evaluate_js_function(
162
164
  'function(element) { return element.innerText.replace(/^[^\\S\\xa0]+|[^\\S\\xa0]+$/g, "") }'
163
165
  )
164
166
 
165
- def touch(self):
167
+ async def touch(self):
166
168
  """Simulate touch interaction on the element."""
167
- _rect, center, _is_obscured = self._compute_layout(use_viewport=True)
168
- self.session.perform_interaction_sequence(
169
+ _rect, center, _is_obscured = await self._compute_layout(use_viewport=True)
170
+ await self.session.perform_interaction_sequence(
169
171
  [{"sourceId": self.session.id_, "sourceType": "Touch"}],
170
172
  [{"states": [{"sourceId": self.session.id_, "location": {"x": center.x, "y": center.y}}]}],
171
173
  )
172
174
 
173
- def value_of_css_property(self, property_name) -> str:
175
+ async def value_of_css_property(self, property_name) -> str:
174
176
  """The value of a CSS property."""
175
- return self._evaluate_js_function(
177
+ return await self._evaluate_js_function(
176
178
  "function(element) {"
177
179
  f' return document.defaultView.getComputedStyle(element).getPropertyValue("{property_name}"); '
178
180
  "}"
@@ -182,9 +184,9 @@ class WebElement(SeleniumApi):
182
184
  """Returns whether the element is editable."""
183
185
  return self._evaluate_js_function(IS_EDITABLE)
184
186
 
185
- def _compute_layout(self, scroll_if_needed=True, use_viewport=False):
187
+ async def _compute_layout(self, scroll_if_needed=True, use_viewport=False):
186
188
  try:
187
- result = self.session.compute_element_layout(
189
+ result = await self.session.compute_element_layout(
188
190
  self.node_id, scroll_if_needed, "LayoutViewport" if use_viewport else "Page"
189
191
  )
190
192
  except WirError:
@@ -196,11 +198,11 @@ class WebElement(SeleniumApi):
196
198
  center = Point(x=result["inViewCenterPoint"]["x"], y=result["inViewCenterPoint"]["y"])
197
199
  return rect, center, result["isObscured"]
198
200
 
199
- def _select_option_element(self):
200
- self.session.select_option_element(self.node_id)
201
+ async def _select_option_element(self):
202
+ await self.session.select_option_element(self.node_id)
201
203
 
202
- def _evaluate_js_function(self, function, *args):
203
- return self.session.evaluate_js_function(function, self.id_, *args)
204
+ async def _evaluate_js_function(self, function, *args):
205
+ return await self.session.evaluate_js_function(function, self.id_, *args)
204
206
 
205
207
  def __eq__(self, other):
206
208
  return self.id_ == other.id_
@@ -37,6 +37,7 @@ class SessionProtocol:
37
37
  return response["result"]
38
38
  elif "error" in response:
39
39
  raise WirError(response["error"]["message"])
40
+ raise WirError(f"Unknown response: {response}")
40
41
 
41
42
  async def send_receive(self, method, wait_for_response=True, **kwargs):
42
43
  wir_id = await self.send_command(method, **kwargs)
@@ -50,8 +51,8 @@ class SessionProtocol:
50
51
  await asyncio.sleep(0)
51
52
  return self.inspector.wir_message_results.pop(id_)
52
53
 
53
- def sync_send_receive(self, method, wait_for_response=True, **kwargs):
54
- return self.inspector.await_(self.send_receive(method, wait_for_response, **kwargs))
54
+ async def sync_send_receive(self, method, wait_for_response=True, **kwargs):
55
+ return await self.send_receive(method, wait_for_response, **kwargs)
55
56
 
56
57
  def __getattr__(self, item):
57
58
  return partial(self.sync_send_receive, method=item)