Skip to content

Commit

Permalink
[py] Allow driver path to be set using ENV variables (#14528)
Browse files Browse the repository at this point in the history

---------

Co-authored-by: Sri Harsha <[email protected]>
  • Loading branch information
Delta456 and harsha509 authored Oct 4, 2024
1 parent a67a2df commit a2cacc1
Show file tree
Hide file tree
Showing 12 changed files with 81 additions and 5 deletions.
3 changes: 3 additions & 0 deletions py/selenium/webdriver/chromium/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ def __init__(
service_args: typing.Optional[typing.List[str]] = None,
log_output: SubprocessStdAlias = None,
env: typing.Optional[typing.Mapping[str, str]] = None,
driver_path_env_key: str = None,
**kwargs,
) -> None:
self.service_args = service_args or []
driver_path_env_key = driver_path_env_key or "SE_CHROMEDRIVER"

if isinstance(log_output, str):
self.service_args.append(f"--log-path={log_output}")
Expand All @@ -56,6 +58,7 @@ def __init__(
port=port,
env=env,
log_output=self.log_output,
driver_path_env_key=driver_path_env_key,
**kwargs,
)

Expand Down
2 changes: 1 addition & 1 deletion py/selenium/webdriver/chromium/webdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(
options.binary_location = finder.get_browser_path()
options.browser_version = None

self.service.path = finder.get_driver_path()
self.service.path = self.service.env_path() or finder.get_driver_path()
self.service.start()

executor = ChromiumRemoteConnection(
Expand Down
8 changes: 7 additions & 1 deletion py/selenium/webdriver/common/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from platform import system
from subprocess import PIPE
from time import sleep
from typing import Optional
from typing import cast
from urllib import request
from urllib.error import URLError
Expand Down Expand Up @@ -53,6 +54,7 @@ def __init__(
port: int = 0,
log_output: SubprocessStdAlias = None,
env: typing.Optional[typing.Mapping[typing.Any, typing.Any]] = None,
driver_path_env_key: str = None,
**kwargs,
) -> None:
if isinstance(log_output, str):
Expand All @@ -64,12 +66,13 @@ def __init__(
else:
self.log_output = log_output

self._path = executable_path
self.port = port or utils.free_port()
# Default value for every python subprocess: subprocess.Popen(..., creationflags=0)
self.popen_kw = kwargs.pop("popen_kw", {})
self.creation_flags = self.popen_kw.pop("creation_flags", 0)
self.env = env or os.environ
self.DRIVER_PATH_ENV_KEY = driver_path_env_key
self._path = self.env_path() or executable_path

@property
def service_url(self) -> str:
Expand Down Expand Up @@ -236,3 +239,6 @@ def _start_process(self, path: str) -> None:
f"'{os.path.basename(self._path)}' executable may have wrong permissions."
) from err
raise

def env_path(self) -> Optional[str]:
return os.getenv(self.DRIVER_PATH_ENV_KEY, None)
3 changes: 3 additions & 0 deletions py/selenium/webdriver/edge/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,18 @@ def __init__(
log_output: SubprocessStdAlias = None,
service_args: typing.Optional[typing.List[str]] = None,
env: typing.Optional[typing.Mapping[str, str]] = None,
driver_path_env_key: str = None,
**kwargs,
) -> None:
self.service_args = service_args or []
driver_path_env_key = driver_path_env_key or "SE_EDGEDRIVER"

super().__init__(
executable_path=executable_path,
port=port,
service_args=service_args,
log_output=log_output,
env=env,
driver_path_env_key=driver_path_env_key,
**kwargs,
)
3 changes: 3 additions & 0 deletions py/selenium/webdriver/firefox/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,18 @@ def __init__(
service_args: typing.Optional[typing.List[str]] = None,
log_output: SubprocessStdAlias = None,
env: typing.Optional[typing.Mapping[str, str]] = None,
driver_path_env_key: str = None,
**kwargs,
) -> None:
self.service_args = service_args or []
driver_path_env_key = driver_path_env_key or "SE_GECKODRIVER"

super().__init__(
executable_path=executable_path,
port=port,
log_output=log_output,
env=env,
driver_path_env_key=driver_path_env_key,
**kwargs,
)

Expand Down
2 changes: 1 addition & 1 deletion py/selenium/webdriver/firefox/webdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def __init__(
options.binary_location = finder.get_browser_path()
options.browser_version = None

self.service.path = finder.get_driver_path()
self.service.path = self.service.env_path() or finder.get_driver_path()
self.service.start()

executor = FirefoxRemoteConnection(
Expand Down
4 changes: 4 additions & 0 deletions py/selenium/webdriver/ie/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def __init__(
service_args: typing.Optional[typing.List[str]] = None,
log_level: typing.Optional[str] = None,
log_output: SubprocessStdAlias = None,
driver_path_env_key: str = None,
**kwargs,
) -> None:
"""Creates a new instance of the Service.
Expand All @@ -46,6 +47,8 @@ def __init__(
Default is "stdout".
"""
self.service_args = service_args or []
driver_path_env_key = driver_path_env_key or "SE_IEDRIVER"

if host:
self.service_args.append(f"--host={host}")
if log_level:
Expand All @@ -55,6 +58,7 @@ def __init__(
executable_path=executable_path,
port=port,
log_output=log_output,
driver_path_env_key=driver_path_env_key,
**kwargs,
)

Expand Down
2 changes: 1 addition & 1 deletion py/selenium/webdriver/ie/webdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __init__(
self.service = service if service else Service()
options = options if options else Options()

self.service.path = DriverFinder(self.service, options).get_driver_path()
self.service.path = self.service.env_path() or DriverFinder(self.service, options).get_driver_path()
self.service.start()

executor = RemoteConnection(
Expand Down
3 changes: 3 additions & 0 deletions py/selenium/webdriver/safari/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,18 @@ def __init__(
service_args: typing.Optional[typing.List[str]] = None,
env: typing.Optional[typing.Mapping[str, str]] = None,
reuse_service=False,
driver_path_env_key: str = None,
**kwargs,
) -> None:
self.service_args = service_args or []
driver_path_env_key = driver_path_env_key or "SE_SAFARIDRIVER"

self.reuse_service = reuse_service
super().__init__(
executable_path=executable_path,
port=port,
env=env,
driver_path_env_key=driver_path_env_key,
**kwargs,
)

Expand Down
2 changes: 1 addition & 1 deletion py/selenium/webdriver/safari/webdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def __init__(
self.service = service if service else Service()
options = options if options else Options()

self.service.path = DriverFinder(self.service, options).get_driver_path()
self.service.path = self.service.env_path() or DriverFinder(self.service, options).get_driver_path()

if not self.service.reuse_service:
self.service.start()
Expand Down
26 changes: 26 additions & 0 deletions py/test/selenium/webdriver/chrome/chrome_service_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,29 @@ def test_log_output_null_default(driver, capfd) -> None:
out, err = capfd.readouterr()
assert "Starting ChromeDriver" not in out
driver.quit()


@pytest.fixture
def service():
return Service()


@pytest.mark.usefixtures("service")
class TestChromeDriverService:
service_path = "/path/to/chromedriver"

@pytest.fixture(autouse=True)
def setup_and_teardown(self):
os.environ["SE_CHROMEDRIVER"] = self.service_path
yield
os.environ.pop("SE_CHROMEDRIVER", None)

def test_uses_path_from_env_variable(self, service):
assert "chromedriver" in service.path

def test_updates_path_after_setting_env_variable(self, service):
new_path = "/foo/bar"
os.environ["SE_CHROMEDRIVER"] = new_path
service.executable_path = self.service_path # Simulating the update

assert "chromedriver" in service.executable_path
28 changes: 28 additions & 0 deletions py/test/selenium/webdriver/firefox/firefox_service_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import os
import subprocess

import pytest

from selenium.webdriver import Firefox
from selenium.webdriver.firefox.service import Service

Expand Down Expand Up @@ -54,3 +56,29 @@ def test_log_output_as_stdout(capfd) -> None:
out, err = capfd.readouterr()
assert "geckodriver\tINFO\tListening" in out
driver.quit()


@pytest.fixture
def service():
return Service()


@pytest.mark.usefixtures("service")
class TestGeckoDriverService:
service_path = "/path/to/geckodriver"

@pytest.fixture(autouse=True)
def setup_and_teardown(self):
os.environ["SE_GECKODRIVER"] = self.service_path
yield
os.environ.pop("SE_GECKODRIVER", None)

def test_uses_path_from_env_variable(self, service):
assert "geckodriver" in service.path

def test_updates_path_after_setting_env_variable(self, service):
new_path = "/foo/bar"
os.environ["SE_GECKODRIVER"] = new_path
service.executable_path = self.service_path # Simulating the update

assert "geckodriver" in service.executable_path

0 comments on commit a2cacc1

Please sign in to comment.