1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this
3# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5from __future__ import absolute_import
6
7import traceback
8
9import six
10
11
12@six.python_2_unicode_compatible
13class MarionetteException(Exception):
14
15    """Raised when a generic non-recoverable exception has occured."""
16
17    status = "webdriver error"
18
19    def __init__(self, message=None, cause=None, stacktrace=None):
20        """Construct new MarionetteException instance.
21
22        :param message: An optional exception message.
23
24        :param cause: An optional tuple of three values giving
25            information about the root exception cause.  Expected
26            tuple values are (type, value, traceback).
27
28        :param stacktrace: Optional string containing a stacktrace
29            (typically from a failed JavaScript execution) that will
30            be displayed in the exception's string representation.
31
32        """
33        self.cause = cause
34        self.stacktrace = stacktrace
35        self._message = six.text_type(message)
36
37    def __str__(self):
38        # pylint: disable=W1645
39        msg = self.message
40        tb = None
41
42        if self.cause:
43            if type(self.cause) is tuple:
44                msg += u", caused by {0!r}".format(self.cause[0])
45                tb = self.cause[2]
46            else:
47                msg += u", caused by {}".format(self.cause)
48
49        if self.stacktrace:
50            st = u"".join(["\t{}\n".format(x) for x in self.stacktrace.splitlines()])
51            msg += u"\nstacktrace:\n{}".format(st)
52
53        if tb:
54            msg += u": " + u"".join(traceback.format_tb(tb))
55
56        return six.text_type(msg)
57
58    @property
59    def message(self):
60        return self._message
61
62
63class DetachedShadowRootException(MarionetteException):
64    status = "detached shadow root"
65
66
67class ElementNotSelectableException(MarionetteException):
68    status = "element not selectable"
69
70
71class ElementClickInterceptedException(MarionetteException):
72    status = "element click intercepted"
73
74
75class InsecureCertificateException(MarionetteException):
76    status = "insecure certificate"
77
78
79class InvalidArgumentException(MarionetteException):
80    status = "invalid argument"
81
82
83class InvalidSessionIdException(MarionetteException):
84    status = "invalid session id"
85
86
87class TimeoutException(MarionetteException):
88    status = "timeout"
89
90
91class JavascriptException(MarionetteException):
92    status = "javascript error"
93
94
95class NoSuchElementException(MarionetteException):
96    status = "no such element"
97
98
99class NoSuchShadowRootException(MarionetteException):
100    status = "no such shadow root"
101
102
103class NoSuchWindowException(MarionetteException):
104    status = "no such window"
105
106
107class StaleElementException(MarionetteException):
108    status = "stale element reference"
109
110
111class ScriptTimeoutException(MarionetteException):
112    status = "script timeout"
113
114
115class ElementNotVisibleException(MarionetteException):
116    """Deprecated.  Will be removed with the release of Firefox 54."""
117
118    status = "element not visible"
119
120    def __init__(
121        self,
122        message="Element is not currently visible and may not be manipulated",
123        stacktrace=None,
124        cause=None,
125    ):
126        super(ElementNotVisibleException, self).__init__(
127            message, cause=cause, stacktrace=stacktrace
128        )
129
130
131class ElementNotAccessibleException(MarionetteException):
132    status = "element not accessible"
133
134
135class ElementNotInteractableException(MarionetteException):
136    status = "element not interactable"
137
138
139class NoSuchFrameException(MarionetteException):
140    status = "no such frame"
141
142
143class InvalidElementStateException(MarionetteException):
144    status = "invalid element state"
145
146
147class NoAlertPresentException(MarionetteException):
148    status = "no such alert"
149
150
151class InvalidCookieDomainException(MarionetteException):
152    status = "invalid cookie domain"
153
154
155class UnableToSetCookieException(MarionetteException):
156    status = "unable to set cookie"
157
158
159class InvalidElementCoordinates(MarionetteException):
160    status = "invalid element coordinates"
161
162
163class InvalidSelectorException(MarionetteException):
164    status = "invalid selector"
165
166
167class MoveTargetOutOfBoundsException(MarionetteException):
168    status = "move target out of bounds"
169
170
171class SessionNotCreatedException(MarionetteException):
172    status = "session not created"
173
174
175class UnexpectedAlertOpen(MarionetteException):
176    status = "unexpected alert open"
177
178
179class UnknownCommandException(MarionetteException):
180    status = "unknown command"
181
182
183class UnknownException(MarionetteException):
184    status = "unknown error"
185
186
187class UnsupportedOperationException(MarionetteException):
188    status = "unsupported operation"
189
190
191class UnresponsiveInstanceException(Exception):
192    pass
193
194
195es_ = [
196    e
197    for e in locals().values()
198    if type(e) == type and issubclass(e, MarionetteException)
199]
200by_string = {e.status: e for e in es_}
201
202
203def lookup(identifier):
204    """Finds error exception class by associated Selenium JSON wire
205    protocol number code, or W3C WebDriver protocol string.
206
207    """
208    return by_string.get(identifier, MarionetteException)
209