diff --git a/examples/cdp_mode/ReadMe.md b/examples/cdp_mode/ReadMe.md index b98f8e68a6d..77b91a766fb 100644 --- a/examples/cdp_mode/ReadMe.md +++ b/examples/cdp_mode/ReadMe.md @@ -164,11 +164,11 @@ with SB(uc=True, test=True, locale="en", ad_block=True) as sb: sb.cdp.highlight_overlay("div.pokemon-ability-info") sb.sleep(2) sb.cdp.open("https://events.pokemon.com/EventLocator/") - sb.sleep(3) - sb.cdp.click('button span:contains("Premier Events")') - sb.sleep(1) - events = sb.cdp.select_all('div[class="event-info"]') - print("*** Upcoming Premier Events for Pokémon: ***") + sb.sleep(2) + sb.cdp.click('span:contains("Championship")') + sb.sleep(2) + events = sb.cdp.select_all("div.event-info__title") + print("*** Pokémon Championship Events: ***") for event in events: print("* " + event.text) sb.sleep(2) diff --git a/examples/cdp_mode/raw_pokemon.py b/examples/cdp_mode/raw_pokemon.py index b8b4829b6e6..5abf36f6770 100644 --- a/examples/cdp_mode/raw_pokemon.py +++ b/examples/cdp_mode/raw_pokemon.py @@ -31,11 +31,11 @@ sb.cdp.highlight_overlay("div.pokemon-ability-info") sb.sleep(2) sb.cdp.open("https://events.pokemon.com/EventLocator/") - sb.sleep(3) - sb.cdp.click('button span:contains("Premier Events")') - sb.sleep(1) - events = sb.cdp.select_all('div[class="event-info"]') - print("*** Upcoming Premier Events for Pokémon: ***") + sb.sleep(2) + sb.cdp.click('span:contains("Championship")') + sb.sleep(2) + events = sb.cdp.select_all("div.event-info__title") + print("*** Pokémon Championship Events: ***") for event in events: print("* " + event.text) sb.sleep(2) diff --git a/examples/presenter/uc_presentation_4.py b/examples/presenter/uc_presentation_4.py index 36bc7ab9e5f..e16ed4e050e 100644 --- a/examples/presenter/uc_presentation_4.py +++ b/examples/presenter/uc_presentation_4.py @@ -472,7 +472,7 @@ def test_presentation_4(self): sb.sleep(0.5) sb.scroll_into_view("a#advSearch") sb.sleep(0.5) - sb.cdp.mouse_click("a#advSearch") + sb.cdp.click("a#advSearch") sb.sleep(1.2) sb.cdp.click('img[src*="img/pokedex/detail/025.png"]') sb.cdp.assert_text("Pikachu", 'div[class*="title"]') @@ -484,24 +484,16 @@ def test_presentation_4(self): sb.cdp.flash("div.pokemon-ability-info") name = sb.cdp.get_text("label.styled-select") info = sb.cdp.get_text("div.version-descriptions p.active") - print("\n\n*** %s: ***\n* %s" % (name, info)) + print("*** %s: ***\n* %s" % (name, info)) sb.sleep(2) sb.cdp.highlight_overlay("div.pokemon-ability-info") sb.sleep(2) - sb.cdp.click('a[href="https://www.pokemon.com/us/play-pokemon/"]') - sb.sleep(0.6) - sb.cdp.click('h3:contains("Find an Event")') - location = "Concord, MA, USA" - sb.cdp.type('input[data-testid="location-search"]', location) - sb.sleep(1.5) - sb.cdp.click( - "div.autocomplete-dropdown-container div.suggestion-item" - ) - sb.sleep(0.6) - sb.cdp.click('img[alt="search-icon"]') + sb.cdp.open("https://events.pokemon.com/EventLocator/") + sb.sleep(2) + sb.cdp.click('span:contains("Championship")') sb.sleep(2) - events = sb.cdp.select_all('div[data-testid="event-name"]') - print("\n*** Pokemon events near %s: ***" % location) + events = sb.cdp.select_all("div.event-info__title") + print("*** Pokémon Championship Events: ***") for event in events: print("* " + event.text) sb.sleep(2) diff --git a/mkdocs_build/requirements.txt b/mkdocs_build/requirements.txt index f3bebc7e166..327886dd1d0 100644 --- a/mkdocs_build/requirements.txt +++ b/mkdocs_build/requirements.txt @@ -14,7 +14,7 @@ pathspec==0.12.1 Babel==2.17.0 paginate==0.5.7 mkdocs==1.6.1 -mkdocs-material==9.6.21 +mkdocs-material==9.6.22 mkdocs-exclude-search==0.6.6 mkdocs-simple-hooks==0.1.5 mkdocs-material-extensions==1.3.1 diff --git a/requirements.txt b/requirements.txt index a933d1e0b54..3ba928a114e 100755 --- a/requirements.txt +++ b/requirements.txt @@ -34,9 +34,9 @@ pygments>=2.19.2 pyreadline3>=3.5.4;platform_system=="Windows" tabcompleter>=1.4.0 pdbp>=1.7.1 -idna==3.10 +idna>=3.11 chardet==5.2.0 -charset-normalizer>=3.4.3,<4 +charset-normalizer>=3.4.4,<4 urllib3>=1.26.20,<2;python_version<"3.10" urllib3>=1.26.20,<2.6.0;python_version>="3.10" requests==2.32.4;python_version<"3.9" @@ -87,7 +87,8 @@ rich>=14.2.0,<15 # ("pip install -r requirements.txt" also installs this, but "pip install -e ." won't.) coverage>=7.6.1;python_version<"3.9" -coverage>=7.10.7;python_version>="3.9" +coverage>=7.10.7;python_version>="3.9" and python_version<"3.10" +coverage>=7.11.0;python_version>="3.10" pytest-cov>=5.0.0;python_version<"3.9" pytest-cov>=7.0.0;python_version>="3.9" flake8==5.0.4;python_version<"3.9" diff --git a/seleniumbase/__version__.py b/seleniumbase/__version__.py index ddb7f76a9ea..2984fa9fe87 100755 --- a/seleniumbase/__version__.py +++ b/seleniumbase/__version__.py @@ -1,2 +1,2 @@ # seleniumbase package -__version__ = "4.42.5" +__version__ = "4.42.6" diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index ffbd5df8d59..2d5db1b88db 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -985,17 +985,15 @@ def __install_pyautogui_if_missing(): import pyautogui with suppress(Exception): use_pyautogui_ver = constants.PyAutoGUI.VER - if pyautogui.__version__ != use_pyautogui_ver: - del pyautogui - shared_utils.pip_install( - "pyautogui", version=use_pyautogui_ver - ) + u_pv = shared_utils.make_version_tuple(use_pyautogui_ver) + pv = shared_utils.make_version_tuple(pyautogui.__version__) + if pv < u_pv: + del pyautogui # To get newer ver + shared_utils.pip_install("pyautogui", version="Latest") import pyautogui except Exception: print("\nPyAutoGUI required! Installing now...") - shared_utils.pip_install( - "pyautogui", version=constants.PyAutoGUI.VER - ) + shared_utils.pip_install("pyautogui", version="Latest") try: import pyautogui except Exception: diff --git a/seleniumbase/core/sb_cdp.py b/seleniumbase/core/sb_cdp.py index bd3d94d0d41..835c82fba66 100644 --- a/seleniumbase/core/sb_cdp.py +++ b/seleniumbase/core/sb_cdp.py @@ -912,6 +912,12 @@ def send_keys(self, selector, text, timeout=None): element.scroll_into_view() if text.endswith("\n") or text.endswith("\r"): text = text[:-1] + "\r\n" + elif ( + element.tag_name == "textarea" + and "\n" in text + and "\r" not in text + ): + text = text.replace("\n", "\r") element.send_keys(text) self.__slow_mode_pause_if_set() self.loop.run_until_complete(self.page.sleep(0.025)) @@ -927,6 +933,12 @@ def press_keys(self, selector, text, timeout=None): if text.endswith("\n") or text.endswith("\r"): submit = True text = text[:-1] + elif ( + element.tag_name == "textarea" + and "\n" in text + and "\r" not in text + ): + text = text.replace("\n", "\r") for key in text: element.send_keys(key) time.sleep(0.044) @@ -947,6 +959,12 @@ def type(self, selector, text, timeout=None): element.clear_input() if text.endswith("\n") or text.endswith("\r"): text = text[:-1] + "\r\n" + elif ( + element.tag_name == "textarea" + and "\n" in text + and "\r" not in text + ): + text = text.replace("\n", "\r") element.send_keys(text) self.__slow_mode_pause_if_set() self.loop.run_until_complete(self.page.sleep(0.025)) @@ -1555,17 +1573,15 @@ def __install_pyautogui_if_missing(self): import pyautogui with suppress(Exception): use_pyautogui_ver = constants.PyAutoGUI.VER - if pyautogui.__version__ != use_pyautogui_ver: - del pyautogui - shared_utils.pip_install( - "pyautogui", version=use_pyautogui_ver - ) + u_pv = shared_utils.make_version_tuple(use_pyautogui_ver) + pv = shared_utils.make_version_tuple(pyautogui.__version__) + if pv < u_pv: + del pyautogui # To get newer ver + shared_utils.pip_install("pyautogui", version="Latest") import pyautogui except Exception: print("\nPyAutoGUI required! Installing now...") - shared_utils.pip_install( - "pyautogui", version=constants.PyAutoGUI.VER - ) + shared_utils.pip_install("pyautogui", version="Latest") try: import pyautogui except Exception: diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index a6f61b48d0e..f8017249cf7 100644 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -114,9 +114,7 @@ def __initialize_variables(self): self.driver = None self.environment = None self.env = None # Add a shortened version of self.environment - self.version_list = [ - int(i) for i in __version__.split(".") if i.isdigit() - ] + self.version_list = shared_utils.make_version_list(__version__) self.version_tuple = tuple(self.version_list) self.version_info = self.version_tuple self.time = time.time @@ -14491,11 +14489,11 @@ def __activate_virtual_display(self): import pyautogui with suppress(Exception): use_pyautogui_ver = constants.PyAutoGUI.VER - if pyautogui.__version__ != use_pyautogui_ver: + u_pv = shared_utils.make_version_tuple(use_pyautogui_ver) + pv = shared_utils.make_version_tuple(pyautogui.__version__) + if pv < u_pv: del pyautogui # To get newer ver - shared_utils.pip_install( - "pyautogui", version=use_pyautogui_ver - ) + shared_utils.pip_install("pyautogui", version="Latest") import pyautogui pyautogui_is_installed = True except Exception: @@ -14504,9 +14502,7 @@ def __activate_virtual_display(self): "Installing now..." ) print("\n" + message) - shared_utils.pip_install( - "pyautogui", version=constants.PyAutoGUI.VER - ) + shared_utils.pip_install("pyautogui", version="Latest") import pyautogui pyautogui_is_installed = True if ( diff --git a/seleniumbase/fixtures/shared_utils.py b/seleniumbase/fixtures/shared_utils.py index 3b76f65f688..908c226688c 100644 --- a/seleniumbase/fixtures/shared_utils.py +++ b/seleniumbase/fixtures/shared_utils.py @@ -18,16 +18,35 @@ def pip_install(package, version=None): pip_install_lock = fasteners.InterProcessLock( constants.PipInstall.LOCKFILE ) + upgrade_to_latest = False + if ( + version + and ("U" in str(version).upper() or "L" in str(version).upper()) + ): + # Upgrade to Latest when specified with "U" or "L" + upgrade_to_latest = True with pip_install_lock: if not version: subprocess.check_call( [sys.executable, "-m", "pip", "install", package] ) - else: + elif not upgrade_to_latest: package_and_version = package + "==" + str(version) subprocess.check_call( [sys.executable, "-m", "pip", "install", package_and_version] ) + else: + subprocess.check_call( + [sys.executable, "-m", "pip", "install", "-U", package] + ) + + +def make_version_list(version_str): + return [int(i) for i in version_str.split(".") if i.isdigit()] + + +def make_version_tuple(version_str): + return tuple(make_version_list(version_str)) def get_mfa_code(totp_key=None): diff --git a/seleniumbase/undetected/cdp_driver/cdp_util.py b/seleniumbase/undetected/cdp_driver/cdp_util.py index 7cc750cb635..83ecd55eb79 100644 --- a/seleniumbase/undetected/cdp_driver/cdp_util.py +++ b/seleniumbase/undetected/cdp_driver/cdp_util.py @@ -121,22 +121,26 @@ def __activate_virtual_display_as_needed( import pyautogui with suppress(Exception): use_pyautogui_ver = constants.PyAutoGUI.VER - if pyautogui.__version__ != use_pyautogui_ver: + u_pv = shared_utils.make_version_tuple( + use_pyautogui_ver + ) + pv = shared_utils.make_version_tuple( + pyautogui.__version__ + ) + if pv < u_pv: del pyautogui # To get newer ver shared_utils.pip_install( - "pyautogui", version=use_pyautogui_ver + "pyautogui", version="Latest" ) import pyautogui pyautogui_is_installed = True except Exception: message = ( - "PyAutoGUI is required for UC Mode on Linux! " + "PyAutoGUI is required for CDP Mode on Linux! " "Installing now..." ) print("\n" + message) - shared_utils.pip_install( - "pyautogui", version=constants.PyAutoGUI.VER - ) + shared_utils.pip_install("pyautogui", version="Latest") import pyautogui pyautogui_is_installed = True if ( diff --git a/setup.py b/setup.py index 0003bf56a87..f19d8a62b76 100755 --- a/setup.py +++ b/setup.py @@ -181,9 +181,9 @@ 'pyreadline3>=3.5.4;platform_system=="Windows"', "tabcompleter>=1.4.0", "pdbp>=1.7.1", - "idna==3.10", + "idna>=3.11", 'chardet==5.2.0', - 'charset-normalizer>=3.4.3,<4', + 'charset-normalizer>=3.4.4,<4', 'urllib3>=1.26.20,<2;python_version<"3.10"', 'urllib3>=1.26.20,<2.6.0;python_version>="3.10"', 'requests==2.32.4;python_version<"3.9"', @@ -243,7 +243,8 @@ # Usage: coverage run -m pytest; coverage html; coverage report "coverage": [ 'coverage>=7.6.1;python_version<"3.9"', - 'coverage>=7.10.7;python_version>="3.9"', + 'coverage>=7.10.7;python_version>="3.9" and python_version<"3.10"', + 'coverage>=7.11.0;python_version>="3.10"', 'pytest-cov>=5.0.0;python_version<"3.9"', 'pytest-cov>=7.0.0;python_version>="3.9"', ], @@ -286,7 +287,8 @@ # (An optional library for image-processing.) "pillow": [ 'Pillow>=10.4.0;python_version<"3.9"', - 'Pillow>=11.3.0;python_version>="3.9"', + 'Pillow>=11.3.0;python_version>="3.9" and python_version<"3.10"', + 'Pillow>=12.0.0;python_version>="3.10"', ], # pip install -e .[pip-system-certs] # (If you see [SSL: CERTIFICATE_VERIFY_FAILED], then get this.)