Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/py/selenium/webdriver/support/event_firing_webdriver.py
1864 views
1
# Licensed to the Software Freedom Conservancy (SFC) under one
2
# or more contributor license agreements. See the NOTICE file
3
# distributed with this work for additional information
4
# regarding copyright ownership. The SFC licenses this file
5
# to you under the Apache License, Version 2.0 (the
6
# "License"); you may not use this file except in compliance
7
# with the License. You may obtain a copy of the License at
8
#
9
# http://www.apache.org/licenses/LICENSE-2.0
10
#
11
# Unless required by applicable law or agreed to in writing,
12
# software distributed under the License is distributed on an
13
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
# KIND, either express or implied. See the License for the
15
# specific language governing permissions and limitations
16
# under the License.
17
18
from typing import Any
19
20
from selenium.common.exceptions import WebDriverException
21
from selenium.webdriver.common.by import By
22
from selenium.webdriver.remote.webdriver import WebDriver
23
from selenium.webdriver.remote.webelement import WebElement
24
25
from .abstract_event_listener import AbstractEventListener
26
27
28
def _wrap_elements(result, ef_driver):
29
# handle the case if another wrapper wraps EventFiringWebElement
30
if isinstance(result, EventFiringWebElement):
31
return result
32
if isinstance(result, WebElement):
33
return EventFiringWebElement(result, ef_driver)
34
if isinstance(result, list):
35
return [_wrap_elements(item, ef_driver) for item in result]
36
return result
37
38
39
class EventFiringWebDriver:
40
"""A wrapper around an arbitrary WebDriver instance which supports firing
41
events."""
42
43
def __init__(self, driver: WebDriver, event_listener: AbstractEventListener) -> None:
44
"""Creates a new instance of the EventFiringWebDriver.
45
46
:Args:
47
- driver : A WebDriver instance
48
- event_listener : Instance of a class that subclasses AbstractEventListener and implements it fully
49
or partially
50
51
Example:
52
53
::
54
55
from selenium.webdriver import Firefox
56
from selenium.webdriver.support.events import EventFiringWebDriver, AbstractEventListener
57
58
59
class MyListener(AbstractEventListener):
60
def before_navigate_to(self, url, driver):
61
print("Before navigate to %s" % url)
62
63
def after_navigate_to(self, url, driver):
64
print("After navigate to %s" % url)
65
66
67
driver = Firefox()
68
ef_driver = EventFiringWebDriver(driver, MyListener())
69
ef_driver.get("http://www.google.co.in/")
70
"""
71
if not isinstance(driver, WebDriver):
72
raise WebDriverException("A WebDriver instance must be supplied")
73
if not isinstance(event_listener, AbstractEventListener):
74
raise WebDriverException("Event listener must be a subclass of AbstractEventListener")
75
self._driver = driver
76
self._driver._wrap_value = self._wrap_value
77
self._listener = event_listener
78
79
@property
80
def wrapped_driver(self) -> WebDriver:
81
"""Returns the WebDriver instance wrapped by this
82
EventsFiringWebDriver."""
83
return self._driver
84
85
def get(self, url: str) -> None:
86
self._dispatch("navigate_to", (url, self._driver), "get", (url,))
87
88
def back(self) -> None:
89
self._dispatch("navigate_back", (self._driver,), "back", ())
90
91
def forward(self) -> None:
92
self._dispatch("navigate_forward", (self._driver,), "forward", ())
93
94
def execute_script(self, script: str, *args):
95
unwrapped_args = (script,) + self._unwrap_element_args(args)
96
return self._dispatch("execute_script", (script, self._driver), "execute_script", unwrapped_args)
97
98
def execute_async_script(self, script, *args):
99
unwrapped_args = (script,) + self._unwrap_element_args(args)
100
return self._dispatch("execute_script", (script, self._driver), "execute_async_script", unwrapped_args)
101
102
def close(self) -> None:
103
self._dispatch("close", (self._driver,), "close", ())
104
105
def quit(self) -> None:
106
self._dispatch("quit", (self._driver,), "quit", ())
107
108
def find_element(self, by=By.ID, value=None) -> WebElement:
109
return self._dispatch("find", (by, value, self._driver), "find_element", (by, value))
110
111
def find_elements(self, by=By.ID, value=None) -> list[WebElement]:
112
return self._dispatch("find", (by, value, self._driver), "find_elements", (by, value))
113
114
def _dispatch(self, l_call: str, l_args: tuple[Any, ...], d_call: str, d_args: tuple[Any, ...]):
115
getattr(self._listener, f"before_{l_call}")(*l_args)
116
try:
117
result = getattr(self._driver, d_call)(*d_args)
118
except Exception as exc:
119
self._listener.on_exception(exc, self._driver)
120
raise
121
getattr(self._listener, f"after_{l_call}")(*l_args)
122
return _wrap_elements(result, self)
123
124
def _unwrap_element_args(self, args):
125
if isinstance(args, EventFiringWebElement):
126
return args.wrapped_element
127
if isinstance(args, tuple):
128
return tuple(self._unwrap_element_args(item) for item in args)
129
if isinstance(args, list):
130
return [self._unwrap_element_args(item) for item in args]
131
return args
132
133
def _wrap_value(self, value):
134
if isinstance(value, EventFiringWebElement):
135
return WebDriver._wrap_value(self._driver, value.wrapped_element)
136
return WebDriver._wrap_value(self._driver, value)
137
138
def __setattr__(self, item, value):
139
if item.startswith("_") or not hasattr(self._driver, item):
140
object.__setattr__(self, item, value)
141
else:
142
try:
143
object.__setattr__(self._driver, item, value)
144
except Exception as exc:
145
self._listener.on_exception(exc, self._driver)
146
raise
147
148
def __getattr__(self, name):
149
def _wrap(*args, **kwargs):
150
try:
151
result = attrib(*args, **kwargs)
152
return _wrap_elements(result, self)
153
except Exception as exc:
154
self._listener.on_exception(exc, self._driver)
155
raise
156
157
try:
158
attrib = getattr(self._driver, name)
159
return _wrap if callable(attrib) else attrib
160
except Exception as exc:
161
self._listener.on_exception(exc, self._driver)
162
raise
163
164
165
class EventFiringWebElement:
166
"""A wrapper around WebElement instance which supports firing events."""
167
168
def __init__(self, webelement: WebElement, ef_driver: EventFiringWebDriver) -> None:
169
"""Creates a new instance of the EventFiringWebElement."""
170
self._webelement = webelement
171
self._ef_driver = ef_driver
172
self._driver = ef_driver.wrapped_driver
173
self._listener = ef_driver._listener
174
175
@property
176
def wrapped_element(self) -> WebElement:
177
"""Returns the WebElement wrapped by this EventFiringWebElement
178
instance."""
179
return self._webelement
180
181
def click(self) -> None:
182
self._dispatch("click", (self._webelement, self._driver), "click", ())
183
184
def clear(self) -> None:
185
self._dispatch("change_value_of", (self._webelement, self._driver), "clear", ())
186
187
def send_keys(self, *value) -> None:
188
self._dispatch("change_value_of", (self._webelement, self._driver), "send_keys", value)
189
190
def find_element(self, by=By.ID, value=None) -> WebElement:
191
return self._dispatch("find", (by, value, self._driver), "find_element", (by, value))
192
193
def find_elements(self, by=By.ID, value=None) -> list[WebElement]:
194
return self._dispatch("find", (by, value, self._driver), "find_elements", (by, value))
195
196
def _dispatch(self, l_call, l_args, d_call, d_args):
197
getattr(self._listener, f"before_{l_call}")(*l_args)
198
try:
199
result = getattr(self._webelement, d_call)(*d_args)
200
except Exception as exc:
201
self._listener.on_exception(exc, self._driver)
202
raise
203
getattr(self._listener, f"after_{l_call}")(*l_args)
204
return _wrap_elements(result, self._ef_driver)
205
206
def __setattr__(self, item, value):
207
if item.startswith("_") or not hasattr(self._webelement, item):
208
object.__setattr__(self, item, value)
209
else:
210
try:
211
object.__setattr__(self._webelement, item, value)
212
except Exception as exc:
213
self._listener.on_exception(exc, self._driver)
214
raise
215
216
def __getattr__(self, name):
217
def _wrap(*args, **kwargs):
218
try:
219
result = attrib(*args, **kwargs)
220
return _wrap_elements(result, self._ef_driver)
221
except Exception as exc:
222
self._listener.on_exception(exc, self._driver)
223
raise
224
225
try:
226
attrib = getattr(self._webelement, name)
227
return _wrap if callable(attrib) else attrib
228
except Exception as exc:
229
self._listener.on_exception(exc, self._driver)
230
raise
231
232
233
# Register a virtual subclass.
234
WebElement.register(EventFiringWebElement)
235
236