diff --git a/splinter/browser.py b/splinter/browser.py index beb52e667..a1cbfdd5b 100644 --- a/splinter/browser.py +++ b/splinter/browser.py @@ -6,6 +6,15 @@ import sys +try: + from httplib import HTTPException +except ImportError: + from http.client import HTTPException + +from urllib3.exceptions import MaxRetryError + +from selenium.common.exceptions import WebDriverException + from splinter.driver.webdriver.firefox import WebDriver as FirefoxWebDriver from splinter.driver.webdriver.remote import WebDriver as RemoteWebDriver from splinter.driver.webdriver.chrome import WebDriver as ChromeWebDriver @@ -43,7 +52,23 @@ pass -def Browser(driver_name="firefox", *args, **kwargs): +def get_driver(driver, retry_count=3, *args, **kwargs): + """Try to instantiate the driver. + + Common selenium errors are caught and a retry attempt occurs. + This can mitigate issues running on Remote WebDriver. + + """ + for _ in range(retry_count): + try: + return driver(*args, **kwargs) + except (IOError, HTTPException, WebDriverException, MaxRetryError) as e: + pass + + raise e + + +def Browser(driver_name="firefox", retry_count=3, *args, **kwargs): """ Returns a driver instance for the given name. @@ -61,4 +86,5 @@ def Browser(driver_name="firefox", *args, **kwargs): driver = _DRIVERS[driver_name] except KeyError: raise DriverNotFoundError("No driver for %s" % driver_name) - return driver(*args, **kwargs) + + return get_driver(driver, *args, **kwargs) diff --git a/splinter/driver/webdriver/remote.py b/splinter/driver/webdriver/remote.py index 8e023e322..3638fa92d 100644 --- a/splinter/driver/webdriver/remote.py +++ b/splinter/driver/webdriver/remote.py @@ -5,12 +5,17 @@ # license that can be found in the LICENSE file. from selenium.webdriver import Remote +from selenium.webdriver.remote import remote_connection from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from splinter.driver.webdriver import ( BaseWebDriver, WebDriverElement, ) from splinter.driver.webdriver.cookie_manager import CookieManager +from splinter.driver.webdriver.remote_connection import patch_request + +# MonkeyPatch RemoteConnection +remote_connection.RemoteConnection._request = patch_request class WebDriver(BaseWebDriver): diff --git a/splinter/driver/webdriver/remote_connection.py b/splinter/driver/webdriver/remote_connection.py new file mode 100644 index 000000000..27c1e156f --- /dev/null +++ b/splinter/driver/webdriver/remote_connection.py @@ -0,0 +1,27 @@ +import socket + +try: + from httplib import HTTPException +except ImportError: + from http.client import HTTPException + +import urllib3 +from urllib3.exceptions import MaxRetryError + +from selenium.webdriver.remote import remote_connection + + +# Get the original _request and store for future use in the monkey patched version as 'super' +old_request = remote_connection.RemoteConnection._request + + +def patch_request(self, *args, **kwargs): + """Override _request to set socket timeout to some appropriate value.""" + exception = HTTPException('Unable to get response') + for _ in range(3): + try: + return old_request(self, *args, **kwargs) + except (socket.error, HTTPException, IOError, OSError, MaxRetryError) as exc: + exception = exc + self._conn = urllib3.PoolManager(timeout=self._timeout) + raise exception