From a7e28ac407fc63afdcfbaadc642b5a97b77a1375 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 5 Aug 2026 00:28:34 -0400 Subject: [PATCH 1/5] Patch the vendored version of nest_asyncio for Python 3.14+ --- seleniumbase/core/nest_asyncio.py | 78 +++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/seleniumbase/core/nest_asyncio.py b/seleniumbase/core/nest_asyncio.py index ce248c236e0..24bafd3c7b8 100644 --- a/seleniumbase/core/nest_asyncio.py +++ b/seleniumbase/core/nest_asyncio.py @@ -115,6 +115,84 @@ def _get_event_loop(stacklevel=3): asyncio.Future = asyncio.futures._CFuture = asyncio.futures.Future = ( asyncio.futures._PyFuture ) + + # ----------------------------------------------------------------- + # Python 3.14+ FIX: Hybrid Task Visibility. + # Playwright background loops natively run _CTasks. + # Patched loops run _PyTasks. + # We must keep both environments synchronized and visible to current_task() + if sys.version_info >= (3, 14, 0): + _c_current_task = asyncio.current_task + _c_all_tasks = asyncio.all_tasks + _c_swap_current_task = ( + getattr(asyncio.tasks, "_swap_current_task", None) + ) + + def _patched_current_task(loop=None): + # 1. Check C-level state (finds Playwright / Extension tasks) + t = _c_current_task(loop) + if t is not None: + return t + # 2. Check pure-Python state (finds patched nest_asyncio tasks) + if hasattr(asyncio.tasks, "_py_current_task"): + return asyncio.tasks._py_current_task(loop) + return None + + def _patched_all_tasks(loop=None): + tasks = _c_all_tasks(loop) or set() + if hasattr(asyncio.tasks, "_py_all_tasks"): + tasks.update(asyncio.tasks._py_all_tasks(loop) or set()) + return tasks + + def _patched_swap_current_task(loop, task): + old_c = None + if _c_swap_current_task is not None: + try: + old_c = _c_swap_current_task(loop, None) + except (KeyError, RuntimeError): + pass + + old_py = None + if hasattr(asyncio.tasks, "_py_swap_current_task"): + try: + old_py = asyncio.tasks._py_swap_current_task(loop, None) + except (KeyError, RuntimeError): + pass + + if task is not None: + if _c_swap_current_task is not None: + try: + _c_swap_current_task(loop, task) + except (TypeError, ValueError): + pass + if hasattr(asyncio.tasks, "_py_swap_current_task"): + try: + asyncio.tasks._py_swap_current_task(loop, task) + except (TypeError, ValueError): + pass + + return old_c or old_py + + asyncio.tasks.current_task = _patched_current_task + asyncio.current_task = _patched_current_task + asyncio.tasks.all_tasks = _patched_all_tasks + asyncio.all_tasks = _patched_all_tasks + if _c_swap_current_task is not None: + asyncio.tasks._swap_current_task = _patched_swap_current_task + + for func in ( + "_enter_task", + "_leave_task", + "_register_task", + "_unregister_task", + "_register_eager_task", + "_unregister_eager_task", + ): + py_func = f"_py{func}" + if hasattr(asyncio.tasks, py_func): + setattr(asyncio.tasks, func, getattr(asyncio.tasks, py_func)) + # ----------------------------------------------------------------- + asyncio.get_event_loop = _get_event_loop events._get_event_loop = events.get_event_loop = asyncio.get_event_loop asyncio.run = run From 076956c14a944b25ff191189b32123220e490fff Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 5 Aug 2026 00:30:10 -0400 Subject: [PATCH 2/5] Update timing of stealthy CDP Mode clicks --- seleniumbase/undetected/cdp_driver/element.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/seleniumbase/undetected/cdp_driver/element.py b/seleniumbase/undetected/cdp_driver/element.py index 1cf41868976..3230e25041e 100644 --- a/seleniumbase/undetected/cdp_driver/element.py +++ b/seleniumbase/undetected/cdp_driver/element.py @@ -527,7 +527,7 @@ async def mouse_click_async( asyncio.create_task(self.flash_async(0.25))''' with suppress(Exception): await self.mouse_move_async() - await asyncio.sleep(random.uniform(0.0035, 0.0048)) + await asyncio.sleep(random.uniform(0.0036, 0.0046)) x = center[0] + random.uniform(-0.85, 0.85) y = center[1] + random.uniform(-0.85, 0.85) asyncio.create_task( @@ -546,7 +546,7 @@ async def mouse_click_async( ) if not timeframe or timeframe <= 0: # If 0 (or less), hold for a small amount of time - await asyncio.sleep(random.uniform(0.0126, 0.0152)) + await asyncio.sleep(random.uniform(0.0142, 0.0152)) x += random.uniform(-0.12, 0.12) y += random.uniform(-0.12, 0.12) else: From 0455ee62040c1b5185430035fd851518a9c83b84 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 5 Aug 2026 00:30:51 -0400 Subject: [PATCH 3/5] Refresh Python dependencies --- requirements.txt | 4 ++-- setup.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index 2de612f723f..df73d24e15e 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ pip>=26.0.1;python_version<"3.10" -pip>=26.2;python_version>="3.10" -packaging>=26.2 +pip>=26.2.1;python_version>="3.10" +packaging>=26.3 setuptools~=70.2;python_version<"3.10" setuptools>=83.0.0;python_version>="3.10" wheel>=0.47.0 diff --git a/setup.py b/setup.py index a8fb145f509..5368cbd182f 100755 --- a/setup.py +++ b/setup.py @@ -163,8 +163,8 @@ python_requires=">=3.9", install_requires=[ 'pip>=26.0.1;python_version<"3.10"', - 'pip>=26.2;python_version>="3.10"', - 'packaging>=26.2', + 'pip>=26.2.1;python_version>="3.10"', + 'packaging>=26.3', 'setuptools~=70.2;python_version<"3.10"', # Newer ones had issues 'setuptools>=83.0.0;python_version>="3.10"', 'wheel>=0.47.0', @@ -278,7 +278,7 @@ 'pdfminer.six==20260107;python_version>="3.10"', 'cryptography==50.0.0', 'cffi==2.0.0;python_version<"3.10"', - 'cffi==2.1.0;python_version>="3.10"', + 'cffi==2.1.1;python_version>="3.10"', 'pycparser==2.23;python_version<"3.10"', 'pycparser==3.0;python_version>="3.10"', ], From b050714d848b370bd7500acfc01010607b6cb6d3 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 5 Aug 2026 00:31:19 -0400 Subject: [PATCH 4/5] Update CDP Mode examples --- examples/cdp_mode/playwright/raw_clearcote_sync.py | 2 +- examples/cdp_mode/raw_cdp_clearcote.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/cdp_mode/playwright/raw_clearcote_sync.py b/examples/cdp_mode/playwright/raw_clearcote_sync.py index 4e9d2ea67f2..cf320e985f3 100644 --- a/examples/cdp_mode/playwright/raw_clearcote_sync.py +++ b/examples/cdp_mode/playwright/raw_clearcote_sync.py @@ -17,7 +17,7 @@ sb.select_option_by_text("select", "Mouse") sb.click('button:contains("Run the audit")') sb.sleep(6) - sb.assert_element("div.text-successText", timeout=8) + sb.assert_element("div.text-successText", timeout=10) try: sb.assert_text("100", "div.text-successText", timeout=5) sb.highlight('div.text-successText:contains("100")') diff --git a/examples/cdp_mode/raw_cdp_clearcote.py b/examples/cdp_mode/raw_cdp_clearcote.py index 3324efb0f3a..2938c4f0d5b 100644 --- a/examples/cdp_mode/raw_cdp_clearcote.py +++ b/examples/cdp_mode/raw_cdp_clearcote.py @@ -11,7 +11,7 @@ sb.select_option_by_text("select", "Mouse") sb.click('button:contains("Run the audit")') sb.sleep(6) -sb.assert_element("div.text-successText", timeout=8) +sb.assert_element("div.text-successText", timeout=10) try: sb.assert_text("100", "div.text-successText", timeout=5) sb.highlight('div.text-successText:contains("100")') From 9d98315c3989a4739d6e1b2aa1da7d0cb8a56732 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Wed, 5 Aug 2026 00:31:37 -0400 Subject: [PATCH 5/5] Version 4.51.10 --- seleniumbase/__version__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index a71768509c1..66c9f7777d4 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.51.9" +__version__ = "4.51.10"