Skip to content

Commit 3dbaf41

Browse files
authored
Merge pull request #2884 from seleniumbase/better-uc-mode-multithreading
Improve multithreading in UC Mode
2 parents 5a23445 + 9ce7863 commit 3dbaf41

File tree

6 files changed

+55
-33
lines changed

6 files changed

+55
-33
lines changed

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ pygments==2.17.2;python_version<"3.8"
6464
pygments==2.18.0;python_version>="3.8"
6565
pyreadline3==3.4.1;platform_system=="Windows"
6666
tabcompleter==1.3.0
67-
pdbp==1.5.0
67+
pdbp==1.5.1
6868
colorama==0.4.6
6969
pyotp==2.9.0
7070
python-xlib==0.33;platform_system=="Linux"

seleniumbase/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# seleniumbase package
2-
__version__ = "4.28.1"
2+
__version__ = "4.28.2"

seleniumbase/core/browser_launcher.py

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,9 @@ def uc_special_open_if_cf(
389389
driver.execute_script('window.open("%s","_blank");' % url)
390390
driver.close()
391391
if mobile_emulator:
392-
driver.switch_to.window(driver.window_handles[-1])
392+
page_actions.switch_to_window(
393+
driver, driver.window_handles[-1], 2
394+
)
393395
uc_metrics = {}
394396
if (
395397
isinstance(device_width, int)
@@ -419,7 +421,9 @@ def uc_special_open_if_cf(
419421
except Exception:
420422
pass
421423
if not mobile_emulator:
422-
driver.switch_to.window(driver.window_handles[-1])
424+
page_actions.switch_to_window(
425+
driver, driver.window_handles[-1], 2
426+
)
423427
else:
424428
driver.default_get(url) # The original one
425429
else:
@@ -450,7 +454,7 @@ def uc_open_with_tab(driver, url):
450454
with driver:
451455
driver.execute_script('window.open("%s","_blank");' % url)
452456
driver.close()
453-
driver.switch_to.window(driver.window_handles[-1])
457+
page_actions.switch_to_window(driver, driver.window_handles[-1], 2)
454458
else:
455459
driver.default_get(url) # The original one
456460
return None
@@ -476,10 +480,14 @@ def uc_open_with_reconnect(driver, url, reconnect_time=None):
476480
driver.reconnect(reconnect_time)
477481
time.sleep(0.004)
478482
try:
479-
driver.switch_to.window(driver.window_handles[-1])
483+
page_actions.switch_to_window(
484+
driver, driver.window_handles[-1], 2
485+
)
480486
except InvalidSessionIdException:
481487
time.sleep(0.05)
482-
driver.switch_to.window(driver.window_handles[-1])
488+
page_actions.switch_to_window(
489+
driver, driver.window_handles[-1], 2
490+
)
483491
else:
484492
driver.default_get(url) # The original one
485493
return None
@@ -546,17 +554,17 @@ def uc_click(
546554
driver.reconnect(reconnect_time)
547555

548556

549-
def verify_pyautogui_has_a_headed_browser():
557+
def verify_pyautogui_has_a_headed_browser(driver):
550558
"""PyAutoGUI requires a headed browser so that it can
551559
focus on the correct element when performing actions."""
552-
if sb_config.headless or sb_config.headless2:
560+
if hasattr(driver, "_is_hidden") and driver._is_hidden:
553561
raise Exception(
554562
"PyAutoGUI can't be used in headless mode!"
555563
)
556564

557565

558-
def install_pyautogui_if_missing():
559-
verify_pyautogui_has_a_headed_browser()
566+
def install_pyautogui_if_missing(driver):
567+
verify_pyautogui_has_a_headed_browser(driver)
560568
pip_find_lock = fasteners.InterProcessLock(
561569
constants.PipInstall.FINDLOCK
562570
)
@@ -608,7 +616,7 @@ def get_configured_pyautogui(pyautogui_copy):
608616

609617

610618
def uc_gui_press_key(driver, key):
611-
install_pyautogui_if_missing()
619+
install_pyautogui_if_missing(driver)
612620
import pyautogui
613621
pyautogui = get_configured_pyautogui(pyautogui)
614622
gui_lock = fasteners.InterProcessLock(
@@ -619,7 +627,7 @@ def uc_gui_press_key(driver, key):
619627

620628

621629
def uc_gui_press_keys(driver, keys):
622-
install_pyautogui_if_missing()
630+
install_pyautogui_if_missing(driver)
623631
import pyautogui
624632
pyautogui = get_configured_pyautogui(pyautogui)
625633
gui_lock = fasteners.InterProcessLock(
@@ -631,7 +639,7 @@ def uc_gui_press_keys(driver, keys):
631639

632640

633641
def uc_gui_write(driver, text):
634-
install_pyautogui_if_missing()
642+
install_pyautogui_if_missing(driver)
635643
import pyautogui
636644
pyautogui = get_configured_pyautogui(pyautogui)
637645
gui_lock = fasteners.InterProcessLock(
@@ -648,7 +656,7 @@ def uc_gui_handle_cf(driver, frame="iframe"):
648656
and 'aria-label="Cloudflare"' not in source
649657
):
650658
return
651-
install_pyautogui_if_missing()
659+
install_pyautogui_if_missing(driver)
652660
import pyautogui
653661
pyautogui = get_configured_pyautogui(pyautogui)
654662
gui_lock = fasteners.InterProcessLock(
@@ -664,9 +672,7 @@ def uc_gui_handle_cf(driver, frame="iframe"):
664672
if not is_in_frame:
665673
# Make sure the window is on top
666674
page_actions.switch_to_window(
667-
driver,
668-
driver.current_window_handle,
669-
timeout=settings.SMALL_TIMEOUT,
675+
driver, driver.current_window_handle, 2
670676
)
671677
if not is_in_frame or needs_switch:
672678
# Currently not in frame (or nested frame outside CF one)
@@ -1634,10 +1640,6 @@ def get_driver(
16341640
if headless2 and browser_name == constants.Browser.FIREFOX:
16351641
headless2 = False # Only for Chromium
16361642
headless = True
1637-
if not hasattr(sb_config, "headless"):
1638-
sb_config.headless = headless
1639-
if not hasattr(sb_config, "headless2"):
1640-
sb_config.headless2 = headless2
16411643
if (
16421644
binary_location
16431645
and isinstance(binary_location, str)
@@ -4035,6 +4037,8 @@ def get_local_driver(
40354037
driver, *args, **kwargs
40364038
)
40374039
)
4040+
driver._is_hidden = (headless or headless2)
4041+
driver._is_using_uc = True
40384042
if mobile_emulator:
40394043
uc_metrics = {}
40404044
if (

seleniumbase/fixtures/page_actions.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
By.PARTIAL_LINK_TEXT # "partial link text"
1919
"""
2020
import codecs
21+
import fasteners
2122
import os
2223
import time
2324
from selenium.common.exceptions import ElementNotInteractableException
@@ -32,6 +33,7 @@
3233
from seleniumbase.common.exceptions import LinkTextNotFoundException
3334
from seleniumbase.common.exceptions import TextNotVisibleException
3435
from seleniumbase.config import settings
36+
from seleniumbase.fixtures import constants
3537
from seleniumbase.fixtures import page_utils
3638
from seleniumbase.fixtures import shared_utils
3739

@@ -1428,6 +1430,18 @@ def switch_to_frame(driver, frame, timeout=settings.SMALL_TIMEOUT):
14281430
timeout_exception(Exception, message)
14291431

14301432

1433+
def __switch_to_window(driver, window_handle):
1434+
if hasattr(driver, "_is_using_uc") and driver._is_using_uc:
1435+
gui_lock = fasteners.InterProcessLock(
1436+
constants.MultiBrowser.PYAUTOGUILOCK
1437+
)
1438+
with gui_lock:
1439+
driver.switch_to.window(window_handle)
1440+
else:
1441+
driver.switch_to.window(window_handle)
1442+
return True
1443+
1444+
14311445
def switch_to_window(driver, window, timeout=settings.SMALL_TIMEOUT):
14321446
"""
14331447
Wait for a window to appear, and switch to it. This should be usable
@@ -1451,7 +1465,7 @@ def switch_to_window(driver, window, timeout=settings.SMALL_TIMEOUT):
14511465
shared_utils.check_if_time_limit_exceeded()
14521466
try:
14531467
window_handle = driver.window_handles[window]
1454-
driver.switch_to.window(window_handle)
1468+
__switch_to_window(driver, window_handle)
14551469
return True
14561470
except IndexError:
14571471
now_ms = time.time() * 1000.0
@@ -1472,7 +1486,7 @@ def switch_to_window(driver, window, timeout=settings.SMALL_TIMEOUT):
14721486
for x in range(int(timeout * 10)):
14731487
shared_utils.check_if_time_limit_exceeded()
14741488
try:
1475-
driver.switch_to.window(window_handle)
1489+
__switch_to_window(driver, window_handle)
14761490
return True
14771491
except NoSuchWindowException:
14781492
now_ms = time.time() * 1000.0

seleniumbase/undetected/__init__.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -278,15 +278,19 @@ def __init__(
278278
options.binary_location, *options.arguments
279279
)
280280
else:
281-
browser = subprocess.Popen(
282-
[options.binary_location, *options.arguments],
283-
stdin=subprocess.PIPE,
284-
stdout=subprocess.PIPE,
285-
stderr=subprocess.PIPE,
286-
close_fds=IS_POSIX,
287-
creationflags=creationflags,
281+
gui_lock = fasteners.InterProcessLock(
282+
constants.MultiBrowser.PYAUTOGUILOCK
288283
)
289-
self.browser_pid = browser.pid
284+
with gui_lock:
285+
browser = subprocess.Popen(
286+
[options.binary_location, *options.arguments],
287+
stdin=subprocess.PIPE,
288+
stdout=subprocess.PIPE,
289+
stderr=subprocess.PIPE,
290+
close_fds=IS_POSIX,
291+
creationflags=creationflags,
292+
)
293+
self.browser_pid = browser.pid
290294
service_ = None
291295
log_output = subprocess.PIPE
292296
if sys.version_info < (3, 8):

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@
212212
'pygments==2.18.0;python_version>="3.8"',
213213
'pyreadline3==3.4.1;platform_system=="Windows"',
214214
"tabcompleter==1.3.0",
215-
"pdbp==1.5.0",
215+
"pdbp==1.5.1",
216216
'colorama==0.4.6',
217217
'pyotp==2.9.0',
218218
'python-xlib==0.33;platform_system=="Linux"',

0 commit comments

Comments
 (0)