seleniumbase 4.24.10__py3-none-any.whl → 4.33.15__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sbase/__init__.py +1 -0
- sbase/steps.py +7 -0
- seleniumbase/__init__.py +16 -7
- seleniumbase/__version__.py +1 -1
- seleniumbase/behave/behave_sb.py +97 -32
- seleniumbase/common/decorators.py +16 -7
- seleniumbase/config/proxy_list.py +3 -3
- seleniumbase/config/settings.py +4 -0
- seleniumbase/console_scripts/logo_helper.py +47 -8
- seleniumbase/console_scripts/run.py +345 -335
- seleniumbase/console_scripts/sb_behave_gui.py +5 -12
- seleniumbase/console_scripts/sb_caseplans.py +6 -13
- seleniumbase/console_scripts/sb_commander.py +5 -12
- seleniumbase/console_scripts/sb_install.py +62 -54
- seleniumbase/console_scripts/sb_mkchart.py +13 -20
- seleniumbase/console_scripts/sb_mkdir.py +11 -17
- seleniumbase/console_scripts/sb_mkfile.py +69 -43
- seleniumbase/console_scripts/sb_mkpres.py +13 -20
- seleniumbase/console_scripts/sb_mkrec.py +88 -21
- seleniumbase/console_scripts/sb_objectify.py +30 -30
- seleniumbase/console_scripts/sb_print.py +5 -12
- seleniumbase/console_scripts/sb_recorder.py +16 -11
- seleniumbase/core/browser_launcher.py +1658 -221
- seleniumbase/core/detect_b_ver.py +7 -8
- seleniumbase/core/log_helper.py +42 -27
- seleniumbase/core/mysql.py +1 -4
- seleniumbase/core/proxy_helper.py +35 -30
- seleniumbase/core/recorder_helper.py +24 -5
- seleniumbase/core/sb_cdp.py +1951 -0
- seleniumbase/core/sb_driver.py +162 -8
- seleniumbase/core/settings_parser.py +6 -0
- seleniumbase/core/style_sheet.py +10 -0
- seleniumbase/extensions/recorder.zip +0 -0
- seleniumbase/fixtures/base_case.py +1234 -632
- seleniumbase/fixtures/constants.py +10 -1
- seleniumbase/fixtures/js_utils.py +171 -144
- seleniumbase/fixtures/page_actions.py +177 -13
- seleniumbase/fixtures/page_utils.py +25 -53
- seleniumbase/fixtures/shared_utils.py +97 -11
- seleniumbase/js_code/active_css_js.py +1 -1
- seleniumbase/js_code/recorder_js.py +1 -1
- seleniumbase/plugins/base_plugin.py +2 -3
- seleniumbase/plugins/driver_manager.py +340 -65
- seleniumbase/plugins/pytest_plugin.py +276 -47
- seleniumbase/plugins/sb_manager.py +412 -99
- seleniumbase/plugins/selenium_plugin.py +122 -17
- seleniumbase/translate/translator.py +0 -7
- seleniumbase/undetected/__init__.py +59 -52
- seleniumbase/undetected/cdp.py +0 -1
- seleniumbase/undetected/cdp_driver/__init__.py +1 -0
- seleniumbase/undetected/cdp_driver/_contradict.py +110 -0
- seleniumbase/undetected/cdp_driver/browser.py +829 -0
- seleniumbase/undetected/cdp_driver/cdp_util.py +458 -0
- seleniumbase/undetected/cdp_driver/config.py +334 -0
- seleniumbase/undetected/cdp_driver/connection.py +639 -0
- seleniumbase/undetected/cdp_driver/element.py +1168 -0
- seleniumbase/undetected/cdp_driver/tab.py +1323 -0
- seleniumbase/undetected/dprocess.py +4 -7
- seleniumbase/undetected/options.py +6 -8
- seleniumbase/undetected/patcher.py +11 -13
- seleniumbase/undetected/reactor.py +0 -1
- seleniumbase/undetected/webelement.py +16 -3
- {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/LICENSE +1 -1
- {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/METADATA +299 -252
- {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/RECORD +68 -70
- {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/WHEEL +1 -1
- sbase/ReadMe.txt +0 -2
- seleniumbase/ReadMe.md +0 -25
- seleniumbase/common/ReadMe.md +0 -71
- seleniumbase/console_scripts/ReadMe.md +0 -731
- seleniumbase/drivers/ReadMe.md +0 -27
- seleniumbase/extensions/ReadMe.md +0 -12
- seleniumbase/masterqa/ReadMe.md +0 -61
- seleniumbase/resources/ReadMe.md +0 -31
- seleniumbase/resources/favicon.ico +0 -0
- seleniumbase/utilities/selenium_grid/ReadMe.md +0 -84
- seleniumbase/utilities/selenium_ide/ReadMe.md +0 -111
- {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.24.10.dist-info → seleniumbase-4.33.15.dist-info}/top_level.txt +0 -0
@@ -16,7 +16,7 @@ def get_domain_url(url):
|
|
16
16
|
Into this:
|
17
17
|
https://blog.xkcd.com
|
18
18
|
"""
|
19
|
-
if not url.startswith("http://"
|
19
|
+
if not url.startswith(("http://", "https://")):
|
20
20
|
return url
|
21
21
|
url_header = url.split("://")[0]
|
22
22
|
simple_url = url.split("://")[1]
|
@@ -40,45 +40,25 @@ def swap_selector_and_by_if_reversed(selector, by):
|
|
40
40
|
|
41
41
|
def is_xpath_selector(selector):
|
42
42
|
"""Determine if a selector is an xpath selector."""
|
43
|
-
|
44
|
-
selector.startswith("/")
|
45
|
-
or selector.startswith("./")
|
46
|
-
or selector.startswith("(")
|
47
|
-
):
|
48
|
-
return True
|
49
|
-
return False
|
43
|
+
return selector.startswith(("/", "./", "("))
|
50
44
|
|
51
45
|
|
52
46
|
def is_link_text_selector(selector):
|
53
47
|
"""Determine if a selector is a link text selector."""
|
54
|
-
|
55
|
-
selector.startswith("link=")
|
56
|
-
or selector.startswith("link_text=")
|
57
|
-
or selector.startswith("text=")
|
58
|
-
):
|
59
|
-
return True
|
60
|
-
return False
|
48
|
+
return selector.startswith(("link=", "link_text=", "text="))
|
61
49
|
|
62
50
|
|
63
51
|
def is_partial_link_text_selector(selector):
|
64
52
|
"""Determine if a selector is a partial link text selector."""
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
or selector.startswith("p_link=")
|
70
|
-
or selector.startswith("p_link_text=")
|
71
|
-
or selector.startswith("p_text=")
|
72
|
-
):
|
73
|
-
return True
|
74
|
-
return False
|
53
|
+
return selector.startswith((
|
54
|
+
"partial_link=", "partial_link_text=", "partial_text=",
|
55
|
+
"p_link=", "p_link_text=", "p_text="
|
56
|
+
))
|
75
57
|
|
76
58
|
|
77
59
|
def is_name_selector(selector):
|
78
60
|
"""Determine if a selector is a name selector."""
|
79
|
-
|
80
|
-
return True
|
81
|
-
return False
|
61
|
+
return selector.startswith(("name=", "&"))
|
82
62
|
|
83
63
|
|
84
64
|
def recalculate_selector(selector, by, xp_ok=True):
|
@@ -108,12 +88,18 @@ def recalculate_selector(selector, by, xp_ok=True):
|
|
108
88
|
name = get_name_from_selector(selector)
|
109
89
|
selector = '[name="%s"]' % name
|
110
90
|
by = By.CSS_SELECTOR
|
111
|
-
if xp_ok:
|
112
|
-
|
113
|
-
|
114
|
-
by = By.XPATH
|
91
|
+
if xp_ok and ":contains(" in selector and by == By.CSS_SELECTOR:
|
92
|
+
selector = css_to_xpath.convert_css_to_xpath(selector)
|
93
|
+
by = By.XPATH
|
115
94
|
if by == "":
|
116
95
|
by = By.CSS_SELECTOR
|
96
|
+
if not is_valid_by(by):
|
97
|
+
valid_by_options = [
|
98
|
+
"css selector", "link text", "partial link text",
|
99
|
+
"name", "xpath", "id", "tag name", "class name",
|
100
|
+
]
|
101
|
+
msg = "Choose a `by` from: %s." % valid_by_options
|
102
|
+
raise Exception('Invalid `by`: "%s"\n%s' % (by, msg))
|
117
103
|
return (selector, by)
|
118
104
|
|
119
105
|
|
@@ -123,21 +109,10 @@ def looks_like_a_page_url(url):
|
|
123
109
|
possible typos when calling self.get(url), which will try to
|
124
110
|
navigate to the page if a URL is detected, but will instead call
|
125
111
|
self.get_element(URL_AS_A_SELECTOR) if the input is not a URL."""
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
or url.startswith("about:")
|
131
|
-
or url.startswith("blob:")
|
132
|
-
or url.startswith("chrome:")
|
133
|
-
or url.startswith("data:")
|
134
|
-
or url.startswith("edge:")
|
135
|
-
or url.startswith("file:")
|
136
|
-
or url.startswith("view-source:")
|
137
|
-
):
|
138
|
-
return True
|
139
|
-
else:
|
140
|
-
return False
|
112
|
+
return url.startswith((
|
113
|
+
"http:", "https:", "://", "about:", "blob:", "chrome:",
|
114
|
+
"data:", "edge:", "file:", "view-source:"
|
115
|
+
))
|
141
116
|
|
142
117
|
|
143
118
|
def get_link_text_from_selector(selector):
|
@@ -190,12 +165,9 @@ def is_valid_url(url):
|
|
190
165
|
)
|
191
166
|
if (
|
192
167
|
regex.match(url)
|
193
|
-
or url.startswith(
|
194
|
-
|
195
|
-
|
196
|
-
or url.startswith("data:")
|
197
|
-
or url.startswith("edge:")
|
198
|
-
or url.startswith("file:")
|
168
|
+
or url.startswith((
|
169
|
+
"about:", "blob:", "chrome:", "data:", "edge:", "file:"
|
170
|
+
))
|
199
171
|
):
|
200
172
|
return True
|
201
173
|
else:
|
@@ -1,8 +1,11 @@
|
|
1
1
|
"""Shared utility methods"""
|
2
|
+
import colorama
|
2
3
|
import os
|
4
|
+
import pathlib
|
3
5
|
import platform
|
4
6
|
import sys
|
5
7
|
import time
|
8
|
+
from contextlib import suppress
|
6
9
|
from seleniumbase import config as sb_config
|
7
10
|
from seleniumbase.fixtures import constants
|
8
11
|
|
@@ -67,6 +70,89 @@ def get_terminal_width():
|
|
67
70
|
return width
|
68
71
|
|
69
72
|
|
73
|
+
def fix_colorama_if_windows():
|
74
|
+
if is_windows():
|
75
|
+
colorama.just_fix_windows_console()
|
76
|
+
|
77
|
+
|
78
|
+
def fix_url_as_needed(url):
|
79
|
+
if not url:
|
80
|
+
url = "data:,"
|
81
|
+
elif url.startswith("//"):
|
82
|
+
url = "https:" + url
|
83
|
+
elif ":" not in url:
|
84
|
+
url = "https://" + url
|
85
|
+
return url
|
86
|
+
|
87
|
+
|
88
|
+
def reconnect_if_disconnected(driver):
|
89
|
+
if (
|
90
|
+
hasattr(driver, "_is_using_uc")
|
91
|
+
and driver._is_using_uc
|
92
|
+
and hasattr(driver, "is_connected")
|
93
|
+
and not driver.is_connected()
|
94
|
+
):
|
95
|
+
with suppress(Exception):
|
96
|
+
driver.connect()
|
97
|
+
|
98
|
+
|
99
|
+
def is_cdp_swap_needed(driver):
|
100
|
+
"""
|
101
|
+
When someone is using CDP Mode with a disconnected webdriver,
|
102
|
+
but they forget to reconnect before calling a webdriver method,
|
103
|
+
this method is used to substitute the webdriver method for a
|
104
|
+
CDP Mode method instead, which keeps CDP Stealth Mode enabled.
|
105
|
+
For other webdriver methods, SeleniumBase will reconnect first.
|
106
|
+
"""
|
107
|
+
return (
|
108
|
+
hasattr(driver, "is_cdp_mode_active")
|
109
|
+
and driver.is_cdp_mode_active()
|
110
|
+
and hasattr(driver, "is_connected")
|
111
|
+
and not driver.is_connected()
|
112
|
+
)
|
113
|
+
|
114
|
+
|
115
|
+
def is_chrome_130_or_newer(self, binary_location=None):
|
116
|
+
from seleniumbase.core import detect_b_ver
|
117
|
+
|
118
|
+
"""Due to changes in Chrome-130, UC Mode freezes at start-up
|
119
|
+
unless the user-data-dir already exists and is populated."""
|
120
|
+
with suppress(Exception):
|
121
|
+
if not binary_location:
|
122
|
+
ver = detect_b_ver.get_browser_version_from_os("google-chrome")
|
123
|
+
else:
|
124
|
+
ver = detect_b_ver.get_browser_version_from_binary(
|
125
|
+
binary_location
|
126
|
+
)
|
127
|
+
if ver and len(ver) > 3 and int(ver.split(".")[0]) >= 130:
|
128
|
+
return True
|
129
|
+
return False
|
130
|
+
|
131
|
+
|
132
|
+
def make_dir_files_writable(dir_path):
|
133
|
+
# Make all files in the given directory writable.
|
134
|
+
for file_path in pathlib.Path(dir_path).glob("*"):
|
135
|
+
if file_path.is_file():
|
136
|
+
mode = os.stat(file_path).st_mode
|
137
|
+
mode |= (mode & 0o444) >> 1 # copy R bits to W
|
138
|
+
with suppress(Exception):
|
139
|
+
os.chmod(file_path, mode)
|
140
|
+
|
141
|
+
|
142
|
+
def make_writable(file_path):
|
143
|
+
# Set permissions to: "If you can read it, you can write it."
|
144
|
+
mode = os.stat(file_path).st_mode
|
145
|
+
mode |= (mode & 0o444) >> 1 # copy R bits to W
|
146
|
+
os.chmod(file_path, mode)
|
147
|
+
|
148
|
+
|
149
|
+
def make_executable(file_path):
|
150
|
+
# Set permissions to: "If you can read it, you can execute it."
|
151
|
+
mode = os.stat(file_path).st_mode
|
152
|
+
mode |= (mode & 0o444) >> 2 # copy R bits to X
|
153
|
+
os.chmod(file_path, mode)
|
154
|
+
|
155
|
+
|
70
156
|
def format_exc(exception, message):
|
71
157
|
"""Formats an exception message to make the output cleaner."""
|
72
158
|
from selenium.common.exceptions import ElementNotVisibleException
|
@@ -81,46 +167,46 @@ def format_exc(exception, message):
|
|
81
167
|
from seleniumbase.common.exceptions import TextNotVisibleException
|
82
168
|
from seleniumbase.common import exceptions
|
83
169
|
|
84
|
-
if exception
|
170
|
+
if exception is Exception:
|
85
171
|
exc = Exception
|
86
172
|
return exc, message
|
87
|
-
elif exception
|
173
|
+
elif exception is ElementNotVisibleException:
|
88
174
|
exc = exceptions.ElementNotVisibleException
|
89
175
|
elif exception == "ElementNotVisibleException":
|
90
176
|
exc = exceptions.ElementNotVisibleException
|
91
|
-
elif exception
|
177
|
+
elif exception is LinkTextNotFoundException:
|
92
178
|
exc = exceptions.LinkTextNotFoundException
|
93
179
|
elif exception == "LinkTextNotFoundException":
|
94
180
|
exc = exceptions.LinkTextNotFoundException
|
95
|
-
elif exception
|
181
|
+
elif exception is NoSuchElementException:
|
96
182
|
exc = exceptions.NoSuchElementException
|
97
183
|
elif exception == "NoSuchElementException":
|
98
184
|
exc = exceptions.NoSuchElementException
|
99
|
-
elif exception
|
185
|
+
elif exception is TextNotVisibleException:
|
100
186
|
exc = exceptions.TextNotVisibleException
|
101
187
|
elif exception == "TextNotVisibleException":
|
102
188
|
exc = exceptions.TextNotVisibleException
|
103
|
-
elif exception
|
189
|
+
elif exception is NoAlertPresentException:
|
104
190
|
exc = exceptions.NoAlertPresentException
|
105
191
|
elif exception == "NoAlertPresentException":
|
106
192
|
exc = exceptions.NoAlertPresentException
|
107
|
-
elif exception
|
193
|
+
elif exception is NoSuchAttributeException:
|
108
194
|
exc = exceptions.NoSuchAttributeException
|
109
195
|
elif exception == "NoSuchAttributeException":
|
110
196
|
exc = exceptions.NoSuchAttributeException
|
111
|
-
elif exception
|
197
|
+
elif exception is NoSuchFrameException:
|
112
198
|
exc = exceptions.NoSuchFrameException
|
113
199
|
elif exception == "NoSuchFrameException":
|
114
200
|
exc = exceptions.NoSuchFrameException
|
115
|
-
elif exception
|
201
|
+
elif exception is NoSuchWindowException:
|
116
202
|
exc = exceptions.NoSuchWindowException
|
117
203
|
elif exception == "NoSuchWindowException":
|
118
204
|
exc = exceptions.NoSuchWindowException
|
119
|
-
elif exception
|
205
|
+
elif exception is NoSuchFileException:
|
120
206
|
exc = exceptions.NoSuchFileException
|
121
207
|
elif exception == "NoSuchFileException":
|
122
208
|
exc = exceptions.NoSuchFileException
|
123
|
-
elif exception
|
209
|
+
elif exception is NoSuchOptionException:
|
124
210
|
exc = exceptions.NoSuchOptionException
|
125
211
|
elif exception == "NoSuchOptionException":
|
126
212
|
exc = exceptions.NoSuchOptionException
|
@@ -2,6 +2,7 @@
|
|
2
2
|
import ast
|
3
3
|
import sys
|
4
4
|
import time
|
5
|
+
from contextlib import suppress
|
5
6
|
from nose.plugins import Plugin
|
6
7
|
from seleniumbase import config as sb_config
|
7
8
|
from seleniumbase.config import settings
|
@@ -305,14 +306,12 @@ class Base(Plugin):
|
|
305
306
|
if python3_11_or_newer and py311_patch2:
|
306
307
|
# Handle a bug on Python 3.11 where exceptions aren't seen
|
307
308
|
sb_config._browser_version = None
|
308
|
-
|
309
|
+
with suppress(Exception):
|
309
310
|
test._BaseCase__set_last_page_screenshot()
|
310
311
|
test._BaseCase__set_last_page_url()
|
311
312
|
test._BaseCase__set_last_page_source()
|
312
313
|
sb_config._browser_version = test._get_browser_version()
|
313
314
|
test._log_fail_data()
|
314
|
-
except Exception:
|
315
|
-
pass
|
316
315
|
sb_config._excinfo_tb = err
|
317
316
|
log_path = None
|
318
317
|
if hasattr(sb_config, "_test_logpath"):
|