From d65c52cd18c0728b405b4807b525c423b0ac3cb2 Mon Sep 17 00:00:00 2001 From: Michael Mintz Date: Mon, 23 Sep 2024 00:49:23 -0400 Subject: [PATCH] Make multiple updates --- sbase/__init__.py | 1 + seleniumbase/__init__.py | 5 +- seleniumbase/behave/behave_sb.py | 56 +- seleniumbase/config/settings.py | 4 + seleniumbase/console_scripts/sb_behave_gui.py | 10 +- seleniumbase/console_scripts/sb_caseplans.py | 12 +- seleniumbase/console_scripts/sb_commander.py | 10 +- seleniumbase/console_scripts/sb_recorder.py | 8 +- seleniumbase/core/browser_launcher.py | 107 +-- seleniumbase/core/mysql.py | 5 +- seleniumbase/core/recorder_helper.py | 29 +- seleniumbase/core/sb_driver.py | 5 +- seleniumbase/fixtures/base_case.py | 689 ++++++------------ seleniumbase/fixtures/js_utils.py | 71 +- seleniumbase/fixtures/page_actions.py | 9 +- seleniumbase/fixtures/page_utils.py | 78 +- seleniumbase/plugins/base_plugin.py | 5 +- seleniumbase/plugins/driver_manager.py | 97 ++- seleniumbase/plugins/pytest_plugin.py | 29 +- seleniumbase/plugins/sb_manager.py | 122 +++- seleniumbase/plugins/selenium_plugin.py | 9 +- seleniumbase/undetected/__init__.py | 51 +- seleniumbase/undetected/dprocess.py | 10 +- seleniumbase/undetected/options.py | 9 +- seleniumbase/undetected/patcher.py | 5 +- setup.py | 9 +- 26 files changed, 648 insertions(+), 797 deletions(-) diff --git a/sbase/__init__.py b/sbase/__init__.py index b45beac8..ff1a31a5 100644 --- a/sbase/__init__.py +++ b/sbase/__init__.py @@ -11,3 +11,4 @@ from seleniumbase import MasterQA # noqa from seleniumbase import page_actions # noqa from seleniumbase import page_utils # noqa from seleniumbase import SB # noqa +from seleniumbase import translate # noqa diff --git a/seleniumbase/__init__.py b/seleniumbase/__init__.py index e84a7d36..0f536be7 100644 --- a/seleniumbase/__init__.py +++ b/seleniumbase/__init__.py @@ -10,7 +10,7 @@ from selenium import webdriver from seleniumbase.__version__ import __version__ from seleniumbase.common import decorators # noqa from seleniumbase.common import encryption # noqa -from seleniumbase.core import colored_traceback +from seleniumbase.core import colored_traceback # noqa from seleniumbase.core.browser_launcher import get_driver # noqa from seleniumbase.fixtures import js_utils # noqa from seleniumbase.fixtures import page_actions # noqa @@ -36,8 +36,7 @@ if sys.version_info[0] < 3 and "pdbp" in locals(): pdb.DefaultConfig.sticky_by_default = True colored_traceback.add_hook() os.environ["SE_AVOID_STATS"] = "true" # Disable Selenium Manager stats -if sys.version_info >= (3, 7): - webdriver.TouchActions = None # Lifeline for past selenium-wire versions +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)" diff --git a/seleniumbase/behave/behave_sb.py b/seleniumbase/behave/behave_sb.py index 901bf76c..17609334 100644 --- a/seleniumbase/behave/behave_sb.py +++ b/seleniumbase/behave/behave_sb.py @@ -48,6 +48,7 @@ behave -D agent="User Agent String" -D demo -D headless2 (Use the new headless mode, which supports extensions.) -D headed (Run tests in headed/GUI mode on Linux OS, where not default.) -D xvfb (Run tests using the Xvfb virtual display server on Linux OS.) +-D xvfb-metrics=STRING (Set Xvfb display size on Linux: "Width,Height".) -D locale=LOCALE_CODE (Set the Language Locale Code for the web browser.) -D pdb (Activate Post Mortem Debug Mode if a test fails.) -D interval=SECONDS (The autoplay interval for presentations & tour steps) @@ -90,6 +91,7 @@ behave -D agent="User Agent String" -D demo -D rcs | -D reuse-class-session (Reuse session for tests in class/feature) -D crumbs (Delete all cookies between tests reusing a session.) -D disable-beforeunload (Disable the "beforeunload" event on Chrome.) +-D window-position=X,Y (Set the browser's starting window position.) -D window-size=WIDTH,HEIGHT (Set the browser's starting window size.) -D maximize (Start tests with the browser window maximized.) -D screenshot (Save a screenshot at the end of each test.) @@ -104,6 +106,7 @@ import colorama import os import re import sys +from contextlib import suppress from seleniumbase import config as sb_config from seleniumbase.config import settings from seleniumbase.core import download_helper @@ -145,6 +148,7 @@ def get_configured_sb(context): sb.headless_active = False sb.headed = False sb.xvfb = False + sb.xvfb_metrics = None sb.start_page = None sb.locale_code = None sb.pdb_option = False @@ -193,6 +197,7 @@ def get_configured_sb(context): sb._disable_beforeunload = False sb.visual_baseline = False sb.use_wire = False + sb.window_position = None sb.window_size = None sb.maximize_option = False sb.is_context_manager = False @@ -302,6 +307,13 @@ def get_configured_sb(context): if low_key == "xvfb": sb.xvfb = True continue + # Handle: -D xvfb-metrics=STR / xvfb_metrics=STR + if low_key in ["xvfb-metrics", "xvfb_metrics"]: + xvfb_metrics = userdata[key] + if xvfb_metrics == "true": + xvfb_metrics = sb.xvfb_metrics # revert to default + sb.xvfb_metrics = xvfb_metrics + continue # Handle: -D start-page=URL / start_page=URL / url=URL if low_key in ["start-page", "start_page", "url"]: start_page = userdata[key] @@ -601,6 +613,13 @@ def get_configured_sb(context): 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] + if window_position == "true": + window_position = sb.window_position # revert to default + sb.window_position = window_position + continue # Handle: -D window-size=Width,Height / window_size=Width,Height if low_key in ["window-size", "window_size"]: window_size = userdata[key] @@ -904,6 +923,29 @@ def get_configured_sb(context): else: sb.enable_ws = False sb.disable_ws = True + if sb.window_position: + window_position = sb.window_position + if window_position.count(",") != 1: + message = ( + '\n\n window_position expects an "x,y" string!' + '\n (Your input was: "%s")\n' % window_position + ) + raise Exception(message) + window_position = window_position.replace(" ", "") + win_x = None + win_y = None + try: + win_x = int(window_position.split(",")[0]) + win_y = int(window_position.split(",")[1]) + except Exception: + message = ( + '\n\n Expecting integer values for "x,y"!' + '\n (window_position input was: "%s")\n' + % window_position + ) + raise Exception(message) + settings.WINDOW_START_X = win_x + settings.WINDOW_START_Y = win_y if sb.window_size: window_size = sb.window_size if window_size.count(",") != 1: @@ -938,9 +980,11 @@ def get_configured_sb(context): sb_config.is_pytest = False sb_config.is_nosetest = False sb_config.is_context_manager = False + sb_config.window_position = sb.window_position sb_config.window_size = sb.window_size sb_config.maximize_option = sb.maximize_option sb_config.xvfb = sb.xvfb + sb_config.xvfb_metrics = sb.xvfb_metrics sb_config.reuse_class_session = sb._reuse_class_session sb_config.save_screenshot = sb.save_screenshot_after_test sb_config.no_screenshot = sb.no_screenshot_after_test @@ -1162,12 +1206,10 @@ def behave_dashboard_prepare(): sb_config.item_count_untested = sb_config.item_count dash_path = os.path.join(os.getcwd(), "dashboard.html") star_len = len("Dashboard: ") + len(dash_path) - try: + with suppress(Exception): terminal_size = os.get_terminal_size().columns if terminal_size > 30 and star_len > terminal_size: star_len = terminal_size - except Exception: - pass stars = "*" * star_len c1 = "" cr = "" @@ -1263,7 +1305,7 @@ def _perform_behave_unconfigure_(): def do_final_driver_cleanup_as_needed(): - try: + with suppress(Exception): if hasattr(sb_config, "last_driver") and sb_config.last_driver: if ( not is_windows @@ -1271,8 +1313,6 @@ def do_final_driver_cleanup_as_needed(): or sb_config.last_driver.service.process ): sb_config.last_driver.quit() - except Exception: - pass def _perform_behave_terminal_summary_(): @@ -1281,12 +1321,10 @@ def _perform_behave_terminal_summary_(): ) dash_path = os.path.join(os.getcwd(), "dashboard.html") equals_len = len("Dashboard: ") + len(dash_path) - try: + with suppress(Exception): terminal_size = os.get_terminal_size().columns if terminal_size > 30 and equals_len > terminal_size: equals_len = terminal_size - except Exception: - pass equals = "=" * (equals_len + 2) c2 = "" cr = "" diff --git a/seleniumbase/config/settings.py b/seleniumbase/config/settings.py index 0b282210..c0980f01 100644 --- a/seleniumbase/config/settings.py +++ b/seleniumbase/config/settings.py @@ -110,6 +110,10 @@ DISABLE_CSP_ON_CHROME = False # (This applies when using --proxy=[PROXY_STRING] for using a proxy server.) RAISE_INVALID_PROXY_STRING_EXCEPTION = True +# Default browser coordinates when opening new windows for tests. +WINDOW_START_X = 20 +WINDOW_START_Y = 54 + # Default browser resolutions when opening new windows for tests. # (Headless resolutions take priority, and include all browsers.) # (Firefox starts maximized by default when running in GUI Mode.) diff --git a/seleniumbase/console_scripts/sb_behave_gui.py b/seleniumbase/console_scripts/sb_behave_gui.py index 2708d6e3..6902c46a 100644 --- a/seleniumbase/console_scripts/sb_behave_gui.py +++ b/seleniumbase/console_scripts/sb_behave_gui.py @@ -16,16 +16,16 @@ Output: import colorama import subprocess import sys +import tkinter as tk +from seleniumbase.fixtures import shared_utils +from tkinter.scrolledtext import ScrolledText -if sys.version_info <= (3, 7): +if sys.version_info <= (3, 8): current_version = ".".join(str(ver) for ver in sys.version_info[:3]) raise Exception( - "\n* SBase Commander requires Python 3.7 or newer!" + "\n* SBase Commander requires Python 3.8 or newer!" "\n** You are currently using Python %s" % current_version ) -from seleniumbase.fixtures import shared_utils -import tkinter as tk # noqa: E402 -from tkinter.scrolledtext import ScrolledText # noqa: E402 def set_colors(use_colors): diff --git a/seleniumbase/console_scripts/sb_caseplans.py b/seleniumbase/console_scripts/sb_caseplans.py index 57e287c0..63c5a3a0 100644 --- a/seleniumbase/console_scripts/sb_caseplans.py +++ b/seleniumbase/console_scripts/sb_caseplans.py @@ -20,17 +20,17 @@ import colorama import os import subprocess import sys +import tkinter as tk +from seleniumbase.fixtures import shared_utils +from tkinter import messagebox +from tkinter.scrolledtext import ScrolledText -if sys.version_info <= (3, 7): +if sys.version_info <= (3, 8): current_version = ".".join(str(ver) for ver in sys.version_info[:3]) raise Exception( - "\n* SBase Case Plans Generator requires Python 3.7 or newer!" + "\n* SBase Case Plans Generator requires Python 3.8 or newer!" "\n** You are currently using Python %s" % current_version ) -from seleniumbase.fixtures import shared_utils -import tkinter as tk # noqa: E402 -from tkinter import messagebox # noqa: E402 -from tkinter.scrolledtext import ScrolledText # noqa: E402 def set_colors(use_colors): diff --git a/seleniumbase/console_scripts/sb_commander.py b/seleniumbase/console_scripts/sb_commander.py index bc23cc69..a5a15b8d 100644 --- a/seleniumbase/console_scripts/sb_commander.py +++ b/seleniumbase/console_scripts/sb_commander.py @@ -21,16 +21,16 @@ import colorama import os import subprocess import sys +import tkinter as tk +from seleniumbase.fixtures import shared_utils +from tkinter.scrolledtext import ScrolledText -if sys.version_info <= (3, 7): +if sys.version_info <= (3, 8): current_version = ".".join(str(ver) for ver in sys.version_info[:3]) raise Exception( - "\n* SBase Commander requires Python 3.7 or newer!" + "\n* SBase Commander requires Python 3.8 or newer!" "\n** You are currently using Python %s" % current_version ) -from seleniumbase.fixtures import shared_utils -import tkinter as tk # noqa: E402 -from tkinter.scrolledtext import ScrolledText # noqa: E402 def set_colors(use_colors): diff --git a/seleniumbase/console_scripts/sb_recorder.py b/seleniumbase/console_scripts/sb_recorder.py index 0e9e3365..173ee954 100644 --- a/seleniumbase/console_scripts/sb_recorder.py +++ b/seleniumbase/console_scripts/sb_recorder.py @@ -18,23 +18,23 @@ import colorama import os import subprocess import sys +import tkinter as tk from seleniumbase import config as sb_config from seleniumbase.fixtures import page_utils from seleniumbase.fixtures import shared_utils +from tkinter import messagebox sb_config.rec_subprocess_p = None sb_config.rec_subprocess_used = False sys_executable = sys.executable if " " in sys_executable: sys_executable = "python" -if sys.version_info <= (3, 7): +if sys.version_info <= (3, 8): current_version = ".".join(str(ver) for ver in sys.version_info[:3]) raise Exception( - "\n* Recorder Desktop requires Python 3.7 or newer!" + "\n* Recorder Desktop requires Python 3.8 or newer!" "\n*** You are currently using Python %s" % current_version ) -import tkinter as tk # noqa: E402 -from tkinter import messagebox # noqa: E402 def set_colors(use_colors): diff --git a/seleniumbase/core/browser_launcher.py b/seleniumbase/core/browser_launcher.py index 35637023..03845961 100644 --- a/seleniumbase/core/browser_launcher.py +++ b/seleniumbase/core/browser_launcher.py @@ -9,6 +9,7 @@ import time import types import urllib3 import warnings +from contextlib import suppress from selenium import webdriver from selenium.common.exceptions import ElementClickInterceptedException from selenium.common.exceptions import InvalidSessionIdException @@ -277,7 +278,7 @@ def chromedriver_on_path(): def get_uc_driver_version(full=False): uc_driver_version = None if os.path.exists(LOCAL_UC_DRIVER): - try: + with suppress(Exception): output = subprocess.check_output( '"%s" --version' % LOCAL_UC_DRIVER, shell=True ) @@ -292,8 +293,6 @@ def get_uc_driver_version(full=False): uc_driver_version = full_version else: uc_driver_version = output - except Exception: - pass return uc_driver_version @@ -372,7 +371,7 @@ def uc_special_open_if_cf( ): if url.startswith("http:") or url.startswith("https:"): special = False - try: + with suppress(Exception): req_get = requests_get(url, proxy_string) status_str = str(req_get.status_code) if ( @@ -384,8 +383,6 @@ def uc_special_open_if_cf( special = True if status_str == "403" or status_str == "429": time.sleep(0.06) # Forbidden / Blocked! (Wait first!) - except Exception: - pass if special: time.sleep(0.05) with driver: @@ -416,13 +413,11 @@ def uc_special_open_if_cf( "mobile": True } ) - try: + with suppress(Exception): driver.execute_cdp_cmd( 'Emulation.setDeviceMetricsOverride', set_device_metrics_override ) - except Exception: - pass if not mobile_emulator: page_actions.switch_to_window( driver, driver.window_handles[-1], 2 @@ -529,13 +524,11 @@ def uc_click( timeout=settings.SMALL_TIMEOUT, reconnect_time=None, ): - try: + with suppress(Exception): rct = float(by) # Add shortcut: driver.uc_click(selector, RCT) if not reconnect_time: reconnect_time = rct by = "css selector" - except Exception: - pass element = driver.wait_for_selector(selector, by=by, timeout=timeout) tag_name = element.tag_name if not tag_name == "span" and not tag_name == "input": # Must be "visible" @@ -574,7 +567,7 @@ def install_pyautogui_if_missing(driver): with pip_find_lock: # Prevent issues with multiple processes try: import pyautogui - try: + with suppress(Exception): use_pyautogui_ver = constants.PyAutoGUI.VER if pyautogui.__version__ != use_pyautogui_ver: del pyautogui @@ -582,8 +575,6 @@ def install_pyautogui_if_missing(driver): "pyautogui", version=use_pyautogui_ver ) import pyautogui - except Exception: - pass except Exception: print("\nPyAutoGUI required! Installing now...") shared_utils.pip_install( @@ -794,12 +785,10 @@ def uc_gui_click_x_y(driver, x, y, timeframe=0.25): y = y * width_ratio _uc_gui_click_x_y(driver, x, y, timeframe=timeframe, uc_lock=False) return - try: + with suppress(Exception): page_actions.switch_to_window( driver, driver.current_window_handle, 2, uc_lock=False ) - except Exception: - pass _uc_gui_click_x_y(driver, x, y, timeframe=timeframe, uc_lock=False) @@ -1002,10 +991,8 @@ def _uc_gui_click_captcha( driver.uc_open_with_disconnect(driver.current_url, 3.8) else: driver.disconnect() - try: - _uc_gui_click_x_y(driver, x, y, timeframe=0.54321) - except Exception: - pass + with suppress(Exception): + _uc_gui_click_x_y(driver, x, y, timeframe=0.32) reconnect_time = (float(constants.UC.RECONNECT_TIME) / 2.0) + 0.6 if IS_LINUX: reconnect_time = constants.UC.RECONNECT_TIME + 0.2 @@ -1047,12 +1034,12 @@ def _uc_gui_click_captcha( return if blind: driver.uc_open_with_disconnect(driver.current_url, 3.8) - _uc_gui_click_x_y(driver, x, y, timeframe=1.05) + _uc_gui_click_x_y(driver, x, y, timeframe=0.32) else: driver.uc_open_with_reconnect(driver.current_url, 3.8) if _on_a_captcha_page(driver): driver.disconnect() - _uc_gui_click_x_y(driver, x, y, timeframe=1.05) + _uc_gui_click_x_y(driver, x, y, timeframe=0.32) driver.reconnect(reconnect_time) @@ -1232,13 +1219,11 @@ def _uc_gui_handle_captcha_(driver, frame="iframe", ctype=None): and sb_config._saved_cf_tab_count ): driver.uc_open_with_disconnect(driver.current_url, 3.8) - try: + with suppress(Exception): for i in range(sb_config._saved_cf_tab_count): pyautogui.press("\t") time.sleep(0.027) pyautogui.press(" ") - except Exception: - pass else: driver.disconnect() pyautogui.press(" ") @@ -1919,13 +1904,11 @@ def _set_chrome_options( else: chromium_arg_item = "--" + chromium_arg_item if "remote-debugging-port=" in chromium_arg_item: - try: + with suppress(Exception): # Extra processing for UC Mode chrome_options._remote_debugging_port = int( chromium_arg_item.split("remote-debugging-port=")[1] ) - except Exception: - pass if "set-binary" in chromium_arg_item and not binary_location: br_app = "google-chrome" binary_loc = detect_b_ver.get_binary_location( @@ -2577,14 +2560,12 @@ def get_remote_driver( try: from seleniumwire import webdriver import blinker - try: + 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 ) - except Exception: - pass del blinker except Exception: shared_utils.pip_install( @@ -3008,14 +2989,12 @@ def get_local_driver( try: from seleniumwire import webdriver import blinker - try: + 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 ) - except Exception: - pass del blinker except Exception: shared_utils.pip_install( @@ -3306,7 +3285,7 @@ def get_local_driver( edge_driver_version = None edgedriver_upgrade_needed = False if os.path.exists(LOCAL_EDGEDRIVER): - try: + with suppress(Exception): output = subprocess.check_output( '"%s" --version' % LOCAL_EDGEDRIVER, shell=True ) @@ -3332,8 +3311,6 @@ def get_local_driver( edge_driver_version = output if driver_version == "keep": driver_version = edge_driver_version - except Exception: - pass use_version = find_edgedriver_version_to_use( use_version, driver_version ) @@ -3437,7 +3414,7 @@ def get_local_driver( edge_options.add_argument("--headless=new") elif headless and undetectable: # (For later: UC Mode doesn't support Edge now) - try: + with suppress(Exception): if int(use_version) >= 109: edge_options.add_argument("--headless=new") elif ( @@ -3447,8 +3424,6 @@ def get_local_driver( edge_options.add_argument("--headless=chrome") else: pass # Will need Xvfb on Linux - except Exception: - pass elif headless: if "--headless" not in edge_options.arguments: edge_options.add_argument("--headless") @@ -3748,19 +3723,15 @@ def get_local_driver( constants.MultiBrowser.DRIVER_FIXING_LOCK ) with edgedriver_fixing_lock: - try: + with suppress(Exception): if not _was_driver_repaired(): _repair_edgedriver(edge_version) _mark_driver_repaired() - except Exception: - pass else: - try: + with suppress(Exception): if not _was_driver_repaired(): _repair_edgedriver(edge_version) _mark_driver_repaired() - except Exception: - pass driver = Edge(service=service, options=edge_options) return extend_driver(driver) elif browser_name == constants.Browser.SAFARI: @@ -3912,7 +3883,7 @@ def get_local_driver( ch_driver_version = None path_chromedriver = chromedriver_on_path() if os.path.exists(LOCAL_CHROMEDRIVER): - try: + with suppress(Exception): output = subprocess.check_output( '"%s" --version' % LOCAL_CHROMEDRIVER, shell=True ) @@ -3926,8 +3897,6 @@ def get_local_driver( ch_driver_version = output if driver_version == "keep": driver_version = ch_driver_version - except Exception: - pass elif path_chromedriver: try: make_driver_executable_if_not(path_chromedriver) @@ -3936,7 +3905,7 @@ def get_local_driver( "\nWarning: Could not make chromedriver" " executable: %s" % e ) - try: + with suppress(Exception): output = subprocess.check_output( '"%s" --version' % path_chromedriver, shell=True ) @@ -3950,8 +3919,6 @@ def get_local_driver( ch_driver_version = output if driver_version == "keep": use_version = ch_driver_version - except Exception: - pass disable_build_check = True uc_driver_version = None if is_using_uc(undetectable, browser_name): @@ -4144,7 +4111,7 @@ def get_local_driver( if IS_ARM_MAC and use_uc: intel_for_uc = True # Use Intel driver for UC Mode if os.path.exists(LOCAL_CHROMEDRIVER): - try: + with suppress(Exception): output = subprocess.check_output( '"%s" --version' % LOCAL_CHROMEDRIVER, shell=True, @@ -4157,8 +4124,6 @@ def get_local_driver( output = full_ch_driver_version.split(".")[0] if int(output) >= 2: ch_driver_version = output - except Exception: - pass if ( ( not use_uc @@ -4296,7 +4261,7 @@ def get_local_driver( chrome_options.add_argument( "--user-agent=%s" % user_agent ) - try: + with suppress(Exception): if ( ( not user_agent @@ -4402,7 +4367,7 @@ def get_local_driver( service=service, options=headless_options, ) - try: + with suppress(Exception): user_agent = driver.execute_script( "return navigator.userAgent;" ) @@ -4424,11 +4389,7 @@ def get_local_driver( "--user-agent=%s" % user_agent ) sb_config.uc_agent_cache = user_agent - except Exception: - pass driver.quit() - except Exception: - pass uc_path = None if os.path.exists(LOCAL_UC_DRIVER): uc_path = LOCAL_UC_DRIVER @@ -4751,13 +4712,11 @@ def get_local_driver( "mobile": True } ) - try: + with suppress(Exception): driver.execute_cdp_cmd( 'Emulation.setDeviceMetricsOverride', set_device_metrics_override ) - except Exception: - pass return extend_driver(driver) else: # Running headless on Linux (and not using --uc) try: @@ -4803,23 +4762,19 @@ def get_local_driver( ) with chromedr_fixing_lock: if not _was_driver_repaired(): - try: + with suppress(Exception): _repair_chromedriver( chrome_options, chrome_options, mcv ) _mark_driver_repaired() - except Exception: - pass else: if not _was_driver_repaired(): - try: + with suppress(Exception): _repair_chromedriver( chrome_options, chrome_options, mcv ) - except Exception: - pass _mark_driver_repaired() - try: + with suppress(Exception): service = ChromeService( log_output=os.devnull, service_args=["--disable-build-check"], @@ -4829,8 +4784,6 @@ def get_local_driver( options=chrome_options, ) return extend_driver(driver) - except Exception: - pass # Use the virtual display on Linux during headless errors logging.debug( "\nWarning: Chrome failed to launch in" @@ -4851,14 +4804,12 @@ def get_local_driver( if is_using_uc(undetectable, browser_name): raise # Try again if Chrome didn't launch - try: + with suppress(Exception): service = ChromeService(service_args=["--disable-build-check"]) driver = webdriver.Chrome( service=service, options=chrome_options ) return extend_driver(driver) - except Exception: - pass if user_data_dir: print("\nUnable to set user_data_dir while starting Chrome!\n") raise diff --git a/seleniumbase/core/mysql.py b/seleniumbase/core/mysql.py index 1a2edb6c..a1bf47dd 100644 --- a/seleniumbase/core/mysql.py +++ b/seleniumbase/core/mysql.py @@ -35,10 +35,7 @@ class DatabaseManager: import cryptography # noqa: F401 import pymysql except Exception: - if sys.version_info < (3, 7): - shared_utils.pip_install("PyMySQL[rsa]", version="1.0.2") - else: - shared_utils.pip_install("PyMySQL[rsa]", version="1.1.0") + shared_utils.pip_install("PyMySQL[rsa]", version="1.1.1") import pymysql db_server = settings.DB_HOST db_port = settings.DB_PORT diff --git a/seleniumbase/core/recorder_helper.py b/seleniumbase/core/recorder_helper.py index 3a137297..40f9cef4 100644 --- a/seleniumbase/core/recorder_helper.py +++ b/seleniumbase/core/recorder_helper.py @@ -422,9 +422,14 @@ def generate_sbase_code(srt_actions): ): import unicodedata - action[1][0] = unicodedata.normalize("NFKC", action[1][0]) - action[1][0] = action[1][0].replace("\n", "\\n") - action[1][0] = action[1][0].replace("\u00B6", "") + text_list = False + try: + action[1][0] = unicodedata.normalize("NFKC", action[1][0]) + action[1][0] = action[1][0].replace("\n", "\\n") + action[1][0] = action[1][0].replace("\u00B6", "") + except Exception: + text_list = True + method = "assert_text" if action[0] == "as_et": method = "assert_exact_text" @@ -437,7 +442,17 @@ def generate_sbase_code(srt_actions): elif action[0] == "da_et": method = "deferred_assert_exact_text" if action[1][1] != "html": - if '"' not in action[1][0] and '"' not in action[1][1]: + if text_list and '"' not in action[1][1]: + sb_actions.append( + 'self.%s(%s, "%s")' + % (method, action[1][0], action[1][1]) + ) + elif text_list and "'" not in action[1][1]: + sb_actions.append( + "self.%s(%s, '%s')" + % (method, action[1][0], action[1][1]) + ) + elif '"' not in action[1][0] and '"' not in action[1][1]: sb_actions.append( 'self.%s("%s", "%s")' % (method, action[1][0], action[1][1]) @@ -458,7 +473,11 @@ def generate_sbase_code(srt_actions): % (method, action[1][0], action[1][1]) ) else: - if '"' not in action[1][0]: + if text_list: + sb_actions.append( + 'self.%s(%s)' % (method, action[1][0]) + ) + elif '"' not in action[1][0]: sb_actions.append( 'self.%s("%s")' % (method, action[1][0]) ) diff --git a/seleniumbase/core/sb_driver.py b/seleniumbase/core/sb_driver.py index 3ca7a495..02dd0de4 100644 --- a/seleniumbase/core/sb_driver.py +++ b/seleniumbase/core/sb_driver.py @@ -1,4 +1,5 @@ """Add new methods to extend the driver""" +from contextlib import suppress from selenium.webdriver.remote.webelement import WebElement from seleniumbase.fixtures import js_utils from seleniumbase.fixtures import page_actions @@ -36,10 +37,8 @@ class DriverMethods(): selector, by = page_utils.swap_selector_and_by_if_reversed( selector, by ) - try: + with suppress(Exception): return self.driver.default_find_element(by=by, value=selector) - except Exception: - pass raise Exception('No such Element: {%s} (by="%s")!' % (selector, by)) def get_attribute(self, selector, attribute, by="css selector"): diff --git a/seleniumbase/fixtures/base_case.py b/seleniumbase/fixtures/base_case.py index 15fde7b4..e8a81c4a 100644 --- a/seleniumbase/fixtures/base_case.py +++ b/seleniumbase/fixtures/base_case.py @@ -33,6 +33,7 @@ Page elements are given enough time to load before WebDriver acts on them. Code becomes greatly simplified and easier to maintain.""" import codecs +import colorama import fasteners import json import logging @@ -45,7 +46,7 @@ import textwrap import time import unittest import urllib3 -from contextlib import contextmanager +from contextlib import contextmanager, suppress from selenium.common.exceptions import ( ElementClickInterceptedException as ECI_Exception, ElementNotInteractableException as ENI_Exception, @@ -57,6 +58,7 @@ from selenium.common.exceptions import ( TimeoutException, WebDriverException, ) +from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.remote.remote_connection import LOGGER @@ -73,9 +75,11 @@ from seleniumbase.common.exceptions import ( VisualException, ) from seleniumbase.config import settings +from seleniumbase.core import browser_launcher from seleniumbase.core import download_helper from seleniumbase.core import log_helper from seleniumbase.core import session_helper +from seleniumbase.core import visual_helper from seleniumbase.fixtures import constants from seleniumbase.fixtures import css_to_xpath from seleniumbase.fixtures import js_utils @@ -180,6 +184,8 @@ class BaseCase(unittest.TestCase): self._chart_series_count = {} self._tour_steps = {} self._xvfb_display = None + self._xvfb_width = None + self._xvfb_height = None @classmethod def main(self, name, file, *args): @@ -221,10 +227,8 @@ class BaseCase(unittest.TestCase): if self.__needs_minimum_wait(): time.sleep(0.04) pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass url = str(url).strip() # Remove leading and trailing whitespace if not self.__looks_like_a_page_url(url): # url should start with one of the following: @@ -352,18 +356,12 @@ class BaseCase(unittest.TestCase): if self.undetectable: self.__uc_frame_layer = 0 if self.demo_mode: - if ( - self.driver.current_url.startswith("http") - or self.driver.current_url.startswith("file") - or self.driver.current_url.startswith("data") - ): + if self.driver.current_url.startswith(("http", "file", "data")): if not js_utils.is_jquery_activated(self.driver): - try: + with suppress(Exception): js_utils.add_js_link( self.driver, constants.JQuery.MIN_JS ) - except Exception: - pass self.__demo_mode_pause_if_active() def get(self, url): @@ -421,10 +419,8 @@ class BaseCase(unittest.TestCase): if scroll and not self.demo_mode and not self.slow_mode: self.__scroll_to_element(element, selector, by) pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass pre_window_count = len(self.driver.window_handles) try: if ( @@ -438,7 +434,7 @@ class BaseCase(unittest.TestCase): href = None new_tab = False onclick = None - try: + with suppress(Exception): if self.headless and element.tag_name.lower() == "a": # Handle a special case of opening a new tab (headless) href = element.get_attribute("href").strip() @@ -448,20 +444,14 @@ class BaseCase(unittest.TestCase): new_tab = True if new_tab and self.__looks_like_a_page_url(href): if onclick: - try: + with suppress(Exception): self.execute_script(onclick) - except Exception: - pass current_window = self.driver.current_window_handle self.open_new_window() - try: + with suppress(Exception): self.open(href) - except Exception: - pass self.switch_to_window(current_window) return - except Exception: - pass # Normal click self.__element_click(element) except Stale_Exception: @@ -474,10 +464,8 @@ class BaseCase(unittest.TestCase): timeout=timeout, original_selector=original_selector, ) - try: + with suppress(Exception): self.__scroll_to_element(element, selector, by) - except Exception: - pass if self.browser == "safari" and by == By.LINK_TEXT: self.__jquery_click(selector, by=by) elif self.browser == "safari": @@ -485,7 +473,7 @@ class BaseCase(unittest.TestCase): else: self.__element_click(element) except ENI_Exception as e: - try: + with suppress(Exception): if ( "element has zero size" in e.msg and element.tag_name.lower() == "a" @@ -497,8 +485,6 @@ class BaseCase(unittest.TestCase): if self.__needs_minimum_wait(): time.sleep(0.04) return - except Exception: - pass self.wait_for_ready_state_complete() time.sleep(0.1) element = page_actions.wait_for_element_visible( @@ -511,12 +497,10 @@ class BaseCase(unittest.TestCase): if not page_actions.is_element_clickable( self.driver, selector, by ): - try: + with suppress(Exception): self.wait_for_element_clickable( selector, by, timeout=1.8 ) - except Exception: - pass # Find out which element would get the click instead element = page_actions.wait_for_element_visible( self.driver, selector, @@ -527,7 +511,7 @@ class BaseCase(unittest.TestCase): href = None new_tab = False onclick = None - try: + with suppress(Exception): if element.tag_name.lower() == "a": # Handle a special case of opening a new tab (non-headless) href = element.get_attribute("href").strip() @@ -537,20 +521,14 @@ class BaseCase(unittest.TestCase): new_tab = True if new_tab and self.__looks_like_a_page_url(href): if onclick: - try: + with suppress(Exception): self.execute_script(onclick) - except Exception: - pass current_window = self.driver.current_window_handle self.open_new_window() - try: + with suppress(Exception): self.open(href) - except Exception: - pass self.switch_to_window(current_window) return - except Exception: - pass if scroll and not self.demo_mode and not self.slow_mode: self.__scroll_to_element(element, selector, by) if self.browser == "firefox" or self.browser == "safari": @@ -632,10 +610,8 @@ class BaseCase(unittest.TestCase): self.switch_to_window(-1) if settings.WAIT_FOR_RSC_ON_CLICKS: if not self.undetectable: - try: + with suppress(Exception): self.wait_for_ready_state_complete() - except Exception: - pass if self.__needs_minimum_wait() or self.browser == "safari": time.sleep(0.05) else: @@ -643,10 +619,8 @@ class BaseCase(unittest.TestCase): else: if not self.undetectable: # A smaller subset of self.wait_for_ready_state_complete() - try: + with suppress(Exception): self.wait_for_angularjs(timeout=settings.MINI_TIMEOUT) - except Exception: - pass if self.__needs_minimum_wait() or self.browser == "safari": time.sleep(0.045) try: @@ -656,10 +630,8 @@ class BaseCase(unittest.TestCase): if self.__needs_minimum_wait(): time.sleep(0.075) except Exception: - try: + with suppress(Exception): self.wait_for_ready_state_complete() - except Exception: - pass if self.__needs_minimum_wait(): time.sleep(0.05) else: @@ -697,8 +669,6 @@ class BaseCase(unittest.TestCase): self.click(selector, by=by, timeout=timeout, delay=0.25) def double_click(self, selector, by="css selector", timeout=None): - from selenium.webdriver.common.action_chains import ActionChains - self.__check_scope() if not timeout: timeout = settings.SMALL_TIMEOUT @@ -729,10 +699,8 @@ class BaseCase(unittest.TestCase): original_selector=original_selector, ) pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass try: if self.browser == "safari": # Jump to the "except" block where the other script should work @@ -782,8 +750,6 @@ class BaseCase(unittest.TestCase): def context_click(self, selector, by="css selector", timeout=None): """(A context click is a right-click that opens a context menu.)""" - from selenium.webdriver.common.action_chains import ActionChains - self.__check_scope() if not timeout: timeout = settings.SMALL_TIMEOUT @@ -814,10 +780,8 @@ class BaseCase(unittest.TestCase): original_selector=original_selector, ) pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass try: if self.browser == "safari": # Jump to the "except" block where the other script should work @@ -935,19 +899,15 @@ class BaseCase(unittest.TestCase): element = self.wait_for_element_clickable( selector, by=by, timeout=timeout ) - try: + with suppress(Exception): element.clear() - except Exception: - pass # Clearing the text field first might not be necessary except Exception: pass # Clearing the text field first might not be necessary self.__demo_mode_pause_if_active(tiny=True) pre_action_url = None if self.demo_mode: - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass text = self.__get_type_checked_text(text) try: if not text.endswith("\n"): @@ -1057,10 +1017,8 @@ class BaseCase(unittest.TestCase): self.__scroll_to_element(element, selector, by) pre_action_url = None if self.demo_mode: - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass text = self.__get_type_checked_text(text) try: if not text.endswith("\n"): @@ -1233,11 +1191,9 @@ class BaseCase(unittest.TestCase): selector, by=by, timeout=timeout ) element.clear() - try: + with suppress(Exception): backspaces = Keys.BACK_SPACE * 42 # Autofill Defense element.send_keys(backspaces) - except Exception: - pass except Exception: element.clear() @@ -1334,17 +1290,13 @@ class BaseCase(unittest.TestCase): if hasattr(self, "recorder_mode") and self.recorder_mode: self.save_recorded_actions() pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass self.__last_page_load_url = None self.driver.back() - try: + with suppress(Exception): if pre_action_url == self.driver.current_url: self.driver.back() # Again because the page was redirected - except Exception: - pass if self.recorder_mode: time_stamp = self.execute_script("return Date.now();") origin = self.get_origin() @@ -1424,6 +1376,7 @@ class BaseCase(unittest.TestCase): self.open(url) def is_element_present(self, selector, by="css selector"): + """Returns whether the element exists in the HTML.""" self.wait_for_ready_state_complete() selector, by = self.__recalculate_selector(selector, by) if self.__is_shadow_selector(selector): @@ -1431,6 +1384,7 @@ class BaseCase(unittest.TestCase): return page_actions.is_element_present(self.driver, selector, by) def is_element_visible(self, selector, by="css selector"): + """Returns whether the element is visible on the page.""" self.wait_for_ready_state_complete() selector, by = self.__recalculate_selector(selector, by) if self.__is_shadow_selector(selector): @@ -1452,6 +1406,7 @@ class BaseCase(unittest.TestCase): return page_actions.is_element_enabled(self.driver, selector, by) def is_text_visible(self, text, selector="html", by="css selector"): + """Returns whether the text substring is visible in the element.""" self.wait_for_ready_state_complete() time.sleep(0.01) selector, by = self.__recalculate_selector(selector, by) @@ -1460,6 +1415,8 @@ class BaseCase(unittest.TestCase): return page_actions.is_text_visible(self.driver, text, selector, by) def is_exact_text_visible(self, text, selector="html", by="css selector"): + """Returns whether the text is exactly equal to the element text. + (Leading and trailing whitespace is ignored in the verification.)""" self.wait_for_ready_state_complete() time.sleep(0.01) selector, by = self.__recalculate_selector(selector, by) @@ -1498,6 +1455,7 @@ class BaseCase(unittest.TestCase): ) def is_link_text_visible(self, link_text): + """Returns whether there's an exact match for the link text.""" self.wait_for_ready_state_complete() time.sleep(0.01) return page_actions.is_element_visible( @@ -1505,6 +1463,7 @@ class BaseCase(unittest.TestCase): ) def is_partial_link_text_visible(self, partial_link_text): + """Returns whether there's a substring match for the link text.""" self.wait_for_ready_state_complete() time.sleep(0.01) return page_actions.is_element_visible( @@ -1633,10 +1592,8 @@ class BaseCase(unittest.TestCase): if self.__needs_minimum_wait(): time.sleep(0.04) pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass pre_window_count = len(self.driver.window_handles) try: element = self.wait_for_link_text_visible(link_text, timeout=0.2) @@ -1707,10 +1664,8 @@ class BaseCase(unittest.TestCase): # switch to the last one if it exists. self.switch_to_window(-1) if settings.WAIT_FOR_RSC_ON_PAGE_LOADS: - try: + with suppress(Exception): self.wait_for_ready_state_complete() - except Exception: - pass if self.demo_mode: if self.driver.current_url != pre_action_url: if not js_utils.is_jquery_activated(self.driver): @@ -1736,10 +1691,8 @@ class BaseCase(unittest.TestCase): partial_link_text, timeout=timeout ) pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass pre_window_count = len(self.driver.window_handles) try: element = self.wait_for_partial_link_text( @@ -1822,10 +1775,8 @@ class BaseCase(unittest.TestCase): # switch to the last one if it exists. self.switch_to_window(-1) if settings.WAIT_FOR_RSC_ON_PAGE_LOADS: - try: + with suppress(Exception): self.wait_for_ready_state_complete() - except Exception: - pass if self.demo_mode: if self.driver.current_url != pre_action_url: if not js_utils.is_jquery_activated(self.driver): @@ -1941,10 +1892,8 @@ class BaseCase(unittest.TestCase): original_attribute = attribute original_value = value if scroll and self.is_element_visible(selector, by=by): - try: + with suppress(Exception): self.scroll_to(selector, by=by, timeout=timeout) - except Exception: - pass attribute = re.escape(attribute) attribute = self.__escape_quotes_if_needed(attribute) value = re.escape(value) @@ -1989,10 +1938,8 @@ class BaseCase(unittest.TestCase): attribute, value, ) - try: + with suppress(Exception): self.execute_script(script) - except Exception: - pass if self.recorder_mode and self.__current_url_is_recordable(): if self.get_session_storage_item("pause_recorder") == "no": time_stamp = self.execute_script("return Date.now();") @@ -2021,10 +1968,8 @@ class BaseCase(unittest.TestCase): timeout = self.__get_new_timeout(timeout) selector, by = self.__recalculate_selector(selector, by) if self.is_element_visible(selector, by=by): - try: + with suppress(Exception): self.scroll_to(selector, by=by, timeout=timeout) - except Exception: - pass attribute = re.escape(attribute) attribute = self.__escape_quotes_if_needed(attribute) css_selector = self.convert_to_css_selector(selector, by=by) @@ -2053,10 +1998,8 @@ class BaseCase(unittest.TestCase): css_selector, attribute, ) - try: + with suppress(Exception): self.execute_script(script) - except Exception: - pass def get_property( self, selector, property, by="css selector", timeout=None @@ -2202,20 +2145,16 @@ class BaseCase(unittest.TestCase): element = self.wait_for_element_present( selector, by=by, timeout=timeout ) - try: + with suppress(Exception): # If the first element isn't visible, wait a little. if not element.is_displayed(): time.sleep(0.16) if self.undetectable: time.sleep(0.06) - except Exception: - pass elements = self.find_elements(selector, by=by) pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass pre_window_count = len(self.driver.window_handles) click_count = 0 for element in elements: @@ -2298,10 +2237,8 @@ class BaseCase(unittest.TestCase): number = 0 element = elements[number] pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass pre_window_count = len(self.driver.window_handles) try: self.__scroll_to_element(element) @@ -2344,22 +2281,18 @@ class BaseCase(unittest.TestCase): if self.is_element_visible(selector, by=by): self.click(selector, by=by) elif timeout > 0: - try: + with suppress(Exception): self.wait_for_element_visible( selector, by=by, timeout=timeout ) - except Exception: - pass if self.is_element_visible(selector, by=by): self.click(selector, by=by) def click_active_element(self): self.wait_for_ready_state_complete() pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass pre_window_count = len(self.driver.window_handles) if self.recorder_mode: selector = js_utils.get_active_element_css(self.driver) @@ -2492,12 +2425,10 @@ class BaseCase(unittest.TestCase): ) # Handle switches that sit on checkboxes with zero opacity: # Change the opacity a bit to allow the click to succeed. - try: + with suppress(Exception): self.execute_script( 'arguments[0].style.opacity="0.001";', element ) - except Exception: - pass if self.is_element_visible(selector, by=by): self.click(selector, by=by) else: @@ -2505,14 +2436,12 @@ class BaseCase(unittest.TestCase): self.__dont_record_js_click = True self.js_click(selector, by="css selector") self.__dont_record_js_click = False - try: + with suppress(Exception): self.execute_script( 'arguments[0].style.opacity="arguments[1]";', element, opacity, ) - except Exception: - pass def select_if_unselected(self, selector, by="css selector"): """Same as check_if_unchecked()""" @@ -2532,12 +2461,10 @@ class BaseCase(unittest.TestCase): ) # Handle switches that sit on checkboxes with zero opacity: # Change the opacity a bit to allow the click to succeed. - try: + with suppress(Exception): self.execute_script( 'arguments[0].style.opacity="0.001";', element ) - except Exception: - pass if self.is_element_visible(selector, by=by): self.click(selector, by=by) else: @@ -2545,14 +2472,12 @@ class BaseCase(unittest.TestCase): self.__dont_record_js_click = True self.js_click(selector, by="css selector") self.__dont_record_js_click = False - try: + with suppress(Exception): self.execute_script( 'arguments[0].style.opacity="arguments[1]";', element, opacity, ) - except Exception: - pass def unselect_if_selected(self, selector, by="css selector"): """Same as uncheck_if_checked()""" @@ -2611,14 +2536,12 @@ class BaseCase(unittest.TestCase): iframe_identifier = '[class="%s"]' % iframe_class else: continue - try: + with suppress(Exception): self.switch_to_frame(iframe_identifier, timeout=1) if self.__needs_minimum_wait(): time.sleep(0.02) if self.is_element_present(selector, by=by): return iframe_identifier - except Exception: - pass self.switch_to_default_content() if self.__needs_minimum_wait(): time.sleep(0.02) @@ -2692,10 +2615,8 @@ class BaseCase(unittest.TestCase): self.__demo_mode_highlight_if_active(original_selector, original_by) self.scroll_to(hover_selector, by=hover_by) pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass pre_window_count = len(self.driver.window_handles) if self.recorder_mode and self.__current_url_is_recordable(): if self.get_session_storage_item("pause_recorder") == "no": @@ -2759,10 +2680,8 @@ class BaseCase(unittest.TestCase): self.__switch_to_newest_window_if_not_blank() elif self.browser == "safari": # Release the hover by hovering elsewhere - try: + with suppress(Exception): page_actions.hover_on_element(self.driver, "body") - except Exception: - pass if self.demo_mode: if self.driver.current_url != pre_action_url: if not js_utils.is_jquery_activated(self.driver): @@ -2822,10 +2741,8 @@ class BaseCase(unittest.TestCase): self.__demo_mode_highlight_if_active(original_selector, original_by) self.scroll_to(hover_selector, by=hover_by) pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass pre_window_count = len(self.driver.window_handles) outdated_driver = False element = None @@ -2886,7 +2803,7 @@ class BaseCase(unittest.TestCase): timeout=None, jquery=False, ): - """Drag and drop an element from one selector to another.""" + """Drag-and-drop an element from one selector to another.""" self.__check_scope() if not timeout: timeout = settings.SMALL_TIMEOUT @@ -2933,7 +2850,7 @@ class BaseCase(unittest.TestCase): def drag_and_drop_with_offset( self, selector, x, y, by="css selector", timeout=None ): - """Drag and drop an element to an {X,Y}-offset location.""" + """Drag-and-drop an element to an {X,Y}-offset location.""" self.__check_scope() if not timeout: timeout = settings.SMALL_TIMEOUT @@ -3013,10 +2930,8 @@ class BaseCase(unittest.TestCase): dropdown_selector, dropdown_by ) pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass pre_window_count = len(self.driver.window_handles) try: if option_by == "index": @@ -3291,10 +3206,8 @@ class BaseCase(unittest.TestCase): self.open("data:text/html,
") inner_head = """document.getElementsByTagName("head")[0].innerHTML""" inner_body = """document.getElementsByTagName("body")[0].innerHTML""" - try: + with suppress(Exception): self.wait_for_element_present("body", timeout=1) - except Exception: - pass if not found_body: self.execute_script('''%s = \"%s\"''' % (inner_body, html_string)) elif found_body and not found_head: @@ -4096,8 +4009,6 @@ class BaseCase(unittest.TestCase): "Valid options = {%s}" % (browser, valid_browsers) ) # Launch a web browser - from seleniumbase.core import browser_launcher - new_driver = browser_launcher.get_driver( browser_name=browser_name, headless=headless, @@ -4193,7 +4104,8 @@ class BaseCase(unittest.TestCase): self.driver.maximize_window() self.wait_for_ready_state_complete() else: - self.driver.set_window_size(width, height) + with suppress(Exception): + self.driver.set_window_size(width, height) except Exception: pass # Keep existing browser resolution elif self.browser == "safari": @@ -4204,10 +4116,8 @@ class BaseCase(unittest.TestCase): except Exception: pass # Keep existing browser resolution else: - try: - self.driver.set_window_rect(10, 20, width, height) - except Exception: - pass + with suppress(Exception): + self.driver.set_window_rect(10, 46, width, height) if self.start_page and len(self.start_page) >= 4: if page_utils.is_valid_url(self.start_page): self.open(self.start_page) @@ -4655,14 +4565,17 @@ class BaseCase(unittest.TestCase): from seleniumbase.js_code.recorder_js import recorder_js if not self.is_chromium(): + if "linux" not in sys.platform: + c1 = colorama.Fore.BLUE + colorama.Back.LIGHTCYAN_EX + c2 = colorama.Fore.BLUE + colorama.Back.LIGHTGREEN_EX + cr = colorama.Style.RESET_ALL + sc = c1 + "Selenium" + c2 + "Base" + cr raise Exception( - "The Recorder is only for Chromium browsers: (Chrome or Edge)" + "The %s Recorder is for Chromium only!\n" + " (Supported browsers: Chrome and Edge)" % sc ) url = self.driver.current_url - if ( - url.startswith("data:") or url.startswith("about:") - or url.startswith("chrome:") or url.startswith("edge:") - ): + if url.startswith(("data:", "about:", "chrome:", "edge:")): message = ( "The URL in Recorder-Mode cannot start with: " '"data:", "about:", "chrome:", or "edge:"!' @@ -4671,7 +4584,7 @@ class BaseCase(unittest.TestCase): return if self.recorder_ext: return # The Recorder extension is already active - try: + with suppress(Exception): recorder_on = self.get_session_storage_item("recorder_activated") if not recorder_on == "yes": self.execute_script(recorder_js) @@ -4680,8 +4593,6 @@ class BaseCase(unittest.TestCase): print("\n" + message) p_msg = "Recorder Mode ACTIVE.
[ESC]: Pause. [~`]: Resume." self.post_message(p_msg, pause=False, style="error") - except Exception: - pass def __current_url_is_recordable(self): url = self.get_current_url() @@ -4721,10 +4632,7 @@ class BaseCase(unittest.TestCase): def __get_recorded_actions_on_active_tab(self): url = self.driver.current_url - if ( - url.startswith("data:") or url.startswith("about:") - or url.startswith("chrome:") or url.startswith("edge:") - ): + if url.startswith(("data:", "about:", "chrome:", "edge:")): return [] self.__origins_to_save.append(self.get_origin()) actions = self.get_session_storage_item("recorded_actions") @@ -4735,9 +4643,9 @@ class BaseCase(unittest.TestCase): return [] def __process_recorded_actions(self): + """Generates code after the SeleniumBase Recorder runs.""" if self.driver is None: return - import colorama from seleniumbase.core import recorder_helper raw_actions = [] # All raw actions from sessionStorage @@ -4939,10 +4847,7 @@ class BaseCase(unittest.TestCase): or srt_actions[n - 1][0] == "jq_cl" or srt_actions[n - 1][0] == "jq_ca" ): - if ( - srt_actions[n - 1][1].startswith("input") - or srt_actions[n - 1][1].startswith("button") - ): + if srt_actions[n - 1][1].startswith(("input", "button")): srt_actions[n][0] = "f_url" elif srt_actions[n - 1][0] == "input": if srt_actions[n - 1][2].endswith("\n"): @@ -5290,7 +5195,6 @@ class BaseCase(unittest.TestCase): and (filename == "base_case.py" or methodname == "runTest") ): import traceback - stack_base = traceback.format_stack()[0].split(os.sep)[-1] test_base = stack_base.split(", in ")[0] if hasattr(self, "cm_filename") and self.cm_filename: @@ -5360,11 +5264,9 @@ class BaseCase(unittest.TestCase): if recordings_folder.endswith("/"): recordings_folder = recordings_folder[:-1] if not os.path.exists(recordings_folder): - try: + with suppress(Exception): os.makedirs(recordings_folder) sys.stdout.write("\nCreated recordings%s" % os.sep) - except Exception: - pass data = [] data.append("") @@ -5465,12 +5367,10 @@ class BaseCase(unittest.TestCase): if not new_file: rec_message = ">>> RECORDING ADDED to: " star_len = len(rec_message) + len(file_path) - try: + with suppress(Exception): terminal_size = os.get_terminal_size().columns if terminal_size > 30 and star_len > terminal_size: star_len = terminal_size - except Exception: - pass spc = "\n\n" if hasattr(self, "rec_print") and self.rec_print: spc = "" @@ -5543,22 +5443,16 @@ class BaseCase(unittest.TestCase): if recordings_folder.endswith("/"): recordings_folder = recordings_folder[:-1] if not os.path.exists(recordings_folder): - try: + with suppress(Exception): os.makedirs(recordings_folder) - except Exception: - pass features_folder = os.path.join(recordings_folder, "features") if not os.path.exists(features_folder): - try: + with suppress(Exception): os.makedirs(features_folder) - except Exception: - pass steps_folder = os.path.join(features_folder, "steps") if not os.path.exists(steps_folder): - try: + with suppress(Exception): os.makedirs(steps_folder) - except Exception: - pass file_name = filename.split(".")[0] if hasattr(self, "is_behave") and self.is_behave: @@ -5573,12 +5467,10 @@ class BaseCase(unittest.TestCase): if not new_file: rec_message = ">>> RECORDING ADDED to: " star_len = len(rec_message) + len(file_path) - try: + with suppress(Exception): terminal_size = os.get_terminal_size().columns if terminal_size > 30 and star_len > terminal_size: star_len = terminal_size - except Exception: - pass spc = "\n" if hasattr(self, "rec_print") and self.rec_print: spc = "" @@ -5684,16 +5576,14 @@ class BaseCase(unittest.TestCase): print("Created recordings/features/steps/imported.py") def bring_active_window_to_front(self): - """Brings the active browser window to the front. - This is useful when multiple drivers are being used.""" + """Brings the active browser window to the front (on top). + Useful when multiple drivers are being used at the same time.""" self.__check_scope() - try: + with suppress(Exception): if not self.__is_in_frame(): # Only bring the window to the front if not in a frame # because the driver resets itself to default content. self.switch_to_window(self.driver.current_window_handle) - except Exception: - pass def bring_to_front(self, selector, by="css selector"): """Updates the Z-index of a page element to bring it into view. @@ -5723,7 +5613,7 @@ class BaseCase(unittest.TestCase): def highlight_click( self, selector, by="css selector", loops=3, scroll=True, timeout=None, ): - """Highlights the element and then clicks it.""" + """Highlights the element, and then clicks it.""" self.__check_scope() if not timeout: timeout = settings.SMALL_TIMEOUT @@ -5782,10 +5672,8 @@ class BaseCase(unittest.TestCase): if not loops: loops = settings.HIGHLIGHTS if scroll and self.browser != "safari": - try: + with suppress(Exception): self.__slow_scroll_to_element(element) - except Exception: - pass if self.highlights: loops = self.highlights if self.browser == "ie": @@ -5815,7 +5703,7 @@ class BaseCase(unittest.TestCase): self, selector, by="css selector", loops=None, scroll=True ): """This method uses fancy JavaScript to highlight an element. - (Commonly used during Demo Mode automatically)""" + (Automatically using in S_e_l_e_n_i_u_m_B_a_s_e Demo Mode)""" self.__check_scope() selector, by = self.__recalculate_selector(selector, by, xp_ok=False) element = self.wait_for_element_visible( @@ -5935,14 +5823,12 @@ class BaseCase(unittest.TestCase): count = 0 elements = self.find_elements(selector, by=by) for element in elements: - try: + with suppress(Exception): if element.is_displayed(): self.__highlight_element( element, loops=loops, scroll=scroll ) count += 1 - except Exception: - pass if limit > 0 and count >= limit: break @@ -6189,10 +6075,8 @@ class BaseCase(unittest.TestCase): time_stamp = 0 action = ["", "", "", time_stamp] pre_action_url = None - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass pre_window_count = len(self.driver.window_handles) if self.recorder_mode and not self.__dont_record_js_click: time_stamp = self.execute_script("return Date.now();") @@ -6294,10 +6178,8 @@ class BaseCase(unittest.TestCase): # If a click closes the active window, # switch to the last one if it exists. self.switch_to_window(-1) - try: + with suppress(Exception): self.wait_for_ready_state_complete() - except Exception: - pass self.__demo_mode_pause_if_active() def js_click_if_present(self, selector, by="css selector", timeout=0): @@ -6309,10 +6191,8 @@ class BaseCase(unittest.TestCase): if self.is_element_present(selector, by=by): self.js_click(selector, by=by) elif timeout > 0: - try: + with suppress(Exception): self.wait_for_element_present(selector, by=by, timeout=timeout) - except Exception: - pass if self.is_element_present(selector, by=by): self.js_click(selector, by=by) @@ -6325,10 +6205,8 @@ class BaseCase(unittest.TestCase): if self.is_element_visible(selector, by=by): self.js_click(selector, by=by) elif timeout > 0: - try: + with suppress(Exception): self.wait_for_element_visible(selector, by=by, timeout=timeout) - except Exception: - pass if self.is_element_visible(selector, by=by): self.js_click(selector, by=by) @@ -6421,13 +6299,11 @@ class BaseCase(unittest.TestCase): """Hide the first element on the page that matches the selector.""" self.__check_scope() element = None - try: + with suppress(Exception): self.wait_for_element_visible("body", timeout=1.5) element = self.wait_for_element_present( selector, by=by, timeout=0.5 ) - except Exception: - pass selector, by = self.__recalculate_selector(selector, by) css_selector = self.convert_to_css_selector(selector, by=by) if ":contains(" in css_selector and element: @@ -6453,10 +6329,8 @@ class BaseCase(unittest.TestCase): def hide_elements(self, selector, by="css selector"): """Hide all elements on the page that match the selector.""" self.__check_scope() - try: + with suppress(Exception): self.wait_for_element_visible("body", timeout=1.5) - except Exception: - pass selector, by = self.__recalculate_selector(selector, by) css_selector = self.convert_to_css_selector(selector, by=by) if ":contains(" in css_selector: @@ -6479,11 +6353,9 @@ class BaseCase(unittest.TestCase): """Show the first element on the page that matches the selector.""" self.__check_scope() element = None - try: + with suppress(Exception): self.wait_for_element_visible("body", timeout=1.5) element = self.wait_for_element_present(selector, by=by, timeout=1) - except Exception: - pass selector, by = self.__recalculate_selector(selector, by) css_selector = self.convert_to_css_selector(selector, by=by) if ":contains(" in css_selector and element: @@ -6509,10 +6381,8 @@ class BaseCase(unittest.TestCase): def show_elements(self, selector, by="css selector"): """Show all elements on the page that match the selector.""" self.__check_scope() - try: + with suppress(Exception): self.wait_for_element_visible("body", timeout=1.5) - except Exception: - pass selector, by = self.__recalculate_selector(selector, by) css_selector = self.convert_to_css_selector(selector, by=by) if ":contains(" in css_selector: @@ -6535,13 +6405,11 @@ class BaseCase(unittest.TestCase): """Remove the first element on the page that matches the selector.""" self.__check_scope() element = None - try: + with suppress(Exception): self.wait_for_element_visible("body", timeout=1.5) element = self.wait_for_element_present( selector, by=by, timeout=0.5 ) - except Exception: - pass selector, by = self.__recalculate_selector(selector, by) css_selector = self.convert_to_css_selector(selector, by=by) if ":contains(" in css_selector and element: @@ -6567,10 +6435,8 @@ class BaseCase(unittest.TestCase): def remove_elements(self, selector, by="css selector"): """Remove all elements on the page that match the selector.""" self.__check_scope() - try: + with suppress(Exception): self.wait_for_element_visible("body", timeout=1.5) - except Exception: - pass selector, by = self.__recalculate_selector(selector, by) css_selector = self.convert_to_css_selector(selector, by=by) if ":contains(" in css_selector: @@ -6635,10 +6501,8 @@ class BaseCase(unittest.TestCase): $elements[index].setAttribute('class', new_class);}""" % css_selector ) - try: + with suppress(Exception): self.execute_script(script) - except Exception: - pass if self.recorder_mode and self.__current_url_is_recordable(): if self.get_session_storage_item("pause_recorder") == "no": time_stamp = self.execute_script("return Date.now();") @@ -6656,10 +6520,8 @@ class BaseCase(unittest.TestCase): self.is_chromium() and self.driver.current_url.startswith("http") ): - try: + with suppress(Exception): self.driver.execute_script("window.onbeforeunload=null;") - except Exception: - pass def get_domain_url(self, url): self.__check_scope() @@ -6675,12 +6537,10 @@ class BaseCase(unittest.TestCase): from bs4 import BeautifulSoup if not source: - try: + with suppress(Exception): self.wait_for_element_visible( "body", timeout=settings.MINI_TIMEOUT ) - except Exception: - pass source = self.get_page_source() return BeautifulSoup(source, "html.parser") @@ -6693,11 +6553,9 @@ class BaseCase(unittest.TestCase): time.sleep(0.08) if self.undetectable: time.sleep(0.02) - try: + with suppress(Exception): self.wait_for_element_present("body", timeout=1.5) self.wait_for_element_visible("body", timeout=1.5) - except Exception: - pass if self.__needs_minimum_wait(): time.sleep(0.25) if self.undetectable: @@ -6911,12 +6769,7 @@ class BaseCase(unittest.TestCase): try: from pdfminer.high_level import extract_text except Exception: - if not sys.version_info >= (3, 8): - shared_utils.pip_install( - "pdfminer.six", version="20221105" - ) - else: - shared_utils.pip_install("pdfminer.six") + shared_utils.pip_install("pdfminer.six") from pdfminer.high_level import extract_text if not password: password = "" @@ -7036,10 +6889,8 @@ class BaseCase(unittest.TestCase): if len(folder) < 1: raise Exception("Minimum folder name length = 1.") if not os.path.exists(folder): - try: + with suppress(Exception): os.makedirs(folder) - except Exception: - pass def choose_file( self, selector, file_path, by="css selector", timeout=None @@ -7079,10 +6930,8 @@ class BaseCase(unittest.TestCase): self.__scroll_to_element(element, selector, by) pre_action_url = None if self.demo_mode: - try: + with suppress(Exception): pre_action_url = self.driver.current_url - except Exception: - pass if self.recorder_mode and self.__current_url_is_recordable(): if self.get_session_storage_item("pause_recorder") == "no": time_stamp = self.execute_script("return Date.now();") @@ -7370,10 +7219,8 @@ class BaseCase(unittest.TestCase): Those paths are usually the same. (browser-dependent).""" if self.is_downloaded_file_present(file, browser=browser): file_path = self.get_path_of_downloaded_file(file, browser=browser) - try: + with suppress(Exception): os.remove(file_path) - except Exception: - pass def delete_downloaded_file(self, file, browser=False): """Same as self.delete_downloaded_file_if_present() @@ -7390,10 +7237,8 @@ class BaseCase(unittest.TestCase): Those paths are usually the same. (browser-dependent).""" if self.is_downloaded_file_present(file, browser=browser): file_path = self.get_path_of_downloaded_file(file, browser=browser) - try: + with suppress(Exception): os.remove(file_path) - except Exception: - pass def assert_downloaded_file(self, file, timeout=None, browser=False): """Asserts that the file exists in SeleniumBase's [Downloads Folder]. @@ -7450,13 +7295,11 @@ class BaseCase(unittest.TestCase): self.__extra_actions.append(action) if self.demo_mode: messenger_post = "ASSERT DOWNLOADED FILE: [%s]" % file - try: + with suppress(Exception): js_utils.activate_jquery(self.driver) js_utils.post_messenger_success_message( self.driver, messenger_post, self.message_duration ) - except Exception: - pass def assert_downloaded_file_regex(self, regex, timeout=None, browser=False): """Assert the filename regex exists in SeleniumBase's Downloads Folder. @@ -7505,13 +7348,11 @@ class BaseCase(unittest.TestCase): messenger_post = ( "ASSERT DOWNLOADED FILE REGEX: [%s]" % regex ) - try: + with suppress(Exception): js_utils.activate_jquery(self.driver) js_utils.post_messenger_success_message( self.driver, messenger_post, self.message_duration ) - except Exception: - pass def assert_data_in_downloaded_file( self, data, file, timeout=None, browser=False @@ -7530,37 +7371,37 @@ class BaseCase(unittest.TestCase): def assert_true(self, expr, msg=None): """Asserts that the expression is True. - Will raise an exception if the statement if False.""" + Raises an exception if the statement if False.""" self.assertTrue(expr, msg=msg) def assert_false(self, expr, msg=None): """Asserts that the expression is False. - Will raise an exception if the statement if True.""" + Raises an exception if the statement if True.""" self.assertFalse(expr, msg=msg) def assert_equal(self, first, second, msg=None): """Asserts that the two values are equal. - Will raise an exception if the values are not equal.""" + Raises an exception if the values are not equal.""" self.assertEqual(first, second, msg=msg) def assert_not_equal(self, first, second, msg=None): """Asserts that the two values are not equal. - Will raise an exception if the values are equal.""" + Raises an exception if the values are equal.""" self.assertNotEqual(first, second, msg=msg) def assert_in(self, first, second, msg=None): """Asserts that the first string is in the second string. - Will raise an exception if the first string is not in the second.""" + Raises an exception if the first string is not in the second.""" self.assertIn(first, second, msg=msg) def assert_not_in(self, first, second, msg=None): """Asserts that the first string is not in the second string. - Will raise an exception if the first string is in the second string.""" + Raises an exception if the first string is in the second string.""" self.assertNotIn(first, second, msg=msg) def assert_raises(self, *args, **kwargs): """Asserts that the following block of code raises an exception. - Will raise an exception if the block of code has no exception. + Raises an exception if the block of code has no exception. Usage Example => # Verify that the expected exception is raised. with self.assert_raises(Exception): @@ -8180,17 +8021,15 @@ class BaseCase(unittest.TestCase): else: if the_type == "range" and ":contains\\(" not in css_selector: # Some input sliders need a mouse event to trigger listeners. - try: + with suppress(Exception): mouse_move_script = ( """m_elm = document.querySelector('%s');""" """m_evt = new Event('mousemove');""" """m_elm.dispatchEvent(m_evt);""" % css_selector ) self.execute_script(mouse_move_script) - except Exception: - pass elif the_type == "range" and ":contains\\(" in css_selector: - try: + with suppress(Exception): element = self.wait_for_element_present( original_selector, by=by, timeout=1 ) @@ -8200,8 +8039,6 @@ class BaseCase(unittest.TestCase): """m_elm.dispatchEvent(m_evt);""" ) self.execute_script(mouse_move_script, element) - except Exception: - pass self.__demo_mode_pause_if_active() if not self.demo_mode and not self.slow_mode: if self.__needs_minimum_wait(): @@ -8221,13 +8058,11 @@ class BaseCase(unittest.TestCase): text = self.__get_type_checked_text(text) self.set_value(selector, text, by=by, timeout=timeout) if not text.endswith("\n"): - try: + with suppress(Exception): element = page_actions.wait_for_element_present( self.driver, selector, by, timeout=0.2 ) element.send_keys(" " + Keys.BACK_SPACE) - except Exception: - pass def js_type(self, selector, text, by="css selector", timeout=None): """Same as self.js_update_text() @@ -8347,13 +8182,11 @@ class BaseCase(unittest.TestCase): ) element.send_keys(Keys.RETURN) else: - try: + with suppress(Exception): element = self.wait_for_element_present( original_selector, by=original_by, timeout=0.2 ) element.send_keys(" " + Keys.BACK_SPACE) - except Exception: - pass self.__demo_mode_pause_if_active() def jquery_type(self, selector, text, by="css selector", timeout=None): @@ -8530,10 +8363,8 @@ class BaseCase(unittest.TestCase): def get_recorded_console_logs(self): """Get console logs recorded after "start_recording_console_logs()".""" logs = [] - try: + with suppress(Exception): logs = self.execute_script("return console.logs;") - except Exception: - pass return logs ############ @@ -8916,7 +8747,7 @@ class BaseCase(unittest.TestCase): self, selector, by="css selector", timeout=None ): """Same as self.assert_element_absent() - Will raise an exception if the element stays present. + Raises an exception if the element stays present. A hidden element counts as a present element, which fails this assert. If you want to assert that elements are hidden instead of nonexistent, use assert_element_not_visible() instead. @@ -8978,10 +8809,8 @@ class BaseCase(unittest.TestCase): """This method raises an exception if the active window is closed. (This provides a much cleaner exception message in this situation.)""" active_window = None - try: + with suppress(Exception): active_window = self.driver.current_window_handle # Fails if None - except Exception: - pass if not active_window: raise NoSuchWindowException("Active window was already closed!") @@ -8995,10 +8824,8 @@ class BaseCase(unittest.TestCase): """ if hasattr(sb_config, "_multithreaded") and sb_config._multithreaded: if not isinstance(msg, str): - try: + with suppress(Exception): msg = str(msg) - except Exception: - pass sys.stderr.write(msg + "\n") else: print(msg) @@ -9412,7 +9239,7 @@ class BaseCase(unittest.TestCase): def assert_element(self, selector, by="css selector", timeout=None): """Similar to wait_for_element_visible(), but returns nothing. - As above, will raise an exception if nothing can be found. + As above, raises an exception if nothing can be found. Returns True if successful. Default timeout = SMALL_TIMEOUT.""" self.__check_scope() if not timeout: @@ -9452,7 +9279,7 @@ class BaseCase(unittest.TestCase): self, selector, by="css selector", timeout=None ): """Same as self.assert_element() - As above, will raise an exception if nothing can be found.""" + As above, raises an exception if nothing can be found.""" self.__check_scope() if not timeout: timeout = settings.SMALL_TIMEOUT @@ -9678,6 +9505,7 @@ class BaseCase(unittest.TestCase): """Similar to wait_for_text_visible() Raises an exception if the element or the text is not found. The text only needs to be a subset within the complete text. + The text can be a string or a list/tuple of text substrings. Returns True if successful. Default timeout = SMALL_TIMEOUT.""" self.__check_scope() if not timeout: @@ -9686,26 +9514,45 @@ class BaseCase(unittest.TestCase): timeout = self.__get_new_timeout(timeout) original_selector = selector selector, by = self.__recalculate_selector(selector, by) - if self.__is_shadow_selector(selector): + if isinstance(text, (list, tuple)): + text_list = text + for _text in text_list: + self.wait_for_text_visible( + _text, selector, by=by, timeout=timeout + ) + if self.demo_mode: + a_t = "ASSERT TEXT" + i_n = "in" + if self._language != "English": + from seleniumbase.fixtures.words import SD + + a_t = SD.translate_assert_text(self._language) + i_n = SD.translate_in(self._language) + messenger_post = "%s: {%s} %s %s: %s" % ( + a_t, _text, i_n, by.upper(), selector + ) + self.__highlight_with_assert_success( + messenger_post, selector, by + ) + elif self.__is_shadow_selector(selector): self.__assert_shadow_text_visible(text, selector, timeout) return True - self.wait_for_text_visible(text, selector, by=by, timeout=timeout) - if self.demo_mode: - a_t = "ASSERT TEXT" - i_n = "in" - if self._language != "English": - from seleniumbase.fixtures.words import SD + else: + self.wait_for_text_visible(text, selector, by=by, timeout=timeout) + if self.demo_mode: + a_t = "ASSERT TEXT" + i_n = "in" + if self._language != "English": + from seleniumbase.fixtures.words import SD - a_t = SD.translate_assert_text(self._language) - i_n = SD.translate_in(self._language) - messenger_post = "%s: {%s} %s %s: %s" % ( - a_t, - text, - i_n, - by.upper(), - selector, - ) - self.__highlight_with_assert_success(messenger_post, selector, by) + a_t = SD.translate_assert_text(self._language) + i_n = SD.translate_in(self._language) + messenger_post = "%s: {%s} %s %s: %s" % ( + a_t, text, i_n, by.upper(), selector + ) + self.__highlight_with_assert_success( + messenger_post, selector, by + ) if self.recorder_mode and self.__current_url_is_recordable(): if self.get_session_storage_item("pause_recorder") == "no": if by == By.XPATH: @@ -9747,11 +9594,7 @@ class BaseCase(unittest.TestCase): a_t = SD.translate_assert_exact_text(self._language) i_n = SD.translate_in(self._language) messenger_post = "%s: {%s} %s %s: %s" % ( - a_t, - text, - i_n, - by.upper(), - selector, + a_t, text, i_n, by.upper(), selector ) self.__highlight_with_assert_success(messenger_post, selector, by) if self.recorder_mode and self.__current_url_is_recordable(): @@ -9791,10 +9634,7 @@ class BaseCase(unittest.TestCase): a_t = SD.translate_assert_non_empty_text(self._language) i_n = SD.translate_in(self._language) messenger_post = "%s %s %s: %s" % ( - a_t, - i_n, - by.upper(), - selector, + a_t, i_n, by.upper(), selector ) self.__highlight_with_assert_success(messenger_post, selector, by) if self.recorder_mode and self.__current_url_is_recordable(): @@ -9889,7 +9729,7 @@ class BaseCase(unittest.TestCase): def assert_link_text(self, link_text, timeout=None): """Similar to wait_for_link_text_visible(), but returns nothing. - As above, will raise an exception if nothing can be found. + As above, raises an exception if nothing can be found. Returns True if successful. Default timeout = SMALL_TIMEOUT.""" self.__check_scope() if not timeout: @@ -9938,7 +9778,7 @@ class BaseCase(unittest.TestCase): def assert_partial_link_text(self, partial_link_text, timeout=None): """Similar to wait_for_partial_link_text(), but returns nothing. - As above, will raise an exception if nothing can be found. + As above, raises an exception if nothing can be found. Returns True if successful. Default timeout = SMALL_TIMEOUT.""" self.__check_scope() if not timeout: @@ -9984,7 +9824,7 @@ class BaseCase(unittest.TestCase): def assert_element_absent(self, selector, by="css selector", timeout=None): """Similar to wait_for_element_absent() - As above, will raise an exception if the element stays present. + As above, raises an exception if the element stays present. A hidden element counts as a present element, which fails this assert. If you want to assert that elements are hidden instead of nonexistent, use assert_element_not_visible() instead. @@ -10025,7 +9865,7 @@ class BaseCase(unittest.TestCase): self, selector, by="css selector", timeout=None ): """Similar to wait_for_element_not_visible() - As above, will raise an exception if the element stays visible. + As above, raises an exception if the element stays visible. Returns True if successful. Default timeout = SMALL_TIMEOUT.""" self.__check_scope() if not timeout: @@ -10341,7 +10181,7 @@ class BaseCase(unittest.TestCase): countdown_on = True countdown = 3 minified_exception += line + "\n" - elif line.startswith("+") or line.startswith("-"): + elif line.startswith(("+", "-")): minified_exception += line + "\n" elif line.startswith("?"): minified_exception += line + "\n" @@ -10390,8 +10230,6 @@ class BaseCase(unittest.TestCase): shutil.copy(latest_png_path, latest_copy_path) if len(self.__visual_baseline_copies) != 1: return # Skip the rest when deferred visual asserts are used - from seleniumbase.core import visual_helper - the_html = visual_helper.get_sbs_html() file_path = os.path.join(test_logpath, constants.SideBySide.HTML_FILE) out_file = codecs.open(file_path, "w+", encoding="utf-8") @@ -10478,12 +10316,10 @@ class BaseCase(unittest.TestCase): self.check_window(name="github_page", level=2) self.check_window(name="wikipedia_page", level=3) """ self.wait_for_ready_state_complete() - try: + with suppress(Exception): self.wait_for_element_visible( "body", timeout=settings.MINI_TIMEOUT ) - except Exception: - pass if self.__needs_minimum_wait(): time.sleep(0.08) if level == "0": @@ -10509,7 +10345,6 @@ class BaseCase(unittest.TestCase): if not name or len(name) < 1: name = "default" name = str(name) - from seleniumbase.core import visual_helper visual_helper.visual_baseline_folder_setup() baseline_dir = constants.VisualBaseline.STORAGE_FOLDER @@ -10792,14 +10627,12 @@ class BaseCase(unittest.TestCase): if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT: timeout = self.__get_new_timeout(timeout) self.__deferred_assert_count += 1 - try: + with suppress(Exception): url = self.get_current_url() if url == self.__last_url_of_deferred_assert: timeout = 0.6 # Was already on page (full wait not needed) else: self.__last_url_of_deferred_assert = url - except Exception: - pass if self.recorder_mode and self.__current_url_is_recordable(): if self.get_session_storage_item("pause_recorder") == "no": time_stamp = self.execute_script("return Date.now();") @@ -10829,14 +10662,12 @@ class BaseCase(unittest.TestCase): if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT: timeout = self.__get_new_timeout(timeout) self.__deferred_assert_count += 1 - try: + with suppress(Exception): url = self.get_current_url() if url == self.__last_url_of_deferred_assert: timeout = 0.6 # Was already on page (full wait not needed) else: self.__last_url_of_deferred_assert = url - except Exception: - pass if self.recorder_mode and self.__current_url_is_recordable(): if self.get_session_storage_item("pause_recorder") == "no": time_stamp = self.execute_script("return Date.now();") @@ -10866,14 +10697,12 @@ class BaseCase(unittest.TestCase): if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT: timeout = self.__get_new_timeout(timeout) self.__deferred_assert_count += 1 - try: + with suppress(Exception): url = self.get_current_url() if url == self.__last_url_of_deferred_assert: timeout = 0.6 # Was already on page (full wait not needed) else: self.__last_url_of_deferred_assert = url - except Exception: - pass if self.recorder_mode and self.__current_url_is_recordable(): if self.get_session_storage_item("pause_recorder") == "no": time_stamp = self.execute_script("return Date.now();") @@ -10904,14 +10733,12 @@ class BaseCase(unittest.TestCase): if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT: timeout = self.__get_new_timeout(timeout) self.__deferred_assert_count += 1 - try: + with suppress(Exception): url = self.get_current_url() if url == self.__last_url_of_deferred_assert: timeout = 0.6 # Was already on page (full wait not needed) else: self.__last_url_of_deferred_assert = url - except Exception: - pass if self.recorder_mode and self.__current_url_is_recordable(): if self.get_session_storage_item("pause_recorder") == "no": time_stamp = self.execute_script("return Date.now();") @@ -10948,14 +10775,12 @@ class BaseCase(unittest.TestCase): if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT: timeout = self.__get_new_timeout(timeout) self.__deferred_assert_count += 1 - try: + with suppress(Exception): url = self.get_current_url() if url == self.__last_url_of_deferred_assert: timeout = 0.6 # Was already on page (full wait not needed) else: self.__last_url_of_deferred_assert = url - except Exception: - pass if self.recorder_mode and self.__current_url_is_recordable(): if self.get_session_storage_item("pause_recorder") == "no": time_stamp = self.execute_script("return Date.now();") @@ -11391,10 +11216,8 @@ class BaseCase(unittest.TestCase): if saved_presentations_folder.endswith("/"): saved_presentations_folder = saved_presentations_folder[:-1] if not os.path.exists(saved_presentations_folder): - try: + with suppress(Exception): os.makedirs(saved_presentations_folder) - except Exception: - pass file_path = os.path.join(saved_presentations_folder, filename) out_file = codecs.open(file_path, "w+", encoding="utf-8") out_file.writelines(the_html) @@ -11448,7 +11271,7 @@ class BaseCase(unittest.TestCase): self._presentation_slides[name].pop() self.open_html_file(file_path) presentation_folder = constants.Presentations.SAVED_FOLDER - try: + with suppress(Exception): while ( len(self.driver.window_handles) > 0 and presentation_folder in self.get_current_url() @@ -11459,8 +11282,6 @@ class BaseCase(unittest.TestCase): ): break time.sleep(0.05) - except Exception: - pass ############ @@ -12090,10 +11911,8 @@ class BaseCase(unittest.TestCase): if saved_charts_folder.endswith("/"): saved_charts_folder = saved_charts_folder[:-1] if not os.path.exists(saved_charts_folder): - try: + with suppress(Exception): os.makedirs(saved_charts_folder) - except Exception: - pass file_path = os.path.join(saved_charts_folder, filename) out_file = codecs.open(file_path, "w+", encoding="utf-8") out_file.writelines(the_html) @@ -12133,17 +11952,15 @@ class BaseCase(unittest.TestCase): self.open_html_file(file_path) chart_folder = constants.Charts.SAVED_FOLDER if interval == 0: - try: + with suppress(Exception): print("\n*** Close the browser window to continue ***") # Will also continue if manually navigating to a new page while len(self.driver.window_handles) > 0 and ( chart_folder in self.get_current_url() ): time.sleep(0.05) - except Exception: - pass else: - try: + with suppress(Exception): start_ms = time.time() * 1000.0 stop_ms = start_ms + (interval * 1000.0) for x in range(int(interval * 10)): @@ -12155,8 +11972,6 @@ class BaseCase(unittest.TestCase): if chart_folder not in self.get_current_url(): break time.sleep(0.1) - except Exception: - pass def extract_chart(self, chart_name=None): """Extracts the HTML from a SeleniumBase-generated chart. @@ -12968,10 +12783,8 @@ class BaseCase(unittest.TestCase): ) time.sleep(0.02) jf = "document.querySelector('.jconfirm-box').focus();" - try: + with suppress(Exception): self.execute_script(jf) - except Exception: - pass waiting_for_response = True while waiting_for_response: time.sleep(0.05) @@ -13043,10 +12856,8 @@ class BaseCase(unittest.TestCase): ) time.sleep(0.02) jf = "document.querySelector('.jconfirm-box input.jqc_input').focus();" - try: + with suppress(Exception): self.execute_script(jf) - except Exception: - pass waiting_for_response = True while waiting_for_response: time.sleep(0.05) @@ -13107,10 +12918,8 @@ class BaseCase(unittest.TestCase): ) time.sleep(0.02) jf = "document.querySelector('.jconfirm-box input.jqc_input').focus();" - try: + with suppress(Exception): self.execute_script(jf) - except Exception: - pass waiting_for_response = True while waiting_for_response: time.sleep(0.05) @@ -13185,12 +12994,10 @@ class BaseCase(unittest.TestCase): if not page_actions.is_element_clickable( self.driver, selector, by ): - try: + with suppress(Exception): self.wait_for_element_clickable( selector, by, timeout=1.8 ) - except Exception: - pass # If the regular mouse-simulated click fails, do a basic JS click script = ( """document.querySelector('%s').click();""" @@ -13266,8 +13073,6 @@ class BaseCase(unittest.TestCase): timeout=None, center=None, ): - from selenium.webdriver.common.action_chains import ActionChains - self.wait_for_ready_state_complete() if self.__needs_minimum_wait(): time.sleep(0.14) @@ -13464,7 +13269,7 @@ class BaseCase(unittest.TestCase): for dropdown in matching_dropdowns: # The same class names might be used for multiple dropdowns if dropdown.is_displayed(): - try: + with suppress(Exception): try: page_actions.hover_element( self.driver, @@ -13485,9 +13290,6 @@ class BaseCase(unittest.TestCase): timeout=0.12, ) return True - except Exception: - pass - return False def __get_href_from_partial_link_text(self, link_text, hard_fail=True): @@ -13528,7 +13330,7 @@ class BaseCase(unittest.TestCase): for dropdown in matching_dropdowns: # The same class names might be used for multiple dropdowns if dropdown.is_displayed(): - try: + with suppress(Exception): try: page_actions.hover_element( self.driver, dropdown @@ -13550,8 +13352,6 @@ class BaseCase(unittest.TestCase): timeout=0.12, ) return True - except Exception: - pass return False def __recalculate_selector(self, selector, by, xp_ok=True): @@ -13778,7 +13578,7 @@ class BaseCase(unittest.TestCase): from sbvirtualdisplay import Display width = settings.HEADLESS_START_WIDTH height = settings.HEADLESS_START_HEIGHT - try: + with suppress(Exception): self._xvfb_display = Display( visible=0, size=(width, height) ) @@ -13786,11 +13586,9 @@ class BaseCase(unittest.TestCase): sb_config._virtual_display = self._xvfb_display self.headless_active = True sb_config.headless_active = True - except Exception: - pass def __activate_virtual_display_as_needed(self): - """Should be needed only on Linux. + """This is only needed on Linux. The "--xvfb" arg is still useful, as it prevents headless mode, which is the default mode on Linux unless using another arg.""" if "linux" in sys.platform and (not self.headed or self.xvfb): @@ -13829,7 +13627,7 @@ class BaseCase(unittest.TestCase): pyautogui_is_installed = False try: import pyautogui - try: + with suppress(Exception): use_pyautogui_ver = constants.PyAutoGUI.VER if pyautogui.__version__ != use_pyautogui_ver: del pyautogui # To get newer ver @@ -13837,8 +13635,6 @@ class BaseCase(unittest.TestCase): "pyautogui", version=use_pyautogui_ver ) import pyautogui - except Exception: - pass pyautogui_is_installed = True except Exception: message = ( @@ -14090,12 +13886,10 @@ class BaseCase(unittest.TestCase): selector, timeout=timeout, must_be_visible=True ) if clear_first: - try: + with suppress(Exception): element.clear() backspaces = Keys.BACK_SPACE * 42 # Autofill Defense element.send_keys(backspaces) - except Exception: - pass text = self.__get_type_checked_text(text) if not text.endswith("\n"): element.send_keys(text) @@ -14111,12 +13905,10 @@ class BaseCase(unittest.TestCase): element = self.__get_shadow_element( selector, timeout=timeout, must_be_visible=True ) - try: + with suppress(Exception): element.clear() backspaces = Keys.BACK_SPACE * 42 # Autofill Defense element.send_keys(backspaces) - except Exception: - pass def __get_shadow_text(self, selector, timeout): element = self.__get_shadow_element( @@ -14236,19 +14028,13 @@ class BaseCase(unittest.TestCase): a_t = SD.translate_assert_text(self._language) i_n = SD.translate_in(self._language) messenger_post = "%s: {%s} %s %s: %s" % ( - a_t, - text, - i_n, - by.upper(), - selector, + a_t, text, i_n, by.upper(), selector ) - try: + with suppress(Exception): js_utils.activate_jquery(self.driver) js_utils.post_messenger_success_message( self.driver, messenger_post, self.message_duration ) - except Exception: - pass def __assert_exact_shadow_text_visible(self, text, selector, timeout): self.__wait_for_exact_shadow_text_visible(text, selector, timeout) @@ -14262,19 +14048,13 @@ class BaseCase(unittest.TestCase): a_t = SD.translate_assert_exact_text(self._language) i_n = SD.translate_in(self._language) messenger_post = "%s: {%s} %s %s: %s" % ( - a_t, - text, - i_n, - by.upper(), - selector, + a_t, text, i_n, by.upper(), selector ) - try: + with suppress(Exception): js_utils.activate_jquery(self.driver) js_utils.post_messenger_success_message( self.driver, messenger_post, self.message_duration ) - except Exception: - pass def __assert_non_empty_shadow_text_visible(self, selector, timeout, strip): self.__wait_for_non_empty_shadow_text_visible(selector, timeout, strip) @@ -14288,18 +14068,13 @@ class BaseCase(unittest.TestCase): a_t = SD.translate_assert_non_empty_text(self._language) i_n = SD.translate_in(self._language) messenger_post = "%s %s %s: %s" % ( - a_t, - i_n, - by.upper(), - selector, + a_t, i_n, by.upper(), selector ) - try: + with suppress(Exception): js_utils.activate_jquery(self.driver) js_utils.post_messenger_success_message( self.driver, messenger_post, self.message_duration ) - except Exception: - pass def __is_shadow_element_present(self, selector): try: @@ -14451,13 +14226,11 @@ class BaseCase(unittest.TestCase): a_t = SD.translate_assert(self._language) messenger_post = "%s %s: %s" % (a_t, by.upper(), selector) - try: + with suppress(Exception): js_utils.activate_jquery(self.driver) js_utils.post_messenger_success_message( self.driver, messenger_post, self.message_duration ) - except Exception: - pass def __assert_shadow_element_visible(self, selector): element = self.__get_shadow_element(selector) @@ -14472,13 +14245,11 @@ class BaseCase(unittest.TestCase): a_t = SD.translate_assert(self._language) messenger_post = "%s %s: %s" % (a_t, by.upper(), selector) - try: + with suppress(Exception): js_utils.activate_jquery(self.driver) js_utils.post_messenger_success_message( self.driver, messenger_post, self.message_duration ) - except Exception: - pass ############ @@ -14928,7 +14699,7 @@ class BaseCase(unittest.TestCase): if not hasattr(sb_config, "shared_driver"): sb_config.shared_driver = None if sb_config.shared_driver: - try: + with suppress(Exception): self._default_driver = sb_config.shared_driver self.driver = sb_config.shared_driver self._drivers_list = [sb_config.shared_driver] @@ -14942,12 +14713,8 @@ class BaseCase(unittest.TestCase): self.switch_to_window(0) if self._crumbs: self.wait_for_ready_state_complete() - try: + with suppress(Exception): self.driver.delete_all_cookies() - except Exception: - pass - except Exception: - pass if self._reuse_session and sb_config.shared_driver and has_url: good_start_page = False if self.recorder_ext: @@ -15034,10 +14801,8 @@ class BaseCase(unittest.TestCase): if self.driver.timeouts.implicit_wait > 0: self.driver.implicitly_wait(0) except Exception: - try: + with suppress(Exception): self.driver.implicitly_wait(0) - except Exception: - pass self._default_driver = self.driver if self._reuse_session: sb_config.shared_driver = self.driver @@ -15056,13 +14821,11 @@ class BaseCase(unittest.TestCase): self.set_time_limit(self.time_limit) # Configure the page load timeout - try: + with suppress(Exception): if hasattr(settings, "PAGE_LOAD_TIMEOUT"): self.driver.set_page_load_timeout(settings.PAGE_LOAD_TIMEOUT) else: self.driver.set_page_load_timeout(120) # Selenium uses 300 - except Exception: - pass # Set the start time for the test (in ms). # Although the pytest clock starts before setUp() begins, @@ -15091,7 +14854,7 @@ class BaseCase(unittest.TestCase): not self.__last_page_screenshot and not self.__last_page_screenshot_png ): - try: + with suppress(Exception): try: element = page_actions.wait_for_element_visible( self.driver, @@ -15121,14 +14884,10 @@ class BaseCase(unittest.TestCase): element.screenshot_as_base64 ) except Exception: - try: + with suppress(Exception): self.__last_page_screenshot = ( self.driver.get_screenshot_as_base64() ) - except Exception: - pass - except Exception: - pass if not self.__last_page_screenshot: self.__last_page_screenshot = SCREENSHOT_UNDEFINED self.__last_page_screenshot_png = SCREENSHOT_UNDEFINED @@ -15138,12 +14897,10 @@ class BaseCase(unittest.TestCase): element.screenshot_as_png ) except Exception: - try: + with suppress(Exception): self.__last_page_screenshot_png = ( self.driver.get_screenshot_as_png() ) - except Exception: - pass else: import base64 @@ -15158,12 +14915,10 @@ class BaseCase(unittest.TestCase): element.screenshot_as_png ) except Exception: - try: + with suppress(Exception): self.__last_page_screenshot_png = ( self.driver.get_screenshot_as_png() ) - except Exception: - pass sb_config._last_page_screenshot_png = self.__last_page_screenshot_png def __set_last_page_url(self): @@ -15215,7 +14970,6 @@ class BaseCase(unittest.TestCase): data_payload.state = state if err: import traceback - tb_string = traceback.format_exc() if "Message: " in tb_string: data_payload.message = ( @@ -15250,7 +15004,7 @@ class BaseCase(unittest.TestCase): def __add_pytest_html_extra(self): if not self.__added_pytest_html_extra: - try: + with suppress(Exception): if self.with_selenium: if not self.__last_page_screenshot: self.__set_last_page_screenshot() @@ -15277,8 +15031,6 @@ class BaseCase(unittest.TestCase): ): self._html_report_extra.append(extra_url) self._html_report_extra.append(extra_image) - except Exception: - pass def __delay_driver_quit(self): delay_driver_quit = False @@ -15372,7 +15124,6 @@ class BaseCase(unittest.TestCase): context_id = None if filename == "base_case.py" or methodname == "runTest": import traceback - stack_base = traceback.format_stack()[0].split(", in ")[0] test_base = stack_base.split(", in ")[0].split(os.sep)[-1] if hasattr(self, "cm_filename") and self.cm_filename: @@ -16094,7 +15845,14 @@ class BaseCase(unittest.TestCase): self.driver.window_handles except Exception: self.driver.connect() - self.__process_recorded_actions() + try: + self.__process_recorded_actions() + except Exception as e: + print("\n (Recorder) Code-generation exception:") + if hasattr(e, "msg"): + print("\n" + str(e.msg)) + else: + print(e) self.__called_teardown = True self.__called_setup = False try: @@ -16131,10 +15889,8 @@ class BaseCase(unittest.TestCase): try: self.driver.window_handles except Exception: - try: + with suppress(Exception): self.driver.connect() - except Exception: - pass self.__slow_mode_pause_if_active() has_exception = self.__has_exception() sb_config._has_exception = has_exception @@ -16324,7 +16080,6 @@ class BaseCase(unittest.TestCase): else: # (Pynose / Behave / Pure Python) if hasattr(self, "is_behave") and self.is_behave: - import colorama if sb_config.behave_scenario.status.name == "failed": has_exception = True sb_config._has_exception = True diff --git a/seleniumbase/fixtures/js_utils.py b/seleniumbase/fixtures/js_utils.py index de7420a8..ff85ed57 100644 --- a/seleniumbase/fixtures/js_utils.py +++ b/seleniumbase/fixtures/js_utils.py @@ -2,6 +2,7 @@ import re import requests import time +from contextlib import suppress from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import WebDriverException from selenium.webdriver.common.by import By @@ -56,11 +57,9 @@ def execute_async_script(driver, script, timeout=settings.LARGE_TIMEOUT): def wait_for_angularjs(driver, timeout=settings.LARGE_TIMEOUT, **kwargs): if hasattr(settings, "SKIP_JS_WAITS") and settings.SKIP_JS_WAITS: return - try: + with suppress(Exception): # This closes pop-up alerts driver.execute_script("") - except Exception: - pass if ( (hasattr(driver, "_is_using_uc") and driver._is_using_uc) or not settings.WAIT_FOR_ANGULARJS @@ -92,10 +91,8 @@ def wait_for_angularjs(driver, timeout=settings.LARGE_TIMEOUT, **kwargs): "handler": handler, "suffix": suffix, } - try: + with suppress(Exception): execute_async_script(driver, script, timeout=timeout) - except Exception: - pass def convert_to_css_selector(selector, by=By.CSS_SELECTOR): @@ -191,14 +188,12 @@ def raise_unable_to_load_jquery_exception(driver): def activate_jquery(driver): # If "jQuery is not defined" on a website, use this method to activate it. # This method is needed because jQuery is not always defined on web sites. - try: + with suppress(Exception): # Let's first find out if jQuery is already defined. driver.execute_script("jQuery('html');") # Since that command worked, jQuery is defined. Let's return. return - except Exception: - # jQuery is not currently defined. Let's proceed by defining it. - pass + # jQuery is not defined. It will be loaded in the next part. jquery_js = constants.JQuery.MIN_JS add_js_link(driver, jquery_js) for x in range(36): @@ -390,11 +385,9 @@ def highlight(driver, selector, by="css selector", loops=4): def highlight_with_js(driver, selector, loops=4, o_bs=""): - try: + with suppress(Exception): # This closes any pop-up alerts driver.execute_script("") - except Exception: - pass if selector == "html": selector = "body" selector_no_spaces = selector.replace(" ", "") @@ -490,11 +483,9 @@ def highlight_with_js(driver, selector, loops=4, o_bs=""): def highlight_element_with_js(driver, element, loops=4, o_bs=""): - try: + with suppress(Exception): # This closes any pop-up alerts driver.execute_script("") - except Exception: - pass script = ( """arguments[0].style.boxShadow = '0px 0px 6px 6px rgba(128, 128, 128, 0.5)';""" @@ -566,11 +557,9 @@ def highlight_element_with_js(driver, element, loops=4, o_bs=""): def highlight_with_jquery(driver, selector, loops=4, o_bs=""): - try: + with suppress(Exception): # This closes any pop-up alerts driver.execute_script("") - except Exception: - pass if selector == "html": selector = "body" selector_no_spaces = selector.replace(" ", "") @@ -908,11 +897,9 @@ def set_messenger_theme( time.sleep(0.03) activate_messenger(driver) time.sleep(0.15) - try: + with suppress(Exception): driver.execute_script(msg_style) time.sleep(0.02) - except Exception: - pass time.sleep(0.05) @@ -949,7 +936,7 @@ def post_messenger_success_message(driver, message, msg_dur=None): if not msg_dur: msg_dur = settings.DEFAULT_MESSAGE_DURATION msg_dur = float(msg_dur) - try: + with suppress(Exception): theme = "future" location = "bottom_right" if hasattr(sb_config, "mobile_emulator") and sb_config.mobile_emulator: @@ -957,28 +944,22 @@ def post_messenger_success_message(driver, message, msg_dur=None): set_messenger_theme(driver, theme=theme, location=location) post_message(driver, message, msg_dur, style="success") time.sleep(msg_dur + 0.07) - except Exception: - pass def post_messenger_error_message(driver, message, msg_dur=None): if not msg_dur: msg_dur = settings.DEFAULT_MESSAGE_DURATION msg_dur = float(msg_dur) - try: + with suppress(Exception): set_messenger_theme(driver, theme="block", location="top_center") post_message(driver, message, msg_dur, style="error") time.sleep(msg_dur + 0.07) - except Exception: - pass def highlight_with_js_2(driver, message, selector, o_bs, msg_dur): - try: + with suppress(Exception): # This closes any pop-up alerts driver.execute_script("") - except Exception: - pass if selector == "html": selector = "body" selector_no_spaces = selector.replace(" ", "") @@ -991,11 +972,9 @@ def highlight_with_js_2(driver, message, selector, o_bs, msg_dur): else: early_exit = True # Changing the box-shadow changes the selector if early_exit: - try: + with suppress(Exception): activate_jquery(driver) post_messenger_success_message(driver, message, msg_dur) - except Exception: - pass return script = ( """document.querySelector('%s').style.boxShadow = @@ -1047,11 +1026,9 @@ def highlight_with_js_2(driver, message, selector, o_bs, msg_dur): except Exception: return time.sleep(0.0181) - try: + with suppress(Exception): activate_jquery(driver) post_messenger_success_message(driver, message, msg_dur) - except Exception: - pass script = """document.querySelector('%s').style.boxShadow = '%s';""" % ( selector, o_bs, @@ -1063,11 +1040,9 @@ def highlight_with_js_2(driver, message, selector, o_bs, msg_dur): def highlight_element_with_js_2(driver, message, element, o_bs, msg_dur): - try: + with suppress(Exception): # This closes any pop-up alerts driver.execute_script("") - except Exception: - pass script = ( """arguments[0].style.boxShadow = '0px 0px 6px 6px rgba(128, 128, 128, 0.5)';""" @@ -1113,11 +1088,9 @@ def highlight_element_with_js_2(driver, message, element, o_bs, msg_dur): except Exception: return time.sleep(0.0181) - try: + with suppress(Exception): activate_jquery(driver) post_messenger_success_message(driver, message, msg_dur) - except Exception: - pass script = """arguments[0].style.boxShadow = '%s';""" % (o_bs) try: driver.execute_script(script, element) @@ -1138,11 +1111,9 @@ def highlight_with_jquery_2(driver, message, selector, o_bs, msg_dur): else: early_exit = True # Changing the box-shadow changes the selector if early_exit: - try: + with suppress(Exception): activate_jquery(driver) post_messenger_success_message(driver, message, msg_dur) - except Exception: - pass return script = ( """jQuery('%s').css('box-shadow', @@ -1195,11 +1166,9 @@ def highlight_with_jquery_2(driver, message, selector, o_bs, msg_dur): return time.sleep(0.0181) - try: + with suppress(Exception): activate_jquery(driver) post_messenger_success_message(driver, message, msg_dur) - except Exception: - pass script = """jQuery('%s').css('box-shadow', '%s');""" % (selector, o_bs) try: @@ -1484,12 +1453,10 @@ def get_drag_and_drop_with_offset_script(selector, x, y): def clear_out_console_logs(driver): - try: + with suppress(Exception): # Clear out the current page log before navigating to a new page # (To make sure that assert_no_js_errors() uses current results) driver.get_log("browser") - except Exception: - pass def _jq_format(code): diff --git a/seleniumbase/fixtures/page_actions.py b/seleniumbase/fixtures/page_actions.py index f6c657fa..3e0b1506 100644 --- a/seleniumbase/fixtures/page_actions.py +++ b/seleniumbase/fixtures/page_actions.py @@ -21,6 +21,7 @@ import codecs import fasteners import os import time +from contextlib import suppress from selenium.common.exceptions import ElementNotInteractableException from selenium.common.exceptions import ElementNotVisibleException from selenium.common.exceptions import NoAlertPresentException @@ -1409,12 +1410,10 @@ def switch_to_frame(driver, frame, timeout=settings.SMALL_TIMEOUT): else: by = "css selector" if is_element_visible(driver, frame, by=by): - try: + with suppress(Exception): element = driver.find_element(by=by, value=frame) driver.switch_to.frame(element) return True - except Exception: - pass now_ms = time.time() * 1000.0 if now_ms >= stop_ms: break @@ -1548,12 +1547,10 @@ def click_if_visible( if is_element_visible(driver, selector, by=by): click(driver, selector, by=by, timeout=1) elif timeout > 0: - try: + with suppress(Exception): wait_for_element_visible( driver, selector, by=by, timeout=timeout ) - except Exception: - pass if is_element_visible(driver, selector, by=by): click(driver, selector, by=by, timeout=1) diff --git a/seleniumbase/fixtures/page_utils.py b/seleniumbase/fixtures/page_utils.py index 18044a8b..ae02add9 100644 --- a/seleniumbase/fixtures/page_utils.py +++ b/seleniumbase/fixtures/page_utils.py @@ -16,7 +16,7 @@ def get_domain_url(url): Into this: https://blog.xkcd.com """ - if not url.startswith("http://") and not url.startswith("https://"): + if not url.startswith(("http://", "https://")): return url url_header = url.split("://")[0] simple_url = url.split("://")[1] @@ -40,45 +40,25 @@ def swap_selector_and_by_if_reversed(selector, by): def is_xpath_selector(selector): """Determine if a selector is an xpath selector.""" - if ( - selector.startswith("/") - or selector.startswith("./") - or selector.startswith("(") - ): - return True - return False + return selector.startswith(("/", "./", "(")) def is_link_text_selector(selector): """Determine if a selector is a link text selector.""" - if ( - selector.startswith("link=") - or selector.startswith("link_text=") - or selector.startswith("text=") - ): - return True - return False + return selector.startswith(("link=", "link_text=", "text=")) def is_partial_link_text_selector(selector): """Determine if a selector is a partial link text selector.""" - if ( - selector.startswith("partial_link=") - or selector.startswith("partial_link_text=") - or selector.startswith("partial_text=") - or selector.startswith("p_link=") - or selector.startswith("p_link_text=") - or selector.startswith("p_text=") - ): - return True - return False + return selector.startswith(( + "partial_link=", "partial_link_text=", "partial_text=", + "p_link=", "p_link_text=", "p_text=" + )) def is_name_selector(selector): """Determine if a selector is a name selector.""" - if selector.startswith("name=") or selector.startswith("&"): - return True - return False + return selector.startswith(("name=", "&")) def recalculate_selector(selector, by, xp_ok=True): @@ -108,10 +88,9 @@ def recalculate_selector(selector, by, xp_ok=True): name = get_name_from_selector(selector) selector = '[name="%s"]' % name by = By.CSS_SELECTOR - if xp_ok: - if ":contains(" in selector and by == By.CSS_SELECTOR: - selector = css_to_xpath.convert_css_to_xpath(selector) - by = By.XPATH + if xp_ok and ":contains(" in selector and by == By.CSS_SELECTOR: + selector = css_to_xpath.convert_css_to_xpath(selector) + by = By.XPATH if by == "": by = By.CSS_SELECTOR if not is_valid_by(by): @@ -130,21 +109,10 @@ def looks_like_a_page_url(url): possible typos when calling self.get(url), which will try to navigate to the page if a URL is detected, but will instead call self.get_element(URL_AS_A_SELECTOR) if the input is not a URL.""" - if ( - url.startswith("http:") - or url.startswith("https:") - or url.startswith("://") - or url.startswith("about:") - or url.startswith("blob:") - or url.startswith("chrome:") - or url.startswith("data:") - or url.startswith("edge:") - or url.startswith("file:") - or url.startswith("view-source:") - ): - return True - else: - return False + return url.startswith(( + "http:", "https:", "://", "about:", "blob:", "chrome:", + "data:", "edge:", "file:", "view-source:" + )) def get_link_text_from_selector(selector): @@ -195,18 +163,12 @@ def is_valid_url(url): r"(?:/?|[/?]\S+)$", re.IGNORECASE, ) - if ( + return ( regex.match(url) - or url.startswith("about:") - or url.startswith("blob:") - or url.startswith("chrome:") - or url.startswith("data:") - or url.startswith("edge:") - or url.startswith("file:") - ): - return True - else: - return False + or url.startswith(( + "about:", "blob:", "chrome:", "data:", "edge:", "file:" + )) + ) def _get_unique_links(page_url, soup): diff --git a/seleniumbase/plugins/base_plugin.py b/seleniumbase/plugins/base_plugin.py index 61b6da01..2c4f945a 100644 --- a/seleniumbase/plugins/base_plugin.py +++ b/seleniumbase/plugins/base_plugin.py @@ -2,6 +2,7 @@ import ast import sys import time +from contextlib import suppress from nose.plugins import Plugin from seleniumbase import config as sb_config from seleniumbase.config import settings @@ -305,14 +306,12 @@ class Base(Plugin): if python3_11_or_newer and py311_patch2: # Handle a bug on Python 3.11 where exceptions aren't seen sb_config._browser_version = None - try: + with suppress(Exception): test._BaseCase__set_last_page_screenshot() test._BaseCase__set_last_page_url() test._BaseCase__set_last_page_source() sb_config._browser_version = test._get_browser_version() test._log_fail_data() - except Exception: - pass sb_config._excinfo_tb = err log_path = None if hasattr(sb_config, "_test_logpath"): diff --git a/seleniumbase/plugins/driver_manager.py b/seleniumbase/plugins/driver_manager.py index fe1d462a..a3f19e5a 100644 --- a/seleniumbase/plugins/driver_manager.py +++ b/seleniumbase/plugins/driver_manager.py @@ -7,7 +7,7 @@ Usage --> ``with DriverContext() as driver:`` Example --> -``` +```python from seleniumbase import DriverContext with DriverContext() as driver: @@ -27,7 +27,7 @@ Usage --> ``driver = Driver()`` Example --> -``` +```python from seleniumbase import Driver driver = Driver() @@ -75,7 +75,7 @@ def Driver( proxy=None, # Use proxy. Format: "SERVER:PORT" or "USER:PASS@SERVER:PORT". proxy_bypass_list=None, # Skip proxy when using the listed domains. proxy_pac_url=None, # Use PAC file. (Format: URL or USERNAME:PASSWORD@URL) - multi_proxy=False, # Allow multiple proxies with auth when multi-threaded. + multi_proxy=None, # Allow multiple proxies with auth when multi-threaded. agent=None, # Modify the web browser's User-Agent string. cap_file=None, # The desired capabilities to use with a Selenium Grid. cap_string=None, # The desired capabilities to use with a Selenium Grid. @@ -133,7 +133,98 @@ def Driver( wire=None, # Shortcut / Duplicate of "use_wire". pls=None, # Shortcut / Duplicate of "page_load_strategy". ): + """ + * SeleniumBase Driver as a Python Context Manager or a returnable object. * + + Example 1: (context manager format) + ----------------------------------- + .. code-block:: python + from seleniumbase import DriverContext + + with DriverContext() as driver: + driver.get("https://google.com/ncr") + + Example 2: (as a Python returnable) + ----------------------------------- + .. code-block:: python + from seleniumbase import Driver + + driver = Driver() + driver.get("https://google.com/ncr") + + Optional Parameters: + -------------------- + browser: # Choose from "chrome", "edge", "firefox", or "safari". + headless: # The original headless mode for Chromium and Firefox. + headless2: # Chromium's new headless mode. (Has more features) + headed: # Run tests in headed/GUI mode on Linux, where not default. + locale_code: # Set the Language Locale Code for the web browser. + protocol: # The Selenium Grid protocol: "http" or "https". + servername: # The Selenium Grid server/IP used for tests. + port: # The Selenium Grid port used by the test server. + proxy: # Use proxy. Format: "SERVER:PORT" or "USER:PASS@SERVER:PORT". + proxy_bypass_list: # Skip proxy when using the listed domains. + proxy_pac_url: # Use PAC file. (Format: URL or USERNAME:PASSWORD@URL) + multi_proxy: # Allow multiple proxies with auth when multi-threaded. + agent: # Modify the web browser's User-Agent string. + cap_file: # The desired capabilities to use with a Selenium Grid. + cap_string: # The desired capabilities to use with a Selenium Grid. + recorder_ext: # Enables the SeleniumBase Recorder Chromium extension. + disable_js: # Disable JavaScript on websites. Pages might break! + disable_csp: # Disable the Content Security Policy of websites. + enable_ws: # Enable Web Security on Chromium-based browsers. + disable_ws: # Reverse of "enable_ws". (None and False are different) + enable_sync: # Enable "Chrome Sync" on websites. + use_auto_ext: # Use Chrome's automation extension. + undetectable: # Use undetected-chromedriver to evade bot-detection. + uc_cdp_events: # Capture CDP events in undetected-chromedriver mode. + uc_subprocess: # Use undetected-chromedriver as a subprocess. + log_cdp_events: # Capture {"performance": "ALL", "browser": "ALL"} + no_sandbox: # (DEPRECATED) - "--no-sandbox" is always used now. + disable_gpu: # (DEPRECATED) - GPU is disabled if not "swiftshader". + incognito: # Enable Chromium's Incognito mode. + guest_mode: # Enable Chromium's Guest mode. + dark_mode: # Enable Chromium's Dark mode. + devtools: # Open Chromium's DevTools when the browser opens. + remote_debug: # Enable Chrome's Debugger on "http://localhost:9222". + enable_3d_apis: # Enable WebGL and 3D APIs. + swiftshader: # Chrome: --use-gl=angle / --use-angle=swiftshader-webgl + ad_block_on: # Block some types of display ads from loading. + host_resolver_rules: # Set host-resolver-rules, comma-separated. + block_images: # Block images from loading during tests. + do_not_track: # Tell websites that you don't want to be tracked. + chromium_arg: # "ARG=N,ARG2" (Set Chromium args, ","-separated.) + firefox_arg: # "ARG=N,ARG2" (Set Firefox args, comma-separated.) + firefox_pref: # SET (Set Firefox PREFERENCE:VALUE set, ","-separated) + user_data_dir: # Set the Chrome user data directory to use. + extension_zip: # Load a Chrome Extension .zip|.crx, comma-separated. + extension_dir: # Load a Chrome Extension directory, comma-separated. + disable_features: # "F1,F2" (Disable Chrome features, ","-separated.) + binary_location: # Set path of the Chromium browser binary to use. + driver_version: # Set the chromedriver or uc_driver version to use. + page_load_strategy: # Set Chrome PLS to "normal", "eager", or "none". + use_wire: # Use selenium-wire's webdriver over selenium webdriver. + external_pdf: # Set Chrome "plugins.always_open_pdf_externally":True. + window_position: # Set the browser's starting window position: "X,Y" + window_size: # Set the browser's starting window size: "Width,Height" + is_mobile: # Use the mobile device emulator while running tests. + mobile: # Shortcut / Duplicate of "is_mobile". + d_width: # Set device width + d_height: # Set device height + d_p_r: # Set device pixel ratio + uc: # Shortcut / Duplicate of "undetectable". + undetected: # Shortcut / Duplicate of "undetectable". + uc_cdp: # Shortcut / Duplicate of "uc_cdp_events". + uc_sub: # Shortcut / Duplicate of "uc_subprocess". + log_cdp: # Shortcut / Duplicate of "log_cdp_events". + ad_block: # Shortcut / Duplicate of "ad_block_on". + server: # Shortcut / Duplicate of "servername". + guest: # Shortcut / Duplicate of "guest_mode". + wire: # Shortcut / Duplicate of "use_wire". + pls: # Shortcut / Duplicate of "page_load_strategy". + """ from seleniumbase import config as sb_config + from seleniumbase.config import settings from seleniumbase.fixtures import constants from seleniumbase.fixtures import shared_utils diff --git a/seleniumbase/plugins/pytest_plugin.py b/seleniumbase/plugins/pytest_plugin.py index 89f6e1b9..16de9d68 100644 --- a/seleniumbase/plugins/pytest_plugin.py +++ b/seleniumbase/plugins/pytest_plugin.py @@ -4,6 +4,7 @@ import os import pytest import sys import time +from contextlib import suppress from seleniumbase import config as sb_config from seleniumbase.config import settings from seleniumbase.core import log_helper @@ -1848,10 +1849,8 @@ def _create_dashboard_assets_(): abs_path = os.path.abspath(".") assets_folder = os.path.join(abs_path, "assets") if not os.path.exists(assets_folder): - try: + with suppress(Exception): os.makedirs(assets_folder, exist_ok=True) - except Exception: - pass pytest_style_css = os.path.join(assets_folder, "pytest_style.css") add_pytest_style_css = True if os.path.exists(pytest_style_css): @@ -1923,12 +1922,10 @@ def pytest_collection_finish(session): dash_path = os.path.join(os.getcwd(), "dashboard.html") dash_url = "file://" + dash_path.replace("\\", "/") star_len = len("Dashboard: ") + len(dash_url) - try: + with suppress(Exception): terminal_size = os.get_terminal_size().columns if terminal_size > 30 and star_len > terminal_size: star_len = terminal_size - except Exception: - pass stars = "*" * star_len c1 = "" cr = "" @@ -1970,11 +1967,11 @@ def pytest_runtest_teardown(item): (Has zero effect on tests using --reuse-session / --rs)""" if "--co" in sys_argv or "--collect-only" in sys_argv: return - try: + with suppress(Exception): if hasattr(item, "_testcase") or hasattr(sb_config, "_sb_pdb_driver"): if hasattr(item, "_testcase"): self = item._testcase - try: + with suppress(Exception): if ( hasattr(self, "driver") and self.driver @@ -1982,22 +1979,18 @@ def pytest_runtest_teardown(item): ): if not (is_windows or self.driver.service.process): self.driver.quit() - except Exception: - pass elif ( hasattr(sb_config, "_sb_pdb_driver") and sb_config._sb_pdb_driver ): - try: + with suppress(Exception): if ( not is_windows or sb_config._sb_pdb_driver.service.process ): sb_config._sb_pdb_driver.quit() sb_config._sb_pdb_driver = None - except Exception: - pass - try: + with suppress(Exception): if ( hasattr(self, "_xvfb_display") and self._xvfb_display @@ -2014,10 +2007,6 @@ def pytest_runtest_teardown(item): ): sb_config._virtual_display.stop() sb_config._virtual_display = None - except Exception: - pass - except Exception: - pass if ( ( sb_config._has_exception @@ -2398,7 +2387,7 @@ def pytest_runtest_makereport(item, call): ) if log_path: sb_config._log_fail_data() - try: + with suppress(Exception): extra_report = None if hasattr(item, "_testcase"): extra_report = item._testcase._html_report_extra @@ -2443,5 +2432,3 @@ def pytest_runtest_makereport(item, call): "" % constants.Dashboard.LIVE_JS ) report.extra.append(pytest_html.extras.html(refresh_updates)) - except Exception: - pass diff --git a/seleniumbase/plugins/sb_manager.py b/seleniumbase/plugins/sb_manager.py index aa9d93de..4427910f 100644 --- a/seleniumbase/plugins/sb_manager.py +++ b/seleniumbase/plugins/sb_manager.py @@ -7,7 +7,7 @@ Usage --> ``with SB() as sb:`` Example --> -``` +```python from seleniumbase import SB with SB() as sb: # Many args! Eg. SB(browser="edge") @@ -41,7 +41,7 @@ def SB( proxy=None, # Use proxy. Format: "SERVER:PORT" or "USER:PASS@SERVER:PORT". proxy_bypass_list=None, # Skip proxy when using the listed domains. proxy_pac_url=None, # Use PAC file. (Format: URL or USERNAME:PASSWORD@URL) - multi_proxy=False, # Allow multiple proxies with auth when multi-threaded. + multi_proxy=None, # Allow multiple proxies with auth when multi-threaded. agent=None, # Modify the web browser's User-Agent string. cap_file=None, # The desired capabilities to use with a Selenium Grid. cap_string=None, # The desired capabilities to use with a Selenium Grid. @@ -127,6 +127,124 @@ def SB( interval=None, # SECONDS (Autoplay interval for SB Slides & Tour steps.) time_limit=None, # SECONDS (Safely fail tests that exceed the time limit.) ): + """ + * SeleniumBase as a Python Context Manager * + + Example: + -------- + .. code-block:: python + from seleniumbase import SB + + with SB() as sb: # Many args! Eg. SB(browser="edge") + sb.open("https://google.com/ncr") + sb.type('[name="q"]', "SeleniumBase on GitHub") + sb.submit('[name="q"]') + sb.click('a[href*="github.com/seleniumbase"]') + sb.highlight("div.Layout-main") + sb.highlight("div.Layout-sidebar") + sb.sleep(0.5) + + Optional Parameters: + -------------------- + test: Test Mode: Output, Logging, Continue on failure unless "rtf". + rtf: Shortcut / Duplicate of "raise_test_failure". + raise_test_failure: If "test" mode, raise Exception on 1st failure. + browser: Choose from "chrome", "edge", "firefox", or "safari". + headless: The original headless mode for Chromium and Firefox. + headless2: Chromium's new headless mode. (Has more features) + locale_code: Set the Language Locale Code for the web browser. + protocol: The Selenium Grid protocol: "http" or "https". + servername: The Selenium Grid server/IP used for tests. + port: The Selenium Grid port used by the test server. + proxy: Use proxy. Format: "SERVER:PORT" or "USER:PASS@SERVER:PORT". + proxy_bypass_list: Skip proxy when using the listed domains. + proxy_pac_url: Use PAC file. (Format: URL or USERNAME:PASSWORD@URL) + multi_proxy: # Allow multiple proxies with auth when multi-threaded. + agent: Modify the web browser's User-Agent string. + cap_file: The desired capabilities to use with a Selenium Grid. + cap_string: The desired capabilities to use with a Selenium Grid. + recorder_ext: Enables the SeleniumBase Recorder Chromium extension. + disable_js: Disable JavaScript on websites. Pages might break! + disable_csp: Disable the Content Security Policy of websites. + enable_ws: Enable Web Security on Chromium-based browsers. + enable_sync: Enable "Chrome Sync" on websites. + use_auto_ext: Use Chrome's automation extension. + undetectable: Use undetected-chromedriver to evade bot-detection. + uc_cdp_events: Capture CDP events in undetected-chromedriver mode. + uc_subprocess: Use undetected-chromedriver as a subprocess. + log_cdp_events: Capture {"performance": "ALL", "browser": "ALL"} + incognito: Enable Chromium's Incognito mode. + guest_mode: Enable Chromium's Guest mode. + dark_mode: Enable Chromium's Dark mode. + devtools: Open Chromium's DevTools when the browser opens. + remote_debug: Enable Chrome's Debugger on "http://localhost:9222". + enable_3d_apis: Enable WebGL and 3D APIs. + swiftshader: Chrome: --use-gl=angle / --use-angle=swiftshader-webgl + ad_block_on: Block some types of display ads from loading. + host_resolver_rules: Set host-resolver-rules, comma-separated. + block_images: Block images from loading during tests. + do_not_track: Tell websites that you don't want to be tracked. + chromium_arg: "ARG=N,ARG2" (Set Chromium args, ","-separated.) + firefox_arg: "ARG=N,ARG2" (Set Firefox args, comma-separated.) + firefox_pref: SET (Set Firefox PREFERENCE:VALUE set, ","-separated) + user_data_dir: Set the Chrome user data directory to use. + extension_zip: Load a Chrome Extension .zip|.crx, comma-separated. + extension_dir: Load a Chrome Extension directory, comma-separated. + disable_features: "F1,F2" (Disable Chrome features, ","-separated.) + binary_location: Set path of the Chromium browser binary to use. + driver_version: Set the chromedriver or uc_driver version to use. + skip_js_waits: Skip JS Waits (readyState=="complete" and Angular). + wait_for_angularjs: Wait for AngularJS to load after some actions. + use_wire: Use selenium-wire's webdriver over selenium webdriver. + external_pdf: Set Chrome "plugins.always_open_pdf_externally":True. + window_position: Set the browser's starting window position: "X,Y" + window_size: Set the browser's starting window size: "Width,Height" + is_mobile: Use the mobile device emulator while running tests. + mobile: Shortcut / Duplicate of "is_mobile". + device_metrics: Set mobile metrics: "CSSWidth,CSSHeight,PixelRatio" + xvfb: Run tests using the Xvfb virtual display server on Linux OS. + xvfb_metrics: Set Xvfb display size on Linux: "Width,Height". + start_page: The starting URL for the web browser when tests begin. + rec_print: If Recorder is enabled, prints output after tests end. + rec_behave: Like Recorder Mode, but also generates behave-gherkin. + record_sleep: If Recorder enabled, also records self.sleep calls. + data: Extra test data. Access with "self.data" in tests. + var1: Extra test data. Access with "self.var1" in tests. + var2: Extra test data. Access with "self.var2" in tests. + var3: Extra test data. Access with "self.var3" in tests. + variables: DICT (Extra test data. Access with "self.variables") + account: Set account. Access with "self.account" in tests. + environment: Set the test env. Access with "self.env" in tests. + headed: Run tests in headed/GUI mode on Linux, where not default. + maximize: Start tests with the browser window maximized. + disable_ws: Reverse of "enable_ws". (None and False are different) + disable_beforeunload: Disable the "beforeunload" event on Chromium. + settings_file: A file for overriding default SeleniumBase settings. + uc: Shortcut / Duplicate of "undetectable". + undetected: Shortcut / Duplicate of "undetectable". + uc_cdp: Shortcut / Duplicate of "uc_cdp_events". + uc_sub: Shortcut / Duplicate of "uc_subprocess". + log_cdp: Shortcut / Duplicate of "log_cdp_events". + ad_block: Shortcut / Duplicate of "ad_block_on". + server: Shortcut / Duplicate of "servername". + guest: Shortcut / Duplicate of "guest_mode". + wire: Shortcut / Duplicate of "use_wire". + pls: Shortcut / Duplicate of "page_load_strategy". + sjw: Shortcut / Duplicate of "skip_js_waits". + wfa: Shortcut / Duplicate of "wait_for_angularjs". + save_screenshot: Save a screenshot at the end of each test. + no_screenshot: No screenshots saved unless tests directly ask it. + page_load_strategy: Set Chrome PLS to "normal", "eager", or "none". + timeout_multiplier: Multiplies the default timeout values. + js_checking_on: Check for JavaScript errors after page loads. + slow: Slow down the automation. Faster than using Demo Mode. + demo: Slow down and visually see test actions as they occur. + demo_sleep: SECONDS (Set wait time after Slow & Demo Mode actions.) + message_duration: SECONDS (The time length for Messenger alerts.) + highlights: Number of highlight animations for Demo Mode actions. + interval: SECONDS (Autoplay interval for SB Slides & Tour steps.) + time_limit: SECONDS (Safely fail tests that exceed the time limit.) + """ import os import sys import time diff --git a/seleniumbase/plugins/selenium_plugin.py b/seleniumbase/plugins/selenium_plugin.py index fee7ee2f..edbd340a 100644 --- a/seleniumbase/plugins/selenium_plugin.py +++ b/seleniumbase/plugins/selenium_plugin.py @@ -1,5 +1,6 @@ """Selenium Plugin for SeleniumBase tests that run with pynose / nosetests""" import sys +from contextlib import suppress from nose.plugins import Plugin from seleniumbase import config as sb_config from seleniumbase.config import settings @@ -1308,7 +1309,7 @@ class SeleniumBrowser(Plugin): ): width = settings.HEADLESS_START_WIDTH height = settings.HEADLESS_START_HEIGHT - try: + with suppress(Exception): from sbvirtualdisplay import Display self._xvfb_display = Display(visible=0, size=(width, height)) @@ -1316,8 +1317,6 @@ class SeleniumBrowser(Plugin): sb_config._virtual_display = self._xvfb_display self.headless_active = True sb_config.headless_active = True - except Exception: - pass sb_config._is_timeout_changed = False sb_config._SMALL_TIMEOUT = settings.SMALL_TIMEOUT sb_config._LARGE_TIMEOUT = settings.LARGE_TIMEOUT @@ -1350,7 +1349,7 @@ class SeleniumBrowser(Plugin): pass except Exception: pass - try: + with suppress(Exception): if ( hasattr(self, "_xvfb_display") and self._xvfb_display @@ -1367,5 +1366,3 @@ class SeleniumBrowser(Plugin): ): sb_config._virtual_display.stop() sb_config._virtual_display = None - except Exception: - pass diff --git a/seleniumbase/undetected/__init__.py b/seleniumbase/undetected/__init__.py index 40283f43..36d6d3a5 100644 --- a/seleniumbase/undetected/__init__.py +++ b/seleniumbase/undetected/__init__.py @@ -10,6 +10,7 @@ import selenium.webdriver.chrome.service import selenium.webdriver.chrome.webdriver import selenium.webdriver.common.service import selenium.webdriver.remote.command +from contextlib import suppress from .cdp import CDP from .cdp import PageElement from .dprocess import start_detached @@ -201,11 +202,9 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): # Create a temporary folder for the user-data profile. options.add_argument(arg) if not language: - try: + with suppress(Exception): import locale language = locale.getlocale()[0].replace("_", "-") - except Exception: - pass if ( not language or "English" in language @@ -242,7 +241,7 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): ) if hasattr(options, 'handle_prefs'): options.handle_prefs(user_data_dir) - try: + with suppress(Exception): import json with open( os.path.join( @@ -263,8 +262,6 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): fs.seek(0, 0) fs.truncate() json.dump(config, fs) - except Exception: - pass creationflags = 0 if "win32" in sys.platform: creationflags = subprocess.CREATE_NO_WINDOW @@ -293,8 +290,6 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): self.browser_pid = browser.pid service_ = None log_output = subprocess.PIPE - if sys.version_info < (3, 8): - log_output = os.devnull if patch_driver: service_ = selenium.webdriver.chrome.service.Service( executable_path=self.patcher.executable_path, @@ -342,7 +337,7 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): def _get_cdc_props(self): cdc_props = [] - try: + with suppress(Exception): cdc_props = self.execute_script( """ let objectToInspect = window, @@ -355,8 +350,6 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): return result.filter(i => i.match(/^[a-z]{3}_[a-z]{22}_.*/i)) """ ) - except Exception: - pass return cdc_props def _hook_remove_cdc_props(self, cdc_props): @@ -427,50 +420,38 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): - Starts the chromedriver service that runs in the background. - Recreates the session.""" if hasattr(self, "service"): - try: + with suppress(Exception): self.service.stop() - except Exception: - pass if isinstance(timeout, str): if timeout.lower() == "breakpoint": breakpoint() # To continue: pass # Type "c" & press ENTER! else: time.sleep(timeout) - try: + with suppress(Exception): self.service.start() - except Exception: - pass time.sleep(0.012) - try: + with suppress(Exception): self.start_session() - except Exception: - pass time.sleep(0.012) def disconnect(self): """Stops the chromedriver service that runs in the background. To use driver methods again, you MUST call driver.connect()""" if hasattr(self, "service"): - try: + with suppress(Exception): self.service.stop() - except Exception: - pass time.sleep(0.012) def connect(self): """Starts the chromedriver service that runs in the background and recreates the session.""" if hasattr(self, "service"): - try: + with suppress(Exception): self.service.start() - except Exception: - pass time.sleep(0.012) - try: + with suppress(Exception): self.start_session() - except Exception: - pass time.sleep(0.012) def start_session(self, capabilities=None): @@ -496,12 +477,10 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): if hasattr(self, "service") and getattr(self.service, "process", None): logger.debug("Stopping webdriver service") self.service.stop() - try: + with suppress(Exception): if self.reactor and isinstance(self.reactor, Reactor): logger.debug("Shutting down Reactor") self.reactor.event.set() - except Exception: - pass if ( hasattr(self, "keep_user_data_dir") and hasattr(self, "user_data_dir") @@ -530,18 +509,14 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver): self.patcher = None def __del__(self): - try: + with suppress(Exception): if "win32" in sys.platform: self.stop_client() self.command_executor.close() else: super().quit() - except Exception: - pass - try: + with suppress(Exception): self.quit() - except Exception: - pass def __enter__(self): return self diff --git a/seleniumbase/undetected/dprocess.py b/seleniumbase/undetected/dprocess.py index acfdc558..dc6009b8 100644 --- a/seleniumbase/undetected/dprocess.py +++ b/seleniumbase/undetected/dprocess.py @@ -3,7 +3,10 @@ import os import sys import atexit import logging +import platform +from contextlib import suppress from subprocess import PIPE +from subprocess import Popen CREATE_NEW_PROCESS_GROUP = 0x00000200 DETACHED_PROCESS = 0x00000008 @@ -37,9 +40,6 @@ def start_detached(executable, *args): def _start_detached(executable, *args, writer=None): # Configure Launch kwargs = {} - import platform - from subprocess import Popen - if platform.system() == "Windows": kwargs.update( creationflags=DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP @@ -58,11 +58,9 @@ def _cleanup(): import signal for pid in REGISTERED: - try: + with suppress(Exception): logging.getLogger(__name__).debug("cleaning up pid %d " % pid) os.kill(pid, signal.SIGTERM) - except Exception: - pass atexit.register(_cleanup) diff --git a/seleniumbase/undetected/options.py b/seleniumbase/undetected/options.py index b93f3966..2f83cec7 100644 --- a/seleniumbase/undetected/options.py +++ b/seleniumbase/undetected/options.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import json import os +from contextlib import suppress from selenium.webdriver.chromium.options import ChromiumOptions @@ -49,7 +50,7 @@ class ChromeOptions(ChromiumOptions): undot_prefs, self._undot_key(key, value) ) prefs_file = os.path.join(default_path, "Preferences") - try: + with suppress(Exception): if os.path.exists(prefs_file): with open( prefs_file, encoding="utf-8", mode="r", errors="ignore" @@ -57,13 +58,9 @@ class ChromeOptions(ChromiumOptions): undot_prefs = self._merge_nested( json.load(f), undot_prefs ) - except Exception: - pass - try: + with suppress(Exception): with open(prefs_file, encoding="utf-8", mode="w") as f: json.dump(undot_prefs, f) - except Exception: - pass # Remove experimental_options to avoid errors del self._experimental_options["prefs"] exclude_switches = self.experimental_options.get("excludeSwitches") diff --git a/seleniumbase/undetected/patcher.py b/seleniumbase/undetected/patcher.py index 11ffa1e2..1375e177 100644 --- a/seleniumbase/undetected/patcher.py +++ b/seleniumbase/undetected/patcher.py @@ -8,6 +8,7 @@ import string import sys import time import zipfile +from contextlib import suppress logger = logging.getLogger(__name__) IS_POSIX = sys.platform.startswith(("darwin", "cygwin", "linux")) @@ -53,10 +54,8 @@ class Patcher(object): self.executable_path = None prefix = "undetected" if not os.path.exists(self.data_path): - try: + with suppress(Exception): os.makedirs(self.data_path, exist_ok=True) - except Exception: - pass if not executable_path: self.executable_path = os.path.join( self.data_path, "_".join([prefix, self.exe_name]) diff --git a/setup.py b/setup.py index 6066e850..8b9b74f7 100755 --- a/setup.py +++ b/setup.py @@ -1,5 +1,5 @@ """Setup steps for installing SeleniumBase dependencies and plugins. -(Uses selenium 4.x and is compatible with Python 3.7+)""" +(Uses selenium 4.x and is compatible with Python 3.8+)""" from setuptools import setup, find_packages # noqa: F401 import os import sys @@ -47,7 +47,7 @@ if sys.argv[-1] == "publish": print("\n*** Installing build: *** (Required for PyPI uploads)\n") os.system("python -m pip install --upgrade 'build'") print("\n*** Installing pkginfo: *** (Required for PyPI uploads)\n") - os.system("python -m pip install --upgrade 'pkginfo'") + os.system("python -m pip install 'pkginfo'") print("\n*** Installing readme-renderer: *** (For PyPI uploads)\n") os.system("python -m pip install --upgrade 'readme-renderer'") print("\n*** Installing jaraco.classes: *** (For PyPI uploads)\n") @@ -79,12 +79,14 @@ setup( long_description_content_type="text/markdown", url="https://github.com/seleniumbase/SeleniumBase", project_urls={ + "Homepage": "https://github.com/seleniumbase/SeleniumBase", "Changelog": "https://github.com/seleniumbase/SeleniumBase/releases", "Download": "https://pypi.org/project/seleniumbase/#files", - "Gitter": "https://gitter.im/seleniumbase/SeleniumBase", "Blog": "https://seleniumbase.com/", + "Discord": "https://discord.gg/EdhQTn3EyE", "PyPI": "https://pypi.org/project/seleniumbase/", "Source": "https://github.com/seleniumbase/SeleniumBase", + "Repository": "https://github.com/seleniumbase/SeleniumBase", "Documentation": "https://seleniumbase.io/", }, platforms=["Windows", "Linux", "Mac OS-X"], @@ -120,7 +122,6 @@ setup( "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10",