I forked this repo to be more concise. The code is here. I'll paste it below since that seems to be the style. I removed the class definitions at the bottom that I didn't change -- the edit I'm concerned with is the use of the "class_factory" function at the bottom.
Is this good? Pythonic?
from selenium.webdriver import DesiredCapabilities
from selenium.webdriver.firefox.webdriver import WebDriver as _Firefox
from selenium.webdriver.chrome.webdriver import WebDriver as _Chrome
from selenium.webdriver.ie.webdriver import WebDriver as _Ie
from selenium.webdriver.remote.webdriver import WebDriver as _Remote
from selenium.webdriver.phantomjs.webdriver import WebDriver as _PhantomJS
from webdriverplus.utils import _download
from webdriverplus.webdriver import WebDriverDecorator
from webdriverplus.webelement import WebElement
import atexit
import os
import socket
import subprocess
import time
try:
from urllib2 import URLError
except ImportError:
from urllib.error import URLError
VERSION = (0, 2, 0)
def get_version():
return '%d.%d.%d' % (VERSION[0], VERSION[1], VERSION[2])
class WebDriver(WebDriverDecorator):
_pool = {} # name -> (instance, signature)
_quit_on_exit = set() # set of instances
_selenium_server = None # Popen object
_default_browser_name = 'firefox'
@classmethod
def _at_exit(cls):
"""
Gets registered to run on system exit.
"""
if cls._selenium_server:
cls._selenium_server.kill()
for driver in cls._quit_on_exit:
try:
driver.quit(force=True)
except URLError:
pass
@classmethod
def _clear(cls):
cls._pool.clear()
@classmethod
def _get_from_pool(cls, browser):
"""Returns (instance, (args, kwargs))"""
return cls._pool.get(browser, (None, (None, None)))
def __new__(cls, browser=None, *args, **kwargs):
browsers = {'firefox':Firefox,
'chrome':Chrome,
'ie':Ie,
'remote':Remote,
'phantomjs':PhantomJS,
'htmlunit':HtmlUnit}
quit_on_exit = kwargs.get('quit_on_exit', True)
reuse_browser = kwargs.get('reuse_browser')
signature = (args, kwargs)
browser = browser or cls._default_browser_name
reused_pooled_browser = False
pooled_browser = None
try:
is_str = isinstance(browser, basestring)
except NameError:
is_str = isinstance(browser, str)
if is_str:
browser = browser.lower()
pooled_browser, pooled_signature = WebDriver._get_from_pool(browser)
if pooled_signature == signature:
driver = pooled_browser
reused_pooled_browser = True
elif browser in browsers.keys():
driver = browsers[browser](*args, **kwargs)
else:
raise BrowserNotSupportedError()
# If a WebDriverDecorator/WebDriver is given, add it to the pool
elif isinstance(browser, WebDriverDecorator):
driver = browser
browser = driver.name
else:
kwargs['driver'] = browser
driver = WebDriverDecorator(*args, **kwargs)
browser = driver.name
if reuse_browser and not reused_pooled_browser:
if pooled_browser:
pooled_browser.quit(force=True)
WebDriver._pool[browser] = (driver, signature)
if quit_on_exit:
WebDriver._quit_on_exit.add(driver)
return driver
def __init__(self, browser='firefox', *args, **kwargs):
pass
# Not actually called. Here for autodoc purposes only.
atexit.register(WebDriver._at_exit)
browser_types = ({'name':'Firefox', 'driver':_Firefox},
{'name':'Chrome', 'driver':_Chrome},
{'name':'Ie', 'driver':_Ie},
{'name':'Remote', 'driver':_Remote},
{'name':'PhantomJS', 'driver':_PhantomJS},)
def class_factory(browser_type, bases):
class Class_(*bases):
def __init__(self, *args, **kwargs):
kwargs['driver'] = browser_type['driver']
super().__init__(*args, **kwargs)
Class_.__name__ = browser_type['name']
return Class_
for browser_type in browser_types:
globals()[browser_type['name']] = class_factory(browser_type,
(WebDriverDecorator,))