seleniumbase 4.24.11__py3-none-any.whl → 4.33.15__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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/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 +1225 -614
- 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.11.dist-info → seleniumbase-4.33.15.dist-info}/LICENSE +1 -1
- {seleniumbase-4.24.11.dist-info → seleniumbase-4.33.15.dist-info}/METADATA +299 -252
- {seleniumbase-4.24.11.dist-info → seleniumbase-4.33.15.dist-info}/RECORD +67 -69
- {seleniumbase-4.24.11.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.11.dist-info → seleniumbase-4.33.15.dist-info}/entry_points.txt +0 -0
- {seleniumbase-4.24.11.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"):
|