Skip to content

Commit a2cacc1

Browse files
Delta456harsha509
andauthored
[py] Allow driver path to be set using ENV variables (#14528)
--------- Co-authored-by: Sri Harsha <[email protected]>
1 parent a67a2df commit a2cacc1

File tree

12 files changed

+81
-5
lines changed

12 files changed

+81
-5
lines changed

py/selenium/webdriver/chromium/service.py

+3
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ def __init__(
3939
service_args: typing.Optional[typing.List[str]] = None,
4040
log_output: SubprocessStdAlias = None,
4141
env: typing.Optional[typing.Mapping[str, str]] = None,
42+
driver_path_env_key: str = None,
4243
**kwargs,
4344
) -> None:
4445
self.service_args = service_args or []
46+
driver_path_env_key = driver_path_env_key or "SE_CHROMEDRIVER"
4547

4648
if isinstance(log_output, str):
4749
self.service_args.append(f"--log-path={log_output}")
@@ -56,6 +58,7 @@ def __init__(
5658
port=port,
5759
env=env,
5860
log_output=self.log_output,
61+
driver_path_env_key=driver_path_env_key,
5962
**kwargs,
6063
)
6164

py/selenium/webdriver/chromium/webdriver.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def __init__(
5151
options.binary_location = finder.get_browser_path()
5252
options.browser_version = None
5353

54-
self.service.path = finder.get_driver_path()
54+
self.service.path = self.service.env_path() or finder.get_driver_path()
5555
self.service.start()
5656

5757
executor = ChromiumRemoteConnection(

py/selenium/webdriver/common/service.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from platform import system
2626
from subprocess import PIPE
2727
from time import sleep
28+
from typing import Optional
2829
from typing import cast
2930
from urllib import request
3031
from urllib.error import URLError
@@ -53,6 +54,7 @@ def __init__(
5354
port: int = 0,
5455
log_output: SubprocessStdAlias = None,
5556
env: typing.Optional[typing.Mapping[typing.Any, typing.Any]] = None,
57+
driver_path_env_key: str = None,
5658
**kwargs,
5759
) -> None:
5860
if isinstance(log_output, str):
@@ -64,12 +66,13 @@ def __init__(
6466
else:
6567
self.log_output = log_output
6668

67-
self._path = executable_path
6869
self.port = port or utils.free_port()
6970
# Default value for every python subprocess: subprocess.Popen(..., creationflags=0)
7071
self.popen_kw = kwargs.pop("popen_kw", {})
7172
self.creation_flags = self.popen_kw.pop("creation_flags", 0)
7273
self.env = env or os.environ
74+
self.DRIVER_PATH_ENV_KEY = driver_path_env_key
75+
self._path = self.env_path() or executable_path
7376

7477
@property
7578
def service_url(self) -> str:
@@ -236,3 +239,6 @@ def _start_process(self, path: str) -> None:
236239
f"'{os.path.basename(self._path)}' executable may have wrong permissions."
237240
) from err
238241
raise
242+
243+
def env_path(self) -> Optional[str]:
244+
return os.getenv(self.DRIVER_PATH_ENV_KEY, None)

py/selenium/webdriver/edge/service.py

+3
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,18 @@ def __init__(
4040
log_output: SubprocessStdAlias = None,
4141
service_args: typing.Optional[typing.List[str]] = None,
4242
env: typing.Optional[typing.Mapping[str, str]] = None,
43+
driver_path_env_key: str = None,
4344
**kwargs,
4445
) -> None:
4546
self.service_args = service_args or []
47+
driver_path_env_key = driver_path_env_key or "SE_EDGEDRIVER"
4648

4749
super().__init__(
4850
executable_path=executable_path,
4951
port=port,
5052
service_args=service_args,
5153
log_output=log_output,
5254
env=env,
55+
driver_path_env_key=driver_path_env_key,
5356
**kwargs,
5457
)

py/selenium/webdriver/firefox/service.py

+3
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,18 @@ def __init__(
4040
service_args: typing.Optional[typing.List[str]] = None,
4141
log_output: SubprocessStdAlias = None,
4242
env: typing.Optional[typing.Mapping[str, str]] = None,
43+
driver_path_env_key: str = None,
4344
**kwargs,
4445
) -> None:
4546
self.service_args = service_args or []
47+
driver_path_env_key = driver_path_env_key or "SE_GECKODRIVER"
4648

4749
super().__init__(
4850
executable_path=executable_path,
4951
port=port,
5052
log_output=log_output,
5153
env=env,
54+
driver_path_env_key=driver_path_env_key,
5255
**kwargs,
5356
)
5457

py/selenium/webdriver/firefox/webdriver.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def __init__(
5858
options.binary_location = finder.get_browser_path()
5959
options.browser_version = None
6060

61-
self.service.path = finder.get_driver_path()
61+
self.service.path = self.service.env_path() or finder.get_driver_path()
6262
self.service.start()
6363

6464
executor = FirefoxRemoteConnection(

py/selenium/webdriver/ie/service.py

+4
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def __init__(
3232
service_args: typing.Optional[typing.List[str]] = None,
3333
log_level: typing.Optional[str] = None,
3434
log_output: SubprocessStdAlias = None,
35+
driver_path_env_key: str = None,
3536
**kwargs,
3637
) -> None:
3738
"""Creates a new instance of the Service.
@@ -46,6 +47,8 @@ def __init__(
4647
Default is "stdout".
4748
"""
4849
self.service_args = service_args or []
50+
driver_path_env_key = driver_path_env_key or "SE_IEDRIVER"
51+
4952
if host:
5053
self.service_args.append(f"--host={host}")
5154
if log_level:
@@ -55,6 +58,7 @@ def __init__(
5558
executable_path=executable_path,
5659
port=port,
5760
log_output=log_output,
61+
driver_path_env_key=driver_path_env_key,
5862
**kwargs,
5963
)
6064

py/selenium/webdriver/ie/webdriver.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def __init__(
4646
self.service = service if service else Service()
4747
options = options if options else Options()
4848

49-
self.service.path = DriverFinder(self.service, options).get_driver_path()
49+
self.service.path = self.service.env_path() or DriverFinder(self.service, options).get_driver_path()
5050
self.service.start()
5151

5252
executor = RemoteConnection(

py/selenium/webdriver/safari/service.py

+3
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,18 @@ def __init__(
3737
service_args: typing.Optional[typing.List[str]] = None,
3838
env: typing.Optional[typing.Mapping[str, str]] = None,
3939
reuse_service=False,
40+
driver_path_env_key: str = None,
4041
**kwargs,
4142
) -> None:
4243
self.service_args = service_args or []
44+
driver_path_env_key = driver_path_env_key or "SE_SAFARIDRIVER"
4345

4446
self.reuse_service = reuse_service
4547
super().__init__(
4648
executable_path=executable_path,
4749
port=port,
4850
env=env,
51+
driver_path_env_key=driver_path_env_key,
4952
**kwargs,
5053
)
5154

py/selenium/webdriver/safari/webdriver.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def __init__(
4545
self.service = service if service else Service()
4646
options = options if options else Options()
4747

48-
self.service.path = DriverFinder(self.service, options).get_driver_path()
48+
self.service.path = self.service.env_path() or DriverFinder(self.service, options).get_driver_path()
4949

5050
if not self.service.reuse_service:
5151
self.service.start()

py/test/selenium/webdriver/chrome/chrome_service_tests.py

+26
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,29 @@ def test_log_output_null_default(driver, capfd) -> None:
9595
out, err = capfd.readouterr()
9696
assert "Starting ChromeDriver" not in out
9797
driver.quit()
98+
99+
100+
@pytest.fixture
101+
def service():
102+
return Service()
103+
104+
105+
@pytest.mark.usefixtures("service")
106+
class TestChromeDriverService:
107+
service_path = "/path/to/chromedriver"
108+
109+
@pytest.fixture(autouse=True)
110+
def setup_and_teardown(self):
111+
os.environ["SE_CHROMEDRIVER"] = self.service_path
112+
yield
113+
os.environ.pop("SE_CHROMEDRIVER", None)
114+
115+
def test_uses_path_from_env_variable(self, service):
116+
assert "chromedriver" in service.path
117+
118+
def test_updates_path_after_setting_env_variable(self, service):
119+
new_path = "/foo/bar"
120+
os.environ["SE_CHROMEDRIVER"] = new_path
121+
service.executable_path = self.service_path # Simulating the update
122+
123+
assert "chromedriver" in service.executable_path

py/test/selenium/webdriver/firefox/firefox_service_tests.py

+28
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import os
1818
import subprocess
1919

20+
import pytest
21+
2022
from selenium.webdriver import Firefox
2123
from selenium.webdriver.firefox.service import Service
2224

@@ -54,3 +56,29 @@ def test_log_output_as_stdout(capfd) -> None:
5456
out, err = capfd.readouterr()
5557
assert "geckodriver\tINFO\tListening" in out
5658
driver.quit()
59+
60+
61+
@pytest.fixture
62+
def service():
63+
return Service()
64+
65+
66+
@pytest.mark.usefixtures("service")
67+
class TestGeckoDriverService:
68+
service_path = "/path/to/geckodriver"
69+
70+
@pytest.fixture(autouse=True)
71+
def setup_and_teardown(self):
72+
os.environ["SE_GECKODRIVER"] = self.service_path
73+
yield
74+
os.environ.pop("SE_GECKODRIVER", None)
75+
76+
def test_uses_path_from_env_variable(self, service):
77+
assert "geckodriver" in service.path
78+
79+
def test_updates_path_after_setting_env_variable(self, service):
80+
new_path = "/foo/bar"
81+
os.environ["SE_GECKODRIVER"] = new_path
82+
service.executable_path = self.service_path # Simulating the update
83+
84+
assert "geckodriver" in service.executable_path

0 commit comments

Comments
 (0)