Skip to content

Commit 238ad3d

Browse files
authored
Merge pull request #3684 from seleniumbase/mostly-memory-improvements
Mostly memory improvements
2 parents b9a89f7 + 5b30240 commit 238ad3d

File tree

8 files changed

+115
-44
lines changed

8 files changed

+115
-44
lines changed

Diff for: mkdocs_build/requirements.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ regex>=2024.11.6
55
pymdown-extensions>=10.14.3
66
pipdeptree>=2.26.0
77
python-dateutil>=2.8.2
8-
Markdown==3.7
8+
Markdown==3.8
99
click==8.1.8
1010
ghp-import==2.1.0
1111
watchdog==6.0.0
@@ -14,7 +14,7 @@ pathspec==0.12.1
1414
Babel==2.17.0
1515
paginate==0.5.7
1616
mkdocs==1.6.1
17-
mkdocs-material==9.6.11
17+
mkdocs-material==9.6.12
1818
mkdocs-exclude-search==0.6.6
1919
mkdocs-simple-hooks==0.1.5
2020
mkdocs-material-extensions==1.3.1

Diff for: requirements.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pip>=25.0.1
2-
packaging>=24.2
2+
packaging>=25.0
33
setuptools~=70.2;python_version<"3.10"
44
setuptools>=78.1.0;python_version>="3.10"
55
wheel>=0.45.1
@@ -61,7 +61,7 @@ pytest-xdist==3.6.1
6161
parameterized==0.9.0
6262
behave==1.2.6
6363
soupsieve==2.6
64-
beautifulsoup4==4.13.3
64+
beautifulsoup4==4.13.4
6565
pyotp==2.9.0
6666
python-xlib==0.33;platform_system=="Linux"
6767
markdown-it-py==3.0.0

Diff for: seleniumbase/__version__.py

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

Diff for: seleniumbase/fixtures/base_case.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ def __initialize_variables(self):
162162
self.__jqc_default_theme = None
163163
self.__jqc_default_color = None
164164
self.__jqc_default_width = None
165+
self.__saved_id = None
165166
# Requires self._* instead of self.__* for external class use
166167
self._language = "English"
167168
self._presentation_slides = {}
@@ -15676,19 +15677,24 @@ def __get_test_id(self):
1567615677
test_id = "%s.%s" % (file_name, scenario_name)
1567715678
return test_id
1567815679
elif hasattr(self, "is_context_manager") and self.is_context_manager:
15680+
if hasattr(self, "_manager_saved_id"):
15681+
self.__saved_id = self._manager_saved_id
15682+
if self.__saved_id:
15683+
return self.__saved_id
1567915684
filename = self.__class__.__module__.split(".")[-1] + ".py"
1568015685
methodname = self._testMethodName
1568115686
context_id = None
1568215687
if filename == "base_case.py" or methodname == "runTest":
1568315688
import traceback
15684-
stack_base = traceback.format_stack()[0].split(", in ")[0]
15685-
test_base = stack_base.split(", in ")[0].split(os.sep)[-1]
15689+
stack_base = traceback.format_stack()[0].split(os.sep)[-1]
15690+
test_base = stack_base.split(", in ")[0]
1568615691
if hasattr(self, "cm_filename") and self.cm_filename:
1568715692
filename = self.cm_filename
1568815693
else:
1568915694
filename = test_base.split('"')[0]
1569015695
methodname = ".line_" + test_base.split(", line ")[-1]
1569115696
context_id = filename.split(".")[0] + methodname
15697+
self.__saved_id = context_id
1569215698
return context_id
1569315699
test_id = "%s.%s.%s" % (
1569415700
self.__class__.__module__,

Diff for: seleniumbase/plugins/sb_manager.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
2424
#########################################
2525
"""
26-
from contextlib import contextmanager
26+
from contextlib import contextmanager, suppress
2727

2828

2929
@contextmanager # Usage: -> ``with SB() as sb:``
@@ -258,6 +258,7 @@ def SB(
258258
time_limit (float): SECONDS (Safely fail tests that exceed the time limit)
259259
"""
260260
import colorama
261+
import gc
261262
import os
262263
import sys
263264
import time
@@ -1231,6 +1232,15 @@ def SB(
12311232
sb.cap_file = sb_config.cap_file
12321233
sb.cap_string = sb_config.cap_string
12331234
sb._has_failure = False # This may change
1235+
1236+
with suppress(Exception):
1237+
stack_base = traceback.format_stack()[0].split(os.sep)[-1]
1238+
test_base = stack_base.split(", in ")[0]
1239+
filename = test_base.split('"')[0]
1240+
methodname = ".line_" + test_base.split(", line ")[-1]
1241+
context_id = filename.split(".")[0] + methodname
1242+
sb._manager_saved_id = context_id
1243+
12341244
if hasattr(sb_config, "headless_active"):
12351245
sb.headless_active = sb_config.headless_active
12361246
else:
@@ -1357,6 +1367,7 @@ def SB(
13571367
"%s%s%s%s%s"
13581368
% (c1, left_space, end_text, right_space, cr)
13591369
)
1370+
gc.collect()
13601371
if test and test_name and not test_passed and raise_test_failure:
13611372
raise exception
13621373
elif (

Diff for: seleniumbase/undetected/__init__.py

+23-10
Original file line numberDiff line numberDiff line change
@@ -145,9 +145,14 @@ def __init__(
145145
debug_port = 9222
146146
special_port_free = False # If the port isn't free, don't use 9222
147147
try:
148-
res = requests.get("http://127.0.0.1:9222", timeout=1)
149-
if res.status_code != 200:
150-
raise Exception("The port is free! It will be used!")
148+
with requests.Session() as session:
149+
res = session.get(
150+
"http://127.0.0.1:9222",
151+
headers={"Connection": "close"},
152+
timeout=2,
153+
)
154+
if res.status_code != 200:
155+
raise Exception("The port is free! It will be used!")
151156
except Exception:
152157
# Use port 9222, which outputs to chrome://inspect/#devices
153158
special_port_free = True
@@ -462,9 +467,7 @@ def reconnect(self, timeout=0.1):
462467
with suppress(Exception):
463468
for window_handle in self.window_handles:
464469
self.switch_to.window(window_handle)
465-
if self.current_url.startswith(
466-
"chrome-extension://"
467-
):
470+
if self.current_url.startswith("chrome-extension://"):
468471
# https://issues.chromium.org/issues/396611138
469472
# (Remove the Linux conditional when resolved)
470473
# (So that close() is always called)
@@ -559,21 +562,31 @@ def quit(self):
559562
logger.debug(e, exc_info=True)
560563
except Exception:
561564
pass
565+
with suppress(Exception):
566+
self.stop_client()
567+
with suppress(Exception):
568+
if hasattr(self, "command_executor") and self.command_executor:
569+
self.command_executor.close()
570+
571+
# Remove instance reference to allow garbage collection
572+
Chrome._instances.discard(self)
573+
562574
if hasattr(self, "service") and getattr(self.service, "process", None):
563575
logger.debug("Stopping webdriver service")
564576
with suppress(Exception):
565-
self.stop_client()
566577
try:
567578
self.service.send_remote_shutdown_command()
568579
except TypeError:
569580
pass
570581
finally:
571582
with suppress(Exception):
572583
self.service._terminate_process()
573-
with suppress(Exception):
574-
if self.reactor and isinstance(self.reactor, Reactor):
575-
logger.debug("Shutting down Reactor")
584+
if self.reactor and hasattr(self.reactor, "event"):
585+
logger.debug("Shutting down Reactor")
586+
with suppress(Exception):
576587
self.reactor.event.set()
588+
self.reactor.join(timeout=2)
589+
self.reactor = None
577590
if (
578591
hasattr(self, "keep_user_data_dir")
579592
and hasattr(self, "user_data_dir")

Diff for: seleniumbase/undetected/cdp.py

+63-22
Original file line numberDiff line numberDiff line change
@@ -53,28 +53,58 @@ def __init__(self, options):
5353
self._session = requests.Session()
5454
self._last_resp = None
5555
self._last_json = None
56-
resp = self.get(self.endpoints.json)
57-
self.sessionId = resp[0]["id"]
58-
self.wsurl = resp[0]["webSocketDebuggerUrl"]
56+
with requests.Session() as session:
57+
resp = session.get(
58+
self.server_addr + self.endpoints.json,
59+
headers={"Connection": "close"},
60+
timeout=2,
61+
)
62+
self.sessionId = resp.json()[0]["id"]
63+
self.wsurl = resp.json()[0]["webSocketDebuggerUrl"]
5964

6065
def tab_activate(self, id=None):
6166
if not id:
6267
active_tab = self.tab_list()[0]
6368
id = active_tab.id
6469
self.wsurl = active_tab.webSocketDebuggerUrl
65-
return self.post(self.endpoints["activate"].format(id=id))
70+
with requests.Session() as session:
71+
resp = session.post(
72+
self.server_addr + self.endpoints["activate"].format(id=id),
73+
headers={"Connection": "close"},
74+
timeout=2,
75+
)
76+
return resp.json()
6677

6778
def tab_list(self):
68-
retval = self.get(self.endpoints["list"])
69-
return [PageElement(o) for o in retval]
79+
with requests.Session() as session:
80+
resp = session.get(
81+
self.server_addr + self.endpoints["list"],
82+
headers={"Connection": "close"},
83+
timeout=2,
84+
)
85+
retval = resp.json()
86+
return [PageElement(o) for o in retval]
7087

7188
def tab_new(self, url):
72-
return self.post(self.endpoints["new"].format(url=url))
89+
with requests.Session() as session:
90+
resp = session.post(
91+
self.server_addr + self.endpoints["new"].format(url=url),
92+
headers={"Connection": "close"},
93+
timeout=2,
94+
)
95+
return resp.json()
7396

7497
def tab_close_last_opened(self):
7598
sessions = self.tab_list()
7699
opentabs = [s for s in sessions if s["type"] == "page"]
77-
return self.post(self.endpoints["close"].format(id=opentabs[-1]["id"]))
100+
with requests.Session() as session:
101+
endp_close = self.endpoints["close"]
102+
resp = session.post(
103+
self.server_addr + endp_close.format(id=opentabs[-1]["id"]),
104+
headers={"Connection": "close"},
105+
timeout=2,
106+
)
107+
return resp.json()
78108

79109
async def send(self, method, params):
80110
pip_find_lock = fasteners.InterProcessLock(
@@ -101,27 +131,38 @@ def get(self, uri):
101131
from urllib.parse import unquote
102132

103133
uri = unquote(uri, errors="strict")
104-
resp = self._session.get(self.server_addr + uri)
105-
try:
106-
self._last_resp = resp
107-
self._last_json = resp.json()
108-
except Exception:
109-
return
110-
else:
111-
return self._last_json
134+
with requests.Session() as session:
135+
resp = session.get(
136+
self.server_addr + uri,
137+
headers={"Connection": "close"},
138+
timeout=2,
139+
)
140+
try:
141+
self._last_resp = resp
142+
self._last_json = resp.json()
143+
except Exception:
144+
return
145+
else:
146+
return self._last_json
112147

113148
def post(self, uri, data=None):
114149
from urllib.parse import unquote
115150

116151
uri = unquote(uri, errors="strict")
117152
if not data:
118153
data = {}
119-
resp = self._session.post(self.server_addr + uri, json=data)
120-
try:
121-
self._last_resp = resp
122-
self._last_json = resp.json()
123-
except Exception:
124-
return self._last_resp
154+
with requests.Session() as session:
155+
resp = session.post(
156+
self.server_addr + uri,
157+
json=data,
158+
headers={"Connection": "close"},
159+
timeout=2,
160+
)
161+
try:
162+
self._last_resp = resp
163+
self._last_json = resp.json()
164+
except Exception:
165+
return self._last_resp
125166

126167
@property
127168
def last_json(self):

Diff for: setup.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@
148148
python_requires=">=3.8",
149149
install_requires=[
150150
'pip>=25.0.1',
151-
'packaging>=24.2',
151+
'packaging>=25.0',
152152
'setuptools~=70.2;python_version<"3.10"', # Newer ones had issues
153153
'setuptools>=78.1.0;python_version>="3.10"',
154154
'wheel>=0.45.1',
@@ -210,7 +210,7 @@
210210
'parameterized==0.9.0',
211211
"behave==1.2.6",
212212
'soupsieve==2.6',
213-
"beautifulsoup4==4.13.3",
213+
"beautifulsoup4==4.13.4",
214214
'pyotp==2.9.0',
215215
'python-xlib==0.33;platform_system=="Linux"',
216216
'markdown-it-py==3.0.0',
@@ -261,7 +261,7 @@
261261
# (An optional library for parsing PDF files.)
262262
"pdfminer": [
263263
'pdfminer.six==20250324;python_version<"3.9"',
264-
'pdfminer.six==20250327;python_version>="3.9"',
264+
'pdfminer.six==20250416;python_version>="3.9"',
265265
'cryptography==39.0.2;python_version<"3.9"',
266266
'cryptography==44.0.2;python_version>="3.9"',
267267
'cffi==1.17.1',
@@ -271,7 +271,7 @@
271271
# (An optional library for image-processing.)
272272
"pillow": [
273273
'Pillow>=10.4.0;python_version<"3.9"',
274-
'Pillow>=11.2.0;python_version>="3.9"',
274+
'Pillow>=11.2.1;python_version>="3.9"',
275275
],
276276
# pip install -e .[pip-system-certs]
277277
# (If you see [SSL: CERTIFICATE_VERIFY_FAILED], then get this.)

0 commit comments

Comments
 (0)