Skip to content

Commit d200f49

Browse files
authored
Merge pull request #3325 from seleniumbase/pytest-and-threading-updates
`pytest` and multi-threading updates
2 parents a353c53 + d1c7fd0 commit d200f49

18 files changed

+177
-48
lines changed

examples/tour_examples/bootstrap_google_tour.py

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ def test_google_tour(self):
3434
self.wait_for_element("#searchboxinput", timeout=20)
3535
self.wait_for_element("#minimap", timeout=20)
3636
self.wait_for_element("#zoom", timeout=20)
37+
self.wait_for_element("#widget-zoom-out")
38+
self.wait_for_element('[jsaction*="minimap.main;"]')
3739

3840
self.create_bootstrap_tour()
3941
self.add_tour_step("Welcome to Google Maps", title="SeleniumBase Tour")

examples/tour_examples/driverjs_maps_tour.py

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ def test_create_tour(self):
88
self.wait_for_element("#searchboxinput", timeout=20)
99
self.wait_for_element("#minimap", timeout=20)
1010
self.wait_for_element("#zoom", timeout=20)
11+
self.wait_for_element("#widget-zoom-out")
12+
self.wait_for_element('[jsaction*="minimap.main;"]')
1113

1214
# Create a website tour using the DriverJS library
1315
# Same as: self.create_driverjs_tour()

examples/tour_examples/google_tour.py

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ def test_google_tour(self):
4040
self.wait_for_element("#searchboxinput")
4141
self.wait_for_element("#minimap")
4242
self.wait_for_element("#zoom")
43+
self.wait_for_element("#widget-zoom-out")
44+
self.wait_for_element('[jsaction*="minimap.main;"]')
4345

4446
# Create a website tour using the IntroJS library
4547
# Same as: self.create_introjs_tour()

examples/tour_examples/hopscotch_google_tour.py

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ def test_google_tour(self):
3434
self.wait_for_element("#searchboxinput", timeout=20)
3535
self.wait_for_element("#minimap", timeout=20)
3636
self.wait_for_element("#zoom", timeout=20)
37+
self.wait_for_element("#widget-zoom-out")
38+
self.wait_for_element('[jsaction*="minimap.main;"]')
3739

3840
self.create_hopscotch_tour()
3941
self.add_tour_step("Welcome to Google Maps", title="SeleniumBase Tour")

examples/tour_examples/introjs_google_tour.py

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ def test_google_tour(self):
3434
self.wait_for_element("#searchboxinput", timeout=20)
3535
self.wait_for_element("#minimap", timeout=20)
3636
self.wait_for_element("#zoom", timeout=20)
37+
self.wait_for_element("#widget-zoom-out")
38+
self.wait_for_element('[jsaction*="minimap.main;"]')
3739

3840
self.set_introjs_colors("#f26721", "#db5409")
3941
self.create_introjs_tour()

examples/tour_examples/maps_introjs_tour.py

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ def test_google_maps_tour(self):
88
self.wait_for_element("#searchboxinput", timeout=20)
99
self.wait_for_element("#minimap", timeout=20)
1010
self.wait_for_element("#zoom", timeout=20)
11+
self.wait_for_element("#widget-zoom-out")
12+
self.wait_for_element('[jsaction*="minimap.main;"]')
1113

1214
self.create_tour(theme="introjs")
1315
self.add_tour_step(

examples/tour_examples/shepherd_google_tour.py

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ def test_google_tour(self):
3434
self.wait_for_element("#searchboxinput", timeout=20)
3535
self.wait_for_element("#minimap", timeout=20)
3636
self.wait_for_element("#zoom", timeout=20)
37+
self.wait_for_element("#widget-zoom-out")
38+
self.wait_for_element('[jsaction*="minimap.main;"]')
3739

3840
self.create_shepherd_tour(theme="dark")
3941
self.add_tour_step("Welcome to Google Maps!")

mkdocs_build/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ lxml==5.3.0
2020
pyquery==2.0.1
2121
readtime==3.0.0
2222
mkdocs==1.6.1
23-
mkdocs-material==9.5.47
23+
mkdocs-material==9.5.48
2424
mkdocs-exclude-search==0.6.6
2525
mkdocs-simple-hooks==0.1.5
2626
mkdocs-material-extensions==1.3.1

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ rich==13.9.4
6464
# ("pip install -r requirements.txt" also installs this, but "pip install -e ." won't.)
6565

6666
coverage>=7.6.1;python_version<"3.9"
67-
coverage>=7.6.8;python_version>="3.9"
67+
coverage>=7.6.9;python_version>="3.9"
6868
pytest-cov>=5.0.0;python_version<"3.9"
6969
pytest-cov>=6.0.0;python_version>="3.9"
7070
flake8==5.0.4;python_version<"3.9"

seleniumbase/__version__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# seleniumbase package
2-
__version__ = "4.33.5"
2+
__version__ = "4.33.6"

seleniumbase/core/browser_launcher.py

+57-25
Original file line numberDiff line numberDiff line change
@@ -97,26 +97,12 @@ def log_d(message):
9797
print(message)
9898

9999

100-
def make_writable(file_path):
101-
# Set permissions to: "If you can read it, you can write it."
102-
mode = os.stat(file_path).st_mode
103-
mode |= (mode & 0o444) >> 1 # copy R bits to W
104-
os.chmod(file_path, mode)
105-
106-
107-
def make_executable(file_path):
108-
# Set permissions to: "If you can read it, you can execute it."
109-
mode = os.stat(file_path).st_mode
110-
mode |= (mode & 0o444) >> 2 # copy R bits to X
111-
os.chmod(file_path, mode)
112-
113-
114100
def make_driver_executable_if_not(driver_path):
115101
# Verify driver has executable permissions. If not, add them.
116102
permissions = oct(os.stat(driver_path)[0])[-3:]
117103
if "4" in permissions or "6" in permissions:
118104
# We want at least a '5' or '7' to make sure it's executable
119-
make_executable(driver_path)
105+
shared_utils.make_executable(driver_path)
120106

121107

122108
def extend_driver(driver):
@@ -566,6 +552,10 @@ def uc_open_with_cdp_mode(driver, url=None):
566552
for tab in driver.cdp_base.tabs[-1::-1]:
567553
if "chrome-extension://" not in str(tab):
568554
with gui_lock:
555+
with suppress(Exception):
556+
shared_utils.make_writable(
557+
constants.MultiBrowser.PYAUTOGUILOCK
558+
)
569559
loop.run_until_complete(tab.activate())
570560
break
571561

@@ -580,11 +570,17 @@ def uc_open_with_cdp_mode(driver, url=None):
580570
if page_tab:
581571
loop.run_until_complete(page_tab.aopen())
582572
with gui_lock:
573+
with suppress(Exception):
574+
shared_utils.make_writable(
575+
constants.MultiBrowser.PYAUTOGUILOCK
576+
)
583577
loop.run_until_complete(page_tab.activate())
584578

585579
loop.run_until_complete(driver.cdp_base.update_targets())
586580
page = loop.run_until_complete(driver.cdp_base.get(url))
587581
with gui_lock:
582+
with suppress(Exception):
583+
shared_utils.make_writable(constants.MultiBrowser.PYAUTOGUILOCK)
588584
loop.run_until_complete(page.activate())
589585
loop.run_until_complete(page.wait())
590586
if not safe_url:
@@ -883,17 +879,12 @@ def install_pyautogui_if_missing(driver):
883879
with pip_find_lock:
884880
pass
885881
except Exception:
886-
# Need write permissions
887-
with suppress(Exception):
888-
make_writable(constants.PipInstall.FINDLOCK)
889-
try:
890-
with pip_find_lock:
891-
pass
892-
except Exception:
893-
# Since missing permissions, skip the locks
894-
__install_pyautogui_if_missing()
895-
return
882+
# Since missing permissions, skip the locks
883+
__install_pyautogui_if_missing()
884+
return
896885
with pip_find_lock: # Prevent issues with multiple processes
886+
with suppress(Exception):
887+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
897888
__install_pyautogui_if_missing()
898889

899890

@@ -1789,6 +1780,8 @@ def _add_chrome_proxy_extension(
17891780
if zip_it:
17901781
proxy_zip_lock = fasteners.InterProcessLock(PROXY_ZIP_LOCK)
17911782
with proxy_zip_lock:
1783+
with suppress(Exception):
1784+
shared_utils.make_writable(PROXY_ZIP_LOCK)
17921785
if multi_proxy:
17931786
_set_proxy_filenames()
17941787
if not os.path.exists(proxy_helper.PROXY_ZIP_PATH):
@@ -1800,6 +1793,8 @@ def _add_chrome_proxy_extension(
18001793
else:
18011794
proxy_dir_lock = fasteners.InterProcessLock(PROXY_DIR_LOCK)
18021795
with proxy_dir_lock:
1796+
with suppress(Exception):
1797+
shared_utils.make_writable(PROXY_DIR_LOCK)
18031798
if multi_proxy:
18041799
_set_proxy_filenames()
18051800
if not os.path.exists(proxy_helper.PROXY_DIR_PATH):
@@ -1825,6 +1820,8 @@ def is_using_uc(undetectable, browser_name):
18251820
def _unzip_to_new_folder(zip_file, folder):
18261821
proxy_dir_lock = fasteners.InterProcessLock(PROXY_DIR_LOCK)
18271822
with proxy_dir_lock:
1823+
with suppress(Exception):
1824+
shared_utils.make_writable(PROXY_DIR_LOCK)
18281825
if not os.path.exists(folder):
18291826
import zipfile
18301827
zip_ref = zipfile.ZipFile(zip_file, "r")
@@ -2934,6 +2931,8 @@ def get_remote_driver(
29342931
constants.PipInstall.FINDLOCK
29352932
)
29362933
with pip_find_lock: # Prevent issues with multiple processes
2934+
with suppress(Exception):
2935+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
29372936
try:
29382937
from seleniumwire import webdriver
29392938
import blinker
@@ -3371,6 +3370,8 @@ def get_local_driver(
33713370
constants.PipInstall.FINDLOCK
33723371
)
33733372
with pip_find_lock: # Prevent issues with multiple processes
3373+
with suppress(Exception):
3374+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
33743375
try:
33753376
from seleniumwire import webdriver
33763377
import blinker
@@ -3434,6 +3435,10 @@ def get_local_driver(
34343435
constants.MultiBrowser.DRIVER_FIXING_LOCK
34353436
)
34363437
with geckodriver_fixing_lock:
3438+
with suppress(Exception):
3439+
shared_utils.make_writable(
3440+
constants.MultiBrowser.DRIVER_FIXING_LOCK
3441+
)
34373442
if not geckodriver_on_path():
34383443
sys_args = sys.argv # Save a copy of sys args
34393444
log_d(
@@ -3736,6 +3741,10 @@ def get_local_driver(
37363741
constants.MultiBrowser.DRIVER_FIXING_LOCK
37373742
)
37383743
with edgedriver_fixing_lock:
3744+
with suppress(Exception):
3745+
shared_utils.make_writable(
3746+
constants.MultiBrowser.DRIVER_FIXING_LOCK
3747+
)
37393748
msg = "Microsoft Edge Driver not found."
37403749
if edgedriver_upgrade_needed:
37413750
msg = "Microsoft Edge Driver update needed."
@@ -4119,6 +4128,10 @@ def get_local_driver(
41194128
constants.MultiBrowser.DRIVER_FIXING_LOCK
41204129
)
41214130
with edgedriver_fixing_lock:
4131+
with suppress(Exception):
4132+
shared_utils.make_writable(
4133+
constants.MultiBrowser.DRIVER_FIXING_LOCK
4134+
)
41224135
with suppress(Exception):
41234136
if not _was_driver_repaired():
41244137
_repair_edgedriver(edge_version)
@@ -4501,6 +4514,10 @@ def get_local_driver(
45014514
constants.MultiBrowser.DRIVER_FIXING_LOCK
45024515
)
45034516
with chromedriver_fixing_lock:
4517+
with suppress(Exception):
4518+
shared_utils.make_writable(
4519+
constants.MultiBrowser.DRIVER_FIXING_LOCK
4520+
)
45044521
msg = "chromedriver update needed. Getting it now:"
45054522
if not path_chromedriver:
45064523
msg = "chromedriver not found. Getting it now:"
@@ -4592,6 +4609,10 @@ def get_local_driver(
45924609
constants.MultiBrowser.DRIVER_FIXING_LOCK
45934610
)
45944611
with uc_lock: # Avoid multithreaded issues
4612+
with suppress(Exception):
4613+
shared_utils.make_writable(
4614+
constants.MultiBrowser.DRIVER_FIXING_LOCK
4615+
)
45954616
if make_uc_driver_from_chromedriver:
45964617
if os.path.exists(LOCAL_CHROMEDRIVER):
45974618
with suppress(Exception):
@@ -4851,6 +4872,10 @@ def get_local_driver(
48514872
if not os.path.exists(cf_lock_path):
48524873
# Avoid multithreaded issues
48534874
with cf_lock:
4875+
with suppress(Exception):
4876+
shared_utils.make_writable(
4877+
cf_lock_path
4878+
)
48544879
# Install Python Certificates (MAC)
48554880
os.system(
48564881
r"bash /Applications/Python*/"
@@ -4994,6 +5019,10 @@ def get_local_driver(
49945019
constants.MultiBrowser.DRIVER_FIXING_LOCK
49955020
)
49965021
with chromedriver_fixing_lock:
5022+
with suppress(Exception):
5023+
shared_utils.make_writable(
5024+
constants.MultiBrowser.DRIVER_FIXING_LOCK
5025+
)
49975026
if not _was_driver_repaired():
49985027
_repair_chromedriver(
49995028
chrome_options, headless_options, mcv
@@ -5192,7 +5221,10 @@ def get_local_driver(
51925221
chromedr_fixing_lock = fasteners.InterProcessLock(
51935222
constants.MultiBrowser.DRIVER_FIXING_LOCK
51945223
)
5224+
D_F_L = constants.MultiBrowser.DRIVER_FIXING_LOCK
51955225
with chromedr_fixing_lock:
5226+
with suppress(Exception):
5227+
shared_utils.make_writable(D_F_L)
51965228
if not _was_driver_repaired():
51975229
with suppress(Exception):
51985230
_repair_chromedriver(

seleniumbase/core/log_helper.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -339,9 +339,10 @@ def log_skipped_test_data(test, test_logpath, driver, browser, reason):
339339
data_to_save.append(" * Skip Reason: %s" % reason)
340340
data_to_save.append("")
341341
file_path = os.path.join(test_logpath, "skip_reason.txt")
342-
log_file = codecs.open(file_path, "w+", encoding="utf-8")
343-
log_file.writelines("\r\n".join(data_to_save))
344-
log_file.close()
342+
with suppress(Exception):
343+
log_file = codecs.open(file_path, "w+", encoding="utf-8")
344+
log_file.writelines("\r\n".join(data_to_save))
345+
log_file.close()
345346

346347

347348
def log_page_source(test_logpath, driver, source=None):
@@ -368,9 +369,10 @@ def log_page_source(test_logpath, driver, source=None):
368369
if not os.path.exists(test_logpath):
369370
os.makedirs(test_logpath)
370371
html_file_path = os.path.join(test_logpath, html_file_name)
371-
html_file = codecs.open(html_file_path, "w+", encoding="utf-8")
372-
html_file.write(page_source)
373-
html_file.close()
372+
with suppress(Exception):
373+
html_file = codecs.open(html_file_path, "w+", encoding="utf-8")
374+
html_file.write(page_source)
375+
html_file.close()
374376

375377

376378
def get_test_id(test):

seleniumbase/core/sb_cdp.py

+12
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,10 @@ def set_attributes(self, selector, attribute, value):
10191019
with suppress(Exception):
10201020
self.loop.run_until_complete(self.page.evaluate(js_code))
10211021

1022+
def __make_sure_pyautogui_lock_is_writable(self):
1023+
with suppress(Exception):
1024+
shared_utils.make_writable(constants.MultiBrowser.PYAUTOGUILOCK)
1025+
10221026
def __verify_pyautogui_has_a_headed_browser(self):
10231027
"""PyAutoGUI requires a headed browser so that it can
10241028
focus on the correct element when performing actions."""
@@ -1039,6 +1043,8 @@ def __install_pyautogui_if_missing(self):
10391043
constants.PipInstall.FINDLOCK
10401044
)
10411045
with pip_find_lock: # Prevent issues with multiple processes
1046+
with suppress(Exception):
1047+
shared_utils.make_writable(constants.PipInstall.FINDLOCK)
10421048
try:
10431049
import pyautogui
10441050
with suppress(Exception):
@@ -1124,6 +1130,7 @@ def gui_press_key(self, key):
11241130
constants.MultiBrowser.PYAUTOGUILOCK
11251131
)
11261132
with gui_lock:
1133+
self.__make_sure_pyautogui_lock_is_writable()
11271134
pyautogui.press(key)
11281135
time.sleep(0.044)
11291136
self.__slow_mode_pause_if_set()
@@ -1137,6 +1144,7 @@ def gui_press_keys(self, keys):
11371144
constants.MultiBrowser.PYAUTOGUILOCK
11381145
)
11391146
with gui_lock:
1147+
self.__make_sure_pyautogui_lock_is_writable()
11401148
for key in keys:
11411149
pyautogui.press(key)
11421150
time.sleep(0.044)
@@ -1151,6 +1159,7 @@ def gui_write(self, text):
11511159
constants.MultiBrowser.PYAUTOGUILOCK
11521160
)
11531161
with gui_lock:
1162+
self.__make_sure_pyautogui_lock_is_writable()
11541163
pyautogui.write(text)
11551164
self.__slow_mode_pause_if_set()
11561165
self.loop.run_until_complete(self.page.wait())
@@ -1171,6 +1180,7 @@ def __gui_click_x_y(self, x, y, timeframe=0.25, uc_lock=False):
11711180
constants.MultiBrowser.PYAUTOGUILOCK
11721181
)
11731182
with gui_lock: # Prevent issues with multiple processes
1183+
self.__make_sure_pyautogui_lock_is_writable()
11741184
pyautogui.moveTo(x, y, timeframe, pyautogui.easeOutQuad)
11751185
if timeframe >= 0.25:
11761186
time.sleep(0.056) # Wait if moving at human-speed
@@ -1191,6 +1201,7 @@ def gui_click_x_y(self, x, y, timeframe=0.25):
11911201
constants.MultiBrowser.PYAUTOGUILOCK
11921202
)
11931203
with gui_lock: # Prevent issues with multiple processes
1204+
self.__make_sure_pyautogui_lock_is_writable()
11941205
self.__install_pyautogui_if_missing()
11951206
import pyautogui
11961207
pyautogui = self.__get_configured_pyautogui(pyautogui)
@@ -1408,6 +1419,7 @@ def gui_hover_and_click(self, hover_selector, click_selector):
14081419
constants.MultiBrowser.PYAUTOGUILOCK
14091420
)
14101421
with gui_lock:
1422+
self.__make_sure_pyautogui_lock_is_writable()
14111423
self.bring_active_window_to_front()
14121424
self.gui_hover_element(hover_selector)
14131425
time.sleep(0.15)

0 commit comments

Comments
 (0)