seleniumbase 4.24.10__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/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
|