pymobiledevice3 5.0.4__py3-none-any.whl → 7.0.6__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.
Files changed (79) hide show
  1. misc/understanding_idevice_protocol_layers.md +10 -5
  2. pymobiledevice3/__main__.py +171 -46
  3. pymobiledevice3/_version.py +2 -2
  4. pymobiledevice3/bonjour.py +22 -21
  5. pymobiledevice3/cli/activation.py +24 -22
  6. pymobiledevice3/cli/afc.py +49 -41
  7. pymobiledevice3/cli/amfi.py +13 -18
  8. pymobiledevice3/cli/apps.py +71 -65
  9. pymobiledevice3/cli/backup.py +134 -93
  10. pymobiledevice3/cli/bonjour.py +31 -29
  11. pymobiledevice3/cli/cli_common.py +175 -232
  12. pymobiledevice3/cli/companion_proxy.py +12 -12
  13. pymobiledevice3/cli/crash.py +95 -52
  14. pymobiledevice3/cli/developer/__init__.py +62 -0
  15. pymobiledevice3/cli/developer/accessibility/__init__.py +65 -0
  16. pymobiledevice3/cli/developer/accessibility/settings.py +43 -0
  17. pymobiledevice3/cli/developer/arbitration.py +50 -0
  18. pymobiledevice3/cli/developer/condition.py +33 -0
  19. pymobiledevice3/cli/developer/core_device.py +294 -0
  20. pymobiledevice3/cli/developer/debugserver.py +244 -0
  21. pymobiledevice3/cli/developer/dvt/__init__.py +438 -0
  22. pymobiledevice3/cli/developer/dvt/core_profile_session.py +295 -0
  23. pymobiledevice3/cli/developer/dvt/simulate_location.py +56 -0
  24. pymobiledevice3/cli/developer/dvt/sysmon/__init__.py +69 -0
  25. pymobiledevice3/cli/developer/dvt/sysmon/process.py +188 -0
  26. pymobiledevice3/cli/developer/fetch_symbols.py +108 -0
  27. pymobiledevice3/cli/developer/simulate_location.py +51 -0
  28. pymobiledevice3/cli/diagnostics/__init__.py +75 -0
  29. pymobiledevice3/cli/diagnostics/battery.py +47 -0
  30. pymobiledevice3/cli/idam.py +42 -0
  31. pymobiledevice3/cli/lockdown.py +70 -75
  32. pymobiledevice3/cli/mounter.py +99 -57
  33. pymobiledevice3/cli/notification.py +38 -26
  34. pymobiledevice3/cli/pcap.py +36 -20
  35. pymobiledevice3/cli/power_assertion.py +15 -16
  36. pymobiledevice3/cli/processes.py +11 -17
  37. pymobiledevice3/cli/profile.py +120 -75
  38. pymobiledevice3/cli/provision.py +27 -26
  39. pymobiledevice3/cli/remote.py +109 -100
  40. pymobiledevice3/cli/restore.py +134 -129
  41. pymobiledevice3/cli/springboard.py +50 -50
  42. pymobiledevice3/cli/syslog.py +145 -65
  43. pymobiledevice3/cli/usbmux.py +66 -27
  44. pymobiledevice3/cli/version.py +2 -5
  45. pymobiledevice3/cli/webinspector.py +232 -156
  46. pymobiledevice3/exceptions.py +6 -2
  47. pymobiledevice3/lockdown.py +5 -1
  48. pymobiledevice3/lockdown_service_provider.py +5 -0
  49. pymobiledevice3/remote/remote_service_discovery.py +18 -10
  50. pymobiledevice3/restore/device.py +28 -4
  51. pymobiledevice3/restore/restore.py +2 -2
  52. pymobiledevice3/service_connection.py +15 -12
  53. pymobiledevice3/services/afc.py +731 -220
  54. pymobiledevice3/services/device_link.py +45 -31
  55. pymobiledevice3/services/idam.py +20 -0
  56. pymobiledevice3/services/lockdown_service.py +12 -9
  57. pymobiledevice3/services/mobile_config.py +1 -0
  58. pymobiledevice3/services/mobilebackup2.py +6 -3
  59. pymobiledevice3/services/os_trace.py +97 -55
  60. pymobiledevice3/services/remote_fetch_symbols.py +13 -8
  61. pymobiledevice3/services/screenshot.py +2 -2
  62. pymobiledevice3/services/web_protocol/alert.py +8 -8
  63. pymobiledevice3/services/web_protocol/automation_session.py +87 -79
  64. pymobiledevice3/services/web_protocol/cdp_screencast.py +2 -1
  65. pymobiledevice3/services/web_protocol/driver.py +71 -70
  66. pymobiledevice3/services/web_protocol/element.py +58 -56
  67. pymobiledevice3/services/web_protocol/selenium_api.py +47 -47
  68. pymobiledevice3/services/web_protocol/session_protocol.py +3 -2
  69. pymobiledevice3/services/web_protocol/switch_to.py +23 -19
  70. pymobiledevice3/services/webinspector.py +42 -67
  71. {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/METADATA +5 -3
  72. {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/RECORD +76 -61
  73. pymobiledevice3/cli/completions.py +0 -50
  74. pymobiledevice3/cli/developer.py +0 -1539
  75. pymobiledevice3/cli/diagnostics.py +0 -110
  76. {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/WHEEL +0 -0
  77. {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/entry_points.txt +0 -0
  78. {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/licenses/LICENSE +0 -0
  79. {pymobiledevice3-5.0.4.dist-info → pymobiledevice3-7.0.6.dist-info}/top_level.txt +0 -0
@@ -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
- elem = self.session.find_elements(by, value, root=self.id_)
57
+ elem = await 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,59 +134,59 @@ 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
- form = self.find_element(By.XPATH, "./ancestor-or-self::form")
147
+ form = await self.find_element(By.XPATH, "./ancestor-or-self::form")
146
148
  submit_code = (
147
149
  "var e = arguments[0].ownerDocument.createEvent('Event');"
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) -> None:
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
  "}"
179
181
  )
180
182
 
181
- def is_editable(self) -> bool:
183
+ async def is_editable(self) -> bool:
182
184
  """Returns whether the element is editable."""
183
- return self._evaluate_js_function(IS_EDITABLE)
185
+ return await 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_
@@ -6,68 +6,68 @@ from pymobiledevice3.services.web_protocol.automation_session import By
6
6
 
7
7
  class SeleniumApi(ABC):
8
8
  @abstractmethod
9
- def find_element(self, by=By.ID, value=None):
9
+ async def find_element(self, by=By.ID, value=None):
10
10
  pass
11
11
 
12
12
  @abstractmethod
13
- def find_elements(self, by=By.ID, value=None):
13
+ async def find_elements(self, by=By.ID, value=None):
14
14
  pass
15
15
 
16
16
  @property
17
17
  @abstractmethod
18
- def screenshot_as_base64(self):
18
+ async def screenshot_as_base64(self) -> str:
19
19
  pass
20
20
 
21
- def find_element_by_class_name(self, name):
22
- return self.find_element(By.CLASS_NAME, name)
21
+ async def find_element_by_class_name(self, name):
22
+ return await self.find_element(By.CLASS_NAME, name)
23
23
 
24
- def find_element_by_css_selector(self, css_selector):
25
- return self.find_element(By.CSS_SELECTOR, css_selector)
24
+ async def find_element_by_css_selector(self, css_selector):
25
+ return await self.find_element(By.CSS_SELECTOR, css_selector)
26
26
 
27
- def find_element_by_id(self, id_):
28
- return self.find_element(value=id_)
27
+ async def find_element_by_id(self, id_):
28
+ return await self.find_element(value=id_)
29
29
 
30
- def find_element_by_link_text(self, link_text):
31
- return self.find_element(By.LINK_TEXT, link_text)
30
+ async def find_element_by_link_text(self, link_text):
31
+ return await self.find_element(By.LINK_TEXT, link_text)
32
32
 
33
- def find_element_by_name(self, name):
34
- return self.find_element(By.NAME, name)
33
+ async def find_element_by_name(self, name):
34
+ return await self.find_element(By.NAME, name)
35
35
 
36
- def find_element_by_partial_link_text(self, link_text):
37
- return self.find_element(By.PARTIAL_LINK_TEXT, link_text)
36
+ async def find_element_by_partial_link_text(self, link_text):
37
+ return await self.find_element(By.PARTIAL_LINK_TEXT, link_text)
38
38
 
39
- def find_element_by_tag_name(self, name):
40
- return self.find_element(By.TAG_NAME, name)
39
+ async def find_element_by_tag_name(self, name):
40
+ return await self.find_element(By.TAG_NAME, name)
41
41
 
42
- def find_element_by_xpath(self, xpath):
43
- return self.find_element(By.XPATH, xpath)
42
+ async def find_element_by_xpath(self, xpath):
43
+ return await self.find_element(By.XPATH, xpath)
44
44
 
45
- def find_elements_by_class_name(self, name):
46
- return self.find_elements(By.CLASS_NAME, name)
45
+ async def find_elements_by_class_name(self, name):
46
+ return await self.find_elements(By.CLASS_NAME, name)
47
47
 
48
- def find_elements_by_css_selector(self, css_selector):
49
- return self.find_elements(By.CSS_SELECTOR, css_selector)
48
+ async def find_elements_by_css_selector(self, css_selector):
49
+ return await self.find_elements(By.CSS_SELECTOR, css_selector)
50
50
 
51
- def find_elements_by_id(self, id_):
52
- return self.find_elements(value=id_)
51
+ async def find_elements_by_id(self, id_):
52
+ return await self.find_elements(value=id_)
53
53
 
54
- def find_elements_by_link_text(self, link_text):
55
- return self.find_elements(By.LINK_TEXT, link_text)
54
+ async def find_elements_by_link_text(self, link_text):
55
+ return await self.find_elements(By.LINK_TEXT, link_text)
56
56
 
57
- def find_elements_by_name(self, name):
58
- return self.find_elements(By.NAME, name)
57
+ async def find_elements_by_name(self, name):
58
+ return await self.find_elements(By.NAME, name)
59
59
 
60
- def find_elements_by_partial_link_text(self, link_text):
61
- return self.find_elements(By.PARTIAL_LINK_TEXT, link_text)
60
+ async def find_elements_by_partial_link_text(self, link_text):
61
+ return await self.find_elements(By.PARTIAL_LINK_TEXT, link_text)
62
62
 
63
- def find_elements_by_tag_name(self, name):
64
- return self.find_elements(By.TAG_NAME, name)
63
+ async def find_elements_by_tag_name(self, name):
64
+ return await self.find_elements(By.TAG_NAME, name)
65
65
 
66
- def find_elements_by_xpath(self, xpath):
67
- return self.find_elements(By.XPATH, xpath)
66
+ async def find_elements_by_xpath(self, xpath):
67
+ return await self.find_elements(By.XPATH, xpath)
68
68
 
69
- def screenshot(self, filename):
70
- png = self.screenshot_as_png()
69
+ async def screenshot(self, filename):
70
+ png = await self.screenshot_as_png()
71
71
  try:
72
72
  with open(filename, "wb") as f:
73
73
  f.write(png)
@@ -75,17 +75,17 @@ class SeleniumApi(ABC):
75
75
  return False
76
76
  return True
77
77
 
78
- def screenshot_as_png(self):
79
- return b64decode(self.screenshot_as_base64.encode("ascii"))
78
+ async def screenshot_as_png(self) -> bytes:
79
+ return b64decode((await self.screenshot_as_base64).encode("ascii"))
80
80
 
81
- def get_screenshot_as_base64(self):
82
- return self.screenshot_as_base64
81
+ async def get_screenshot_as_base64(self) -> str:
82
+ return await self.screenshot_as_base64
83
83
 
84
- def get_screenshot_as_file(self, filename):
85
- return self.screenshot(filename)
84
+ async def get_screenshot_as_file(self, filename):
85
+ return await self.screenshot(filename)
86
86
 
87
- def get_screenshot_as_png(self):
88
- return self.screenshot_as_png()
87
+ async def get_screenshot_as_png(self):
88
+ return await self.screenshot_as_png()
89
89
 
90
- def save_screenshot(self, filename) -> bool:
91
- return self.screenshot(filename)
90
+ async def save_screenshot(self, filename) -> bool:
91
+ return await self.screenshot(filename)
@@ -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)
@@ -11,10 +11,12 @@ class SwitchTo:
11
11
  self.session = session
12
12
 
13
13
  @property
14
- def active_element(self) -> WebElement:
14
+ async def active_element(self) -> WebElement:
15
15
  """Returns the element with focus, or BODY if nothing has focus."""
16
- self.session.wait_for_navigation_to_complete()
17
- elem = self.session.evaluate_js_function("function() { return document.activeElement; }", include_frame=False)
16
+ await self.session.wait_for_navigation_to_complete()
17
+ elem = await self.session.evaluate_js_function(
18
+ "function() { return document.activeElement; }", include_frame=False
19
+ )
18
20
  return WebElement(self.session, elem)
19
21
 
20
22
  @property
@@ -22,11 +24,11 @@ class SwitchTo:
22
24
  """Switches focus to an alert on the page."""
23
25
  return Alert(self.session)
24
26
 
25
- def default_content(self):
27
+ async def default_content(self):
26
28
  """Switch focus to the default frame."""
27
- self.session.switch_to_browsing_context("")
29
+ await self.session.switch_to_browsing_context("")
28
30
 
29
- def frame(self, frame_reference):
31
+ async def frame(self, frame_reference):
30
32
  """
31
33
  Switches focus to the specified frame, by index, name, or web element.
32
34
  :param frame_reference: The name of the window to switch to, an integer representing the index,
@@ -35,32 +37,34 @@ class SwitchTo:
35
37
  if isinstance(frame_reference, (int, WebElement)):
36
38
  frame = frame_reference
37
39
  elif isinstance(frame_reference, str):
38
- elem = self.session.find_elements(By.ID, frame_reference)
40
+ elem = await self.session.find_elements(By.ID, frame_reference)
39
41
  if elem is None:
40
- elem = self.session.find_elements(By.NAME, frame_reference)
42
+ elem = await self.session.find_elements(By.NAME, frame_reference)
41
43
  frame = WebElement(self.session, elem)
42
44
  else:
43
45
  raise TypeError()
44
46
 
45
- self.session.wait_for_navigation_to_complete()
47
+ await self.session.wait_for_navigation_to_complete()
46
48
  if isinstance(frame, int):
47
- self.session.switch_to_frame(frame_ordinal=frame)
49
+ await self.session.switch_to_frame(frame_ordinal=frame)
48
50
  else:
49
- self.session.switch_to_frame(frame_handle=frame)
51
+ await self.session.switch_to_frame(frame_handle=frame)
50
52
 
51
- def new_window(self, type_=""):
53
+ async def new_window(self, type_=""):
52
54
  """Switches to a new top-level browsing context."""
53
- self.session.switch_to_window(self.session.create_window(type_))
55
+ await self.session.switch_to_window(self.session.create_window(type_))
54
56
 
55
- def parent_frame(self):
57
+ async def parent_frame(self):
56
58
  """
57
59
  Switches focus to the parent context. If the current context is the top
58
60
  level browsing context, the context remains unchanged.
59
61
  """
60
- self.session.wait_for_navigation_to_complete()
61
- self.session.switch_to_browsing_context_frame(self.session.top_level_handle, self.session.current_parent_handle)
62
- self.session.switch_to_browsing_context(self.session.current_parent_handle)
62
+ await self.session.wait_for_navigation_to_complete()
63
+ await self.session.switch_to_browsing_context_frame(
64
+ self.session.top_level_handle, self.session.current_parent_handle
65
+ )
66
+ await self.session.switch_to_browsing_context(self.session.current_parent_handle)
63
67
 
64
- def window(self, window_name):
68
+ async def window(self, window_name):
65
69
  """Switches focus to the specified window."""
66
- self.session.switch_to_window(window_name)
70
+ await self.session.switch_to_window(window_name)