Skip to content

Commit dc75ab1

Browse files
authored
Merge pull request #4199 from seleniumbase/cdp-mode-patch-89
CDP Mode: Patch 89
2 parents 9babc67 + b8ce59d commit dc75ab1

File tree

6 files changed

+86
-22
lines changed

6 files changed

+86
-22
lines changed

mkdocs_build/requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
# Minimum Python version: 3.10 (for generating docs only)
33

44
regex>=2025.11.3
5-
pymdown-extensions>=10.19.1
5+
pymdown-extensions>=10.20
66
pipdeptree>=2.30.0
77
python-dateutil>=2.8.2
88
Markdown==3.10
99
click==8.3.1
1010
ghp-import==2.1.0
1111
watchdog==6.0.0
1212
cairocffi==1.7.1
13-
pathspec==0.12.1
13+
pathspec==1.0.1
1414
Babel==2.17.0
1515
paginate==0.5.7
1616
mkdocs==1.6.1

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ setuptools~=70.2;python_version<"3.10"
44
setuptools>=80.9.0;python_version>="3.10"
55
wheel>=0.45.1
66
attrs>=25.4.0
7-
certifi>=2025.11.12
7+
certifi>=2026.1.4
88
exceptiongroup>=1.3.1
99
websockets>=15.0.1
1010
filelock~=3.19.1;python_version<"3.10"
11-
filelock>=3.20.1;python_version>="3.10"
11+
filelock>=3.20.2;python_version>="3.10"
1212
fasteners>=0.20
1313
mycdp>=1.3.2
1414
pynose>=1.5.5

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.45.8"
2+
__version__ = "4.45.9"

seleniumbase/undetected/cdp_driver/browser.py

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from __future__ import annotations
33
import asyncio
44
import atexit
5+
import fasteners
56
import http.cookiejar
67
import json
78
import logging
@@ -15,7 +16,10 @@
1516
import urllib.request
1617
import warnings
1718
from collections import defaultdict
19+
from contextlib import suppress
1820
from seleniumbase import config as sb_config
21+
from seleniumbase.fixtures import constants
22+
from seleniumbase.fixtures import shared_utils
1923
from typing import List, Optional, Set, Tuple, Union
2024
import mycdp as cdp
2125
from . import cdp_util as util
@@ -34,7 +38,7 @@ def get_registered_instances():
3438
def deconstruct_browser():
3539
for _ in __registered__instances__:
3640
if not _.stopped:
37-
_.stop()
41+
_.stop(deconstruct=True)
3842
for attempt in range(5):
3943
try:
4044
if _.config and not _.config.uses_custom_data_dir:
@@ -732,8 +736,11 @@ async def tile_windows(self, windows=None, max_columns: int = 0):
732736
try:
733737
import mss
734738
except Exception:
735-
from seleniumbase.fixtures import shared_utils
736-
shared_utils.pip_install("mss")
739+
pip_find_lock = fasteners.InterProcessLock(
740+
constants.PipInstall.FINDLOCK
741+
)
742+
with pip_find_lock: # Prevent issues with multiple processes
743+
shared_utils.pip_install("mss")
737744
import mss
738745
m = mss.mss()
739746
screen, screen_width, screen_height = 3 * (None,)
@@ -842,11 +849,17 @@ def __next__(self):
842849
else:
843850
del self._i
844851

845-
def stop(self):
852+
def stop(self, deconstruct=False):
853+
if (
854+
not hasattr(sb_config, "_closed_connection_ids")
855+
or not isinstance(sb_config._closed_connection_ids, list)
856+
):
857+
sb_config._closed_connection_ids = []
858+
connection_id = None
859+
with suppress(Exception):
860+
connection_id = self.connection.websocket.id.hex
861+
close_success = False
846862
try:
847-
# asyncio.get_running_loop().create_task(
848-
# self.connection.send(cdp.browser.close())
849-
# )
850863
if self.connection:
851864
asyncio.get_event_loop().create_task(self.connection.aclose())
852865
logger.debug(
@@ -855,19 +868,22 @@ def stop(self):
855868
except RuntimeError:
856869
if self.connection:
857870
try:
858-
# asyncio.run(self.connection.send(cdp.browser.close()))
859871
asyncio.run(self.connection.aclose())
860872
logger.debug("Closed the connection using asyncio.run()")
861873
except Exception:
862874
pass
863875
for _ in range(3):
864876
try:
865-
self._process.terminate()
866-
logger.debug(
867-
"Terminated browser with pid %d successfully."
868-
% self._process.pid
869-
)
870-
break
877+
if connection_id not in sb_config._closed_connection_ids:
878+
self._process.terminate()
879+
logger.debug(
880+
"Terminated browser with pid %d successfully."
881+
% self._process.pid
882+
)
883+
if connection_id:
884+
sb_config._closed_connection_ids.append(connection_id)
885+
close_success = True
886+
break
871887
except (Exception,):
872888
try:
873889
self._process.kill()
@@ -902,6 +918,39 @@ def stop(self):
902918
raise
903919
self._process = None
904920
self._process_pid = None
921+
if (
922+
hasattr(sb_config, "_xvfb_users")
923+
and isinstance(sb_config._xvfb_users, int)
924+
and close_success
925+
and hasattr(sb_config, "_virtual_display")
926+
and sb_config._virtual_display
927+
):
928+
sb_config._xvfb_users -= 1
929+
if sb_config._xvfb_users < 0:
930+
sb_config._xvfb_users = 0
931+
if (
932+
shared_utils.is_linux()
933+
and (
934+
hasattr(sb_config, "_virtual_display")
935+
and sb_config._virtual_display
936+
and hasattr(sb_config._virtual_display, "stop")
937+
)
938+
and sb_config._xvfb_users == 0
939+
):
940+
try:
941+
sb_config._virtual_display.stop()
942+
sb_config._virtual_display = None
943+
sb_config.headless_active = False
944+
except AttributeError:
945+
pass
946+
except Exception:
947+
pass
948+
if (
949+
deconstruct
950+
and connection_id
951+
and connection_id in sb_config._closed_connection_ids
952+
):
953+
sb_config._closed_connection_ids.remove(connection_id)
905954

906955
def quit(self):
907956
self.stop()

seleniumbase/undetected/cdp_driver/cdp_util.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,27 @@ def __activate_virtual_display_as_needed(
5151
headless, headed, xvfb, xvfb_metrics
5252
):
5353
"""This is only needed on Linux."""
54+
reset_virtual_display = False
55+
if IS_LINUX and (not headed or xvfb):
56+
if (
57+
not hasattr(sb_config, "_closed_connection_ids")
58+
or not isinstance(sb_config._closed_connection_ids, list)
59+
):
60+
sb_config._closed_connection_ids = []
61+
if (
62+
not hasattr(sb_config, "_xvfb_users")
63+
or not isinstance(sb_config._xvfb_users, int)
64+
):
65+
reset_virtual_display = True
66+
sb_config._xvfb_users = 0
67+
sb_config._xvfb_users += 1
5468
if (
5569
IS_LINUX
5670
and (not headed or xvfb)
5771
and (
5872
not hasattr(sb_config, "_virtual_display")
5973
or not sb_config._virtual_display
74+
or reset_virtual_display
6075
)
6176
):
6277
from sbvirtualdisplay import Display

setup.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,11 @@
152152
'setuptools>=80.9.0;python_version>="3.10"',
153153
'wheel>=0.45.1',
154154
'attrs>=25.4.0',
155-
'certifi>=2025.11.12',
155+
'certifi>=2026.1.4',
156156
'exceptiongroup>=1.3.1',
157157
'websockets>=15.0.1',
158158
'filelock~=3.19.1;python_version<"3.10"',
159-
'filelock>=3.20.1;python_version>="3.10"',
159+
'filelock>=3.20.2;python_version>="3.10"',
160160
'fasteners>=0.20',
161161
'mycdp>=1.3.2',
162162
'pynose>=1.5.5',
@@ -268,7 +268,7 @@
268268
# (An optional library for image-processing.)
269269
"pillow": [
270270
'Pillow>=11.3.0;python_version<"3.10"',
271-
'Pillow>=12.0.0;python_version>="3.10"',
271+
'Pillow>=12.1.0;python_version>="3.10"',
272272
],
273273
# pip install -e .[pip-system-certs]
274274
# (If you see [SSL: CERTIFICATE_VERIFY_FAILED], then get this.)

0 commit comments

Comments
 (0)