seleniumbase 4.15.15__py3-none-any.whl → 4.16.0__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.
Files changed (53) hide show
  1. sbase/__init__.py +1 -0
  2. seleniumbase/__init__.py +1 -0
  3. seleniumbase/__version__.py +1 -1
  4. seleniumbase/behave/behave_sb.py +12 -19
  5. seleniumbase/common/exceptions.py +5 -0
  6. seleniumbase/config/settings.py +7 -0
  7. seleniumbase/console_scripts/ReadMe.md +2 -2
  8. seleniumbase/console_scripts/run.py +5 -4
  9. seleniumbase/console_scripts/sb_behave_gui.py +6 -9
  10. seleniumbase/console_scripts/sb_caseplans.py +2 -5
  11. seleniumbase/console_scripts/sb_commander.py +5 -8
  12. seleniumbase/console_scripts/sb_install.py +43 -54
  13. seleniumbase/console_scripts/sb_print.py +2 -0
  14. seleniumbase/console_scripts/sb_recorder.py +3 -2
  15. seleniumbase/core/browser_launcher.py +13 -27
  16. seleniumbase/core/capabilities_parser.py +2 -3
  17. seleniumbase/core/detect_b_ver.py +3 -4
  18. seleniumbase/core/jqc_helper.py +2 -4
  19. seleniumbase/core/mysql.py +1 -1
  20. seleniumbase/core/proxy_helper.py +65 -0
  21. seleniumbase/core/recorder_helper.py +1 -1
  22. seleniumbase/core/s3_manager.py +29 -23
  23. seleniumbase/core/session_helper.py +2 -6
  24. seleniumbase/core/settings_parser.py +2 -0
  25. seleniumbase/fixtures/base_case.py +31 -13
  26. seleniumbase/fixtures/constants.py +1 -1
  27. seleniumbase/fixtures/css_to_xpath.py +1 -2
  28. seleniumbase/fixtures/errors.py +2 -7
  29. seleniumbase/fixtures/js_utils.py +8 -16
  30. seleniumbase/fixtures/page_actions.py +3 -6
  31. seleniumbase/fixtures/page_utils.py +1 -1
  32. seleniumbase/fixtures/shared_utils.py +26 -79
  33. seleniumbase/fixtures/xpath_to_css.py +1 -3
  34. seleniumbase/plugins/base_plugin.py +1 -1
  35. seleniumbase/plugins/basic_test_info.py +1 -1
  36. seleniumbase/plugins/db_reporting_plugin.py +2 -2
  37. seleniumbase/plugins/driver_manager.py +2 -1
  38. seleniumbase/plugins/page_source.py +2 -4
  39. seleniumbase/plugins/pytest_plugin.py +9 -8
  40. seleniumbase/plugins/s3_logging_plugin.py +20 -9
  41. seleniumbase/plugins/sb_manager.py +2 -2
  42. seleniumbase/plugins/screen_shots.py +2 -2
  43. seleniumbase/plugins/selenium_plugin.py +5 -8
  44. seleniumbase/translate/translator.py +397 -396
  45. seleniumbase/undetected/__init__.py +17 -37
  46. seleniumbase/utilities/selenium_grid/grid_hub.py +2 -1
  47. seleniumbase/utilities/selenium_grid/grid_node.py +2 -1
  48. {seleniumbase-4.15.15.dist-info → seleniumbase-4.16.0.dist-info}/METADATA +7 -7
  49. {seleniumbase-4.15.15.dist-info → seleniumbase-4.16.0.dist-info}/RECORD +53 -53
  50. {seleniumbase-4.15.15.dist-info → seleniumbase-4.16.0.dist-info}/LICENSE +0 -0
  51. {seleniumbase-4.15.15.dist-info → seleniumbase-4.16.0.dist-info}/WHEEL +0 -0
  52. {seleniumbase-4.15.15.dist-info → seleniumbase-4.16.0.dist-info}/entry_points.txt +0 -0
  53. {seleniumbase-4.15.15.dist-info → seleniumbase-4.16.0.dist-info}/top_level.txt +0 -0
@@ -1,13 +1,15 @@
1
- """Shared utility methods."""
2
- import subprocess
1
+ """Shared utility methods"""
2
+ import os
3
+ import platform
3
4
  import sys
4
- from seleniumbase.config import settings
5
- from seleniumbase.fixtures import constants
5
+ import time
6
6
  from seleniumbase import config as sb_config
7
+ from seleniumbase.fixtures import constants
7
8
 
8
9
 
9
10
  def pip_install(package, version=None):
10
11
  import fasteners
12
+ import subprocess
11
13
 
12
14
  pip_install_lock = fasteners.InterProcessLock(
13
15
  constants.PipInstall.LOCKFILE
@@ -24,17 +26,30 @@ def pip_install(package, version=None):
24
26
  )
25
27
 
26
28
 
29
+ def is_arm_mac():
30
+ """(M1 / M2 Macs use the ARM processor)"""
31
+ return (
32
+ "darwin" in sys.platform
33
+ and (
34
+ "arm" in platform.processor().lower()
35
+ or "arm64" in platform.version().lower()
36
+ )
37
+ )
38
+
39
+
40
+ def is_mac():
41
+ return "darwin" in sys.platform
42
+
43
+
44
+ def is_linux():
45
+ return "linux" in sys.platform
46
+
47
+
27
48
  def is_windows():
28
- platform = sys.platform
29
- if "win32" in platform or "win64" in platform or "x64" in platform:
30
- return True
31
- else:
32
- return False
49
+ return "win32" in sys.platform
33
50
 
34
51
 
35
52
  def get_terminal_width():
36
- import os
37
-
38
53
  width = 80 # default
39
54
  try:
40
55
  width = os.get_terminal_size().columns
@@ -48,72 +63,6 @@ def get_terminal_width():
48
63
  return width
49
64
 
50
65
 
51
- def display_proxy_warning(proxy_string):
52
- import warnings
53
-
54
- message = (
55
- '\nWARNING: Proxy String ["%s"] is NOT in the expected '
56
- '"ip_address:port" or "server:port" format, '
57
- "(OR the key does not exist in "
58
- "seleniumbase.config.proxy_list.PROXY_LIST)." % proxy_string
59
- )
60
- if settings.RAISE_INVALID_PROXY_STRING_EXCEPTION:
61
- raise Exception(message)
62
- else:
63
- message += " *** DEFAULTING to NOT USING a Proxy Server! ***"
64
- warnings.simplefilter("always", Warning) # See Warnings
65
- warnings.warn(message, category=Warning, stacklevel=2)
66
- warnings.simplefilter("default", Warning) # Set Default
67
-
68
-
69
- def validate_proxy_string(proxy_string):
70
- import re
71
- from seleniumbase.config import proxy_list
72
- from seleniumbase.fixtures import page_utils
73
-
74
- if proxy_string in proxy_list.PROXY_LIST.keys():
75
- proxy_string = proxy_list.PROXY_LIST[proxy_string]
76
- if not proxy_string:
77
- return None
78
- valid = False
79
- val_ip = re.match(
80
- r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$", proxy_string
81
- )
82
- if not val_ip:
83
- if proxy_string.startswith("http://"):
84
- proxy_string = proxy_string.split("http://")[1]
85
- elif proxy_string.startswith("https://"):
86
- proxy_string = proxy_string.split("https://")[1]
87
- elif "://" in proxy_string:
88
- if not proxy_string.startswith("socks4://") and not (
89
- proxy_string.startswith("socks5://")
90
- ):
91
- proxy_string = proxy_string.split("://")[1]
92
- chunks = proxy_string.split(":")
93
- if len(chunks) == 2:
94
- if re.match(r"^\d+$", chunks[1]):
95
- if page_utils.is_valid_url("http://" + proxy_string):
96
- valid = True
97
- elif len(chunks) == 3:
98
- if re.match(r"^\d+$", chunks[2]):
99
- if page_utils.is_valid_url("http:" + ":".join(chunks[1:])):
100
- if chunks[0] == "http":
101
- valid = True
102
- elif chunks[0] == "https":
103
- valid = True
104
- elif chunks[0] == "socks4":
105
- valid = True
106
- elif chunks[0] == "socks5":
107
- valid = True
108
- else:
109
- proxy_string = val_ip.group()
110
- valid = True
111
- if not valid:
112
- display_proxy_warning(proxy_string)
113
- proxy_string = None
114
- return proxy_string
115
-
116
-
117
66
  def format_exc(exception, message):
118
67
  """Formats an exception message to make the output cleaner."""
119
68
  from selenium.common.exceptions import ElementNotVisibleException
@@ -198,8 +147,6 @@ def check_if_time_limit_exceeded():
198
147
  and sb_config.time_limit
199
148
  and not sb_config.recorder_mode
200
149
  ):
201
- import time
202
-
203
150
  time_limit = sb_config.time_limit
204
151
  now_ms = int(time.time() * 1000)
205
152
  if now_ms > sb_config.start_time_ms + sb_config.time_limit_ms:
@@ -1,6 +1,4 @@
1
- """
2
- Convert XPath selectors into CSS selectors
3
- """
1
+ """Convert XPath selectors into CSS selectors"""
4
2
  import re
5
3
 
6
4
  _sub_regexes = {
@@ -1,4 +1,4 @@
1
- """The Nosetest plugin for setting base configuration and logging."""
1
+ """Base Plugin for SeleniumBase tests that run with pynose / nosetests"""
2
2
  import ast
3
3
  import sys
4
4
  import time
@@ -1,4 +1,4 @@
1
- """The plugin for saving basic test info for Selenium tests."""
1
+ """Test Info Plugin for SeleniumBase tests that run with pynose / nosetests"""
2
2
  import os
3
3
  import codecs
4
4
  import time
@@ -1,4 +1,4 @@
1
- """The plugin for recording test results in the Testcase Database."""
1
+ """DB Reporting Plugin for SeleniumBase tests that use pynose / nosetests"""
2
2
  import time
3
3
  import uuid
4
4
  from nose.plugins import Plugin
@@ -76,7 +76,7 @@ class DBReporting(Plugin):
76
76
  self.testcase_manager.insert_execution_data(exec_payload)
77
77
 
78
78
  def startTest(self, test):
79
- """At the start of the test, set the testcase details."""
79
+ """At the start of the test, set testcase details."""
80
80
  from seleniumbase.core.application_manager import ApplicationManager
81
81
  from seleniumbase.core.testcase_manager import TestcaseDataPayload
82
82
 
@@ -111,6 +111,7 @@ def Driver(
111
111
  pls=None, # Shortcut / Duplicate of "page_load_strategy".
112
112
  ):
113
113
  from seleniumbase.fixtures import constants
114
+ from seleniumbase.fixtures import shared_utils
114
115
 
115
116
  sys_argv = sys.argv
116
117
  browser_changes = 0
@@ -251,7 +252,7 @@ def Driver(
251
252
  recorder_mode = True
252
253
  recorder_ext = True
253
254
  if (
254
- "linux" in sys.platform
255
+ shared_utils.is_linux()
255
256
  and not headed
256
257
  and not headless
257
258
  and not headless2
@@ -1,4 +1,4 @@
1
- """The plugin for capturing & storing the page source on errors & failures."""
1
+ """PageSource Plugin for SeleniumBase tests that run with pynose / nosetests"""
2
2
  import os
3
3
  import codecs
4
4
  from nose.plugins import Plugin
@@ -7,7 +7,7 @@ from seleniumbase.core import log_helper
7
7
 
8
8
 
9
9
  class PageSource(Plugin):
10
- """Capture the page source when a test fails or raises an error."""
10
+ """Capture the page source after a test fails."""
11
11
  name = "page_source" # Usage: --with-page_source
12
12
  logfile_name = settings.PAGE_SOURCE_NAME
13
13
 
@@ -24,7 +24,6 @@ class PageSource(Plugin):
24
24
  try:
25
25
  page_source = test.driver.page_source
26
26
  except Exception:
27
- # Since we can't get the page source from here, skip saving it
28
27
  return
29
28
  test_logpath = self.options.log_path + "/" + test.id()
30
29
  if not os.path.exists(test_logpath):
@@ -41,7 +40,6 @@ class PageSource(Plugin):
41
40
  try:
42
41
  page_source = test.driver.page_source
43
42
  except Exception:
44
- # Since we can't get the page source from here, don't save it.
45
43
  return
46
44
  test_logpath = self.options.log_path + "/" + test.id()
47
45
  if not os.path.exists(test_logpath):
@@ -8,10 +8,8 @@ from seleniumbase import config as sb_config
8
8
  from seleniumbase.config import settings
9
9
  from seleniumbase.core import log_helper
10
10
  from seleniumbase.fixtures import constants
11
+ from seleniumbase.fixtures import shared_utils
11
12
 
12
- is_windows = False
13
- if sys.platform in ["win32", "win64", "x64"]:
14
- is_windows = True
15
13
  python3_11_or_newer = False
16
14
  if sys.version_info >= (3, 11):
17
15
  python3_11_or_newer = True
@@ -99,8 +97,8 @@ def pytest_addoption(parser):
99
97
  --incognito (Enable Chrome's Incognito mode.)
100
98
  --guest (Enable Chrome's Guest mode.)
101
99
  --devtools (Open Chrome's DevTools when the browser opens.)
102
- --reuse-session | --rs (Reuse browser session for all tests.)
103
- --reuse-class-session | --rcs (Reuse session for tests in class.)
100
+ --rs | --reuse-session (Reuse browser session for all tests.)
101
+ --rcs | --reuse-class-session (Reuse session for tests in class.)
104
102
  --crumbs (Delete all cookies between tests reusing a session.)
105
103
  --disable-beforeunload (Disable the "beforeunload" event on Chrome.)
106
104
  --window-size=WIDTH,HEIGHT (Set the browser's starting window size.)
@@ -1854,7 +1852,10 @@ def pytest_runtest_teardown(item):
1854
1852
  and self.driver
1855
1853
  and "--pdb" not in sys_argv
1856
1854
  ):
1857
- if not is_windows or self.driver.service.process:
1855
+ if not (
1856
+ shared_utils.is_windows()
1857
+ or self.driver.service.process
1858
+ ):
1858
1859
  self.driver.quit()
1859
1860
  except Exception:
1860
1861
  pass
@@ -1864,7 +1865,7 @@ def pytest_runtest_teardown(item):
1864
1865
  ):
1865
1866
  try:
1866
1867
  if (
1867
- not is_windows
1868
+ not shared_utils.is_windows()
1868
1869
  or sb_config._sb_pdb_driver.service.process
1869
1870
  ):
1870
1871
  sb_config._sb_pdb_driver.quit()
@@ -1982,7 +1983,7 @@ def _perform_pytest_unconfigure_():
1982
1983
  if sb_config.shared_driver:
1983
1984
  try:
1984
1985
  if (
1985
- not is_windows
1986
+ not shared_utils.is_windows()
1986
1987
  or sb_config.browser == "ie"
1987
1988
  or sb_config.shared_driver.service.process
1988
1989
  ):
@@ -1,8 +1,6 @@
1
- """The S3 Plugin for uploading test logs to the S3 bucket specified."""
1
+ """S3 Logging Plugin for SeleniumBase tests that run with pynose / nosetests"""
2
2
  import uuid
3
- import logging
4
3
  import os
5
- from seleniumbase.core.s3_manager import S3LoggingBucket
6
4
  from nose.plugins import Plugin
7
5
 
8
6
 
@@ -14,25 +12,38 @@ class S3Logging(Plugin):
14
12
  """Get the options."""
15
13
  super().configure(options, conf)
16
14
  self.options = options
15
+ self.test_id = None
16
+
17
+ def save_data_to_logs(self, data, file_name):
18
+ from seleniumbase.fixtures import page_utils
19
+
20
+ test_logpath = os.path.join(self.options.log_path, self.test_id)
21
+ file_name = str(file_name)
22
+ destination_folder = test_logpath
23
+ page_utils._save_data_as(data, destination_folder, file_name)
17
24
 
18
25
  def afterTest(self, test):
19
- """After each testcase, upload logs to the S3 bucket."""
26
+ """Upload logs to the S3 bucket after tests complete."""
27
+ from seleniumbase.core.s3_manager import S3LoggingBucket
28
+
29
+ self.test_id = test.test.id()
20
30
  s3_bucket = S3LoggingBucket()
21
31
  guid = str(uuid.uuid4().hex)
22
- path = os.path.join(self.options.log_path, test.test.id())
32
+ path = os.path.join(self.options.log_path, self.test_id)
23
33
  uploaded_files = []
24
34
  for logfile in os.listdir(path):
25
35
  logfile_name = "%s/%s/%s" % (
26
36
  guid,
27
- test.test.id(),
37
+ self.test_id,
28
38
  logfile.split(path)[-1],
29
39
  )
30
40
  s3_bucket.upload_file(logfile_name, os.path.join(path, logfile))
31
41
  uploaded_files.append(logfile_name)
32
42
  s3_bucket.save_uploaded_file_names(uploaded_files)
33
- index_file = s3_bucket.upload_index_file(test.id(), guid)
34
- print("\n\n*** Log files uploaded: ***\n%s\n" % index_file)
35
- logging.error("\n\n*** Log files uploaded: ***\n%s\n" % index_file)
43
+ index_file = s3_bucket.upload_index_file(
44
+ test.id(), guid, path, self.save_data_to_logs
45
+ )
46
+ print("\n*** Log files uploaded: ***\n%s\n" % index_file)
36
47
 
37
48
  # If the SB database plugin is also being used,
38
49
  # attach a link to the logs index database row.
@@ -329,11 +329,11 @@ def SB(
329
329
  record_sleep = True
330
330
  else:
331
331
  record_sleep = False
332
- if "linux" not in sys.platform:
332
+ if not shared_utils.is_linux():
333
333
  # The Xvfb virtual display server is for Linux OS Only!
334
334
  xvfb = False
335
335
  if (
336
- "linux" in sys.platform
336
+ shared_utils.is_linux()
337
337
  and not headed
338
338
  and not headless
339
339
  and not headless2
@@ -1,11 +1,11 @@
1
- """The screenshot plugin for selenium tests that run with nosetests."""
1
+ """Screenshot Plugin for SeleniumBase tests that run with pynose / nosetests"""
2
2
  import os
3
3
  from nose.plugins import Plugin
4
4
  from seleniumbase.config import settings
5
5
 
6
6
 
7
7
  class ScreenShots(Plugin):
8
- """This plugin takes a screenshot when a test fails or raises an error."""
8
+ """This plugin takes a screenshot when a test fails."""
9
9
  name = "screen_shots"
10
10
  logfile_name = settings.SCREENSHOT_NAME
11
11
 
@@ -1,14 +1,11 @@
1
- """The Nosetest plugin for setting Selenium test configuration."""
1
+ """Selenium Plugin for SeleniumBase tests that run with pynose / nosetests"""
2
2
  import sys
3
3
  from nose.plugins import Plugin
4
4
  from seleniumbase import config as sb_config
5
5
  from seleniumbase.config import settings
6
6
  from seleniumbase.core import proxy_helper
7
7
  from seleniumbase.fixtures import constants
8
-
9
- is_windows = False
10
- if sys.platform in ["win32", "win64", "x64"]:
11
- is_windows = True
8
+ from seleniumbase.fixtures import shared_utils
12
9
 
13
10
 
14
11
  class SeleniumBrowser(Plugin):
@@ -1150,7 +1147,7 @@ class SeleniumBrowser(Plugin):
1150
1147
  if str(self.options.port) == "443":
1151
1148
  test.test.protocol = "https"
1152
1149
  if (
1153
- "linux" in sys.platform
1150
+ shared_utils.is_linux()
1154
1151
  and not self.options.headed
1155
1152
  and not self.options.headless
1156
1153
  and not self.options.headless2
@@ -1198,7 +1195,7 @@ class SeleniumBrowser(Plugin):
1198
1195
  sb_config.headless_active = False
1199
1196
  self.headless_active = False
1200
1197
  if (
1201
- "linux" in sys.platform
1198
+ shared_utils.is_linux()
1202
1199
  and (not self.options.headed or self.options.xvfb)
1203
1200
  ):
1204
1201
  width = settings.HEADLESS_START_WIDTH
@@ -1235,7 +1232,7 @@ class SeleniumBrowser(Plugin):
1235
1232
  try:
1236
1233
  # If the browser window is still open, close it now.
1237
1234
  if (
1238
- not is_windows
1235
+ not shared_utils.is_windows()
1239
1236
  or test.test.browser == "ie"
1240
1237
  or self.driver.service.process
1241
1238
  ):