Skip to content

Commit 7feae33

Browse files
committed
[py] make custom exception for driver location
1 parent cb6260b commit 7feae33

File tree

7 files changed

+59
-29
lines changed

7 files changed

+59
-29
lines changed

py/selenium/common/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@
3434
from .exceptions import NoAlertPresentException
3535
from .exceptions import NoSuchAttributeException
3636
from .exceptions import NoSuchCookieException
37+
from .exceptions import NoSuchDriverException
3738
from .exceptions import NoSuchElementException
3839
from .exceptions import NoSuchFrameException
3940
from .exceptions import NoSuchShadowRootException
4041
from .exceptions import NoSuchWindowException
4142
from .exceptions import ScreenshotException
42-
from .exceptions import SeleniumManagerException
4343
from .exceptions import SessionNotCreatedException
4444
from .exceptions import StaleElementReferenceException
4545
from .exceptions import TimeoutException
@@ -56,6 +56,7 @@
5656
"NoSuchWindowException",
5757
"NoSuchElementException",
5858
"NoSuchAttributeException",
59+
"NoSuchDriverException",
5960
"NoSuchShadowRootException",
6061
"StaleElementReferenceException",
6162
"InvalidElementStateException",
@@ -82,5 +83,4 @@
8283
"InvalidSessionIdException",
8384
"SessionNotCreatedException",
8485
"UnknownMethodException",
85-
"SeleniumManagerException",
8686
]

py/selenium/common/exceptions.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@
2020
from typing import Optional
2121
from typing import Sequence
2222

23-
SUPPORT_MSG = 'For documentation on this error, please visit:'
24-
ERROR_URL = 'https://www.selenium.dev/documentation/webdriver/troubleshooting/errors'
23+
SUPPORT_MSG = "For documentation on this error, please visit:"
24+
ERROR_URL = "https://www.selenium.dev/documentation/webdriver/troubleshooting/errors"
25+
2526

2627
class WebDriverException(Exception):
2728
"""Base webdriver exception."""
@@ -71,10 +72,11 @@ class NoSuchElementException(WebDriverException):
7172
(webpage is still loading) see selenium.webdriver.support.wait.WebDriverWait()
7273
for how to write a wait wrapper to wait for an element to appear.
7374
"""
75+
7476
def __init__(
7577
self, msg: Optional[str] = None, screen: Optional[str] = None, stacktrace: Optional[Sequence[str]] = None
7678
) -> None:
77-
with_support = f'{msg}; {SUPPORT_MSG} {ERROR_URL}#no-such-element-exception'
79+
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#no-such-element-exception"
7880

7981
super().__init__(with_support, screen, stacktrace)
8082

@@ -109,10 +111,11 @@ class StaleElementReferenceException(WebDriverException):
109111
node is rebuilt.
110112
* Element may have been inside an iframe or another context which was refreshed.
111113
"""
114+
112115
def __init__(
113116
self, msg: Optional[str] = None, screen: Optional[str] = None, stacktrace: Optional[Sequence[str]] = None
114117
) -> None:
115-
with_support = f'{msg}; {SUPPORT_MSG} {ERROR_URL}#stale-element-reference-exception'
118+
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#stale-element-reference-exception"
116119

117120
super().__init__(with_support, screen, stacktrace)
118121

@@ -207,10 +210,11 @@ class InvalidSelectorException(WebDriverException):
207210
expression) or the expression does not select WebElements (e.g.
208211
"count(//input)").
209212
"""
213+
210214
def __init__(
211215
self, msg: Optional[str] = None, screen: Optional[str] = None, stacktrace: Optional[Sequence[str]] = None
212216
) -> None:
213-
with_support = f'{msg}; {SUPPORT_MSG} {ERROR_URL}#invalid-selector-exception'
217+
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}#invalid-selector-exception"
214218

215219
super().__init__(with_support, screen, stacktrace)
216220

@@ -273,5 +277,12 @@ class UnknownMethodException(WebDriverException):
273277
for that URL."""
274278

275279

276-
class SeleniumManagerException(WebDriverException):
277-
"""Raised when an issue interacting with selenium manager occurs."""
280+
class NoSuchDriverException(WebDriverException):
281+
"""Raised when driver is not specified and cannot be located."""
282+
283+
def __init__(
284+
self, msg: Optional[str] = None, screen: Optional[str] = None, stacktrace: Optional[Sequence[str]] = None
285+
) -> None:
286+
with_support = f"{msg}; {SUPPORT_MSG} {ERROR_URL}/driver_location"
287+
288+
super().__init__(with_support, screen, stacktrace)

py/selenium/webdriver/common/driver_finder.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@
1616
# under the License.
1717
import logging
1818
import shutil
19+
from pathlib import Path
1920

20-
from selenium.common.exceptions import WebDriverException
21+
from selenium.common.exceptions import NoSuchDriverException
2122
from selenium.webdriver.common.options import BaseOptions
2223
from selenium.webdriver.common.selenium_manager import SeleniumManager
2324
from selenium.webdriver.common.service import Service
@@ -36,10 +37,13 @@ def __init__(self) -> None:
3637

3738
@staticmethod
3839
def get_path(service: Service, options: BaseOptions) -> str:
40+
path = shutil.which(service.path)
3941
try:
40-
path = shutil.which(service.path) or SeleniumManager().driver_location(options)
41-
except WebDriverException as err:
42-
logger.warning("Unable to obtain driver using Selenium Manager: " + err.msg)
43-
raise err
42+
path = SeleniumManager().driver_location(options) if path is None else path
43+
except Exception as err:
44+
raise NoSuchDriverException(f"Unable to obtain {service.path} using Selenium Manager; {err}")
45+
46+
if path is None or not Path(path).is_file():
47+
raise NoSuchDriverException(f"Unable to locate or obtain {service.path}")
4448

4549
return path

py/selenium/webdriver/common/selenium_manager.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from pathlib import Path
2222
from typing import List
2323

24-
from selenium.common.exceptions import SeleniumManagerException
24+
from selenium.common import WebDriverException
2525
from selenium.webdriver.common.options import BaseOptions
2626

2727
logger = logging.getLogger(__name__)
@@ -57,8 +57,7 @@ def get_binary() -> Path:
5757
path = Path(__file__).parent.joinpath(directory, file)
5858

5959
if not path.is_file():
60-
tracker = "https://github.com/SeleniumHQ/selenium/issues"
61-
raise SeleniumManagerException(f"{path} is missing. Please open an issue on {tracker}")
60+
raise WebDriverException(f"Unable to obtain working Selenium Manager binary; {path}")
6261

6362
return path
6463

@@ -109,15 +108,18 @@ def run(args: List[str]) -> str:
109108
"""
110109
command = " ".join(args)
111110
logger.debug(f"Executing process: {command}")
112-
completed_proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
113-
stdout = completed_proc.stdout.decode("utf-8").rstrip("\n")
114-
stderr = completed_proc.stderr.decode("utf-8").rstrip("\n")
115-
output = json.loads(stdout)
116-
result = output["result"]["message"]
111+
try:
112+
completed_proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
113+
stdout = completed_proc.stdout.decode("utf-8").rstrip("\n")
114+
stderr = completed_proc.stderr.decode("utf-8").rstrip("\n")
115+
output = json.loads(stdout)
116+
result = output["result"]["message"]
117+
except Exception as err:
118+
raise WebDriverException(f"Unsuccessful command executed: {command}; {err}")
119+
117120
if completed_proc.returncode:
118-
raise SeleniumManagerException(f"Selenium Manager failed for: {command}.\n{result}{stderr}")
121+
raise WebDriverException(f"Unsuccessful command executed: {command}.\n{result}{stderr}")
119122
else:
120-
# Selenium Manager exited successfully, return executable path and print warnings
121123
for item in output["logs"]:
122124
if item["level"] == "WARN":
123125
logger.warning(item["message"])

py/test/selenium/webdriver/common/driver_element_finding_tests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ def test_no_such_element_error(driver, pages):
9999
with pytest.raises(NoSuchElementException, match=msg):
100100
driver.find_element(By.ID, "non_Existent_Button")
101101

102+
102103
# By.name positive
103104

104105

py/test/selenium/webdriver/common/selenium_manager_tests.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919

2020
import pytest
2121

22-
from selenium.common.exceptions import SeleniumManagerException
22+
from selenium.common.exceptions import WebDriverException
2323
from selenium.webdriver.chrome.options import Options
24+
from selenium.webdriver.chrome.service import Service
25+
from selenium.webdriver.common.driver_finder import DriverFinder
2426
from selenium.webdriver.common.proxy import Proxy
2527
from selenium.webdriver.common.selenium_manager import SeleniumManager
2628

@@ -85,8 +87,18 @@ def test_proxy_is_used_for_sm(mocker):
8587

8688

8789
def test_stderr_is_propagated_to_exception_messages():
88-
msg = r"Selenium Manager failed for:.* --browser foo --output json\.\nInvalid browser name: foo\n"
89-
with pytest.raises(SeleniumManagerException, match=msg):
90+
msg = r"Unsuccessful command executed:.* --browser foo --output json\.\nInvalid browser name: foo\n"
91+
with pytest.raises(WebDriverException, match=msg):
9092
manager = SeleniumManager()
9193
binary = manager.get_binary()
9294
_ = manager.run([str(binary), "--browser", "foo", "--output", "json"])
95+
96+
97+
def test_driver_finder_error(mocker):
98+
mocker.patch("selenium.webdriver.common.selenium_manager.SeleniumManager.driver_location", return_value=None)
99+
100+
service = Service()
101+
options = Options()
102+
msg = r"Unable to locate or obtain chromedriver.*errors\/driver_location"
103+
with pytest.raises(WebDriverException, match=msg):
104+
DriverFinder.get_path(service, options)

py/test/selenium/webdriver/support/relative_by_tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def test_no_such_element_is_raised_rather_than_index_error(driver, pages):
8686
with pytest.raises(NoSuchElementException) as exc:
8787
anchor = driver.find_element(By.ID, "second")
8888
driver.find_element(locate_with(By.ID, "nonexistentid").above(anchor))
89-
assert exc.value.msg == "Cannot locate relative element with: {'id': 'nonexistentid'}"
89+
assert "Cannot locate relative element with: {'id': 'nonexistentid'}" in exc.value.msg
9090

9191

9292
def test_near_locator_should_find_near_elements(driver, pages):
@@ -105,4 +105,4 @@ def test_near_locator_should_not_find_far_elements(driver, pages):
105105
with pytest.raises(NoSuchElementException) as exc:
106106
driver.find_element(locate_with(By.ID, "rect4").near(rect3))
107107

108-
assert exc.value.msg == "Cannot locate relative element with: {'id': 'rect4'}"
108+
assert "Cannot locate relative element with: {'id': 'rect4'}" in exc.value.msg

0 commit comments

Comments
 (0)