seleniumbase 4.33.5__py3-none-any.whl → 4.33.7__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1451,7 +1451,7 @@ class BaseCase(unittest.TestCase):
1451
1451
  return self.__is_shadow_element_enabled(selector)
1452
1452
  return page_actions.is_element_enabled(self.driver, selector, by)
1453
1453
 
1454
- def is_text_visible(self, text, selector="html", by="css selector"):
1454
+ def is_text_visible(self, text, selector="body", by="css selector"):
1455
1455
  """Returns whether the text substring is visible in the element."""
1456
1456
  self.wait_for_ready_state_complete()
1457
1457
  time.sleep(0.01)
@@ -1460,7 +1460,7 @@ class BaseCase(unittest.TestCase):
1460
1460
  return self.__is_shadow_text_visible(text, selector)
1461
1461
  return page_actions.is_text_visible(self.driver, text, selector, by)
1462
1462
 
1463
- def is_exact_text_visible(self, text, selector="html", by="css selector"):
1463
+ def is_exact_text_visible(self, text, selector="body", by="css selector"):
1464
1464
  """Returns whether the text is exactly equal to the element text.
1465
1465
  (Leading and trailing whitespace is ignored in the verification.)"""
1466
1466
  self.wait_for_ready_state_complete()
@@ -1472,7 +1472,7 @@ class BaseCase(unittest.TestCase):
1472
1472
  self.driver, text, selector, by
1473
1473
  )
1474
1474
 
1475
- def is_non_empty_text_visible(self, selector="html", by="css selector"):
1475
+ def is_non_empty_text_visible(self, selector="body", by="css selector"):
1476
1476
  """Returns whether the element has any non-empty text visible.
1477
1477
  Whitespace-only text is considered empty text."""
1478
1478
  self.wait_for_ready_state_complete()
@@ -1842,7 +1842,7 @@ class BaseCase(unittest.TestCase):
1842
1842
  elif self.slow_mode:
1843
1843
  self.__slow_mode_pause_if_active()
1844
1844
 
1845
- def get_text(self, selector="html", by="css selector", timeout=None):
1845
+ def get_text(self, selector="body", by="css selector", timeout=None):
1846
1846
  self.__check_scope()
1847
1847
  if not timeout:
1848
1848
  timeout = settings.LARGE_TIMEOUT
@@ -2105,7 +2105,7 @@ class BaseCase(unittest.TestCase):
2105
2105
  return property_value
2106
2106
 
2107
2107
  def get_text_content(
2108
- self, selector="html", by="css selector", timeout=None
2108
+ self, selector="body", by="css selector", timeout=None
2109
2109
  ):
2110
2110
  """Returns the text that appears in the HTML for an element.
2111
2111
  This is different from "self.get_text(selector, by="css selector")"
@@ -6093,7 +6093,7 @@ class BaseCase(unittest.TestCase):
6093
6093
  if limit > 0 and count >= limit:
6094
6094
  break
6095
6095
 
6096
- def press_up_arrow(self, selector="html", times=1, by="css selector"):
6096
+ def press_up_arrow(self, selector="body", times=1, by="css selector"):
6097
6097
  """Simulates pressing the UP Arrow on the keyboard.
6098
6098
  By default, "html" will be used as the CSS Selector target.
6099
6099
  You can specify how many times in-a-row the action happens."""
@@ -6115,7 +6115,7 @@ class BaseCase(unittest.TestCase):
6115
6115
  if self.slow_mode:
6116
6116
  time.sleep(0.1)
6117
6117
 
6118
- def press_down_arrow(self, selector="html", times=1, by="css selector"):
6118
+ def press_down_arrow(self, selector="body", times=1, by="css selector"):
6119
6119
  """Simulates pressing the DOWN Arrow on the keyboard.
6120
6120
  By default, "html" will be used as the CSS Selector target.
6121
6121
  You can specify how many times in-a-row the action happens."""
@@ -6137,7 +6137,7 @@ class BaseCase(unittest.TestCase):
6137
6137
  if self.slow_mode:
6138
6138
  time.sleep(0.1)
6139
6139
 
6140
- def press_left_arrow(self, selector="html", times=1, by="css selector"):
6140
+ def press_left_arrow(self, selector="body", times=1, by="css selector"):
6141
6141
  """Simulates pressing the LEFT Arrow on the keyboard.
6142
6142
  By default, "html" will be used as the CSS Selector target.
6143
6143
  You can specify how many times in-a-row the action happens."""
@@ -6159,7 +6159,7 @@ class BaseCase(unittest.TestCase):
6159
6159
  if self.slow_mode:
6160
6160
  time.sleep(0.1)
6161
6161
 
6162
- def press_right_arrow(self, selector="html", times=1, by="css selector"):
6162
+ def press_right_arrow(self, selector="body", times=1, by="css selector"):
6163
6163
  """Simulates pressing the RIGHT Arrow on the keyboard.
6164
6164
  By default, "html" will be used as the CSS Selector target.
6165
6165
  You can specify how many times in-a-row the action happens."""
@@ -7042,6 +7042,8 @@ class BaseCase(unittest.TestCase):
7042
7042
  constants.PipInstall.FINDLOCK
7043
7043
  )
7044
7044
  with pip_find_lock:
7045
+ with suppress(Exception):
7046
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
7045
7047
  if sys.version_info < (3, 9):
7046
7048
  # Fix bug in newer cryptography for Python 3.7 and 3.8:
7047
7049
  # "pyo3_runtime.PanicException: Python API call failed"
@@ -7292,6 +7294,8 @@ class BaseCase(unittest.TestCase):
7292
7294
  constants.PipInstall.FINDLOCK
7293
7295
  )
7294
7296
  with pip_find_lock:
7297
+ with suppress(Exception):
7298
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
7295
7299
  try:
7296
7300
  from PIL import Image, ImageDraw
7297
7301
  except Exception:
@@ -7337,6 +7341,10 @@ class BaseCase(unittest.TestCase):
7337
7341
  constants.MultiBrowser.DOWNLOAD_FILE_LOCK
7338
7342
  )
7339
7343
  with download_file_lock:
7344
+ with suppress(Exception):
7345
+ shared_utils.make_writable(
7346
+ constants.MultiBrowser.DOWNLOAD_FILE_LOCK
7347
+ )
7340
7348
  if not destination_folder:
7341
7349
  destination_folder = constants.Files.DOWNLOADS_FOLDER
7342
7350
  if not os.path.exists(destination_folder):
@@ -7357,6 +7365,10 @@ class BaseCase(unittest.TestCase):
7357
7365
  constants.MultiBrowser.DOWNLOAD_FILE_LOCK
7358
7366
  )
7359
7367
  with download_file_lock:
7368
+ with suppress(Exception):
7369
+ shared_utils.make_writable(
7370
+ constants.MultiBrowser.DOWNLOAD_FILE_LOCK
7371
+ )
7360
7372
  if not destination_folder:
7361
7373
  destination_folder = constants.Files.DOWNLOADS_FOLDER
7362
7374
  if not os.path.exists(destination_folder):
@@ -7462,6 +7474,8 @@ class BaseCase(unittest.TestCase):
7462
7474
  constants.MultiBrowser.FILE_IO_LOCK
7463
7475
  )
7464
7476
  with file_io_lock:
7477
+ with suppress(Exception):
7478
+ shared_utils.make_writable(constants.MultiBrowser.FILE_IO_LOCK)
7465
7479
  with open(fpath, "r") as f:
7466
7480
  data = f.read().strip()
7467
7481
  return data
@@ -9716,7 +9730,7 @@ class BaseCase(unittest.TestCase):
9716
9730
  ############
9717
9731
 
9718
9732
  def wait_for_text_visible(
9719
- self, text, selector="html", by="css selector", timeout=None
9733
+ self, text, selector="body", by="css selector", timeout=None
9720
9734
  ):
9721
9735
  self.__check_scope()
9722
9736
  if not timeout:
@@ -9734,7 +9748,7 @@ class BaseCase(unittest.TestCase):
9734
9748
  )
9735
9749
 
9736
9750
  def wait_for_exact_text_visible(
9737
- self, text, selector="html", by="css selector", timeout=None
9751
+ self, text, selector="body", by="css selector", timeout=None
9738
9752
  ):
9739
9753
  self.__check_scope()
9740
9754
  if not timeout:
@@ -9751,7 +9765,7 @@ class BaseCase(unittest.TestCase):
9751
9765
  )
9752
9766
 
9753
9767
  def wait_for_non_empty_text_visible(
9754
- self, selector="html", by="css selector", timeout=None
9768
+ self, selector="body", by="css selector", timeout=None
9755
9769
  ):
9756
9770
  """Searches for any text in the element of the given selector.
9757
9771
  Returns the element if it has visible text within the timeout.
@@ -9772,7 +9786,7 @@ class BaseCase(unittest.TestCase):
9772
9786
  )
9773
9787
 
9774
9788
  def wait_for_text(
9775
- self, text, selector="html", by="css selector", timeout=None
9789
+ self, text, selector="body", by="css selector", timeout=None
9776
9790
  ):
9777
9791
  """The shorter version of wait_for_text_visible()"""
9778
9792
  self.__check_scope()
@@ -9785,7 +9799,7 @@ class BaseCase(unittest.TestCase):
9785
9799
  )
9786
9800
 
9787
9801
  def wait_for_exact_text(
9788
- self, text, selector="html", by="css selector", timeout=None
9802
+ self, text, selector="body", by="css selector", timeout=None
9789
9803
  ):
9790
9804
  """The shorter version of wait_for_exact_text_visible()"""
9791
9805
  self.__check_scope()
@@ -9798,7 +9812,7 @@ class BaseCase(unittest.TestCase):
9798
9812
  )
9799
9813
 
9800
9814
  def wait_for_non_empty_text(
9801
- self, selector="html", by="css selector", timeout=None
9815
+ self, selector="body", by="css selector", timeout=None
9802
9816
  ):
9803
9817
  """The shorter version of wait_for_non_empty_text_visible()"""
9804
9818
  self.__check_scope()
@@ -9811,7 +9825,7 @@ class BaseCase(unittest.TestCase):
9811
9825
  )
9812
9826
 
9813
9827
  def find_text(
9814
- self, text, selector="html", by="css selector", timeout=None
9828
+ self, text, selector="body", by="css selector", timeout=None
9815
9829
  ):
9816
9830
  """Same as wait_for_text_visible() - returns the element"""
9817
9831
  self.__check_scope()
@@ -9824,7 +9838,7 @@ class BaseCase(unittest.TestCase):
9824
9838
  )
9825
9839
 
9826
9840
  def find_exact_text(
9827
- self, text, selector="html", by="css selector", timeout=None
9841
+ self, text, selector="body", by="css selector", timeout=None
9828
9842
  ):
9829
9843
  """Same as wait_for_exact_text_visible() - returns the element"""
9830
9844
  self.__check_scope()
@@ -9837,7 +9851,7 @@ class BaseCase(unittest.TestCase):
9837
9851
  )
9838
9852
 
9839
9853
  def find_non_empty_text(
9840
- self, selector="html", by="css selector", timeout=None
9854
+ self, selector="body", by="css selector", timeout=None
9841
9855
  ):
9842
9856
  """Same as wait_for_non_empty_text_visible() - returns the element"""
9843
9857
  self.__check_scope()
@@ -9850,7 +9864,7 @@ class BaseCase(unittest.TestCase):
9850
9864
  )
9851
9865
 
9852
9866
  def assert_text_visible(
9853
- self, text, selector="html", by="css selector", timeout=None
9867
+ self, text, selector="body", by="css selector", timeout=None
9854
9868
  ):
9855
9869
  """Same as assert_text()"""
9856
9870
  self.__check_scope()
@@ -9861,7 +9875,7 @@ class BaseCase(unittest.TestCase):
9861
9875
  return self.assert_text(text, selector, by=by, timeout=timeout)
9862
9876
 
9863
9877
  def assert_text(
9864
- self, text, selector="html", by="css selector", timeout=None
9878
+ self, text, selector="body", by="css selector", timeout=None
9865
9879
  ):
9866
9880
  """Similar to wait_for_text_visible()
9867
9881
  Raises an exception if the element or the text is not found.
@@ -9931,7 +9945,7 @@ class BaseCase(unittest.TestCase):
9931
9945
  return True
9932
9946
 
9933
9947
  def assert_exact_text(
9934
- self, text, selector="html", by="css selector", timeout=None
9948
+ self, text, selector="body", by="css selector", timeout=None
9935
9949
  ):
9936
9950
  """Similar to assert_text(), but the text must be exact,
9937
9951
  rather than exist as a subset of the full text.
@@ -9978,7 +9992,7 @@ class BaseCase(unittest.TestCase):
9978
9992
  return True
9979
9993
 
9980
9994
  def assert_non_empty_text(
9981
- self, selector="html", by="css selector", timeout=None
9995
+ self, selector="body", by="css selector", timeout=None
9982
9996
  ):
9983
9997
  """Assert that the element has any non-empty text visible.
9984
9998
  Raises an exception if the element has no text within the timeout.
@@ -10265,7 +10279,7 @@ class BaseCase(unittest.TestCase):
10265
10279
  ############
10266
10280
 
10267
10281
  def wait_for_text_not_visible(
10268
- self, text, selector="html", by="css selector", timeout=None
10282
+ self, text, selector="body", by="css selector", timeout=None
10269
10283
  ):
10270
10284
  self.__check_scope()
10271
10285
  if not timeout:
@@ -10278,7 +10292,7 @@ class BaseCase(unittest.TestCase):
10278
10292
  )
10279
10293
 
10280
10294
  def wait_for_exact_text_not_visible(
10281
- self, text, selector="html", by="css selector", timeout=None
10295
+ self, text, selector="body", by="css selector", timeout=None
10282
10296
  ):
10283
10297
  self.__check_scope()
10284
10298
  if not timeout:
@@ -10291,7 +10305,7 @@ class BaseCase(unittest.TestCase):
10291
10305
  )
10292
10306
 
10293
10307
  def assert_text_not_visible(
10294
- self, text, selector="html", by="css selector", timeout=None
10308
+ self, text, selector="body", by="css selector", timeout=None
10295
10309
  ):
10296
10310
  """Similar to wait_for_text_not_visible()
10297
10311
  Raises an exception if the text is still visible after timeout.
@@ -10312,7 +10326,7 @@ class BaseCase(unittest.TestCase):
10312
10326
  return True
10313
10327
 
10314
10328
  def assert_exact_text_not_visible(
10315
- self, text, selector="html", by="css selector", timeout=None
10329
+ self, text, selector="body", by="css selector", timeout=None
10316
10330
  ):
10317
10331
  """Similar to wait_for_exact_text_not_visible()
10318
10332
  Raises an exception if the exact text is still visible after timeout.
@@ -11069,7 +11083,7 @@ class BaseCase(unittest.TestCase):
11069
11083
  return False
11070
11084
 
11071
11085
  def deferred_assert_text(
11072
- self, text, selector="html", by="css selector", timeout=None, fs=False
11086
+ self, text, selector="body", by="css selector", timeout=None, fs=False
11073
11087
  ):
11074
11088
  """A non-terminating assertion for text from an element on a page.
11075
11089
  Failures will be saved until the process_deferred_asserts()
@@ -11105,7 +11119,7 @@ class BaseCase(unittest.TestCase):
11105
11119
  return False
11106
11120
 
11107
11121
  def deferred_assert_exact_text(
11108
- self, text, selector="html", by="css selector", timeout=None, fs=False
11122
+ self, text, selector="body", by="css selector", timeout=None, fs=False
11109
11123
  ):
11110
11124
  """A non-terminating assertion for exact text from an element.
11111
11125
  Failures will be saved until the process_deferred_asserts()
@@ -11144,7 +11158,7 @@ class BaseCase(unittest.TestCase):
11144
11158
 
11145
11159
  def deferred_assert_non_empty_text(
11146
11160
  self,
11147
- selector="html",
11161
+ selector="body",
11148
11162
  by="css selector",
11149
11163
  timeout=None,
11150
11164
  fs=False,
@@ -11264,7 +11278,7 @@ class BaseCase(unittest.TestCase):
11264
11278
  )
11265
11279
 
11266
11280
  def delayed_assert_text(
11267
- self, text, selector="html", by="css selector", timeout=None, fs=False
11281
+ self, text, selector="body", by="css selector", timeout=None, fs=False
11268
11282
  ):
11269
11283
  """Same as self.deferred_assert_text()"""
11270
11284
  return self.deferred_assert_text(
@@ -11272,7 +11286,7 @@ class BaseCase(unittest.TestCase):
11272
11286
  )
11273
11287
 
11274
11288
  def delayed_assert_exact_text(
11275
- self, text, selector="html", by="css selector", timeout=None, fs=False
11289
+ self, text, selector="body", by="css selector", timeout=None, fs=False
11276
11290
  ):
11277
11291
  """Same as self.deferred_assert_exact_text()"""
11278
11292
  return self.deferred_assert_exact_text(
@@ -11281,7 +11295,7 @@ class BaseCase(unittest.TestCase):
11281
11295
 
11282
11296
  def delayed_assert_non_empty_text(
11283
11297
  self,
11284
- selector="html",
11298
+ selector="body",
11285
11299
  by="css selector",
11286
11300
  timeout=None,
11287
11301
  fs=False,
@@ -14057,19 +14071,12 @@ class BaseCase(unittest.TestCase):
14057
14071
  with pip_find_lock:
14058
14072
  pass
14059
14073
  except Exception:
14060
- # Need write permissions
14061
- with suppress(Exception):
14062
- mode = os.stat(constants.PipInstall.FINDLOCK).st_mode
14063
- mode |= (mode & 0o444) >> 1 # copy R bits to W
14064
- os.chmod(constants.PipInstall.FINDLOCK, mode)
14065
- try:
14066
- with pip_find_lock:
14067
- pass
14068
- except Exception:
14069
- # Since missing permissions, skip the locks
14070
- self.__activate_virtual_display()
14071
- return
14074
+ # Since missing permissions, skip the locks
14075
+ self.__activate_virtual_display()
14076
+ return
14072
14077
  with pip_find_lock: # Prevent issues with multiple processes
14078
+ with suppress(Exception):
14079
+ shared_utils.make_writable(constants.PipInstall.FINDLOCK)
14073
14080
  self.__activate_virtual_display()
14074
14081
 
14075
14082
  def __ad_block_as_needed(self):
@@ -15091,6 +15098,10 @@ class BaseCase(unittest.TestCase):
15091
15098
  if self.dashboard:
15092
15099
  if self._multithreaded:
15093
15100
  with self.dash_lock:
15101
+ with suppress(Exception):
15102
+ shared_utils.make_writable(
15103
+ constants.Dashboard.LOCKFILE
15104
+ )
15094
15105
  if not self._dash_initialized:
15095
15106
  sb_config._dashboard_initialized = True
15096
15107
  self._dash_initialized = True
@@ -15650,6 +15661,8 @@ class BaseCase(unittest.TestCase):
15650
15661
  constants.Dashboard.LOCKFILE
15651
15662
  )
15652
15663
  with self.dash_lock:
15664
+ with suppress(Exception):
15665
+ shared_utils.make_writable(constants.Dashboard.LOCKFILE)
15653
15666
  self.__process_dashboard(has_exception, init)
15654
15667
  else:
15655
15668
  self.__process_dashboard(has_exception, init)
@@ -16419,6 +16432,10 @@ class BaseCase(unittest.TestCase):
16419
16432
  if self.dashboard:
16420
16433
  if self._multithreaded:
16421
16434
  with self.dash_lock:
16435
+ with suppress(Exception):
16436
+ shared_utils.make_writable(
16437
+ constants.Dashboard.LOCKFILE
16438
+ )
16422
16439
  self.__process_dashboard(has_exception)
16423
16440
  else:
16424
16441
  self.__process_dashboard(has_exception)
@@ -1188,6 +1188,8 @@ def highlight_with_jquery_2(driver, message, selector, o_bs, msg_dur):
1188
1188
  def get_active_element_css(driver):
1189
1189
  from seleniumbase.js_code import active_css_js
1190
1190
 
1191
+ if shared_utils.is_cdp_swap_needed(driver):
1192
+ return driver.cdp.get_active_element_css()
1191
1193
  return execute_script(driver, active_css_js.get_active_element_css)
1192
1194
 
1193
1195
 
@@ -1,6 +1,7 @@
1
1
  """Shared utility methods"""
2
2
  import colorama
3
3
  import os
4
+ import pathlib
4
5
  import platform
5
6
  import sys
6
7
  import time
@@ -128,6 +129,30 @@ def is_chrome_130_or_newer(self, binary_location=None):
128
129
  return False
129
130
 
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
+
131
156
  def format_exc(exception, message):
132
157
  """Formats an exception message to make the output cleaner."""
133
158
  from selenium.common.exceptions import ElementNotVisibleException
@@ -2143,6 +2143,9 @@ def _perform_pytest_unconfigure_(config):
2143
2143
  log_helper.archive_logs_if_set(
2144
2144
  constants.Logs.LATEST + "/", sb_config.archive_logs
2145
2145
  )
2146
+ if os.path.exists("./assets/"): # Used by pytest-html reports
2147
+ with suppress(Exception):
2148
+ shared_utils.make_dir_files_writable("./assets/")
2146
2149
  log_helper.clear_empty_logs()
2147
2150
  # Dashboard post-processing: Disable time-based refresh and stamp complete
2148
2151
  if not hasattr(sb_config, "dashboard") or not sb_config.dashboard:
@@ -2207,8 +2210,28 @@ def _perform_pytest_unconfigure_(config):
2207
2210
  )
2208
2211
  with open(html_report_path, "w", encoding="utf-8") as f:
2209
2212
  f.write(the_html_r) # Finalize the HTML report
2213
+ with suppress(Exception):
2214
+ shared_utils.make_writable(html_report_path)
2210
2215
  with open(html_report_path_copy, "w", encoding="utf-8") as f:
2211
- f.write(the_html_r) # Finalize the HTML report
2216
+ f.write(the_html_r) # Finalize the HTML report copy
2217
+ with suppress(Exception):
2218
+ shared_utils.make_writable(html_report_path_copy)
2219
+ assets_style = "./assets/style.css"
2220
+ if os.path.exists(assets_style):
2221
+ html_style = None
2222
+ with open(assets_style, "r", encoding="utf-8") as f:
2223
+ html_style = f.read()
2224
+ if html_style:
2225
+ html_style = html_style.replace("top: -50px;", "top: 2px;")
2226
+ html_style = html_style.replace("+ 50px)", "+ 40px)")
2227
+ html_style = html_style.replace("ht: 240px;", "ht: 228px;")
2228
+ html_style = html_style.replace(
2229
+ "- 80px);", "- 80px);\n margin-bottom: -42px;"
2230
+ )
2231
+ with open(assets_style, "w", encoding="utf-8") as f:
2232
+ f.write(html_style)
2233
+ with suppress(Exception):
2234
+ shared_utils.make_writable(assets_style)
2212
2235
  # Done with "pytest_unconfigure" unless using the Dashboard
2213
2236
  return
2214
2237
  stamp = ""
@@ -2290,6 +2313,24 @@ def _perform_pytest_unconfigure_(config):
2290
2313
  )
2291
2314
  with open(dashboard_path, "w", encoding="utf-8") as f:
2292
2315
  f.write(the_html_d) # Finalize the dashboard
2316
+ with suppress(Exception):
2317
+ shared_utils.make_writable(dashboard_path)
2318
+ assets_style = "./assets/style.css"
2319
+ if os.path.exists(assets_style):
2320
+ html_style = None
2321
+ with open(assets_style, "r", encoding="utf-8") as f:
2322
+ html_style = f.read()
2323
+ if html_style:
2324
+ html_style = html_style.replace("top: -50px;", "top: 2px;")
2325
+ html_style = html_style.replace("+ 50px)", "+ 40px)")
2326
+ html_style = html_style.replace("ht: 240px;", "ht: 228px;")
2327
+ html_style = html_style.replace(
2328
+ "- 80px);", "- 80px);\n margin-bottom: -42px;"
2329
+ )
2330
+ with open(assets_style, "w", encoding="utf-8") as f:
2331
+ f.write(html_style)
2332
+ with suppress(Exception):
2333
+ shared_utils.make_writable(assets_style)
2293
2334
  # Part 2: Appending a pytest html report with dashboard data
2294
2335
  html_report_path = None
2295
2336
  if sb_config._html_report_name:
@@ -2370,8 +2411,12 @@ def _perform_pytest_unconfigure_(config):
2370
2411
  )
2371
2412
  with open(html_report_path, "w", encoding="utf-8") as f:
2372
2413
  f.write(the_html_r) # Finalize the HTML report
2414
+ with suppress(Exception):
2415
+ shared_utils.make_writable(html_report_path)
2373
2416
  with open(html_report_path_copy, "w", encoding="utf-8") as f:
2374
- f.write(the_html_r) # Finalize the HTML report
2417
+ f.write(the_html_r) # Finalize the HTML report copy
2418
+ with suppress(Exception):
2419
+ shared_utils.make_writable(html_report_path_copy)
2375
2420
  except KeyboardInterrupt:
2376
2421
  pass
2377
2422
  except Exception:
@@ -883,6 +883,8 @@ class Element:
883
883
  self,
884
884
  duration: typing.Union[float, int] = 0.5,
885
885
  color: typing.Optional[str] = "EE4488",
886
+ x_offset: typing.Union[float, int] = 0,
887
+ y_offset: typing.Union[float, int] = 0,
886
888
  ):
887
889
  """
888
890
  Displays for a short time a red dot on the element.
@@ -910,8 +912,8 @@ class Element:
910
912
  "width:8px;height:8px;border-radius:50%;background:#{};"
911
913
  "animation:show-pointer-ani {:.2f}s ease 1;"
912
914
  ).format(
913
- pos.center[0] - 4, # -4 to account for drawn circle itself (w,h)
914
- pos.center[1] - 4,
915
+ pos.center[0] + x_offset - 4, # -4 to account for the circle
916
+ pos.center[1] + y_offset - 4, # -4 to account for the circle
915
917
  color,
916
918
  duration,
917
919
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: seleniumbase
3
- Version: 4.33.5
3
+ Version: 4.33.7
4
4
  Summary: A complete web automation framework for end-to-end testing.
5
5
  Home-page: https://github.com/seleniumbase/SeleniumBase
6
6
  Author: Michael Mintz
@@ -126,7 +126,7 @@ Requires-Dist: allure-python-commons>=2.13.5; extra == "allure"
126
126
  Requires-Dist: allure-behave>=2.13.5; extra == "allure"
127
127
  Provides-Extra: coverage
128
128
  Requires-Dist: coverage>=7.6.1; python_version < "3.9" and extra == "coverage"
129
- Requires-Dist: coverage>=7.6.8; python_version >= "3.9" and extra == "coverage"
129
+ Requires-Dist: coverage>=7.6.9; python_version >= "3.9" and extra == "coverage"
130
130
  Requires-Dist: pytest-cov>=5.0.0; python_version < "3.9" and extra == "coverage"
131
131
  Requires-Dist: pytest-cov>=6.0.0; python_version >= "3.9" and extra == "coverage"
132
132
  Provides-Extra: flake8
@@ -3,7 +3,7 @@ sbase/__main__.py,sha256=G0bVB1-DM4PGwQ1KyOupaWCs4ePbChZNNWuX2htim5U,647
3
3
  sbase/steps.py,sha256=_WvAjydKqZfTdnZW9LPKkRty-g-lfdUPmLqnZj6ulcs,43013
4
4
  seleniumbase/__init__.py,sha256=OtJh8nGKL4xtZpw8KPqmn7Q6R-86t4cWUDyVF5MbMTo,2398
5
5
  seleniumbase/__main__.py,sha256=dn1p6dgCchmcH1zzTzzQvFwwdQQqnTGH6ULV9m4hv24,654
6
- seleniumbase/__version__.py,sha256=0yzphBzPKyJTvl0mwJ0ISMXG0RNjbnOoBiyWcsdGWqw,46
6
+ seleniumbase/__version__.py,sha256=nUNoxjUDcXHP7bgCzQttf4Edyro2DVTDgt8rIwb4KXs,46
7
7
  seleniumbase/behave/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  seleniumbase/behave/behave_helper.py,sha256=elkl8P9eLulRAioLstE9baYNM9N_PHBmAOcajX-pH_Y,24198
9
9
  seleniumbase/behave/behave_sb.py,sha256=-hza7Nx2U41mSObYiPMi48v3JlPh3sJO3yzP0kqZ1Gk,59174
@@ -36,7 +36,7 @@ seleniumbase/console_scripts/sb_print.py,sha256=tNy-bMDgwHJO3bZxMpmo9weSE8uhbH0C
36
36
  seleniumbase/console_scripts/sb_recorder.py,sha256=fnHb5-kh11Hit-E9Ha-e4QXzqLcZvtij6mb5qNd4B1Q,11032
37
37
  seleniumbase/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
38
  seleniumbase/core/application_manager.py,sha256=e_0sjtI8cjY5BNyZj1QBR0j6_oCScxGmSXYEpcYwuZE,576
39
- seleniumbase/core/browser_launcher.py,sha256=AX1kLcURKVPcZPYG30PSB1Q49revm-9PA_aelPP4Hok,221596
39
+ seleniumbase/core/browser_launcher.py,sha256=0J5J7kXG30aptlPQ3JdFcu8-U4lC_Y6U_47kkHbyKoo,224666
40
40
  seleniumbase/core/capabilities_parser.py,sha256=meIS2uHapTCq2ldfNAToC7r0cKmZDRXuYNKExM1GHDY,6038
41
41
  seleniumbase/core/colored_traceback.py,sha256=DrRWfg7XEnKcgY59Xj7Jdk09H-XqHYBSUpB-DiZt6iY,2020
42
42
  seleniumbase/core/create_db_tables.sql,sha256=VWPtrdiW_HQ6yETHjqTu-VIrTwvd8I8o1NfBeaVSHpU,972
@@ -44,17 +44,17 @@ seleniumbase/core/detect_b_ver.py,sha256=RxeGRMbBUTMrXh5KsS1P1SH7eEKYbzL1vQw1gTd
44
44
  seleniumbase/core/download_helper.py,sha256=qSR54kQISucF4RQaLCOuuerSu6DR41juGi_30HVvWYY,2943
45
45
  seleniumbase/core/encoded_images.py,sha256=rDKJ4cNJSuKiRcFViYU7bjyTS9_moI57gUPRXVg3u2k,14209
46
46
  seleniumbase/core/jqc_helper.py,sha256=2DDQr9Q2jSSZqFzX588jLlUM9oJvyrRWq2aORSIPUdI,10322
47
- seleniumbase/core/log_helper.py,sha256=T_nPPSRSjhqt6TTzVE6pN1owVvIeRBNF5pWK6sl4dMY,22609
47
+ seleniumbase/core/log_helper.py,sha256=N0YbsRy8sEoGQu4BjiAJHC5mK_ydl0YLgRp6jAcwwos,22987
48
48
  seleniumbase/core/mysql.py,sha256=8Fzj3p5dhtDWfMpFqFYxpSwa9s1UltiHsWJ56_aPOqk,3993
49
- seleniumbase/core/proxy_helper.py,sha256=cXhu8ErK9Vjdm82RMaQj7hEq_yUWizSp6LyiD50Ieu4,8020
49
+ seleniumbase/core/proxy_helper.py,sha256=kZnfkflB3XhuL2h-3inmx3UOLS8VAZ385BGCc4H8TvU,8267
50
50
  seleniumbase/core/recorder_helper.py,sha256=fNGjbapXmEsht54x1o6Igk198QdnPxDDnjUOzQxNhNQ,25055
51
51
  seleniumbase/core/report_helper.py,sha256=AIl6Qava2yW1uSzbLpJBlPlYDz0KE-rVhogh8hsGWBo,12201
52
52
  seleniumbase/core/s3_manager.py,sha256=bkeI8I4y19ebWuQG1oEZV5qJbotC6eN8vin31OCNWJk,3521
53
- seleniumbase/core/sb_cdp.py,sha256=NyiooRREzeRQYITMiE9b0WwcH3-u8tMsy-cLJSnxerc,67644
53
+ seleniumbase/core/sb_cdp.py,sha256=Z2do1FqwfFAK-xgrZ6f_-wTMf3DSbI-ShHRZ34nFy5w,70437
54
54
  seleniumbase/core/sb_driver.py,sha256=NGa4adi8OAi2WFtFkEguXg3JCd1p-JuZweIpGNifEfU,13488
55
55
  seleniumbase/core/session_helper.py,sha256=s9zD3PVZEWVzG2h81cCUskbNWLfdjC_LwwQjKptHCak,558
56
56
  seleniumbase/core/settings_parser.py,sha256=KokVXpCiGZhJ-D4Bo-hizPz5r-iefzWoiTANu9zNaq4,7504
57
- seleniumbase/core/style_sheet.py,sha256=tPpJ1xl6Kuw425Z-3Y0OgVRLGXk_ciBDREZjXk_NuPE,11395
57
+ seleniumbase/core/style_sheet.py,sha256=QsfTBtgedfM3uTqgxtd53bhq202p9fwLMbFl9mPZgVg,11892
58
58
  seleniumbase/core/testcase_manager.py,sha256=TblCfo8Zfap1Bayip-qTu9gqT-KALSwXAX4awBpnEHg,4633
59
59
  seleniumbase/core/tour_helper.py,sha256=kj2cz-DGKlw9SX3tWnVp-snpk6Flvqj81-xmKdKDtg0,42555
60
60
  seleniumbase/core/visual_helper.py,sha256=Dj5iJKw-bT_3e6KDqMf0sJi7xs_D96yqLcNc8fqhrjI,3408
@@ -65,14 +65,14 @@ seleniumbase/extensions/disable_csp.zip,sha256=YMifIIgEBiLrEFrS1sfW4Exh4br1V4oK1
65
65
  seleniumbase/extensions/recorder.zip,sha256=OOyzF-Ize2cSRu1CqhzSAq5vusI9hqLLd2OIApUHesI,11918
66
66
  seleniumbase/extensions/sbase_ext.zip,sha256=3s1N8zrVaMz8RQEOIoBzC3KDjtmHwVZRvVsX25Odr_s,8175
67
67
  seleniumbase/fixtures/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
- seleniumbase/fixtures/base_case.py,sha256=XsqsffZcEJfnA323DfgrFy-nRKIsRJ6r6ebylELaiLo,717662
68
+ seleniumbase/fixtures/base_case.py,sha256=6MVQDcQ8woA3sis2hH6epDaVNjefsd2m1xzjJn9mugs,718550
69
69
  seleniumbase/fixtures/constants.py,sha256=e1LppavlrAcI4XBJMq7u5j8SffaQ7SPQps1y0YvZYfY,13649
70
70
  seleniumbase/fixtures/css_to_xpath.py,sha256=9ouDB1xl4MJ2os6JOgTIAyHKOQfuxtxvXC3O5hSnEKA,1954
71
71
  seleniumbase/fixtures/errors.py,sha256=KyxuEVx_e3MPhVrJfNIa_3ltMpbCFxfy_jxK8RFNTns,555
72
- seleniumbase/fixtures/js_utils.py,sha256=t-hqdd75O6Kfe6y5U8986gvZGATpPfDiDnIqeZZodgw,51435
72
+ seleniumbase/fixtures/js_utils.py,sha256=asZJ0LDFv2BPQOzUVKK_9ie8ToGcmFousDnGdb3Vabg,51534
73
73
  seleniumbase/fixtures/page_actions.py,sha256=dbp63c-7asYZyd8aOu57Y3dxQQozp_VJsP5h74s1kBA,66552
74
74
  seleniumbase/fixtures/page_utils.py,sha256=5m7iXpikLs80TJoRO6_gEfXE1AKeQgcH1aFbR8o1C9A,12034
75
- seleniumbase/fixtures/shared_utils.py,sha256=WbPb15IvIWzRtMInKG8DUzJ26UZU-PixdOwTCjXQirU,7545
75
+ seleniumbase/fixtures/shared_utils.py,sha256=G6CsE-Adt-GfuZF-71jXWKSIQW7YZPx8FIM24pVd_yI,8368
76
76
  seleniumbase/fixtures/unittest_helper.py,sha256=sfZ92rZeBAn_sF_yQ3I6_I7h3lyU5-cV_UMegBNoEm8,1294
77
77
  seleniumbase/fixtures/words.py,sha256=FOA4mAYvl3EPVpBTvgvK6YwCL8BdlRCmed685kEe7Vg,7827
78
78
  seleniumbase/fixtures/xpath_to_css.py,sha256=lML56k656fElXJ4NJF07r35FjctrbgQkXUotNk7A-as,8876
@@ -88,7 +88,7 @@ seleniumbase/plugins/basic_test_info.py,sha256=8ov6n417gPbqqvrlT4zrch7l2XcRt-GF2
88
88
  seleniumbase/plugins/db_reporting_plugin.py,sha256=En09qUCoojrk9-vbcnsoHdSELoGmag2GDIyu3jTiJas,7331
89
89
  seleniumbase/plugins/driver_manager.py,sha256=s20s0pJYaNrG0WNwyIC04oUMRVFjtm6V_nS1-EvFm7g,34492
90
90
  seleniumbase/plugins/page_source.py,sha256=loTnXxOj4kxEukuTZEiGyvKBhY3KDVDMnNlHHheTBDE,1889
91
- seleniumbase/plugins/pytest_plugin.py,sha256=p8KTnx-xMuo2uLU-pXBj0d0EJYE_9Eb9jMeHC-zwyw8,102988
91
+ seleniumbase/plugins/pytest_plugin.py,sha256=JjpglUqHkfl6rzdg1SkJ7PMtNRpceOgLNbUi2DyKpJI,105416
92
92
  seleniumbase/plugins/s3_logging_plugin.py,sha256=WDfertQgGOW_SRJpFMaekYD6vBVW9VO62POtXXy2HCM,2319
93
93
  seleniumbase/plugins/sb_manager.py,sha256=qCf6RAkAfziLTGgiJvB3V416RxWoTbRLm9wc-KsB8g8,54419
94
94
  seleniumbase/plugins/screen_shots.py,sha256=1hrXw-hzuZ1BR6Yh7AyWX2ABnvnP73-RCbwdz958gj4,1127
@@ -119,7 +119,7 @@ seleniumbase/undetected/cdp_driver/browser.py,sha256=n8GYspU7b0pfBT4AqhqY6IdGVOZ
119
119
  seleniumbase/undetected/cdp_driver/cdp_util.py,sha256=YhtD2Tm6PLIy9VKbgk8lHdGniS3mObyX4yAC1aG0TgQ,16733
120
120
  seleniumbase/undetected/cdp_driver/config.py,sha256=Rjvde7V-XJ0ihZdTmOmHEVWSuDWm3SprQ3njg8SN3Go,12087
121
121
  seleniumbase/undetected/cdp_driver/connection.py,sha256=sOTUGjbUqKA2hPvDcRCdqw1VQjVGJs7mbgVvzS7ldtE,23360
122
- seleniumbase/undetected/cdp_driver/element.py,sha256=wEHtuF9oiny7cb4QMMjdtD5Yf1z3WOs2_NHEWcscusM,40289
122
+ seleniumbase/undetected/cdp_driver/element.py,sha256=610eW609khWp2hFn9gKUx4DDxeJdPZ5jb0Vxe1W-9PY,40426
123
123
  seleniumbase/undetected/cdp_driver/tab.py,sha256=cmSUg9fRnIVYgeqs-t8Tcg1FrSVIrM5IBQmCMzvl4OQ,50678
124
124
  seleniumbase/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
125
125
  seleniumbase/utilities/selenium_grid/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -135,9 +135,9 @@ seleniumbase/utilities/selenium_grid/start-grid-hub.bat,sha256=Ftq-GrAKRYH2ssDPr
135
135
  seleniumbase/utilities/selenium_grid/start-grid-hub.sh,sha256=KADv0RUHONLL2_I443QFK8PryBpDmKn5Gy0s4o0vDSM,106
136
136
  seleniumbase/utilities/selenium_ide/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
137
137
  seleniumbase/utilities/selenium_ide/convert_ide.py,sha256=pZFnqEJQEKZPyNFjkLD29s2HPQgCrWW9XJWpCPhWOoM,31691
138
- seleniumbase-4.33.5.dist-info/LICENSE,sha256=odSYtWibXBnQ1gBg6CnDZ82n8kLF_if5-2nbqnEyD8k,1085
139
- seleniumbase-4.33.5.dist-info/METADATA,sha256=D84rG0Bm0fkB2p5-CFUNlUUL8KvU5INS56CzgXjSVX4,86528
140
- seleniumbase-4.33.5.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
141
- seleniumbase-4.33.5.dist-info/entry_points.txt,sha256=CNrh2EKNaHYEhO6pP1RJyVLB99LkDDYX7TnUK8xfjqk,623
142
- seleniumbase-4.33.5.dist-info/top_level.txt,sha256=4N97aBOQ8ETCnDnokBsWb07lJfTaq3C1ZzYRxvLMxqU,19
143
- seleniumbase-4.33.5.dist-info/RECORD,,
138
+ seleniumbase-4.33.7.dist-info/LICENSE,sha256=odSYtWibXBnQ1gBg6CnDZ82n8kLF_if5-2nbqnEyD8k,1085
139
+ seleniumbase-4.33.7.dist-info/METADATA,sha256=iP-VXv10VT9xAD7UJPlD8tTJi7J88s6D3GCy1gvec6E,86528
140
+ seleniumbase-4.33.7.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
141
+ seleniumbase-4.33.7.dist-info/entry_points.txt,sha256=CNrh2EKNaHYEhO6pP1RJyVLB99LkDDYX7TnUK8xfjqk,623
142
+ seleniumbase-4.33.7.dist-info/top_level.txt,sha256=4N97aBOQ8ETCnDnokBsWb07lJfTaq3C1ZzYRxvLMxqU,19
143
+ seleniumbase-4.33.7.dist-info/RECORD,,