diff --git a/README.md b/README.md
index acd767d42d2..bb777b2fb38 100755
--- a/README.md
+++ b/README.md
@@ -507,10 +507,10 @@ pip install -e .
▶️ Here's sample output from a chromedriver download. (click to expand)
```zsh
-*** chromedriver to download = 148.0.7778.178 (Latest Stable)
+*** chromedriver to download = 149.0.7827.54 (Latest Stable)
Downloading chromedriver-mac-arm64.zip from:
-https://storage.googleapis.com/chrome-for-testing-public/148.0.7778.178/mac-arm64/chromedriver-mac-arm64.zip ...
+https://storage.googleapis.com/chrome-for-testing-public/149.0.7827.54/mac-arm64/chromedriver-mac-arm64.zip ...
Download Complete!
Extracting ['chromedriver'] from chromedriver-mac-arm64.zip ...
@@ -520,8 +520,8 @@ The file [chromedriver] was saved to:
~/github/SeleniumBase/seleniumbase/drivers/
chromedriver
-Making [chromedriver 148.0.7778.178] executable ...
-[chromedriver 148.0.7778.178] is now ready for use!
+Making [chromedriver 149.0.7827.54] executable ...
+[chromedriver 149.0.7827.54] is now ready for use!
```
@@ -853,7 +853,6 @@ pytest test_coffee_cart.py --trace
--screenshot # (Save a screenshot at the end of each test.)
--no-screenshot # (No screenshots saved unless tests directly ask it.)
--visual-baseline # (Set the visual baseline for Visual/Layout tests.)
---wire # (Use selenium-wire's webdriver for replacing selenium webdriver.)
--external-pdf # (Set Chromium "plugins.always_open_pdf_externally":True.)
--timeout-multiplier=MULTIPLIER # (Multiplies the default timeout values.)
--list-fail-page # (After each failing test, list the URL of the failure.)
diff --git a/examples/ReadMe.md b/examples/ReadMe.md
index 3162b7f0169..fc1f6e06a96 100644
--- a/examples/ReadMe.md
+++ b/examples/ReadMe.md
@@ -4,21 +4,20 @@

-* SeleniumBase "tests" are run with pytest.
+* Many SeleniumBase "tests" run with pytest.
* Chrome is the default browser if not specified.
-* Tests are structured using [25 unique syntax formats](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md).
+* Tests are structured using [25 unique design patterns](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/syntax_formats.md).
* Logs from test failures are saved to `./latest_logs/`.
* Tests can be run with [multiple command-line options](https://github.com/seleniumbase/SeleniumBase/blob/master/help_docs/customizing_test_runs.md).
* Examples can be found in [SeleniumBase/examples/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples).
-* For stealthy examples, see [SeleniumBase/examples/cdp_mode/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode).
+* Stealthy CDP Mode examples: [SeleniumBase/examples/cdp_mode/](https://github.com/seleniumbase/SeleniumBase/tree/master/examples/cdp_mode).
+* Stealthy Playwright examples: [./examples/cdp_mode/playwright/](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/cdp_mode/playwright/ReadMe.md).
(NOTE: Some example tests fail on purpose to demonstrate [logging features](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/example_logs/ReadMe.md).)
--------
-
Example tests with run commands to help you get started:
-
---------
+
Example tests with run commands:
Run an [example test](https://github.com/seleniumbase/SeleniumBase/blob/master/examples/my_first_test.py): (Default option: `--chrome`)
diff --git a/examples/cdp_mode/ReadMe.md b/examples/cdp_mode/ReadMe.md
index 711ee34d27e..aa168cbca3e 100644
--- a/examples/cdp_mode/ReadMe.md
+++ b/examples/cdp_mode/ReadMe.md
@@ -323,6 +323,7 @@ with SB(uc=True, test=True, ad_block=True) as sb:
price_text = price_text.split("current price ")[-1]
price_text = price_text.split(" ")[0]
print(" (" + price_text + ")")
+ item.scroll_into_view()
```
@@ -662,8 +663,7 @@ await tab.set_window_size(left=0, top=0, width=1280, height=1024)
await tab.set_window_rect(left=0, top=0, width=1280, height=1024)
await tab.activate()
await tab.bring_to_front()
-await tab.set_window_state(
- left=0, top=0, width=1280, height=720, state="normal")
+await tab.set_window_state(left=0, top=0, width=1280, height=720, state="normal")
await tab.get_navigation_history()
await tab.get_user_agent()
await tab.get_cookie_string()
@@ -677,8 +677,7 @@ await tab.wait_for(selector="", text="", timeout=10)
await tab.set_attributes(selector, attribute, value)
await tab.internalize_links()
await tab.download_file(url, filename=None)
-await tab.save_screenshot(
- filename="auto", format="png", full_page=False)
+await tab.save_screenshot(filename="auto", format="png", full_page=False)
await tab.print_to_pdf(filename="auto")
await tab.set_download_path(path)
await tab.get_all_linked_sources()
diff --git a/examples/cdp_mode/raw_ad_blocking.py b/examples/cdp_mode/raw_ad_blocking.py
index 783e8334bc2..5567d3a6367 100644
--- a/examples/cdp_mode/raw_ad_blocking.py
+++ b/examples/cdp_mode/raw_ad_blocking.py
@@ -1,3 +1,5 @@
+"""Test Ad-Blocking using mycdp.network.set_blocked_urls().
+tab.send() is the stealthy version of execute_cdp_cmd()."""
import mycdp
from seleniumbase import decorators
from seleniumbase import sb_cdp
@@ -28,4 +30,4 @@ async def block_urls(tab):
sb.assert_false("doubleclick.net" in source)
sb.assert_false("google-analytics.com" in source)
sb.post_message("Blocking was successful!")
- sb.driver.quit()
+ sb.quit()
diff --git a/examples/cdp_mode/raw_antibot.py b/examples/cdp_mode/raw_antibot.py
index 58036f418e6..0c999265d03 100644
--- a/examples/cdp_mode/raw_antibot.py
+++ b/examples/cdp_mode/raw_antibot.py
@@ -1,14 +1,15 @@
+"""CDP Mode bypasses bot-detection and performs stealthy actions.
+sb.press_keys() is a slower sb.type() for human-like speed."""
from seleniumbase import SB
with SB(uc=True, test=True) as sb:
url = "https://seleniumbase.io/antibot/login"
sb.activate_cdp_mode(url)
sb.press_keys("input#username", "demo_user")
- sb.press_keys("input#password", "secret_pass")
+ sb.type("input#password", "secret_pass")
sb.click("button#myButton")
- sb.sleep(1.5)
+ sb.sleep(1.4)
sb.click("a#log-in")
sb.assert_text("Welcome!", "h1")
sb.set_messenger_theme(location="bottom_center")
sb.post_message("SeleniumBase wasn't detected!")
- sb.sleep(1.5)
diff --git a/examples/cdp_mode/raw_basic_cdp.py b/examples/cdp_mode/raw_basic_cdp.py
index 126ddcb8360..dddcb0af6b9 100644
--- a/examples/cdp_mode/raw_basic_cdp.py
+++ b/examples/cdp_mode/raw_basic_cdp.py
@@ -1,7 +1,7 @@
from seleniumbase import sb_cdp
-url = "https://seleniumbase.io/simple/login"
-sb = sb_cdp.Chrome(url)
+sb = sb_cdp.Chrome()
+sb.open("https://seleniumbase.io/simple/login")
sb.type("#username", "demo_user")
sb.type("#password", "secret_pass")
sb.click('a:contains("Sign in")')
@@ -14,4 +14,4 @@
print(nav_item.text)
sb.click_link("Sign out")
sb.assert_text("signed out", "#top_message")
-sb.driver.stop()
+sb.quit()
diff --git a/examples/cdp_mode/raw_cdp_pixelscan.py b/examples/cdp_mode/raw_cdp_pixelscan.py
index 0a73349c161..945cc6ad75e 100644
--- a/examples/cdp_mode/raw_cdp_pixelscan.py
+++ b/examples/cdp_mode/raw_cdp_pixelscan.py
@@ -1,6 +1,6 @@
from seleniumbase import sb_cdp
-sb = sb_cdp.Chrome(incognito=True)
+sb = sb_cdp.Chrome(guest=True, ad_block=True)
sb.open("https://pixelscan.net/fingerprint-check")
sb.sleep(1)
sb.wait_for_element("pxlscn-dynamic-ad")
@@ -13,3 +13,4 @@
sb.highlight("span.status-success")
sb.highlight("pxlscn-fingerprint-masking p")
sb.highlight("pxlscn-bot-detection p")
+print("Bot Not Detected")
diff --git a/examples/cdp_mode/raw_cdp_tavus.py b/examples/cdp_mode/raw_cdp_tavus.py
new file mode 100644
index 00000000000..c398391110f
--- /dev/null
+++ b/examples/cdp_mode/raw_cdp_tavus.py
@@ -0,0 +1,9 @@
+from seleniumbase import sb_cdp
+
+sb = sb_cdp.Chrome()
+sb.open("platform.tavus.io/auth/sign-in?is_developer=true")
+sb.sleep(3)
+sb.solve_captcha()
+sb.sleep(1)
+sb.assert_element('input[type="email"]')
+sb.assert_element('button[type="submit"]')
diff --git a/examples/cdp_mode/raw_cdp_walmart.py b/examples/cdp_mode/raw_cdp_walmart.py
index ceafddb2c10..73e49fab54c 100644
--- a/examples/cdp_mode/raw_cdp_walmart.py
+++ b/examples/cdp_mode/raw_cdp_walmart.py
@@ -43,4 +43,5 @@
price_text = price_text.split("current price ")[-1]
price_text = price_text.split(" ")[0]
print(" (" + price_text + ")")
+ item.scroll_into_view()
sb.driver.stop()
diff --git a/examples/cdp_mode/raw_cf.py b/examples/cdp_mode/raw_cf.py
index 452c6958a9b..d3383161a97 100644
--- a/examples/cdp_mode/raw_cf.py
+++ b/examples/cdp_mode/raw_cf.py
@@ -1,4 +1,5 @@
-"""Using CDP Mode to bypass CAPTCHAs in different ways."""
+"""Using CDP Mode to bypass CAPTCHAs in different ways.
+PyAutoGUI is installed automatically if not already."""
from seleniumbase import SB
with SB(uc=True, test=True, guest=True) as sb:
diff --git a/examples/cdp_mode/raw_mfa_login.py b/examples/cdp_mode/raw_mfa_login.py
index def87484d01..66c9bce30e3 100644
--- a/examples/cdp_mode/raw_mfa_login.py
+++ b/examples/cdp_mode/raw_mfa_login.py
@@ -1,7 +1,7 @@
from seleniumbase import sb_cdp
-url = "https://seleniumbase.io/realworld/login"
-sb = sb_cdp.Chrome(url)
+sb = sb_cdp.Chrome()
+sb.open("https://seleniumbase.io/realworld/login")
sb.type("#username", "demo_user")
sb.type("#password", "secret_pass")
sb.enter_mfa_code("#totpcode", "GAXG2MTEOR3DMMDG")
@@ -9,4 +9,4 @@
sb.click('a:contains("This Page")')
sb.highlight("h1")
sb.highlight("img#image1")
-sb.driver.stop()
+sb.quit()
diff --git a/examples/cdp_mode/raw_mobile_roblox.py b/examples/cdp_mode/raw_mobile_roblox.py
index eee8c146a2e..aaeb5e0b363 100644
--- a/examples/cdp_mode/raw_mobile_roblox.py
+++ b/examples/cdp_mode/raw_mobile_roblox.py
@@ -1,3 +1,5 @@
+"""Test mobile emulation via mycdp.emulation.set_device_metrics_override().
+tab.send() is a stealthy version of Selenium's execute_cdp_cmd() method."""
import mycdp
from seleniumbase import SB
diff --git a/examples/cdp_mode/raw_multi_cdp.py b/examples/cdp_mode/raw_multi_cdp.py
index dbec0400be3..56ea75ea9c6 100644
--- a/examples/cdp_mode/raw_multi_cdp.py
+++ b/examples/cdp_mode/raw_multi_cdp.py
@@ -12,7 +12,7 @@ def main(url):
sb.highlight("button")
sb.click("button")
sb.sleep(2)
- sb.driver.quit()
+ sb.quit()
if __name__ == "__main__":
diff --git a/examples/cdp_mode/raw_pixelscan.py b/examples/cdp_mode/raw_pixelscan.py
index 8976f222fc7..1ceedc79a79 100644
--- a/examples/cdp_mode/raw_pixelscan.py
+++ b/examples/cdp_mode/raw_pixelscan.py
@@ -1,6 +1,6 @@
from seleniumbase import SB
-with SB(uc=True, test=True, incognito=True, ad_block=True) as sb:
+with SB(uc=True, test=True, guest=True, ad_block=True) as sb:
url = "https://pixelscan.net/fingerprint-check"
sb.activate_cdp_mode(url)
sb.sleep(1)
@@ -14,3 +14,4 @@
sb.cdp.highlight("span.status-success")
sb.cdp.highlight("pxlscn-fingerprint-masking p")
sb.cdp.highlight("pxlscn-bot-detection p")
+ print("Bot Not Detected")
diff --git a/examples/cdp_mode/raw_tavus.py b/examples/cdp_mode/raw_tavus.py
new file mode 100644
index 00000000000..c80f848dd52
--- /dev/null
+++ b/examples/cdp_mode/raw_tavus.py
@@ -0,0 +1,10 @@
+from seleniumbase import SB
+
+with SB(uc=True, test=True) as sb:
+ sb.activate_cdp_mode()
+ sb.open("platform.tavus.io/auth/sign-in?is_developer=true")
+ sb.sleep(3)
+ sb.solve_captcha()
+ sb.sleep(1)
+ sb.assert_element('input[type="email"]')
+ sb.assert_element('button[type="submit"]')
diff --git a/examples/cdp_mode/raw_walmart.py b/examples/cdp_mode/raw_walmart.py
index 1fccb4071fb..b39a20cbe6e 100644
--- a/examples/cdp_mode/raw_walmart.py
+++ b/examples/cdp_mode/raw_walmart.py
@@ -44,3 +44,4 @@
price_text = price_text.split("current price ")[-1]
price_text = price_text.split(" ")[0]
print(" (" + price_text + ")")
+ item.scroll_into_view()
diff --git a/examples/cdp_mode/raw_wsform.py b/examples/cdp_mode/raw_wsform.py
index aee5bbb1567..3046e40016c 100644
--- a/examples/cdp_mode/raw_wsform.py
+++ b/examples/cdp_mode/raw_wsform.py
@@ -1,3 +1,6 @@
+"""CDP Mode for bypassing bot-detection & CAPTCHAs.
+Note: sb.uc_gui_click_captcha() requires PyAutoGUI,
+which is installed automatically if not already."""
from seleniumbase import SB
with SB(uc=True, test=True, locale="en", incognito=True) as sb:
@@ -5,5 +8,5 @@
sb.activate_cdp_mode(url)
sb.sleep(2)
sb.scroll_into_view("div.grid")
- sb.uc_gui_click_captcha()
+ sb.uc_gui_click_captcha() # PyAutoGUI mouse click
sb.sleep(2)
diff --git a/examples/presenter/multi_uc.py b/examples/presenter/multi_uc.py
index de7e1853f18..c56d3720b90 100644
--- a/examples/presenter/multi_uc.py
+++ b/examples/presenter/multi_uc.py
@@ -1,4 +1,4 @@
-"""Part of the UC presentation"""
+"""Part of the UC presentation. (Upgraded for CDP Mode.)"""
import pytest
from random import randint
from seleniumbase import BaseCase
@@ -7,18 +7,11 @@
@pytest.mark.parametrize("", [[]] * 3)
def test_multi_threaded(sb):
- url = "https://gitlab.com/users/sign_in"
- sb.driver.uc_open_with_reconnect(url, 3)
- sb.set_window_rect(randint(0, 755), randint(38, 403), 700, 500)
- try:
- sb.assert_text("Username", '[for="user_login"]', timeout=3)
- sb.post_message("SeleniumBase wasn't detected", duration=4)
- sb._print("\n Success! Website did not detect Selenium! ")
- except Exception:
- sb.driver.uc_open_with_reconnect(url, 3)
- try:
- sb.assert_text("Username", '[for="user_login"]', timeout=3)
- sb.post_message("SeleniumBase wasn't detected", duration=4)
- sb._print("\n Success! Website did not detect Selenium! ")
- except Exception:
- sb.fail('Selenium was detected! Try using: "pytest --uc"')
+ sb.activate_cdp_mode() # If not UC Mode, then 2nd browser
+ sb.set_window_rect(randint(4, 680), randint(8, 380), 840, 520)
+ sb.open("https://gitlab.com/users/sign_in")
+ sb.sleep(2)
+ sb.solve_captcha()
+ sb.assert_text("Username", '[for="user_login"]', timeout=3)
+ sb.post_message("SeleniumBase wasn't detected", duration=4)
+ sb._print("\n Success: SeleniumBase wasn't detected! ")
diff --git a/examples/raw_antibot_login.py b/examples/raw_antibot_login.py
index 0ee882616b1..6950fdbf81d 100644
--- a/examples/raw_antibot_login.py
+++ b/examples/raw_antibot_login.py
@@ -1,4 +1,6 @@
-"""UC Mode has PyAutoGUI methods for CAPTCHA-bypass."""
+"""UC Mode has PyAutoGUI methods for stealthy actions.
+PyAutoGUI gets installed automatically if not already.
+This old UC Mode code is made obsolete by CDP Mode."""
from seleniumbase import SB
with SB(uc=True, test=True) as sb:
@@ -7,7 +9,7 @@
sb.uc_gui_write("\t" + "demo_user")
sb.uc_gui_write("\t" + "secret_pass")
sb.uc_gui_press_keys("\t" + " ") # For Single-char keys
- sb.sleep(1.5)
+ sb.sleep(1.4)
sb.uc_gui_press_keys(["\t", "ENTER"]) # Multi-char keys
sb.reconnect(1.8)
sb.assert_text("Welcome!", "h1")
diff --git a/examples/raw_brotector_captcha.py b/examples/raw_brotector_captcha.py
index b123b29f274..5f8fcee6b8c 100644
--- a/examples/raw_brotector_captcha.py
+++ b/examples/raw_brotector_captcha.py
@@ -1,9 +1,8 @@
-"""UC Mode has PyAutoGUI methods for CAPTCHA-bypass."""
from seleniumbase import SB
with SB(uc=True, test=True) as sb:
- url = "https://seleniumbase.io/apps/brotector"
- sb.uc_open_with_disconnect(url, 2.2)
- sb.uc_gui_press_key("\t")
- sb.uc_gui_press_key(" ")
- sb.reconnect(2.2)
+ sb.activate_cdp_mode()
+ sb.open("https://seleniumbase.io/apps/brotector")
+ sb.click("button span#mySpan")
+ sb.assert_text("SUCCESS", "label#pText")
+ sb.highlight("label#pText")
diff --git a/examples/raw_cdp_logging.py b/examples/raw_cdp_logging.py
index 51885103cc8..9d893a760e9 100644
--- a/examples/raw_cdp_logging.py
+++ b/examples/raw_cdp_logging.py
@@ -1,3 +1,5 @@
+"""NOTE: This uses plain UC Mode, which was replaced by UC + CDP Mode.
+PyAutoGUI is installed automatically for uc_gui methods if not already."""
from rich.pretty import pprint
from seleniumbase import Driver
diff --git a/examples/raw_form_turnstile.py b/examples/raw_form_turnstile.py
index 7af920545bd..bf3d8eba76a 100644
--- a/examples/raw_form_turnstile.py
+++ b/examples/raw_form_turnstile.py
@@ -1,8 +1,9 @@
+"""CDP Mode for bypassing bot-detection & CAPTCHAs."""
from seleniumbase import SB
with SB(uc=True, test=True) as sb:
- url = "seleniumbase.io/apps/form_turnstile"
- sb.uc_open_with_reconnect(url, 1.1)
+ sb.activate_cdp_mode()
+ sb.open("seleniumbase.io/apps/form_turnstile")
sb.press_keys("#name", "SeleniumBase")
sb.press_keys("#email", "test@test.test")
sb.press_keys("#phone", "1-555-555-5555")
@@ -12,8 +13,8 @@
sb.click('span:contains("9:00 PM")')
sb.highlight_click('input[value="AR"] + span')
sb.click('input[value="cc"] + span')
- sb.scroll_to('div[class*="cf-turnstile"]')
- sb.uc_gui_handle_captcha()
+ sb.scroll_down(40)
+ sb.solve_captcha()
sb.highlight("img#captcha-success", timeout=3)
sb.highlight_click('button:contains("Request & Pay")')
sb.highlight("img#submit-success")
diff --git a/examples/raw_gui_click.py b/examples/raw_gui_click.py
index ec96cb51ae5..e4a22aa4bc0 100644
--- a/examples/raw_gui_click.py
+++ b/examples/raw_gui_click.py
@@ -1,8 +1,11 @@
+"""CDP Mode for bypassing bot-detection & CAPTCHAs.
+Note: sb.uc_gui_click_captcha() requires PyAutoGUI,
+which is installed automatically if not already."""
from seleniumbase import SB
with SB(uc=True, test=True) as sb:
- url = "seleniumbase.io/apps/form_turnstile"
- sb.activate_cdp_mode(url)
+ sb.activate_cdp_mode()
+ sb.open("seleniumbase.io/apps/form_turnstile")
sb.press_keys("#name", "SeleniumBase")
sb.press_keys("#email", "test@test.test")
sb.press_keys("#phone", "1-555-555-5555")
@@ -14,7 +17,7 @@
sb.click('input[value="cc"] + span')
sb.scroll_to('div[class*="cf-turnstile"]')
sb.scroll_down(40)
- sb.uc_gui_click_captcha()
+ sb.uc_gui_click_captcha() # PyAutoGUI mouse click
sb.highlight("img#captcha-success", timeout=3)
sb.highlight_click('button:contains("Request & Pay")')
sb.highlight("img#submit-success")
diff --git a/examples/raw_hobbit.py b/examples/raw_hobbit.py
index 51fbc98dd83..2fc91b0d510 100644
--- a/examples/raw_hobbit.py
+++ b/examples/raw_hobbit.py
@@ -1,11 +1,9 @@
-"""UC Mode has PyAutoGUI methods for CAPTCHA-bypass."""
from seleniumbase import SB
with SB(uc=True, test=True) as sb:
- url = "https://seleniumbase.io/hobbit/login"
- sb.uc_open_with_disconnect(url, 2.2)
- sb.uc_gui_press_keys("\t ")
- sb.reconnect(1.5)
+ sb.activate_cdp_mode()
+ sb.open("https://seleniumbase.io/hobbit/login")
+ sb.click("button span#mySpan")
sb.assert_text("Welcome to Middle Earth!", "h1")
sb.set_messenger_theme(location="bottom_center")
sb.post_message("SeleniumBase wasn't detected!")
diff --git a/examples/raw_parameter_script.py b/examples/raw_parameter_script.py
index 7a61c73cf1b..ee12ea0e3e3 100644
--- a/examples/raw_parameter_script.py
+++ b/examples/raw_parameter_script.py
@@ -82,7 +82,6 @@
sb._crumbs = False
sb._final_debug = False
sb.esc_end = False
- sb.use_wire = False
sb.enable_3d_apis = False
sb.window_position = None
sb.window_size = None
diff --git a/examples/raw_uc_events.py b/examples/raw_uc_events.py
index 9e35f781db2..e55e63debda 100644
--- a/examples/raw_uc_events.py
+++ b/examples/raw_uc_events.py
@@ -1,3 +1,5 @@
+"""NOTE: This uses plain UC Mode, which was replaced by UC + CDP Mode.
+PyAutoGUI is installed automatically for uc_gui methods if not already."""
from rich.pretty import pprint
from seleniumbase import SB
diff --git a/examples/raw_uc_mode.py b/examples/raw_uc_mode.py
index 3634bd605d7..29c1e2ec27b 100644
--- a/examples/raw_uc_mode.py
+++ b/examples/raw_uc_mode.py
@@ -1,4 +1,7 @@
-"""SB Manager using UC Mode for evading bot-detection."""
+"""SB Manager using UC Mode for evading bot-detection.
+Note that plain UC Mode was replaced by the newer CDP Mode:
+Instead of uc_open_with_reconnect, use activate_cdp_mode().
+Instead of uc_gui_click_captcha(), use solve_captcha()."""
from seleniumbase import SB
with SB(uc=True, test=True) as sb:
diff --git a/examples/uc_cdp_events.py b/examples/uc_cdp_events.py
index 526dd70e4e4..947e1d21214 100644
--- a/examples/uc_cdp_events.py
+++ b/examples/uc_cdp_events.py
@@ -1,3 +1,5 @@
+"""NOTE: This uses plain UC Mode, which was replaced by UC + CDP Mode.
+PyAutoGUI is installed automatically for uc_gui methods if not already."""
from rich.pretty import pprint
from seleniumbase import BaseCase
BaseCase.main(__name__, __file__, "--uc", "--uc-cdp")
diff --git a/examples/unit_tests/pytest.ini b/examples/unit_tests/pytest.ini
new file mode 100644
index 00000000000..5fc7a520f3d
--- /dev/null
+++ b/examples/unit_tests/pytest.ini
@@ -0,0 +1,48 @@
+[pytest]
+
+# Display console output. Disable cacheprovider:
+addopts = --capture=tee-sys -p no:cacheprovider
+
+# Skip these directories during test collection:
+norecursedirs = .* build dist recordings temp assets
+
+# Ignore DeprecationWarning, PytestUnknownMarkWarning
+filterwarnings =
+ ignore::pytest.PytestWarning
+ ignore:.*U.*mode is deprecated:DeprecationWarning
+ ignore::pytest.PytestAssertRewriteWarning
+
+# Configure the junit_family option explicitly:
+junit_family = legacy
+
+# Set pytest discovery rules:
+# (Most of the rules here are similar to the default rules.)
+# (Inheriting unittest.TestCase could override these rules.)
+python_files = test_*.py *_test.py *_tests.py *_suite.py
+python_classes = Test* *Test* *Test *Tests *Suite
+python_functions = test_*
+
+# Common pytest markers used in examples:
+# (pytest may require marker registration to prevent warnings.)
+# (Future versions may turn those marker warnings into errors.)
+markers =
+ marker1: custom marker
+ marker2: custom marker
+ marker3: custom marker
+ marker_test_suite: custom marker
+ expected_failure: custom marker
+ local: custom marker
+ remote: custom marker
+ offline: custom marker
+ develop: custom marker
+ qa: custom marker
+ ci: custom marker
+ e2e: custom marker
+ ready: custom marker
+ smoke: custom marker
+ deploy: custom marker
+ active: custom marker
+ master: custom marker
+ release: custom marker
+ staging: custom marker
+ production: custom marker
diff --git a/examples/verify_undetected.py b/examples/verify_undetected.py
index 555c485df8e..d99e0f1257f 100644
--- a/examples/verify_undetected.py
+++ b/examples/verify_undetected.py
@@ -1,17 +1,16 @@
-"""Determine if your browser is detectable by anti-bot services.
-Some sites use scripts to detect Selenium, and then block you.
-To evade detection, add --uc as a pytest command-line option."""
+"""Verify if your browser is detectable by anti-bot services.
+To evade detection, add --uc as a pytest command-line option.
+UC + CDP Mode is used: CDP Mode is activated from UC Mode."""
from seleniumbase import BaseCase
BaseCase.main(__name__, __file__, "--uc")
class UndetectedTest(BaseCase):
def test_browser_is_undetected(self):
- url = "https://gitlab.com/users/sign_in"
- if not self.undetectable:
- self.get_new_driver(undetectable=True)
- self.uc_open_with_reconnect(url)
- self.uc_gui_click_captcha()
+ self.activate_cdp_mode() # If not UC Mode, then 2nd browser
+ self.open("https://gitlab.com/users/sign_in")
+ self.sleep(2)
+ self.solve_captcha() # (Only runs when a CAPTCHA is visible)
self.assert_text("Username", '[for="user_login"]', timeout=3)
self.post_message("SeleniumBase wasn't detected", duration=4)
- self._print("\n Success! Website did not detect Selenium! ")
+ self._print("\n Success: SeleniumBase wasn't detected! ")
diff --git a/help_docs/customizing_test_runs.md b/help_docs/customizing_test_runs.md
index 3e9a6345144..a28bbc19050 100644
--- a/help_docs/customizing_test_runs.md
+++ b/help_docs/customizing_test_runs.md
@@ -224,7 +224,6 @@ pytest my_first_test.py --settings-file=custom_settings.py
--screenshot # (Save a screenshot at the end of each test.)
--no-screenshot # (No screenshots saved unless tests directly ask it.)
--visual-baseline # (Set the visual baseline for Visual/Layout tests.)
---wire # (Use selenium-wire's webdriver for replacing selenium webdriver.)
--external-pdf # (Set Chromium "plugins.always_open_pdf_externally":True.)
--timeout-multiplier=MULTIPLIER # (Multiplies the default timeout values.)
--list-fail-page # (After each failing test, list the URL of the failure.)
@@ -691,7 +690,6 @@ binary_location=None # Set path of the Chromium browser binary to use.
driver_version=None # Set the chromedriver or uc_driver version to use.
skip_js_waits=None # Skip JS Waits (readyState=="complete" and Angular).
wait_for_angularjs=None # Wait for AngularJS to load after some actions.
-use_wire=None # Use selenium-wire's webdriver over selenium webdriver.
external_pdf=None # Set Chrome "plugins.always_open_pdf_externally":True.
window_position=None # Set the browser's starting window position: "X,Y"
window_size=None # Set the browser's starting window size: "Width,Height"
@@ -727,7 +725,6 @@ log_cdp=None # Shortcut / Duplicate of "log_cdp_events".
ad_block=None # Shortcut / Duplicate of "ad_block_on".
server=None # Shortcut / Duplicate of "servername".
guest=None # Shortcut / Duplicate of "guest_mode".
-wire=None # Shortcut / Duplicate of "use_wire".
pls=None # Shortcut / Duplicate of "page_load_strategy".
sjw=None # Shortcut / Duplicate of "skip_js_waits".
wfa=None # Shortcut / Duplicate of "wait_for_angularjs".
@@ -807,7 +804,6 @@ disable_features=None # "F1,F2" (Disable Chrome features, ","-separated.)
binary_location=None # Set path of the Chromium browser binary to use.
driver_version=None # Set the chromedriver or uc_driver version to use.
page_load_strategy=None # Set Chrome PLS to "normal", "eager", or "none".
-use_wire=None # Use selenium-wire's webdriver over selenium webdriver.
external_pdf=None # Set Chrome "plugins.always_open_pdf_externally":True.
window_position=None # Set the browser's starting window position: "X,Y"
window_size=None # Set the browser's starting window size: "Width,Height"
@@ -827,7 +823,6 @@ log_cdp=None # Shortcut / Duplicate of "log_cdp_events".
ad_block=None # Shortcut / Duplicate of "ad_block_on".
server=None # Shortcut / Duplicate of "servername".
guest=None # Shortcut / Duplicate of "guest_mode".
-wire=None # Shortcut / Duplicate of "use_wire".
pls=None # Shortcut / Duplicate of "page_load_strategy".
use_chromium=None # Use base "Chromium"
cft=None # Use "Chrome for Testing"
diff --git a/help_docs/method_summary.md b/help_docs/method_summary.md
index 85b0995f298..ae72d8d3c67 100644
--- a/help_docs/method_summary.md
+++ b/help_docs/method_summary.md
@@ -235,7 +235,6 @@ self.get_new_driver(
binary_location=None,
driver_version=None,
page_load_strategy=None,
- use_wire=None,
external_pdf=None,
is_mobile=None,
d_width=None,
@@ -434,10 +433,6 @@ self.get_session_storage_items()
############
-self.set_wire_proxy(string) # Requires "--wire"!
-
-############
-
self.add_css_link(css_link)
self.add_js_link(js_link)
self.add_css_style(css_style)
diff --git a/help_docs/syntax_formats.md b/help_docs/syntax_formats.md
index 26013ccb530..c1181df1abc 100644
--- a/help_docs/syntax_formats.md
+++ b/help_docs/syntax_formats.md
@@ -282,30 +282,6 @@ class OverrideDriverTest(BaseCase):
(From examples/test_override_driver.py)
-The above format lets you customize [selenium-wire](https://github.com/wkeeling/selenium-wire) for intercepting and inspecting requests and responses during SeleniumBase tests. Here's how a ``selenium-wire`` integration may look:
-
-```python
-from seleniumbase import BaseCase
-from seleniumwire import webdriver # Requires "pip install selenium-wire"
-BaseCase.main(__name__, __file__)
-
-class WireTestCase(BaseCase):
- def get_new_driver(self, *args, **kwargs):
- options = webdriver.ChromeOptions()
- options.add_experimental_option(
- "excludeSwitches", ["enable-automation"]
- )
- options.add_experimental_option("useAutomationExtension", False)
- return webdriver.Chrome(options=options)
-
- def test_simple(self):
- self.open("https://seleniumbase.io/demo_page")
- for request in self.driver.requests:
- print(request.url)
-```
-
-(NOTE: The ``selenium-wire`` integration is now included with ``seleniumbase``: Add ``--wire`` as a ``pytest`` command-line option to activate.)
-
10. Overriding the driver via "sb" fixture
@@ -386,75 +362,6 @@ class TestOverride:
(From examples/test_override_sb_fixture.py)
-Here's how the [selenium-wire](https://github.com/wkeeling/selenium-wire) integration may look when overriding the ``sb`` pytest fixture to override the driver:
-
-```python
-import pytest
-
-@pytest.fixture()
-def sb(request):
- import sys
- from seleniumbase import BaseCase
- from seleniumbase import config as sb_config
- from seleniumwire import webdriver # Requires "pip install selenium-wire"
-
- class BaseClass(BaseCase):
- def get_new_driver(self, *args, **kwargs):
- options = webdriver.ChromeOptions()
- if "linux" in sys.platform:
- options.add_argument("--headless=new")
- options.add_experimental_option(
- "excludeSwitches", ["enable-automation"],
- )
- return webdriver.Chrome(options=options)
-
- def setUp(self):
- super().setUp()
-
- def tearDown(self):
- self.save_teardown_screenshot() # On failure or "--screenshot"
- super().tearDown()
-
- def base_method(self):
- pass
-
- if request.cls:
- request.cls.sb = BaseClass("base_method")
- request.cls.sb.setUp()
- request.cls.sb._needs_tearDown = True
- request.cls.sb._using_sb_fixture = True
- request.cls.sb._using_sb_fixture_class = True
- sb_config._sb_node[request.node.nodeid] = request.cls.sb
- yield request.cls.sb
- if request.cls.sb._needs_tearDown:
- request.cls.sb.tearDown()
- request.cls.sb._needs_tearDown = False
- else:
- sb = BaseClass("base_method")
- sb.setUp()
- sb._needs_tearDown = True
- sb._using_sb_fixture = True
- sb._using_sb_fixture_no_class = True
- sb_config._sb_node[request.node.nodeid] = sb
- yield sb
- if sb._needs_tearDown:
- sb.tearDown()
- sb._needs_tearDown = False
-
-def test_wire_with_no_class(sb):
- sb.open("https://seleniumbase.io/demo_page")
- for request in sb.driver.requests:
- print(request.url)
-
-class TestWire:
- def test_wire_inside_class(self, sb):
- sb.open("https://seleniumbase.io/demo_page")
- for request in sb.driver.requests:
- print(request.url)
-```
-
-(NOTE: The ``selenium-wire`` integration is now included with ``seleniumbase``: Add ``--wire`` as a ``pytest`` command-line option to activate. If you need both ``--wire`` with ``--undetected`` modes together, you'll still need to override ``get_new_driver()``.)
-
11. BaseCase with Chinese translations
@@ -963,36 +870,6 @@ finally:
(From examples/raw_driver_manager.py)
-Here's how the [selenium-wire](https://github.com/wkeeling/selenium-wire) integration may look when using the ``Driver()`` format:
-
-```python
-from seleniumbase import Driver
-
-driver = Driver(wire=True, headless=True)
-try:
- driver.get("https://wikipedia.org")
- for request in driver.requests:
- print(request.url)
-finally:
- driver.quit()
-```
-
-Here's another `selenium-wire` example with the `Driver()` format:
-
-```python
-from seleniumbase import Driver
-
-def intercept_response(request, response):
- print(request.headers)
-
-driver = Driver(wire=True)
-try:
- driver.response_interceptor = intercept_response
- driver.get("https://wikipedia.org")
-finally:
- driver.quit()
-```
-
Here's an example of basic login with the ``Driver()`` format:
```python
diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt
index 5ed1539a88f..b601ffcf1f7 100644
--- a/mkdocs_build/requirements.txt
+++ b/mkdocs_build/requirements.txt
@@ -3,10 +3,10 @@
regex>=2026.5.9
pymdown-extensions>=10.21.3
-pipdeptree>=2.35.3
+pipdeptree>=3.1.0
python-dateutil>=2.8.2
+click>=8.4.1
Markdown==3.10.2
-click==8.4.1
ghp-import==2.1.0
watchdog==6.0.0
cairocffi==1.7.1
diff --git a/requirements.txt b/requirements.txt
index b0909de473a..cd44d8637c5 100755
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,7 +10,7 @@ exceptiongroup>=1.3.1
websockets~=15.0.1;python_version<"3.10"
websockets>=16.0;python_version>="3.10"
filelock~=3.19.1;python_version<"3.10"
-filelock>=3.29.0;python_version>="3.10"
+filelock>=3.29.1;python_version>="3.10"
fasteners>=0.20
mycdp>=1.3.7
pynose>=1.5.5
@@ -30,7 +30,7 @@ pygments>=2.20.0
pyreadline3>=3.5.4;platform_system=="Windows"
tabcompleter>=1.4.1
pdbp>=1.8.2
-idna>=3.17
+idna>=3.18
charset-normalizer>=3.4.7,<4
urllib3>=1.26.20,<2;python_version<"3.10"
urllib3>=2.7.0,<3;python_version>="3.10"
diff --git a/seleniumbase/__init__.py b/seleniumbase/__init__.py
index de258d40f2f..f4bab6f2bbd 100644
--- a/seleniumbase/__init__.py
+++ b/seleniumbase/__init__.py
@@ -3,7 +3,6 @@
import pdb
import sys
from contextlib import suppress
-from selenium import webdriver
from seleniumbase.__version__ import __version__
from seleniumbase.common import decorators # noqa
from seleniumbase.common import encryption # noqa
@@ -45,13 +44,11 @@
pdb.DefaultConfig.sticky_by_default = True
colored_traceback.add_hook()
os.environ["SE_AVOID_STATS"] = "true" # Disable Selenium Manager stats
-webdriver.TouchActions = None # Lifeline for past selenium-wire versions
if sys.version_info >= (3, 10):
collections.Callable = collections.abc.Callable # Lifeline for nosetests
del collections # Undo "import collections" / Simplify "dir(seleniumbase)"
del os # Undo "import os" / Simplify "dir(seleniumbase)"
del sys # Undo "import sys" / Simplify "dir(seleniumbase)"
-del webdriver # Undo "import webdriver" / Simplify "dir(seleniumbase)"
version_list = [int(i) for i in __version__.split(".") if i.isdigit()]
version_tuple = tuple(version_list)
diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py
index 85754b965af..2aab272ac42 100755
--- a/seleniumbase/__version__.py
+++ b/seleniumbase/__version__.py
@@ -1,2 +1,2 @@
# seleniumbase package
-__version__ = "4.49.5"
+__version__ = "4.49.6"
diff --git a/seleniumbase/behave/behave_sb.py b/seleniumbase/behave/behave_sb.py
index 240d1452ac3..6cdfedcb819 100644
--- a/seleniumbase/behave/behave_sb.py
+++ b/seleniumbase/behave/behave_sb.py
@@ -101,7 +101,6 @@
-D screenshot (Save a screenshot at the end of each test.)
-D no-screenshot (No screenshots saved unless tests directly ask it.)
-D visual-baseline (Set the visual baseline for Visual/Layout tests.)
--D wire (Use selenium-wire's webdriver for replacing selenium webdriver.)
-D external-pdf (Set Chromium "plugins.always_open_pdf_externally":True.)
-D timeout-multiplier=MULTIPLIER (Multiplies the default timeout values.)
"""
@@ -204,7 +203,6 @@ def get_configured_sb(context):
sb._crumbs = False
sb._disable_beforeunload = False
sb.visual_baseline = False
- sb.use_wire = False
sb.window_position = None
sb.window_size = None
sb.maximize_option = False
@@ -645,10 +643,6 @@ def get_configured_sb(context):
if low_key in ["visual-baseline", "visual_baseline"]:
sb.visual_baseline = True
continue
- # Handle: -D wire
- if low_key == "wire":
- sb.use_wire = True
- continue
# Handle: -D window-position=X,Y / window_position=X,Y
if low_key in ["window-position", "window_position"]:
window_position = userdata[key]
diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py
index fb7bb4c9c0c..7e7d893da42 100644
--- a/seleniumbase/core/browser_launcher.py
+++ b/seleniumbase/core/browser_launcher.py
@@ -312,8 +312,6 @@ def extend_driver(
driver.execute_cdp_cmd(
"Page.addScriptToEvaluateOnNewDocument", {"source": recorder_code}
)
- if hasattr(driver, "proxy"):
- driver.set_wire_proxy = DM.set_wire_proxy
completed_loads = []
for ext_dir in sb_config._ext_dirs:
if ext_dir not in completed_loads:
@@ -645,14 +643,12 @@ def uc_open_with_cdp_mode(driver, url=None, **kwargs):
import asyncio
from seleniumbase.undetected.cdp_driver import cdp_util
- current_url = None
+ time.sleep(0.012)
try:
- current_url = driver.current_url
+ driver.disconnect()
except Exception:
- driver.connect()
- current_url = driver.current_url
- url_protocol = current_url.split(":")[0]
- driver.disconnect()
+ time.sleep(0.012)
+ driver.disconnect()
cdp_details = driver._get_cdp_details()
cdp_host = cdp_details[1].split("://")[1].split(":")[0]
@@ -2334,7 +2330,6 @@ def _set_chrome_options(
binary_location,
driver_version,
page_load_strategy,
- use_wire,
external_pdf,
servername,
mobile_emulator,
@@ -3071,7 +3066,6 @@ def get_driver(
binary_location=None,
driver_version=None,
page_load_strategy=None,
- use_wire=False,
external_pdf=False,
test_id=None,
mobile_emulator=False,
@@ -3551,7 +3545,6 @@ def get_driver(
binary_location,
driver_version,
page_load_strategy,
- use_wire,
external_pdf,
test_id,
mobile_emulator,
@@ -3610,7 +3603,6 @@ def get_driver(
binary_location,
driver_version,
page_load_strategy,
- use_wire,
external_pdf,
mobile_emulator,
device_width,
@@ -3673,7 +3665,6 @@ def get_remote_driver(
binary_location,
driver_version,
page_load_strategy,
- use_wire,
external_pdf,
test_id,
mobile_emulator,
@@ -3681,35 +3672,6 @@ def get_remote_driver(
device_height,
device_pixel_ratio,
):
- if use_wire:
- pip_find_lock = fasteners.InterProcessLock(
- constants.PipInstall.FINDLOCK
- )
- with pip_find_lock: # Prevent issues with multiple processes
- with suppress(Exception):
- shared_utils.make_writable(constants.PipInstall.FINDLOCK)
- try:
- from seleniumwire import webdriver
- import blinker
- with suppress(Exception):
- use_blinker_ver = constants.SeleniumWire.BLINKER_VER
- if blinker.__version__ != use_blinker_ver:
- shared_utils.pip_install(
- "blinker", version=use_blinker_ver
- )
- del blinker
- except Exception:
- shared_utils.pip_install(
- "blinker", version=constants.SeleniumWire.BLINKER_VER
- )
- shared_utils.pip_install(
- "selenium-wire", version=constants.SeleniumWire.VER
- )
- from seleniumwire import webdriver
- warnings.simplefilter("ignore", category=DeprecationWarning)
- else:
- from selenium import webdriver
-
# Construct the address for connecting to a Selenium Grid
if servername.startswith("https://"):
protocol = "https"
@@ -3810,7 +3772,6 @@ def get_remote_driver(
binary_location,
driver_version,
page_load_strategy,
- use_wire,
external_pdf,
servername,
mobile_emulator,
@@ -3987,7 +3948,6 @@ def get_remote_driver(
binary_location,
driver_version,
page_load_strategy,
- use_wire,
external_pdf,
servername,
mobile_emulator,
@@ -4111,7 +4071,6 @@ def get_local_driver(
binary_location,
driver_version,
page_load_strategy,
- use_wire,
external_pdf,
mobile_emulator,
device_width,
@@ -4170,35 +4129,6 @@ def get_local_driver(
local_uc_driver = driver_dir + "/uc_driver.exe"
b_path = binary_location
use_uc = is_using_uc(undetectable, browser_name)
- if use_wire:
- pip_find_lock = fasteners.InterProcessLock(
- constants.PipInstall.FINDLOCK
- )
- with pip_find_lock: # Prevent issues with multiple processes
- with suppress(Exception):
- shared_utils.make_writable(constants.PipInstall.FINDLOCK)
- try:
- from seleniumwire import webdriver
- import blinker
- with suppress(Exception):
- use_blinker_ver = constants.SeleniumWire.BLINKER_VER
- if blinker.__version__ != use_blinker_ver:
- shared_utils.pip_install(
- "blinker", version=use_blinker_ver
- )
- del blinker
- except Exception:
- shared_utils.pip_install(
- "blinker", version=constants.SeleniumWire.BLINKER_VER
- )
- shared_utils.pip_install(
- "selenium-wire", version=constants.SeleniumWire.VER
- )
- from seleniumwire import webdriver
- warnings.simplefilter("ignore", category=DeprecationWarning)
- else:
- from selenium import webdriver
-
if browser_name == constants.Browser.FIREFOX:
firefox_options = _set_firefox_options(
downloads_path,
@@ -5064,7 +4994,6 @@ def get_local_driver(
binary_location,
driver_version,
page_load_strategy,
- use_wire,
external_pdf,
servername,
mobile_emulator,
@@ -5124,7 +5053,7 @@ def get_local_driver(
and major_chrome_version
and int(major_chrome_version) >= 117
and not use_uc
- and not (remote_debug or devtools or use_wire)
+ and not (remote_debug or devtools)
and not (proxy_string or multi_proxy or proxy_pac_url)
and (not chromium_arg or "debug" not in chromium_arg)
and (not servername or servername == "localhost")
@@ -5632,7 +5561,6 @@ def get_local_driver(
binary_location,
driver_version,
page_load_strategy,
- use_wire,
external_pdf,
servername,
mobile_emulator,
@@ -5888,7 +5816,6 @@ def get_local_driver(
binary_location,
driver_version,
page_load_strategy,
- use_wire,
external_pdf,
servername,
mobile_emulator,
@@ -6213,7 +6140,7 @@ def get_local_driver(
elif extension_zip or extension_dir:
print("\nUnable to load extension while starting Chrome!\n")
raise
- elif headless or headless2 or IS_LINUX or proxy_string or use_wire:
+ elif headless or headless2 or IS_LINUX or proxy_string:
raise
# Try running without any options (bare bones Chrome launch)
if local_chromedriver and os.path.exists(local_chromedriver):
diff --git a/seleniumbase/core/sb_driver.py b/seleniumbase/core/sb_driver.py
index 383b9b5aef2..3108b03ed99 100644
--- a/seleniumbase/core/sb_driver.py
+++ b/seleniumbase/core/sb_driver.py
@@ -409,26 +409,3 @@ def reset_window_size(self):
width = settings.CHROME_START_WIDTH
height = settings.CHROME_START_HEIGHT
self.driver.set_window_rect(x, y, width, height)
-
- def set_wire_proxy(self, string):
- """Set a proxy server for selenium-wire mode ("--wire")
- Examples: (ONLY avilable if using selenium-wire mode!)
- driver.set_wire_proxy("SERVER:PORT")
- driver.set_wire_proxy("socks5://SERVER:PORT")
- driver.set_wire_proxy("USERNAME:PASSWORD@SERVER:PORT")
- """
- the_http = "http"
- the_https = "https"
- if string.startswith("socks4://"):
- the_http = "socks4"
- the_https = "socks4"
- elif string.startswith("socks5://"):
- the_http = "socks5"
- the_https = "socks5"
- string = string.split("//")[-1]
- if hasattr(self.driver, "proxy"):
- self.driver.proxy = {
- "http": "%s://%s" % (the_http, string),
- "https": "%s://%s" % (the_https, string),
- "no_proxy": "localhost,127.0.0.1",
- }
diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py
index a105ad8f602..d274dc72037 100644
--- a/seleniumbase/fixtures/base_case.py
+++ b/seleniumbase/fixtures/base_case.py
@@ -4115,7 +4115,6 @@ def get_new_driver(
binary_location=None,
driver_version=None,
page_load_strategy=None,
- use_wire=None,
external_pdf=None,
is_mobile=None,
d_width=None,
@@ -4177,7 +4176,6 @@ def get_new_driver(
binary_location - the path of the browser binary to use (Chromium)
driver_version - the chromedriver or uc_driver version to force
page_load_strategy - the option to change pageLoadStrategy (Chrome)
- use_wire - Use selenium-wire webdriver instead of the selenium one
external_pdf - "plugins.always_open_pdf_externally": True. (Chrome)
is_mobile - the option to use the mobile emulator (Chrome-only)
d_width - the device width of the mobile emulator (Chrome-only)
@@ -4210,7 +4208,7 @@ def get_new_driver(
" for examples!)"
% (browserstack_ref, sauce_labs_ref)
)
- shortcuts = ["dark", "guest", "locale", "mobile", "pls", "uc", "wire"]
+ shortcuts = ["dark", "guest", "locale", "mobile", "pls", "uc"]
if kwargs:
for key in kwargs.keys():
if key not in shortcuts:
@@ -4326,10 +4324,6 @@ def get_new_driver(
page_load_strategy = self.page_load_strategy
if "pls" in kwargs and not page_load_strategy:
page_load_strategy = kwargs["pls"]
- if use_wire is None:
- use_wire = self.use_wire
- if "wire" in kwargs and not use_wire:
- use_wire = kwargs["wire"]
if external_pdf is None:
external_pdf = self.external_pdf
test_id = self.__get_test_id()
@@ -4408,7 +4402,6 @@ def get_new_driver(
binary_location=binary_location,
driver_version=driver_version,
page_load_strategy=page_load_strategy,
- use_wire=use_wire,
external_pdf=external_pdf,
test_id=test_id,
mobile_emulator=is_mobile,
@@ -5074,6 +5067,8 @@ def activate_cdp_mode(self, url=None, **kwargs):
"""Activate CDP Mode with the URL and kwargs."""
if getattr(self.driver, "_is_using_uc", None):
if self.__is_cdp_swap_needed():
+ if url:
+ self.cdp.open(url, **kwargs)
return # CDP Mode is already active
if not self.is_connected():
self.driver.connect()
@@ -9380,35 +9375,6 @@ def get_session_storage_items(self):
############
- # Methods ONLY for the selenium-wire integration ("--wire")
-
- def set_wire_proxy(self, string):
- """Set a proxy server for selenium-wire mode ("--wire")
- NOTE: This method ONLY works while using "--wire" mode!
- Examples:
- self.set_wire_proxy("SERVER:PORT")
- self.set_wire_proxy("socks5://SERVER:PORT")
- self.set_wire_proxy("USERNAME:PASSWORD@SERVER:PORT") """
- if not string:
- self.driver.proxy = {}
- return
- the_http = "http"
- the_https = "https"
- if string.startswith("socks4://"):
- the_http = "socks4"
- the_https = "socks4"
- elif string.startswith("socks5://"):
- the_http = "socks5"
- the_https = "socks5"
- string = string.split("//")[-1]
- self.driver.proxy = {
- "http": "%s://%s" % (the_http, string),
- "https": "%s://%s" % (the_https, string),
- "no_proxy": "localhost,127.0.0.1",
- }
-
- ############
-
# Duplicates (Avoids name confusion when migrating from other frameworks.)
def open_url(self, url):
@@ -15553,7 +15519,6 @@ def setUp(self, masterqa_mode=False):
self.binary_location = sb_config.binary_location
self.driver_version = sb_config.driver_version
self.page_load_strategy = sb_config.page_load_strategy
- self.use_wire = sb_config.use_wire
self.external_pdf = sb_config.external_pdf
self._final_debug = sb_config.final_debug
self.window_position = sb_config.window_position
@@ -15937,7 +15902,6 @@ def setUp(self, masterqa_mode=False):
binary_location=self.binary_location,
driver_version=self.driver_version,
page_load_strategy=self.page_load_strategy,
- use_wire=self.use_wire,
external_pdf=self.external_pdf,
is_mobile=self.mobile_emulator,
d_width=self.__device_width,
diff --git a/seleniumbase/fixtures/constants.py b/seleniumbase/fixtures/constants.py
index b30c0c96457..6bfe749ec95 100644
--- a/seleniumbase/fixtures/constants.py
+++ b/seleniumbase/fixtures/constants.py
@@ -145,6 +145,7 @@ def get_favicon():
if not hasattr(encoded_images, "REPORT_FAVICON"):
encoded_images.REPORT_FAVICON = encoded_images.get_report_favicon()
return encoded_images.REPORT_FAVICON
+ LOCKFILE = Files.DOWNLOADS_FOLDER + "/htmlreport.lock"
class SideBySide:
@@ -346,12 +347,6 @@ class ProxyPy:
VER = "2.4.3"
-class SeleniumWire:
- # The version installed if selenium-wire is not installed
- VER = "5.1.0"
- BLINKER_VER = "1.7.0" # The "blinker" dependency version
-
-
class PyAutoGUI:
# The version installed if PyAutoGUI is not installed
VER = "0.9.54"
diff --git a/seleniumbase/plugins/driver_manager.py b/seleniumbase/plugins/driver_manager.py
index d24137f0573..7c5c0e910f7 100644
--- a/seleniumbase/plugins/driver_manager.py
+++ b/seleniumbase/plugins/driver_manager.py
@@ -116,7 +116,6 @@ def Driver(
binary_location=None, # Set path of the Chromium browser binary to use.
driver_version=None, # Set the chromedriver or uc_driver version to use.
page_load_strategy=None, # Set Chrome PLS to "normal", "eager", or "none".
- use_wire=None, # Use selenium-wire's webdriver over selenium webdriver.
external_pdf=None, # Set Chrome "plugins.always_open_pdf_externally":True.
window_position=None, # Set the browser's starting window position: "X,Y"
window_size=None, # Set the browser's starting window size: "Width,Height"
@@ -136,7 +135,6 @@ def Driver(
ad_block=None, # Shortcut / Duplicate of "ad_block_on".
server=None, # Shortcut / Duplicate of "servername".
guest=None, # Shortcut / Duplicate of "guest_mode".
- wire=None, # Shortcut / Duplicate of "use_wire".
pls=None, # Shortcut / Duplicate of "page_load_strategy".
cft=None, # Use "Chrome for Testing"
chs=None, # Use "Chrome-Headless-Shell"
@@ -214,7 +212,6 @@ def Driver(
binary_location (str): Set path of the Chromium browser binary to use.
driver_version (str): Set the chromedriver or uc_driver version to use.
page_load_strategy (str): Set Chrome PLS to "normal", "eager", or "none".
- use_wire (bool): Use selenium-wire's webdriver over selenium webdriver.
external_pdf (bool): Set Chrome "plugins.always_open_pdf_externally":True
window_position (x,y): Set the browser's starting window position: "X,Y"
window_size (w,h): Set the browser's starting window size: "Width,Height"
@@ -234,7 +231,6 @@ def Driver(
ad_block (bool): Shortcut / Duplicate of "ad_block_on".
server (str): Shortcut / Duplicate of "servername".
guest (bool): Shortcut / Duplicate of "guest_mode".
- wire (bool): Shortcut / Duplicate of "use_wire".
pls (str): Shortcut / Duplicate of "page_load_strategy".
"""
from seleniumbase import config as sb_config
@@ -873,15 +869,6 @@ def Driver(
do_not_track = True
else:
do_not_track = False
- if use_wire is None and wire is None:
- if "--wire" in sys_argv:
- use_wire = True
- else:
- use_wire = False
- elif use_wire or wire:
- use_wire = True
- else:
- use_wire = False
if external_pdf is None:
if "--external-pdf" in sys_argv or "--external_pdf" in sys_argv:
external_pdf = True
@@ -1019,7 +1006,6 @@ def Driver(
binary_location=binary_location,
driver_version=driver_version,
page_load_strategy=page_load_strategy,
- use_wire=use_wire,
external_pdf=external_pdf,
test_id=test_id,
mobile_emulator=is_mobile,
diff --git a/seleniumbase/plugins/pytest_plugin.py b/seleniumbase/plugins/pytest_plugin.py
index cc90f86d913..1b420780d93 100644
--- a/seleniumbase/plugins/pytest_plugin.py
+++ b/seleniumbase/plugins/pytest_plugin.py
@@ -128,7 +128,6 @@ def pytest_addoption(parser):
--screenshot (Save a screenshot at the end of each test.)
--no-screenshot (No screenshots saved unless tests directly ask it.)
--visual-baseline (Set the visual baseline for Visual/Layout tests.)
- --wire (Use selenium-wire's webdriver for replacing selenium webdriver.)
--external-pdf (Set Chromium "plugins.always_open_pdf_externally":True.)
--timeout-multiplier=MULTIPLIER (Multiplies the default timeout values.)
--list-fail-page (After each failing test, list the URL of the failure.)
@@ -1386,13 +1385,6 @@ def pytest_addoption(parser):
When a test calls self.check_window(), it will
rebuild its files in the visual_baseline folder.""",
)
- parser.addoption(
- "--wire",
- action="store_true",
- dest="use_wire",
- default=False,
- help="""Use selenium-wire's webdriver for selenium webdriver.""",
- )
parser.addoption(
"--external_pdf",
"--external-pdf",
@@ -1665,16 +1657,12 @@ def pytest_addoption(parser):
'\n (Your browser choice was: "%s")\n' % browser_list[0]
)
raise Exception(message)
- if undetectable and "--wire" in sys_argv:
- raise Exception(
- "\n SeleniumBase doesn't support mixing --uc with --wire mode!"
- "\n If you need both, override get_new_driver() from BaseCase:"
- "\n https://seleniumbase.io/help_docs/syntax_formats/#sb_sf_09\n"
- )
def pytest_configure(config):
"""This runs after command-line options have been parsed."""
+ global _pytest_config
+ _pytest_config = config
sb_config.item_count = 0
sb_config.item_count_passed = 0
sb_config.item_count_failed = 0
@@ -1897,7 +1885,6 @@ def pytest_configure(config):
sb_config.save_screenshot = config.getoption("save_screenshot")
sb_config.no_screenshot = config.getoption("no_screenshot")
sb_config.visual_baseline = config.getoption("visual_baseline")
- sb_config.use_wire = config.getoption("use_wire")
sb_config.external_pdf = config.getoption("external_pdf")
sb_config.timeout_multiplier = config.getoption("timeout_multiplier")
sb_config.list_fp = config.getoption("fail_page")
@@ -2176,6 +2163,16 @@ def pytest_collection_finish(session):
)
else:
print("Dashboard: %s%s%s\n%s" % (c1, dash_url, cr, stars))
+ htmlpath = session.config.getoption("--html", default=None)
+ if htmlpath:
+ with suppress(Exception):
+ if getattr(sb_config, "_multithreaded", None):
+ from filelock import FileLock
+ dash_lock = FileLock(constants.Report.LOCKFILE)
+ with dash_lock:
+ _fix_html_report(htmlpath)
+ else:
+ _fix_html_report(htmlpath)
def pytest_runtest_setup(item):
@@ -2191,10 +2188,49 @@ def pytest_runtest_setup(item):
sb_config._latest_display_id = display_id
+def pytest_runtest_logreport(report):
+ with suppress(Exception):
+ if _pytest_config: # Global variable
+ htmlpath = _pytest_config.getoption("--html", default=None)
+ if htmlpath:
+ # The HTML report option is enabled
+ if report.when == "teardown":
+ if getattr(sb_config, "_multithreaded", None):
+ # Multi-threaded tests
+ from filelock import FileLock
+ dash_lock = FileLock(constants.Report.LOCKFILE)
+ with dash_lock:
+ _fix_html_report(htmlpath)
+ else:
+ # Single-threaded tests
+ _fix_html_report(htmlpath)
+
+
+def _fix_html_report(report_path):
+ # (Only if there's a pytest-html report present)
+ with suppress(Exception):
+ abs_path = os.path.abspath(".")
+ html_report_path = os.path.join(abs_path, report_path)
+ if not os.path.exists(html_report_path):
+ return
+ the_html_r = None
+ with open(html_report_path, mode="r", encoding="utf-8") as f:
+ the_html_r = f.read()
+ if "page to ge the" not in the_html_r:
+ return # The typo was already fixed
+ # Collapsible rows are trickier to select for copy/paste
+ the_html_r = the_html_r.replace(
+ "findAll('.collapsible", "//findAll('.collapsible"
+ )
+ # Fix typo in pytest-html 4.0.2
+ # (Later versions have a worse bug that prevents live updates)
+ the_html_r = the_html_r.replace("page to ge the", "page to get the")
+ with open(html_report_path, mode="w", encoding="utf-8") as f:
+ f.write(the_html_r) # Update the HTML report
+
+
def pytest_runtest_teardown(item):
- """This runs after every test with pytest.
- Make sure that webdriver and headless displays have exited.
- (Has zero effect on tests using --reuse-session / --rs)"""
+ """This runs after every test with pytest."""
if "--co" in sys_argv or "--collect-only" in sys_argv:
return
with suppress(Exception):
@@ -2323,10 +2359,7 @@ def _perform_pytest_unconfigure_(config):
reporter = config.pluginmanager.get_plugin("terminalreporter")
start_time = None
- if hasattr(reporter, "_sessionstarttime"):
- start_time = reporter._sessionstarttime # (pytest < 8.4.0)
- else:
- start_time = reporter._session_start.time # (pytest >= 8.4.0)
+ start_time = reporter._session_start.time # (pytest >= 8.4.0)
duration = time.time() - start_time
if not getattr(sb_config, "multi_proxy", None):
proxy_helper.remove_proxy_zip_if_present()
@@ -2663,13 +2696,10 @@ def pytest_unconfigure(config):
return
reporter = config.pluginmanager.get_plugin("terminalreporter")
if (
- not hasattr(reporter, "_sessionstarttime")
- and (
- not hasattr(reporter, "_session_start")
- or (
- hasattr(reporter, "_session_start")
- and not hasattr(reporter._session_start, "time")
- )
+ not hasattr(reporter, "_session_start")
+ or (
+ hasattr(reporter, "_session_start")
+ and not hasattr(reporter._session_start, "time")
)
):
return
diff --git a/seleniumbase/plugins/sb_manager.py b/seleniumbase/plugins/sb_manager.py
index ed8d6798bb7..d95bf6e2417 100644
--- a/seleniumbase/plugins/sb_manager.py
+++ b/seleniumbase/plugins/sb_manager.py
@@ -82,7 +82,6 @@ def SB(
driver_version=None, # Set the chromedriver or uc_driver version to use.
skip_js_waits=None, # Skip JS Waits (readyState=="complete" and Angular).
wait_for_angularjs=None, # Wait for AngularJS to load after some actions.
- use_wire=None, # Use selenium-wire's webdriver over selenium webdriver.
external_pdf=None, # Set Chrome "plugins.always_open_pdf_externally":True.
window_position=None, # Set the browser's starting window position: "X,Y"
window_size=None, # Set the browser's starting window size: "Width,Height"
@@ -118,7 +117,6 @@ def SB(
ad_block=None, # Shortcut / Duplicate of "ad_block_on".
server=None, # Shortcut / Duplicate of "servername".
guest=None, # Shortcut / Duplicate of "guest_mode".
- wire=None, # Shortcut / Duplicate of "use_wire".
pls=None, # Shortcut / Duplicate of "page_load_strategy".
sjw=None, # Shortcut / Duplicate of "skip_js_waits".
wfa=None, # Shortcut / Duplicate of "wait_for_angularjs".
@@ -208,7 +206,6 @@ def SB(
driver_version (str): Set the chromedriver or uc_driver version to use.
skip_js_waits (bool): Skip JS Waits (readyState=="complete" and Angular).
wait_for_angularjs (bool): Wait for AngularJS to load after some actions.
- use_wire (bool): Use selenium-wire's webdriver over selenium webdriver.
external_pdf (bool): Set Chrome "plugins.always_open_pdf_externally":True.
window_position (x,y): Set the browser's starting window position: "X,Y"
window_size (w,h): Set the browser's starting window size: "Width,Height"
@@ -244,7 +241,6 @@ def SB(
ad_block (bool): Shortcut / Duplicate of "ad_block_on".
server (str): Shortcut / Duplicate of "servername".
guest (bool): Shortcut / Duplicate of "guest_mode".
- wire (bool): Shortcut / Duplicate of "use_wire".
pls (str): Shortcut / Duplicate of "page_load_strategy".
sjw (bool): Shortcut / Duplicate of "skip_js_waits".
wfa (bool): Shortcut / Duplicate of "wait_for_angularjs".
@@ -1030,15 +1026,6 @@ def SB(
do_not_track = True
else:
do_not_track = False
- if use_wire is None and wire is None:
- if "--wire" in sys_argv:
- use_wire = True
- else:
- use_wire = False
- elif use_wire or wire:
- use_wire = True
- else:
- use_wire = False
if external_pdf is None:
if "--external-pdf" in sys_argv or "--external_pdf" in sys_argv:
external_pdf = True
@@ -1226,7 +1213,6 @@ def SB(
sb_config.host_resolver_rules = host_resolver_rules
sb_config.block_images = block_images
sb_config.do_not_track = do_not_track
- sb_config.use_wire = use_wire
sb_config.external_pdf = external_pdf
sb_config.remote_debug = remote_debug
sb_config.settings_file = settings_file
@@ -1337,7 +1323,6 @@ def SB(
sb.host_resolver_rules = sb_config.host_resolver_rules
sb.block_images = sb_config.block_images
sb.do_not_track = sb_config.do_not_track
- sb.use_wire = sb_config.use_wire
sb.external_pdf = sb_config.external_pdf
sb.remote_debug = sb_config.remote_debug
sb.settings_file = sb_config.settings_file
diff --git a/seleniumbase/plugins/selenium_plugin.py b/seleniumbase/plugins/selenium_plugin.py
index 3ecf7c0af2d..fd1077851af 100644
--- a/seleniumbase/plugins/selenium_plugin.py
+++ b/seleniumbase/plugins/selenium_plugin.py
@@ -100,7 +100,6 @@ class SeleniumBrowser(Plugin):
--maximize (Start tests with the browser window maximized.)
--screenshot (Save a screenshot at the end of each test.)
--visual-baseline (Set the visual baseline for Visual/Layout tests.)
- --wire (Use selenium-wire's webdriver for replacing selenium webdriver.)
--external-pdf (Set Chromium "plugins.always_open_pdf_externally": True.)
--timeout-multiplier=MULTIPLIER (Multiplies the default timeout values.)
"""
@@ -1047,13 +1046,6 @@ def options(self, parser, env):
When a test calls self.check_window(), it will
rebuild its files in the visual_baseline folder.""",
)
- parser.addoption(
- "--wire",
- action="store_true",
- dest="use_wire",
- default=False,
- help="""Use selenium-wire's webdriver for selenium webdriver.""",
- )
parser.addoption(
"--external_pdf",
"--external-pdf",
@@ -1443,7 +1435,6 @@ def beforeTest(self, test):
test.test.save_screenshot_after_test = self.options.save_screenshot
test.test.no_screenshot_after_test = self.options.no_screenshot
test.test.visual_baseline = self.options.visual_baseline
- test.test.use_wire = self.options.use_wire
test.test.external_pdf = self.options.external_pdf
test.test.timeout_multiplier = self.options.timeout_multiplier
test.test.dashboard = False
@@ -1476,16 +1467,6 @@ def beforeTest(self, test):
else:
self.options.xvfb = True
test.test.xvfb = True
- if self.options.use_wire and self.options.undetectable:
- print(
- "\n"
- "SeleniumBase doesn't support mixing --uc with --wire mode.\n"
- "If you need both, override get_new_driver() from BaseCase:\n"
- "https://seleniumbase.io/help_docs/syntax_formats/#sb_sf_09\n"
- "(Only UC Mode without Wire Mode will be used for this run)\n"
- )
- self.options.use_wire = False
- test.test.use_wire = False
# Recorder Mode can still optimize scripts in --headless2 mode.
if self.options.recorder_mode and self.options.headless:
self.options.headless = False
diff --git a/seleniumbase/undetected/__init__.py b/seleniumbase/undetected/__init__.py
index 70d2f8fcb6d..e37947d8c3b 100644
--- a/seleniumbase/undetected/__init__.py
+++ b/seleniumbase/undetected/__init__.py
@@ -84,7 +84,6 @@ def __init__(
If left as 0, a free port will be found.
enable_cdp_events: (default: False)
- This enables the handling of wire messages.
When enabled, you can subscribe to CDP events by using:
driver.add_cdp_listener("Network.dataReceived", yourcallback)
diff --git a/seleniumbase/undetected/cdp_driver/connection.py b/seleniumbase/undetected/cdp_driver/connection.py
index 920fab3982e..ca4a725be4b 100644
--- a/seleniumbase/undetected/cdp_driver/connection.py
+++ b/seleniumbase/undetected/cdp_driver/connection.py
@@ -314,11 +314,15 @@ async def wait(self, t: Union[int, float] = None):
try:
if isinstance(t, (int, float)):
try:
+ # Pass the coroutine directly to wait_for()
await asyncio.wait_for(
self.listener.idle.wait(), timeout=t
)
- except RuntimeError:
- await self.listener.idle.wait()
+ except (RuntimeError, asyncio.TimeoutError):
+ # If the wait_for() fails or errors out, just pass.
+ # The wait_for() cancels the underlying coroutine.
+ pass
+ # Keep waiting until the absolute time 't' has elapsed
while (loop.time() - start_time) < t:
await asyncio.sleep(0.1)
else:
diff --git a/seleniumbase/undetected/patcher.py b/seleniumbase/undetected/patcher.py
index abba1348b7b..7df17e62c41 100644
--- a/seleniumbase/undetected/patcher.py
+++ b/seleniumbase/undetected/patcher.py
@@ -8,7 +8,6 @@
import time
import zipfile
from contextlib import suppress
-from seleniumbase.console_scripts import sb_install
from seleniumbase.fixtures import shared_utils
logger = logging.getLogger(__name__)
@@ -111,6 +110,7 @@ def auto(self, executable_path=None, force=False, version_main=None):
if int(self.version_main) < 115:
self.unzip_package(self.fetch_package())
else:
+ from seleniumbase.console_scripts import sb_install
sb_install.main(
override="chromedriver %s" % self.version_main,
intel_for_uc=shared_utils.is_arm_mac(),
@@ -131,6 +131,7 @@ def fetch_release_number(self):
path = path.upper()
logger.debug("Getting release number from %s" % path)
if self.version_main and int(self.version_main) > 114:
+ from seleniumbase.console_scripts import sb_install
return (
sb_install.get_cft_latest_version_from_milestone(
str(self.version_main)
diff --git a/setup.py b/setup.py
index 8fc93825a8b..5aece7f1806 100755
--- a/setup.py
+++ b/setup.py
@@ -142,6 +142,7 @@
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
+ "Programming Language :: Python :: 3.15",
"Topic :: Internet",
"Topic :: Internet :: WWW/HTTP :: Browsers",
"Topic :: Scientific/Engineering",
@@ -173,7 +174,7 @@
'websockets~=15.0.1;python_version<"3.10"',
'websockets>=16.0;python_version>="3.10"',
'filelock~=3.19.1;python_version<"3.10"',
- 'filelock>=3.29.0;python_version>="3.10"',
+ 'filelock>=3.29.1;python_version>="3.10"',
'fasteners>=0.20',
'mycdp>=1.3.7',
'pynose>=1.5.5',
@@ -193,7 +194,7 @@
'pyreadline3>=3.5.4;platform_system=="Windows"',
'tabcompleter>=1.4.1',
'pdbp>=1.8.2',
- 'idna>=3.17',
+ 'idna>=3.18',
'charset-normalizer>=3.4.7,<4',
'urllib3>=1.26.20,<2;python_version<"3.10"',
'urllib3>=2.7.0,<3;python_version>="3.10"',
@@ -243,9 +244,9 @@
# Usage: pytest --alluredir=allure_results
# Serve: allure serve allure_results
"allure": [
- 'allure-pytest>=2.13.5',
- 'allure-python-commons>=2.13.5',
- 'allure-behave>=2.13.5',
+ 'allure-pytest>=2.16.0',
+ 'allure-python-commons>=2.16.0',
+ 'allure-behave>=2.16.0',
],
# pip install -e .[coverage]
# Usage: coverage run -m pytest; coverage html; coverage report
@@ -262,12 +263,6 @@
'pyflakes==3.4.0',
'pycodestyle==2.14.0',
],
- # pip install -e .[ipdb]
- # (Not needed for debugging anymore. SeleniumBase now includes "pdbp".)
- "ipdb": [
- "ipdb==0.13.13",
- 'ipython==7.34.0',
- ],
# pip install -e .[mss]
# (An optional library for tile_windows() in CDP Mode.)
"mss": [
@@ -293,7 +288,7 @@
# (If you see [SSL: CERTIFICATE_VERIFY_FAILED], then get this.)
# (May help those with corporate self-signed certs on Windows.)
"pip-system-certs": [
- 'pip-system-certs==4.0;platform_system=="Windows"',
+ 'pip-system-certs>=4.0;platform_system=="Windows"',
],
# pip install -e .[proxy]
# Usage: proxy
@@ -313,24 +308,6 @@
"pyautogui": [
'PyAutoGUI>=0.9.54;platform_system!="Linux"',
],
- # pip install -e .[selenium-stealth]
- "selenium-stealth": [
- 'selenium-stealth==1.0.6',
- ],
- # pip install -e .[selenium-wire]
- "selenium-wire": [
- 'selenium-wire==5.1.0',
- 'pyOpenSSL>=24.2.1',
- 'pyparsing>=3.1.4',
- 'Brotli==1.1.0',
- 'blinker==1.7.0', # Newer ones had issues
- 'h2==4.1.0',
- 'hpack==4.0.0',
- 'hyperframe==6.0.1',
- 'kaitaistruct==0.10',
- 'pyasn1==0.6.1',
- 'zstandard>=0.23.0',
- ],
},
packages=[
"seleniumbase",