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
@@ -1,5 +1,6 @@
|
|
1
1
|
"""Selenium Plugin for SeleniumBase tests that run with pynose / nosetests"""
|
2
2
|
import sys
|
3
|
+
from contextlib import suppress
|
3
4
|
from nose.plugins import Plugin
|
4
5
|
from seleniumbase import config as sb_config
|
5
6
|
from seleniumbase.config import settings
|
@@ -40,11 +41,14 @@ class SeleniumBrowser(Plugin):
|
|
40
41
|
--binary-location=PATH (Set path of the Chromium browser binary to use.)
|
41
42
|
--driver-version=VER (Set the chromedriver or uc_driver version to use.)
|
42
43
|
--sjw (Skip JS Waits for readyState to be "complete" or Angular to load.)
|
44
|
+
--wfa (Wait for AngularJS to be done loading after specific web actions.)
|
43
45
|
--pls=PLS (Set pageLoadStrategy on Chrome: "normal", "eager", or "none".)
|
44
|
-
--headless (
|
45
|
-
--
|
46
|
+
--headless (The default headless mode. Linux uses this mode by default.)
|
47
|
+
--headless1 (Use Chrome's old headless mode. Fast, but has limitations.)
|
48
|
+
--headless2 (Use Chrome's new headless mode, which supports extensions.)
|
46
49
|
--headed (Run tests in headed/GUI mode on Linux OS, where not default.)
|
47
50
|
--xvfb (Run tests using the Xvfb virtual display server on Linux OS.)
|
51
|
+
--xvfb-metrics=STRING (Set Xvfb display size on Linux: "Width,Height".)
|
48
52
|
--locale=LOCALE_CODE (Set the Language Locale Code for the web browser.)
|
49
53
|
--interval=SECONDS (The autoplay interval for presentations & tour steps)
|
50
54
|
--start-page=URL (The starting URL for the web browser when tests begin.)
|
@@ -60,10 +64,12 @@ class SeleniumBrowser(Plugin):
|
|
60
64
|
--block-images (Block images from loading during tests.)
|
61
65
|
--do-not-track (Indicate to websites that you don't want to be tracked.)
|
62
66
|
--verify-delay=SECONDS (The delay before MasterQA verification checks.)
|
67
|
+
--ee / --esc-end (Lets the user end the current test via the ESC key.)
|
63
68
|
--recorder (Enables the Recorder for turning browser actions into code.)
|
64
69
|
--rec-behave (Same as Recorder Mode, but also generates behave-gherkin.)
|
65
70
|
--rec-sleep (If the Recorder is enabled, also records self.sleep calls.)
|
66
71
|
--rec-print (If the Recorder is enabled, prints output after tests end.)
|
72
|
+
--disable-cookies (Disable Cookies on websites. Pages might break!)
|
67
73
|
--disable-js (Disable JavaScript on websites. Pages might break!)
|
68
74
|
--disable-csp (Disable the Content Security Policy of websites.)
|
69
75
|
--disable-ws (Disable Web Security on Chromium-based browsers.)
|
@@ -80,6 +86,7 @@ class SeleniumBrowser(Plugin):
|
|
80
86
|
--dark (Enable Chrome's Dark mode.)
|
81
87
|
--devtools (Open Chrome's DevTools when the browser opens.)
|
82
88
|
--disable-beforeunload (Disable the "beforeunload" event on Chrome.)
|
89
|
+
--window-position=X,Y (Set the browser's starting window position.)
|
83
90
|
--window-size=WIDTH,HEIGHT (Set the browser's starting window size.)
|
84
91
|
--maximize (Start tests with the browser window maximized.)
|
85
92
|
--screenshot (Save a screenshot at the end of each test.)
|
@@ -177,6 +184,17 @@ class SeleniumBrowser(Plugin):
|
|
177
184
|
and wait_for_angularjs(), which are part of many
|
178
185
|
SeleniumBase methods for improving reliability.""",
|
179
186
|
)
|
187
|
+
parser.addoption(
|
188
|
+
"--wfa",
|
189
|
+
"--wait_for_angularjs",
|
190
|
+
"--wait-for-angularjs",
|
191
|
+
action="store_true",
|
192
|
+
dest="wait_for_angularjs",
|
193
|
+
default=False,
|
194
|
+
help="""Add waiting for AngularJS. (The default setting
|
195
|
+
was changed to no longer wait for AngularJS to
|
196
|
+
finish loading as an extra JavaScript call.)""",
|
197
|
+
)
|
180
198
|
parser.addoption(
|
181
199
|
"--protocol",
|
182
200
|
action="store",
|
@@ -421,6 +439,15 @@ class SeleniumBrowser(Plugin):
|
|
421
439
|
UNLESS using a virtual display with Xvfb.
|
422
440
|
Default: False on Mac/Windows. True on Linux.""",
|
423
441
|
)
|
442
|
+
parser.addoption(
|
443
|
+
"--headless1",
|
444
|
+
action="store_true",
|
445
|
+
dest="headless1",
|
446
|
+
default=False,
|
447
|
+
help="""This option activates the old headless mode,
|
448
|
+
which is faster, but has limitations.
|
449
|
+
(May be phased out by Chrome in the future.)""",
|
450
|
+
)
|
424
451
|
parser.addoption(
|
425
452
|
"--headless2",
|
426
453
|
action="store_true",
|
@@ -452,6 +479,17 @@ class SeleniumBrowser(Plugin):
|
|
452
479
|
will no longer be enabled by default on Linux.
|
453
480
|
Default: False. (Linux-ONLY!)""",
|
454
481
|
)
|
482
|
+
parser.addoption(
|
483
|
+
"--xvfb-metrics",
|
484
|
+
"--xvfb_metrics",
|
485
|
+
action="store",
|
486
|
+
dest="xvfb_metrics",
|
487
|
+
default=None,
|
488
|
+
help="""Customize the Xvfb metrics (Width,Height) on Linux.
|
489
|
+
Format: A comma-separated string with the 2 values.
|
490
|
+
Examples: "1920,1080" or "1366,768" or "1024,768".
|
491
|
+
Default: None. (None: "1366,768". Min: "1024,768".)""",
|
492
|
+
)
|
455
493
|
parser.addoption(
|
456
494
|
"--locale_code",
|
457
495
|
"--locale-code",
|
@@ -613,6 +651,16 @@ class SeleniumBrowser(Plugin):
|
|
613
651
|
help="""Setting this overrides the default wait time
|
614
652
|
before each MasterQA verification pop-up.""",
|
615
653
|
)
|
654
|
+
parser.addoption(
|
655
|
+
"--esc-end",
|
656
|
+
"--esc_end",
|
657
|
+
"--ee",
|
658
|
+
action="store_true",
|
659
|
+
dest="esc_end",
|
660
|
+
default=False,
|
661
|
+
help="""End the current test early via the ESC key.
|
662
|
+
The test will be marked as skipped.""",
|
663
|
+
)
|
616
664
|
parser.addoption(
|
617
665
|
"--recorder",
|
618
666
|
"--record",
|
@@ -663,6 +711,15 @@ class SeleniumBrowser(Plugin):
|
|
663
711
|
help="""The option to disable JavaScript on web pages.
|
664
712
|
Warning: Most web pages will stop working!""",
|
665
713
|
)
|
714
|
+
parser.addoption(
|
715
|
+
"--disable_cookies",
|
716
|
+
"--disable-cookies",
|
717
|
+
action="store_true",
|
718
|
+
dest="disable_cookies",
|
719
|
+
default=False,
|
720
|
+
help="""The option to disable Cookies on web pages.
|
721
|
+
Warning: Several pages may stop working!""",
|
722
|
+
)
|
666
723
|
parser.addoption(
|
667
724
|
"--disable_csp",
|
668
725
|
"--disable-csp",
|
@@ -682,6 +739,7 @@ class SeleniumBrowser(Plugin):
|
|
682
739
|
parser.addoption(
|
683
740
|
"--disable_ws",
|
684
741
|
"--disable-ws",
|
742
|
+
"--dws",
|
685
743
|
"--disable-web-security",
|
686
744
|
action="store_true",
|
687
745
|
dest="disable_ws",
|
@@ -863,6 +921,17 @@ class SeleniumBrowser(Plugin):
|
|
863
921
|
on Chromium browsers (Chrome or Edge).
|
864
922
|
This is already the default Firefox option.""",
|
865
923
|
)
|
924
|
+
parser.addoption(
|
925
|
+
"--window-position",
|
926
|
+
"--window_position",
|
927
|
+
action="store",
|
928
|
+
dest="window_position",
|
929
|
+
default=None,
|
930
|
+
help="""The option to set the starting window x,y position.
|
931
|
+
Format: A comma-separated string with the 2 values.
|
932
|
+
Example: "55,66"
|
933
|
+
Default: None. (Will use default values if None)""",
|
934
|
+
)
|
866
935
|
parser.addoption(
|
867
936
|
"--window-size",
|
868
937
|
"--window_size",
|
@@ -961,6 +1030,7 @@ class SeleniumBrowser(Plugin):
|
|
961
1030
|
browser = self.options.browser
|
962
1031
|
test.test.browser = browser
|
963
1032
|
test.test.headless = None
|
1033
|
+
test.test.headless1 = None
|
964
1034
|
test.test.headless2 = None
|
965
1035
|
# As a shortcut, you can use "--edge" instead of "--browser=edge", etc,
|
966
1036
|
# but you can only specify one default browser. (Default: chrome)
|
@@ -1037,6 +1107,29 @@ class SeleniumBrowser(Plugin):
|
|
1037
1107
|
'\n (Your browser choice was: "%s")\n' % browser
|
1038
1108
|
)
|
1039
1109
|
raise Exception(message)
|
1110
|
+
window_position = self.options.window_position
|
1111
|
+
if window_position:
|
1112
|
+
if window_position.count(",") != 1:
|
1113
|
+
message = (
|
1114
|
+
'\n\n window_position expects an "x,y" string!'
|
1115
|
+
'\n (Your input was: "%s")\n' % window_position
|
1116
|
+
)
|
1117
|
+
raise Exception(message)
|
1118
|
+
window_position = window_position.replace(" ", "")
|
1119
|
+
win_x = None
|
1120
|
+
win_y = None
|
1121
|
+
try:
|
1122
|
+
win_x = int(window_position.split(",")[0])
|
1123
|
+
win_y = int(window_position.split(",")[1])
|
1124
|
+
except Exception:
|
1125
|
+
message = (
|
1126
|
+
'\n\n Expecting integer values for "x,y"!'
|
1127
|
+
'\n (window_position input was: "%s")\n'
|
1128
|
+
% window_position
|
1129
|
+
)
|
1130
|
+
raise Exception(message)
|
1131
|
+
settings.WINDOW_START_X = win_x
|
1132
|
+
settings.WINDOW_START_Y = win_y
|
1040
1133
|
window_size = self.options.window_size
|
1041
1134
|
if window_size:
|
1042
1135
|
if window_size.count(",") != 1:
|
@@ -1076,9 +1169,13 @@ class SeleniumBrowser(Plugin):
|
|
1076
1169
|
test.test.cap_file = self.options.cap_file
|
1077
1170
|
test.test.cap_string = self.options.cap_string
|
1078
1171
|
test.test.headless = self.options.headless
|
1172
|
+
test.test.headless1 = self.options.headless1
|
1173
|
+
if test.test.headless1:
|
1174
|
+
test.test.headless = True
|
1079
1175
|
test.test.headless2 = self.options.headless2
|
1080
1176
|
if test.test.headless and test.test.browser == "safari":
|
1081
1177
|
test.test.headless = False # Safari doesn't use headless
|
1178
|
+
test.test.headless1 = False
|
1082
1179
|
if test.test.headless2 and test.test.browser == "firefox":
|
1083
1180
|
test.test.headless2 = False # Only for Chromium browsers
|
1084
1181
|
test.test.headless = True # Firefox has regular headless
|
@@ -1089,11 +1186,14 @@ class SeleniumBrowser(Plugin):
|
|
1089
1186
|
self.options.headless2 = False
|
1090
1187
|
test.test.headed = self.options.headed
|
1091
1188
|
test.test.xvfb = self.options.xvfb
|
1189
|
+
test.test.xvfb_metrics = self.options.xvfb_metrics
|
1092
1190
|
test.test.locale_code = self.options.locale_code
|
1093
1191
|
test.test.interval = self.options.interval
|
1094
1192
|
test.test.start_page = self.options.start_page
|
1095
1193
|
if self.options.skip_js_waits:
|
1096
1194
|
settings.SKIP_JS_WAITS = True
|
1195
|
+
if self.options.wait_for_angularjs:
|
1196
|
+
settings.WAIT_FOR_ANGULARJS = True
|
1097
1197
|
test.test.protocol = self.options.protocol
|
1098
1198
|
test.test.servername = self.options.servername
|
1099
1199
|
test.test.port = self.options.port
|
@@ -1126,6 +1226,7 @@ class SeleniumBrowser(Plugin):
|
|
1126
1226
|
test.test.block_images = self.options.block_images
|
1127
1227
|
test.test.do_not_track = self.options.do_not_track
|
1128
1228
|
test.test.verify_delay = self.options.verify_delay # MasterQA
|
1229
|
+
test.test.esc_end = self.options.esc_end
|
1129
1230
|
test.test.recorder_mode = self.options.recorder_mode
|
1130
1231
|
test.test.recorder_ext = self.options.recorder_mode # Again
|
1131
1232
|
test.test.rec_behave = self.options.rec_behave
|
@@ -1140,6 +1241,7 @@ class SeleniumBrowser(Plugin):
|
|
1140
1241
|
elif self.options.record_sleep:
|
1141
1242
|
test.test.recorder_mode = True
|
1142
1243
|
test.test.recorder_ext = True
|
1244
|
+
test.test.disable_cookies = self.options.disable_cookies
|
1143
1245
|
test.test.disable_js = self.options.disable_js
|
1144
1246
|
test.test.disable_csp = self.options.disable_csp
|
1145
1247
|
test.test.disable_ws = self.options.disable_ws
|
@@ -1166,6 +1268,7 @@ class SeleniumBrowser(Plugin):
|
|
1166
1268
|
test.test.dark_mode = self.options.dark_mode
|
1167
1269
|
test.test.devtools = self.options.devtools
|
1168
1270
|
test.test._disable_beforeunload = self.options._disable_beforeunload
|
1271
|
+
test.test.window_position = self.options.window_position
|
1169
1272
|
test.test.window_size = self.options.window_size
|
1170
1273
|
test.test.maximize_option = self.options.maximize_option
|
1171
1274
|
if self.options.save_screenshot and self.options.no_screenshot:
|
@@ -1192,15 +1295,19 @@ class SeleniumBrowser(Plugin):
|
|
1192
1295
|
and not self.options.headless2
|
1193
1296
|
and not self.options.xvfb
|
1194
1297
|
):
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1298
|
+
if not self.options.undetectable:
|
1299
|
+
print(
|
1300
|
+
"(Linux uses --headless by default. "
|
1301
|
+
"To override, use --headed / --gui. "
|
1302
|
+
"For Xvfb mode instead, use --xvfb. "
|
1303
|
+
"Or you can hide this info by using "
|
1304
|
+
"--headless / --headless2 / --uc.)"
|
1305
|
+
)
|
1306
|
+
self.options.headless = True
|
1307
|
+
test.test.headless = True
|
1308
|
+
else:
|
1309
|
+
self.options.xvfb = True
|
1310
|
+
test.test.xvfb = True
|
1204
1311
|
if self.options.use_wire and self.options.undetectable:
|
1205
1312
|
print(
|
1206
1313
|
"\n"
|
@@ -1214,8 +1321,10 @@ class SeleniumBrowser(Plugin):
|
|
1214
1321
|
# Recorder Mode can still optimize scripts in --headless2 mode.
|
1215
1322
|
if self.options.recorder_mode and self.options.headless:
|
1216
1323
|
self.options.headless = False
|
1324
|
+
self.options.headless1 = False
|
1217
1325
|
self.options.headless2 = True
|
1218
1326
|
test.test.headless = False
|
1327
|
+
test.test.headless1 = False
|
1219
1328
|
test.test.headless2 = True
|
1220
1329
|
if not self.options.headless and not self.options.headless2:
|
1221
1330
|
self.options.headed = True
|
@@ -1229,7 +1338,7 @@ class SeleniumBrowser(Plugin):
|
|
1229
1338
|
):
|
1230
1339
|
width = settings.HEADLESS_START_WIDTH
|
1231
1340
|
height = settings.HEADLESS_START_HEIGHT
|
1232
|
-
|
1341
|
+
with suppress(Exception):
|
1233
1342
|
from sbvirtualdisplay import Display
|
1234
1343
|
|
1235
1344
|
self._xvfb_display = Display(visible=0, size=(width, height))
|
@@ -1237,8 +1346,6 @@ class SeleniumBrowser(Plugin):
|
|
1237
1346
|
sb_config._virtual_display = self._xvfb_display
|
1238
1347
|
self.headless_active = True
|
1239
1348
|
sb_config.headless_active = True
|
1240
|
-
except Exception:
|
1241
|
-
pass
|
1242
1349
|
sb_config._is_timeout_changed = False
|
1243
1350
|
sb_config._SMALL_TIMEOUT = settings.SMALL_TIMEOUT
|
1244
1351
|
sb_config._LARGE_TIMEOUT = settings.LARGE_TIMEOUT
|
@@ -1271,7 +1378,7 @@ class SeleniumBrowser(Plugin):
|
|
1271
1378
|
pass
|
1272
1379
|
except Exception:
|
1273
1380
|
pass
|
1274
|
-
|
1381
|
+
with suppress(Exception):
|
1275
1382
|
if (
|
1276
1383
|
hasattr(self, "_xvfb_display")
|
1277
1384
|
and self._xvfb_display
|
@@ -1288,5 +1395,3 @@ class SeleniumBrowser(Plugin):
|
|
1288
1395
|
):
|
1289
1396
|
sb_config._virtual_display.stop()
|
1290
1397
|
sb_config._virtual_display = None
|
1291
|
-
except Exception:
|
1292
|
-
pass
|
@@ -267,13 +267,6 @@ def process_test_file(code_lines, new_lang):
|
|
267
267
|
|
268
268
|
|
269
269
|
def main():
|
270
|
-
if (
|
271
|
-
"win32" in sys.platform
|
272
|
-
and hasattr(colorama, "just_fix_windows_console")
|
273
|
-
):
|
274
|
-
colorama.just_fix_windows_console()
|
275
|
-
else:
|
276
|
-
colorama.init(autoreset=True)
|
277
270
|
c1 = colorama.Fore.BLUE + colorama.Back.LIGHTCYAN_EX
|
278
271
|
c2 = colorama.Fore.BLUE + colorama.Back.LIGHTYELLOW_EX
|
279
272
|
c3 = colorama.Fore.RED + colorama.Back.LIGHTGREEN_EX
|
@@ -1,4 +1,3 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
1
|
import logging
|
3
2
|
import os
|
4
3
|
import re
|
@@ -10,6 +9,7 @@ import selenium.webdriver.chrome.service
|
|
10
9
|
import selenium.webdriver.chrome.webdriver
|
11
10
|
import selenium.webdriver.common.service
|
12
11
|
import selenium.webdriver.remote.command
|
12
|
+
from contextlib import suppress
|
13
13
|
from .cdp import CDP
|
14
14
|
from .cdp import PageElement
|
15
15
|
from .dprocess import start_detached
|
@@ -132,8 +132,11 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|
132
132
|
options = ChromeOptions()
|
133
133
|
try:
|
134
134
|
if hasattr(options, "_session") and options._session is not None:
|
135
|
-
# Prevent reuse of options
|
136
|
-
|
135
|
+
# Prevent reuse of options.
|
136
|
+
# (Probably a port overlap. Quit existing driver and continue.)
|
137
|
+
logger.debug("You cannot reuse the ChromeOptions object")
|
138
|
+
with suppress(Exception):
|
139
|
+
options._session.quit()
|
137
140
|
except AttributeError:
|
138
141
|
pass
|
139
142
|
options._session = self
|
@@ -201,11 +204,9 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|
201
204
|
# Create a temporary folder for the user-data profile.
|
202
205
|
options.add_argument(arg)
|
203
206
|
if not language:
|
204
|
-
|
207
|
+
with suppress(Exception):
|
205
208
|
import locale
|
206
209
|
language = locale.getlocale()[0].replace("_", "-")
|
207
|
-
except Exception:
|
208
|
-
pass
|
209
210
|
if (
|
210
211
|
not language
|
211
212
|
or "English" in language
|
@@ -234,6 +235,7 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|
234
235
|
"--no-first-run",
|
235
236
|
"--no-service-autorun",
|
236
237
|
"--password-store=basic",
|
238
|
+
"--profile-directory=Default",
|
237
239
|
]
|
238
240
|
)
|
239
241
|
options.add_argument(
|
@@ -242,7 +244,7 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|
242
244
|
)
|
243
245
|
if hasattr(options, 'handle_prefs'):
|
244
246
|
options.handle_prefs(user_data_dir)
|
245
|
-
|
247
|
+
with suppress(Exception):
|
246
248
|
import json
|
247
249
|
with open(
|
248
250
|
os.path.join(
|
@@ -263,8 +265,6 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|
263
265
|
fs.seek(0, 0)
|
264
266
|
fs.truncate()
|
265
267
|
json.dump(config, fs)
|
266
|
-
except Exception:
|
267
|
-
pass
|
268
268
|
creationflags = 0
|
269
269
|
if "win32" in sys.platform:
|
270
270
|
creationflags = subprocess.CREATE_NO_WINDOW
|
@@ -278,19 +278,21 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|
278
278
|
options.binary_location, *options.arguments
|
279
279
|
)
|
280
280
|
else:
|
281
|
-
|
282
|
-
|
283
|
-
stdin=subprocess.PIPE,
|
284
|
-
stdout=subprocess.PIPE,
|
285
|
-
stderr=subprocess.PIPE,
|
286
|
-
close_fds=IS_POSIX,
|
287
|
-
creationflags=creationflags,
|
281
|
+
gui_lock = fasteners.InterProcessLock(
|
282
|
+
constants.MultiBrowser.PYAUTOGUILOCK
|
288
283
|
)
|
289
|
-
|
284
|
+
with gui_lock:
|
285
|
+
browser = subprocess.Popen(
|
286
|
+
[options.binary_location, *options.arguments],
|
287
|
+
stdin=subprocess.PIPE,
|
288
|
+
stdout=subprocess.PIPE,
|
289
|
+
stderr=subprocess.PIPE,
|
290
|
+
close_fds=IS_POSIX,
|
291
|
+
creationflags=creationflags,
|
292
|
+
)
|
293
|
+
self.browser_pid = browser.pid
|
290
294
|
service_ = None
|
291
295
|
log_output = subprocess.PIPE
|
292
|
-
if sys.version_info < (3, 8):
|
293
|
-
log_output = os.devnull
|
294
296
|
if patch_driver:
|
295
297
|
service_ = selenium.webdriver.chrome.service.Service(
|
296
298
|
executable_path=self.patcher.executable_path,
|
@@ -338,7 +340,7 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|
338
340
|
|
339
341
|
def _get_cdc_props(self):
|
340
342
|
cdc_props = []
|
341
|
-
|
343
|
+
with suppress(Exception):
|
342
344
|
cdc_props = self.execute_script(
|
343
345
|
"""
|
344
346
|
let objectToInspect = window,
|
@@ -351,8 +353,6 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|
351
353
|
return result.filter(i => i.match(/^[a-z]{3}_[a-z]{22}_.*/i))
|
352
354
|
"""
|
353
355
|
)
|
354
|
-
except Exception:
|
355
|
-
pass
|
356
356
|
return cdc_props
|
357
357
|
|
358
358
|
def _hook_remove_cdc_props(self, cdc_props):
|
@@ -423,46 +423,57 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|
423
423
|
- Starts the chromedriver service that runs in the background.
|
424
424
|
- Recreates the session."""
|
425
425
|
if hasattr(self, "service"):
|
426
|
-
|
427
|
-
self.service.
|
428
|
-
|
429
|
-
|
426
|
+
with suppress(Exception):
|
427
|
+
if self.service.is_connectable():
|
428
|
+
self.stop_client()
|
429
|
+
self.service.stop()
|
430
430
|
if isinstance(timeout, str):
|
431
431
|
if timeout.lower() == "breakpoint":
|
432
432
|
breakpoint() # To continue:
|
433
433
|
pass # Type "c" & press ENTER!
|
434
434
|
else:
|
435
435
|
time.sleep(timeout)
|
436
|
-
|
436
|
+
with suppress(Exception):
|
437
437
|
self.service.start()
|
438
|
-
|
439
|
-
pass
|
440
|
-
try:
|
438
|
+
with suppress(Exception):
|
441
439
|
self.start_session()
|
442
|
-
|
443
|
-
|
440
|
+
with suppress(Exception):
|
441
|
+
if self.current_url.startswith("chrome-extension://"):
|
442
|
+
self.close()
|
443
|
+
if self.service.is_connectable():
|
444
|
+
self.stop_client()
|
445
|
+
self.service.stop()
|
446
|
+
self.service.start()
|
447
|
+
self.start_session()
|
448
|
+
self._is_connected = True
|
444
449
|
|
445
450
|
def disconnect(self):
|
446
451
|
"""Stops the chromedriver service that runs in the background.
|
447
452
|
To use driver methods again, you MUST call driver.connect()"""
|
448
453
|
if hasattr(self, "service"):
|
449
|
-
|
450
|
-
self.service.
|
451
|
-
|
452
|
-
|
454
|
+
with suppress(Exception):
|
455
|
+
if self.service.is_connectable():
|
456
|
+
self.stop_client()
|
457
|
+
self.service.stop()
|
458
|
+
self._is_connected = False
|
453
459
|
|
454
460
|
def connect(self):
|
455
461
|
"""Starts the chromedriver service that runs in the background
|
456
462
|
and recreates the session."""
|
457
463
|
if hasattr(self, "service"):
|
458
|
-
|
464
|
+
with suppress(Exception):
|
459
465
|
self.service.start()
|
460
|
-
|
461
|
-
pass
|
462
|
-
try:
|
466
|
+
with suppress(Exception):
|
463
467
|
self.start_session()
|
464
|
-
|
465
|
-
|
468
|
+
with suppress(Exception):
|
469
|
+
if self.current_url.startswith("chrome-extension://"):
|
470
|
+
self.close()
|
471
|
+
if self.service.is_connectable():
|
472
|
+
self.stop_client()
|
473
|
+
self.service.stop()
|
474
|
+
self.service.start()
|
475
|
+
self.start_session()
|
476
|
+
self._is_connected = True
|
466
477
|
|
467
478
|
def start_session(self, capabilities=None):
|
468
479
|
if not capabilities:
|
@@ -486,13 +497,13 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|
486
497
|
pass
|
487
498
|
if hasattr(self, "service") and getattr(self.service, "process", None):
|
488
499
|
logger.debug("Stopping webdriver service")
|
489
|
-
|
490
|
-
|
500
|
+
with suppress(Exception):
|
501
|
+
self.stop_client()
|
502
|
+
self.service.stop()
|
503
|
+
with suppress(Exception):
|
491
504
|
if self.reactor and isinstance(self.reactor, Reactor):
|
492
505
|
logger.debug("Shutting down Reactor")
|
493
506
|
self.reactor.event.set()
|
494
|
-
except Exception:
|
495
|
-
pass
|
496
507
|
if (
|
497
508
|
hasattr(self, "keep_user_data_dir")
|
498
509
|
and hasattr(self, "user_data_dir")
|
@@ -521,18 +532,14 @@ class Chrome(selenium.webdriver.chrome.webdriver.WebDriver):
|
|
521
532
|
self.patcher = None
|
522
533
|
|
523
534
|
def __del__(self):
|
524
|
-
|
535
|
+
with suppress(Exception):
|
525
536
|
if "win32" in sys.platform:
|
526
537
|
self.stop_client()
|
527
538
|
self.command_executor.close()
|
528
539
|
else:
|
529
540
|
super().quit()
|
530
|
-
|
531
|
-
pass
|
532
|
-
try:
|
541
|
+
with suppress(Exception):
|
533
542
|
self.quit()
|
534
|
-
except Exception:
|
535
|
-
pass
|
536
543
|
|
537
544
|
def __enter__(self):
|
538
545
|
return self
|
seleniumbase/undetected/cdp.py
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
from seleniumbase.undetected.cdp_driver import cdp_util # noqa
|
@@ -0,0 +1,110 @@
|
|
1
|
+
import warnings as _warnings
|
2
|
+
from collections.abc import Mapping as _Mapping, Sequence as _Sequence
|
3
|
+
import logging
|
4
|
+
|
5
|
+
__logger__ = logging.getLogger(__name__)
|
6
|
+
__all__ = ["cdict", "ContraDict"]
|
7
|
+
|
8
|
+
|
9
|
+
def cdict(*args, **kwargs):
|
10
|
+
"""Factory function"""
|
11
|
+
return ContraDict(*args, **kwargs)
|
12
|
+
|
13
|
+
|
14
|
+
class ContraDict(dict):
|
15
|
+
"""
|
16
|
+
Directly inherited from dict.
|
17
|
+
Accessible by attribute. o.x == o['x']
|
18
|
+
This works also for all corner cases.
|
19
|
+
Native json.dumps and json.loads work with it.
|
20
|
+
|
21
|
+
Names like "keys", "update", "values" etc won't overwrite the methods,
|
22
|
+
but will just be available using dict lookup notation obj['items']
|
23
|
+
instead of obj.items.
|
24
|
+
|
25
|
+
All key names are converted to snake_case.
|
26
|
+
Hyphen's (-), dot's (.) or whitespaces are replaced by underscore (_).
|
27
|
+
Autocomplete works even if the objects comes from a list.
|
28
|
+
Recursive action. Dict assignments will be converted too.
|
29
|
+
"""
|
30
|
+
__module__ = None
|
31
|
+
|
32
|
+
def __init__(self, *args, **kwargs):
|
33
|
+
super().__init__()
|
34
|
+
# silent = kwargs.pop("silent", False)
|
35
|
+
_ = dict(*args, **kwargs)
|
36
|
+
|
37
|
+
super().__setattr__("__dict__", self)
|
38
|
+
for k, v in _.items():
|
39
|
+
_check_key(k, self, False, True)
|
40
|
+
super().__setitem__(k, _wrap(self.__class__, v))
|
41
|
+
|
42
|
+
def __setitem__(self, key, value):
|
43
|
+
super().__setitem__(key, _wrap(self.__class__, value))
|
44
|
+
|
45
|
+
def __setattr__(self, key, value):
|
46
|
+
super().__setitem__(key, _wrap(self.__class__, value))
|
47
|
+
|
48
|
+
def __getattribute__(self, attribute):
|
49
|
+
if attribute in self:
|
50
|
+
return self[attribute]
|
51
|
+
if not _check_key(attribute, self, True, silent=True):
|
52
|
+
return getattr(super(), attribute)
|
53
|
+
return object.__getattribute__(self, attribute)
|
54
|
+
|
55
|
+
|
56
|
+
def _wrap(cls, v):
|
57
|
+
if isinstance(v, _Mapping):
|
58
|
+
v = cls(v)
|
59
|
+
elif isinstance(v, _Sequence) and not isinstance(
|
60
|
+
v, (str, bytes, bytearray, set, tuple)
|
61
|
+
):
|
62
|
+
v = list([_wrap(cls, x) for x in v])
|
63
|
+
return v
|
64
|
+
|
65
|
+
|
66
|
+
_warning_names = (
|
67
|
+
"items",
|
68
|
+
"keys",
|
69
|
+
"values",
|
70
|
+
"update",
|
71
|
+
"clear",
|
72
|
+
"copy",
|
73
|
+
"fromkeys",
|
74
|
+
"get",
|
75
|
+
"items",
|
76
|
+
"keys",
|
77
|
+
"pop",
|
78
|
+
"popitem",
|
79
|
+
"setdefault",
|
80
|
+
"update",
|
81
|
+
"values",
|
82
|
+
"class",
|
83
|
+
)
|
84
|
+
|
85
|
+
_warning_names_message = """\n\
|
86
|
+
While creating a ContraDict object, a key offending key name '{0}'
|
87
|
+
has been found, which might behave unexpected.
|
88
|
+
You will only be able to look it up using key,
|
89
|
+
eg. myobject['{0}']. myobject.{0} will not work with that name."""
|
90
|
+
|
91
|
+
|
92
|
+
def _check_key(
|
93
|
+
key: str, mapping: _Mapping, boolean: bool = False, silent=True
|
94
|
+
):
|
95
|
+
"""Checks `key` and warns if needed.
|
96
|
+
:param key:
|
97
|
+
:param boolean: return True or False instead of passthrough
|
98
|
+
"""
|
99
|
+
e = None
|
100
|
+
if not isinstance(key, (str,)):
|
101
|
+
if boolean:
|
102
|
+
return True
|
103
|
+
return key
|
104
|
+
if key.lower() in _warning_names or any(_ in key for _ in ("-", ".")):
|
105
|
+
if not silent:
|
106
|
+
_warnings.warn(_warning_names_message.format(key))
|
107
|
+
e = True
|
108
|
+
if not boolean:
|
109
|
+
return key
|
110
|
+
return not e
|