Skip to content
Open
20 changes: 20 additions & 0 deletions py/selenium/webdriver/chrome/webdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chromium.webdriver import ChromiumDriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.remote.client_config import ClientConfig


class WebDriver(ChromiumDriver):
Expand All @@ -30,6 +31,7 @@ def __init__(
options: Options | None = None,
service: Service | None = None,
keep_alive: bool = True,
client_config: Optional[ClientConfig] = None,
) -> None:
"""Creates a new instance of the chrome driver.

Expand All @@ -39,6 +41,23 @@ def __init__(
options: This takes an instance of ChromeOptions.
service: Service object for handling the browser driver if you need to pass extra details.
keep_alive: Whether to configure ChromeRemoteConnection to use HTTP keep-alive.
This parameter is ignored if client_config is provided.
client_config: ClientConfig instance for advanced HTTP/WebSocket configuration.
If provided, takes precedence over individual parameters like keep_alive.

Example:
Basic usage::

driver = webdriver.Chrome()

With custom config::

from selenium.webdriver.remote.client_config import ClientConfig
config = ClientConfig(
remote_server_addr="http://localhost:9515",
websocket_timeout=10
)
driver = webdriver.Chrome(client_config=config)
"""
service = service if service else Service()
options = options if options else Options()
Expand All @@ -49,4 +68,5 @@ def __init__(
options=options,
service=service,
keep_alive=keep_alive,
client_config=client_config,
)
11 changes: 11 additions & 0 deletions py/selenium/webdriver/chromium/webdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
from selenium.webdriver.chromium.remote_connection import ChromiumRemoteConnection
from selenium.webdriver.chromium.service import ChromiumService
from selenium.webdriver.common.driver_finder import DriverFinder
from selenium.webdriver.common.utils import normalize_local_driver_config
from selenium.webdriver.remote.client_config import ClientConfig
from selenium.webdriver.remote.command import Command
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver

Expand All @@ -34,6 +36,7 @@ def __init__(
options: ChromiumOptions | None = None,
service: ChromiumService | None = None,
keep_alive: bool = True,
client_config: Optional[ClientConfig] = None,
) -> None:
"""Create a new WebDriver instance, start the service, and create new ChromiumDriver instance.

Expand All @@ -43,6 +46,9 @@ def __init__(
options: This takes an instance of ChromiumOptions.
service: Service object for handling the browser driver if you need to pass extra details.
keep_alive: Whether to configure ChromiumRemoteConnection to use HTTP keep-alive.
This parameter is ignored if client_config is provided.
client_config: ClientConfig instance for advanced HTTP/WebSocket configuration.
If provided, takes precedence over individual parameters like keep_alive.
"""
self.service = service if service else ChromiumService()
options = options if options else ChromiumOptions()
Expand All @@ -55,12 +61,17 @@ def __init__(
self.service.path = self.service.env_path() or finder.get_driver_path()
self.service.start()

client_config = normalize_local_driver_config(
self.service.service_url, user_config=client_config, keep_alive=keep_alive, timeout=120
)

executor = ChromiumRemoteConnection(
remote_server_addr=self.service.service_url,
browser_name=browser_name,
vendor_prefix=vendor_prefix,
keep_alive=keep_alive,
ignore_proxy=options._ignore_local_proxy,
client_config=client_config,
)

try:
Expand Down
16 changes: 16 additions & 0 deletions py/selenium/webdriver/common/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

from selenium.types import AnyKey
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.remote.client_config import ClientConfig

_is_connectable_exceptions = (socket.error, ConnectionResetError)

Expand Down Expand Up @@ -163,3 +164,18 @@ def keys_to_typing(value: Iterable[AnyKey]) -> list[str]:
else:
characters.extend(val)
return characters


def normalize_local_driver_config(
service_url: str, user_config: Optional[ClientConfig] = None, **defaults
) -> ClientConfig:
"""Creates a ClientConfig for local drivers."""
if user_config is None:
return ClientConfig(remote_server_addr=service_url, **defaults)

# Programmatically copy attributes to avoid brittleness
config_args = {
key.lstrip("_"): value for key, value in vars(user_config).items()
}
config_args["remote_server_addr"] = service_url
return ClientConfig(**config_args)
18 changes: 17 additions & 1 deletion py/selenium/webdriver/edge/webdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.edge.options import Options
from selenium.webdriver.edge.service import Service
from selenium.webdriver.remote.client_config import ClientConfig


class WebDriver(ChromiumDriver):
Expand All @@ -30,6 +31,7 @@ def __init__(
options: Options | None = None,
service: Service | None = None,
keep_alive: bool = True,
client_config: Optional[ClientConfig] = None,
) -> None:
"""Creates a new instance of the edge driver.

Expand All @@ -40,7 +42,20 @@ def __init__(
service: Service object for handling the browser driver if you need
to pass extra details.
keep_alive: Whether to configure EdgeRemoteConnection to use HTTP
keep-alive.
keep-alive. This parameter is ignored if client_config is provided.
client_config: ClientConfig instance for advanced HTTP/WebSocket configuration.
If provided, takes precedence over individual parameters like keep_alive.

Example:
Basic usage::

driver = webdriver.Edge()

With custom config::

from selenium.webdriver.remote.client_config import ClientConfig
config = ClientConfig(websocket_timeout=10)
driver = webdriver.Edge(client_config=config)
"""
service = service if service else Service()
options = options if options else Options()
Expand All @@ -51,4 +66,5 @@ def __init__(
options=options,
service=service,
keep_alive=keep_alive,
client_config=client_config,
)
22 changes: 22 additions & 0 deletions py/selenium/webdriver/firefox/webdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@
from io import BytesIO

from selenium.webdriver.common.driver_finder import DriverFinder
from selenium.webdriver.common.utils import normalize_local_driver_config
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.firefox.remote_connection import FirefoxRemoteConnection
from selenium.webdriver.firefox.service import Service
from selenium.webdriver.remote.client_config import ClientConfig
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver


Expand All @@ -39,13 +41,28 @@ def __init__(
options: Options | None = None,
service: Service | None = None,
keep_alive: bool = True,
client_config: Optional[ClientConfig] = None,
) -> None:
"""Create a new instance of the Firefox driver, start the service, and create new instance.

Args:
options: Instance of ``options.Options``.
service: (Optional) service instance for managing the starting and stopping of the driver.
keep_alive: Whether to configure remote_connection.RemoteConnection to use HTTP keep-alive.
This parameter is ignored if client_config is provided.
client_config: ClientConfig instance for advanced HTTP/WebSocket configuration.
If provided, takes precedence over individual parameters like keep_alive.

Example:
Basic usage::

driver = webdriver.Firefox()

With custom config::

from selenium.webdriver.remote.client_config import ClientConfig
config = ClientConfig(websocket_timeout=10)
driver = webdriver.Firefox(client_config=config)
"""
self.service = service if service else Service()
options = options if options else Options()
Expand All @@ -58,10 +75,15 @@ def __init__(
self.service.path = self.service.env_path() or finder.get_driver_path()
self.service.start()

client_config = normalize_local_driver_config(
self.service.service_url, user_config=client_config, keep_alive=keep_alive, timeout=120
)

executor = FirefoxRemoteConnection(
remote_server_addr=self.service.service_url,
keep_alive=keep_alive,
ignore_proxy=options._ignore_local_proxy,
client_config=client_config,
)

try:
Expand Down
21 changes: 20 additions & 1 deletion py/selenium/webdriver/ie/webdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@


from selenium.webdriver.common.driver_finder import DriverFinder
from selenium.webdriver.common.utils import normalize_local_driver_config
from selenium.webdriver.ie.options import Options
from selenium.webdriver.ie.service import Service
from selenium.webdriver.remote.client_config import ClientConfig
Expand All @@ -32,6 +33,7 @@ def __init__(
options: Options | None = None,
service: Service | None = None,
keep_alive: bool = True,
client_config: Optional[ClientConfig] = None,
) -> None:
"""Creates a new instance of the Ie driver.

Expand All @@ -41,14 +43,31 @@ def __init__(
options: IE Options instance, providing additional IE options
service: (Optional) service instance for managing the starting and stopping of the driver.
keep_alive: Whether to configure RemoteConnection to use HTTP keep-alive.
This parameter is ignored if client_config is provided.
client_config: ClientConfig instance for advanced HTTP/WebSocket configuration.
If provided, takes precedence over individual parameters like keep_alive.

Example:
Basic usage::

driver = webdriver.Ie()

With custom config::

from selenium.webdriver.remote.client_config import ClientConfig
config = ClientConfig(websocket_timeout=10)
driver = webdriver.Ie(client_config=config)
"""
self.service = service if service else Service()
options = options if options else Options()

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

client_config = ClientConfig(remote_server_addr=self.service.service_url, keep_alive=keep_alive, timeout=120)
client_config = normalize_local_driver_config(
self.service.service_url, user_config=client_config, keep_alive=keep_alive, timeout=120
)

executor = RemoteConnection(
ignore_proxy=options._ignore_local_proxy,
client_config=client_config,
Expand Down
4 changes: 2 additions & 2 deletions py/selenium/webdriver/remote/client_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class ClientConfig:

def __init__(
self,
remote_server_addr: str,
remote_server_addr: str | None = None,
keep_alive: bool | None = True,
proxy: Proxy | None = Proxy(raw={"proxyType": ProxyType.SYSTEM}),
ignore_certificates: bool | None = False,
Expand All @@ -91,7 +91,7 @@ def __init__(
user_agent: str | None = None,
extra_headers: dict | None = None,
websocket_timeout: float | None = 30.0,
websocket_interval: float | None = 0.1,
websocket_interval: float | None = 0.1
) -> None:
self.remote_server_addr = remote_server_addr
self.keep_alive = keep_alive
Expand Down
24 changes: 23 additions & 1 deletion py/selenium/webdriver/safari/webdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common.driver_finder import DriverFinder
from selenium.webdriver.common.utils import normalize_local_driver_config
from selenium.webdriver.remote.client_config import ClientConfig
from selenium.webdriver.remote.webdriver import WebDriver as RemoteWebDriver
from selenium.webdriver.safari.options import Options
from selenium.webdriver.safari.remote_connection import SafariRemoteConnection
Expand All @@ -29,17 +31,32 @@ class WebDriver(RemoteWebDriver):

def __init__(
self,
keep_alive=True,
keep_alive: bool = True,
options: Options | None = None,
service: Service | None = None,
client_config: ClientConfig | None = None,
) -> None:
"""Create a new Safari driver instance and launch or find a running safaridriver service.

Args:
keep_alive: Whether to configure SafariRemoteConnection to use
HTTP keep-alive. Defaults to True.
This parameter is ignored if client_config is provided.
options: Instance of ``options.Options``.
service: Service object for handling the browser driver if you need to pass extra details
client_config: ClientConfig instance for advanced HTTP/WebSocket configuration.
If provided, takes precedence over individual parameters like keep_alive.

Example:
Basic usage::

driver = webdriver.Safari()

With custom config::

from selenium.webdriver.remote.client_config import ClientConfig
config = ClientConfig(websocket_timeout=10)
driver = webdriver.Safari(client_config=config)
"""
self.service = service if service else Service()
options = options if options else Options()
Expand All @@ -49,10 +66,15 @@ def __init__(
if not self.service.reuse_service:
self.service.start()

client_config = normalize_local_driver_config(
self.service.service_url, user_config=client_config, keep_alive=keep_alive, timeout=120
)

executor = SafariRemoteConnection(
remote_server_addr=self.service.service_url,
keep_alive=keep_alive,
ignore_proxy=options._ignore_local_proxy,
client_config=client_config,
)

try:
Expand Down
Loading