Skip to content

Commit

Permalink
Add splinter.Config, deprecate many browser arguments (#1134)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsfehler committed Jan 25, 2023
1 parent 1d070fd commit 3022710
Show file tree
Hide file tree
Showing 21 changed files with 343 additions and 157 deletions.
16 changes: 16 additions & 0 deletions docs/config.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.. Copyright 2023 splinter authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
.. meta::
:description: Config
:keywords: splinter, python, tutorial, config

++++++
Config
++++++

.. module:: splinter.config

.. autoclass:: Config
:members:
24 changes: 0 additions & 24 deletions docs/drivers/chrome.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,30 +26,6 @@ the ``Browser`` instance:

**Note:** if you have trouble with ``$HOME/.bash_profile``, you can try ``$HOME/.bashrc``.

Headless mode
+++++++++++++

Starting with Chrome 59, Chrome can run in a headless mode.
Further Information: `google developers updates <https://developers.google.com/web/updates/2017/05/nic59#headless>`_

To use headless mode, pass the `headless` argument
when creating a new Browser instance.

.. code-block:: python
from splinter import Browser
browser = Browser('chrome', headless=True)
Incognito mode
++++++++++++++

To use Chrome's incognito mode, pass the `incognito` argument
when creating a Browser instance.

.. code-block:: python
from splinter import Browser
browser = Browser('chrome', incognito=True)

Emulation mode
++++++++++++++
Expand Down
21 changes: 0 additions & 21 deletions docs/drivers/edge.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,6 @@ Selenium Options can be passed to customize Edge's behaviour through the
edge_options = Options()
browser = Browser('edge', options=edge_options)
Headless mode
+++++++++++++

To use headless mode, pass the `headless` argument
when creating a new Browser instance.

.. code-block:: python
from splinter import Browser
browser = Browser('edge', headless=True)
Incognito mode
++++++++++++++

To use Edge's incognito mode, pass the `incognito` argument
when creating a Browser instance.

.. code-block:: python
from splinter import Browser
browser = Browser('edge', incognito=True)
Emulation mode
++++++++++++++
Expand Down
36 changes: 0 additions & 36 deletions docs/drivers/firefox.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,6 @@ the ``Browser`` instance:
**Note:** if you don't provide any driver to ``Browser`` function, ``firefox`` will be used.

Headless mode
+++++++++++++

Starting with Firefox 55, Firefox can run in a headless mode.

To use headless mode, pass the `headless` argument
when creating a new Browser instance.

.. code-block:: python
from splinter import Browser
browser = Browser('firefox', headless=True)
Incognito mode
++++++++++++++

To use Firefox's incognito mode, pass the `incognito` argument
when creating a Browser instance.

.. code-block:: python
from splinter import Browser
browser = Browser('firefox', incognito=True)

Service
+++++++
Expand Down Expand Up @@ -91,19 +68,6 @@ using the ``profile`` keyword (passing the name of the profile as a ``str`` inst
If you don't specify a profile, a new temporary profile will be created (and deleted when you ``close`` the browser).

Firefox Extensions
++++++++++++++++++

An extension for firefox is a .xpi archive.
To use an extension in Firefox webdriver profile you need to give the path of
the extension, using the extensions keyword (passing the extensions as a ``list`` instance):

.. code-block:: python
from splinter import Browser
browser = Browser('firefox', extensions=['extension1.xpi', 'extension2.xpi'])
After the browser is closed, extensions will be deleted from the profile, even if the profile is not a temporary one.

Selenium Capabilities
+++++++++++++++++++++
Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
:hidden:

browser
config
finding
elements-in-the-page
mouse-interaction
Expand Down
9 changes: 8 additions & 1 deletion splinter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,12 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

from splinter.browser import Browser # NOQA
from splinter.browser import Browser
from splinter.config import Config
from splinter.version import __version_info__, __version__ # NOQA


__all__ = [
'Browser',
'Config',
]
8 changes: 4 additions & 4 deletions splinter/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
logger.debug(f'Import Warning: {e}')


def get_driver(driver, retry_count=3, *args, **kwargs):
def get_driver(driver, retry_count=3, config=None, *args, **kwargs):
"""Try to instantiate the driver.
Common selenium errors are caught and a retry attempt occurs.
Expand All @@ -90,14 +90,14 @@ def get_driver(driver, retry_count=3, *args, **kwargs):

for _ in range(retry_count):
try:
return driver(*args, **kwargs)
return driver(config=config, *args, **kwargs)
except driver_exceptions as e:
err = e

raise err


def Browser(driver_name: str = "firefox", retry_count: int = 3, *args, **kwargs): # NOQA: N802
def Browser(driver_name: str = "firefox", retry_count: int = 3, config=None, *args, **kwargs): # NOQA: N802
"""Get a new driver instance.
Extra arguments will be sent to the driver instance.
Expand All @@ -122,4 +122,4 @@ def Browser(driver_name: str = "firefox", retry_count: int = 3, *args, **kwargs)
if driver is None:
raise DriverNotFoundError(f'Driver for {driver_name} was not found.')

return get_driver(driver, retry_count=retry_count, *args, **kwargs)
return get_driver(driver, retry_count=retry_count, config=config, *args, **kwargs)
50 changes: 50 additions & 0 deletions splinter/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from dataclasses import dataclass
from typing import List, Optional


@dataclass
class Config:
"""Standard interface for basic and nearly universal driver flags.
The primary purpose of Config is to reduce the burden on the user to import
Selenium Options objects for common operations. The second purpose is to
avoid argument bloat and drift for the various drivers.
Both Splinter Config and Selenium Options can be used together.
Config will override Options, if applicable.
Config is not a complete replacement for Selenium Options.
For unique and esoteric functionality that is exclusive to one web browser,
Selenium Options should still be used. The purpose of Config is to expose
a universal interface for common functionality, not try to capture all
of it.
Example:
>>> from splinter import Browser, Config
>>>
>>>
>>> my_config = Config(fullscreen=True)
>>> my_browser = Browser(config=my_config)
Attributes:
extensions: Add extensions to the browser.
The full path to each extension must be included.
When the browser is closed extensions will be deleted from
the profile, even if the profile is not a temporary one.
fullscreen: Launch the browser in fullscreen mode.
headless: Launch the browser in headless mode.
Requires Chrome 59+ or Firefox 55+.
incognito: Launch the browser in incognito mode.
user_agent: Set a custom user_agent.
"""
extensions: Optional[List[str]] = None
fullscreen: Optional[bool] = False
headless: Optional[bool] = False
incognito: Optional[bool] = False
user_agent: Optional[str] = ""
18 changes: 13 additions & 5 deletions splinter/driver/djangoclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
# Copyright 2012 splinter authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

from typing import Optional
from urllib import parse

from splinter.config import Config
from splinter.cookie_manager import CookieManagerAPI
from splinter.request_handler.status_code import StatusCode

Expand Down Expand Up @@ -55,7 +56,13 @@ class DjangoClient(LxmlDriver):

driver_name = "django"

def __init__(self, user_agent=None, wait_time=2, **kwargs):
def __init__(
self,
user_agent=None,
wait_time=2,
config: Optional[Config] = None,
**kwargs,
):
from django.test.client import Client

self._custom_headers = kwargs.pop("custom_headers", {})
Expand All @@ -66,9 +73,10 @@ def __init__(self, user_agent=None, wait_time=2, **kwargs):
client_kwargs[key.replace("client_", "")] = value

self._browser = Client(**client_kwargs)
self._user_agent = user_agent

self._cookie_manager = CookieManager(self._browser)
super(DjangoClient, self).__init__(wait_time=wait_time)

super(DjangoClient, self).__init__(wait_time=wait_time, user_agent=user_agent, config=config)

def __enter__(self):
return self
Expand Down Expand Up @@ -97,7 +105,7 @@ def _set_extra_params(self, url):
extra.update({"SERVER_NAME": components.hostname})
if components.port:
extra.update({"SERVER_PORT": components.port})
if self._user_agent:
if self.config.user_agent:
extra.update({"User-Agent": self._user_agent})
if self._custom_headers:
extra.update(self._custom_headers)
Expand Down
12 changes: 10 additions & 2 deletions splinter/driver/flaskclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
# Copyright 2014 splinter authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

from typing import Optional
from urllib.parse import parse_qs, urlparse, urlencode, urlunparse

from splinter.config import Config
from splinter.cookie_manager import CookieManagerAPI
from splinter.request_handler.status_code import StatusCode

Expand Down Expand Up @@ -58,7 +59,14 @@ class FlaskClient(LxmlDriver):

driver_name = "flask"

def __init__(self, app, user_agent=None, wait_time=2, custom_headers=None):
def __init__(
self,
app,
user_agent=None,
wait_time=2,
custom_headers=None,
config: Optional[Config] = None,
):
app.config["TESTING"] = True
self._browser = app.test_client()
self._cookie_manager = CookieManager(self._browser)
Expand Down
13 changes: 11 additions & 2 deletions splinter/driver/lxmldriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
# Copyright 2014 splinter authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

import re
import time

from typing import Optional
from urllib import parse

import lxml.etree
import lxml.html
from lxml.cssselect import CSSSelector

from splinter.config import Config
from splinter.driver import DriverAPI, ElementAPI
from splinter.driver.find_links import FindLinks
from splinter.driver.element_present import ElementPresentMixIn
Expand All @@ -24,7 +26,12 @@ class LxmlDriver(ElementPresentMixIn, DriverAPI):
_response = ""
_url = ""

def __init__(self, user_agent=None, wait_time=2):
def __init__(
self,
user_agent=None,
wait_time=2,
config: Optional[Config] = None,
):
self.wait_time = wait_time
self._history = []
self._last_urls = []
Expand All @@ -33,6 +40,8 @@ def __init__(self, user_agent=None, wait_time=2):

self.links = FindLinks(self)

self.config = config or Config(user_agent=user_agent)

def __enter__(self):
return self

Expand Down

0 comments on commit 3022710

Please sign in to comment.