Skip to content

Commit 6a2017f

Browse files
committed
feat(browser drivers): Changed drivers to use Options and Service objects.
- Everything else is depreciated as of 4.0.0 - Firefox profile directory can no longer by set by selenium. SeleniumHQ/selenium#9949 - Removed save_working_profile_directory from utils.py
1 parent 19c556c commit 6a2017f

File tree

4 files changed

+51
-122
lines changed

4 files changed

+51
-122
lines changed

iarp_utils/browser/browsers.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -502,15 +502,15 @@ class FirefoxBrowser(BrowserBase):
502502
"""
503503
BrowserBase preconfigured to run as Firefox browser.
504504
"""
505-
def __init__(self, *args, profile_directory=None, **kwargs):
505+
def __init__(self, *args, **kwargs):
506506
kwargs['selected_driver'] = FirefoxDriver
507-
super().__init__(*args, profile_directory=profile_directory, **kwargs)
507+
super().__init__(*args, **kwargs)
508508

509509

510510
class ChromeBrowser(BrowserBase):
511511
"""
512512
BrowserBase preconfigured to run as Chrome browser.
513513
"""
514-
def __init__(self, *args, user_data_directory=None, user_data_profile=None, **kwargs):
514+
def __init__(self, *args, **kwargs):
515515
kwargs['selected_driver'] = ChromeDriver
516-
super().__init__(*args, user_data_directory=user_data_directory, user_data_profile=user_data_profile, **kwargs)
516+
super().__init__(*args, **kwargs)

iarp_utils/browser/drivers.py

Lines changed: 46 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
from selenium.webdriver.remote.webdriver import (
2626
WebDriver as RemoteWebDriver,
2727
)
28+
from selenium.webdriver.chrome.options import Options as _ChromeOptions
29+
from selenium.webdriver.chrome.service import Service as _ChromeService
30+
from selenium.webdriver.firefox.options import Options as _FirefoxOptions
31+
from selenium.webdriver.firefox.service import Service as _FirefoxService
2832
except ImportError:
2933
webdriver = None
3034

@@ -117,33 +121,37 @@ def webdriver(self):
117121
def driver(self):
118122
raise NotImplementedError('driver property must be supplied')
119123

124+
@property
125+
def service_class(self):
126+
raise NotImplementedError('service_class property must be supplied')
127+
128+
@property
129+
def options_class(self):
130+
raise NotImplementedError('options_class property must be supplied')
131+
120132
@property
121133
def browser(self) -> RemoteWebDriver:
122134
return self._browser
123135

124-
def get_driver_arguments(self, **kwargs):
125-
""" Returns a dict ready for driver initialization, base locates the driver.
136+
def get_driver_options(self):
137+
return self.options_class()
126138

127-
Args:
128-
**kwargs: other keyword params to pass
139+
def get_driver_service(self):
140+
service = self.service_class()
129141

130-
Returns:
131-
dict
132-
"""
142+
if not WEBDRIVER_IN_PATH:
133143

134-
if WEBDRIVER_IN_PATH:
135-
return kwargs
144+
try:
145+
binary = self.binary_location()
146+
except FileNotFoundError:
147+
# If the binary file could not be found, run a version check
148+
# which will download the latest by default.
149+
self.check_driver_version()
150+
binary = self.binary_location()
136151

137-
try:
138-
binary = self.binary_location()
139-
except FileNotFoundError:
140-
# If the binary file could not be found, run a version check
141-
# which will download the latest by default.
142-
self.check_driver_version()
143-
binary = self.binary_location()
152+
service.path = binary
144153

145-
kwargs.update({'executable_path': binary})
146-
return kwargs
154+
return service
147155

148156
def start(self):
149157
""" Starts the driver and browser with all options. """
@@ -153,8 +161,10 @@ def start(self):
153161
if self._check_driver_version_allowed():
154162
self.check_driver_version()
155163

156-
options = self.get_driver_arguments()
157-
self._browser = self.webdriver(**options)
164+
options = self.get_driver_options()
165+
service = self.get_driver_service()
166+
167+
self._browser = self.webdriver(options=options, service=service)
158168

159169
return self.browser
160170

@@ -293,44 +303,25 @@ def get_driver_version(self):
293303
log.debug(f'{self.__class__.__name__} binary version: found {version}')
294304
return version
295305

296-
def _get_active_profile_data_directory(self):
297-
raise NotImplementedError
298-
299306

300307
class ChromeDriver(DriverBase):
301308
webdriver = webdriver.Chrome
302309
driver = 'chromedriver.exe' if IS_WINDOWS_OS else 'chromedriver'
310+
service_class = _ChromeService
311+
options_class = _ChromeOptions
303312

304-
def __init__(self, user_data_directory=None, user_data_profile=None, **kwargs):
305-
self._user_data_directory = user_data_directory
306-
self._user_data_profile = user_data_profile
313+
def __init__(self, **kwargs):
307314
super().__init__(**kwargs)
308315

309316
if self.headless and not self.user_agent:
310317
# Headless Chrome sends a user agent telling the website its headless. Lets override that.
311318
self.user_agent = f'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 ' \
312319
f'(KHTML, like Gecko) Chrome/{utils.chrome_version()} Safari/537.36'
313320

314-
def get_browser_user_data_directory(self):
315-
# Where is the user data directory?
316-
return self._user_data_directory
317-
318-
def get_browser_user_data_profile(self):
319-
# Which profile within the user_data_directory do we need to load?
320-
return self._user_data_profile
321-
322-
def get_browser_options(self):
323-
options = webdriver.ChromeOptions()
321+
def get_driver_options(self):
322+
options = super().get_driver_options()
324323
options.headless = self.headless
325324

326-
uddir = self.get_browser_user_data_directory()
327-
if uddir:
328-
options.add_argument(f"--user-data-dir={uddir}")
329-
330-
uddprofile = self.get_browser_user_data_profile()
331-
if uddprofile:
332-
options.add_argument(f'--profile-directory={uddprofile}')
333-
334325
if self.download_directory:
335326
options.add_experimental_option('prefs', {
336327
'download.default_directory': self.download_directory
@@ -341,11 +332,6 @@ def get_browser_options(self):
341332

342333
return options
343334

344-
def get_driver_arguments(self):
345-
return super().get_driver_arguments(
346-
options=self.get_browser_options(),
347-
)
348-
349335
def get_browser_version(self):
350336
capabilities = self.get_capabilities()
351337
try:
@@ -435,50 +421,29 @@ def check_driver_version(self):
435421
extracting_file=self.driver
436422
)
437423

438-
def _get_active_profile_data_directory(self):
439-
capabilities = self.get_capabilities()
440-
return capabilities['chrome']['userDataDir']
441-
442424

443425
class FirefoxDriver(DriverBase):
444426
driver = 'geckodriver.exe' if IS_WINDOWS_OS else 'geckodriver'
445427
webdriver = webdriver.Firefox
428+
service_class = _FirefoxService
429+
options_class = _FirefoxOptions
446430

447-
def __init__(self, profile_directory=None, **kwargs):
448-
self._profile_directory = profile_directory
449-
super().__init__(**kwargs)
450-
451-
def get_browser_profile_directory(self):
452-
return self._profile_directory
453-
454-
def get_browser_profile(self):
455-
profile = webdriver.FirefoxProfile(
456-
profile_directory=self.get_browser_profile_directory()
457-
)
431+
def get_driver_options(self):
432+
options = super().get_driver_options()
433+
options.headless = self.headless
458434

459435
if self.download_directory:
460-
profile.set_preference('browser.download.folderList', 2)
461-
profile.set_preference('pdfjs.disabled', True)
462-
profile.set_preference('browser.download.dir', self.download_directory)
463-
profile.set_preference("browser.helperApps.neverAsk.saveToDisk", get_mime_types_as_str(joiner=','))
464-
profile.set_preference('browser.helperApps.alwaysAsk.force', False)
436+
options.set_preference('browser.download.folderList', 2)
437+
options.set_preference('pdfjs.disabled', True)
438+
options.set_preference('browser.download.dir', self.download_directory)
439+
options.set_preference("browser.helperApps.neverAsk.saveToDisk", get_mime_types_as_str(joiner=','))
440+
options.set_preference('browser.helperApps.alwaysAsk.force', False)
465441

466442
if self.user_agent:
467-
profile.set_preference("general.useragent.override", self.user_agent)
443+
options.set_preference("general.useragent.override", self.user_agent)
468444

469-
return profile
470-
471-
def get_browser_options(self):
472-
options = webdriver.FirefoxOptions()
473-
options.headless = self.headless
474445
return options
475446

476-
def get_driver_arguments(self):
477-
return super().get_driver_arguments(
478-
options=self.get_browser_options(),
479-
firefox_profile=self.get_browser_profile()
480-
)
481-
482447
def get_driver_version(self):
483448
try:
484449
version = super().get_driver_version()
@@ -551,7 +516,3 @@ def check_driver_version(self):
551516
local_zip_file=local_zip_file,
552517
extracting_file=self.driver
553518
)
554-
555-
def _get_active_profile_data_directory(self):
556-
capabilities = self.get_capabilities()
557-
return capabilities["moz:profile"]

iarp_utils/browser/utils.py

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
import os
21
import re
32
import subprocess
4-
import shutil
5-
import time
63

74
from ..system import OSTypes
85

@@ -96,32 +93,3 @@ def _process_version_commands(name, cmds, pattern=r'\d+\.\d+\.\d+\.\d+|\d+\.\d+\
9693
if not version:
9794
raise ValueError(f'Could not process version for {name} commands output: {cmds}')
9895
return version.group(0)
99-
100-
101-
def save_working_profile_directory(driver, profile_storage_path):
102-
""" Saves the currently in-use browser profile directory to a custom location.
103-
104-
Args:
105-
driver: The driver running the
106-
profile_storage_path: Where to save the profiles contents.
107-
"""
108-
109-
driver.browser.execute_script("window.close()")
110-
111-
time.sleep(0.5)
112-
113-
# Copy the profile directory (must be done BEFORE driver.quit()!)
114-
current_profile_path = driver.active_driver._get_active_profile_data_directory()
115-
116-
assert os.path.isdir(current_profile_path)
117-
118-
try:
119-
shutil.rmtree(profile_storage_path)
120-
except FileNotFoundError:
121-
pass
122-
123-
shutil.copytree(
124-
src=current_profile_path,
125-
dst=profile_storage_path,
126-
ignore_dangling_symlinks=True
127-
)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name='iarp_utils',
5-
version='1.3.0',
5+
version='2.0.0',
66
description='A personal collection of common python utilities used in various projects',
77
url='https://bitbucket.org/iarp/iarp-python-utils/',
88
author='IARP',

0 commit comments

Comments
 (0)