seleniumbase 4.30.8__py3-none-any.whl → 4.31.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. sbase/__init__.py +1 -0
  2. seleniumbase/__init__.py +2 -3
  3. seleniumbase/__version__.py +1 -1
  4. seleniumbase/behave/behave_sb.py +59 -11
  5. seleniumbase/config/settings.py +4 -0
  6. seleniumbase/console_scripts/logo_helper.py +47 -0
  7. seleniumbase/console_scripts/run.py +7 -4
  8. seleniumbase/console_scripts/sb_behave_gui.py +5 -5
  9. seleniumbase/console_scripts/sb_caseplans.py +6 -6
  10. seleniumbase/console_scripts/sb_commander.py +5 -5
  11. seleniumbase/console_scripts/sb_install.py +10 -2
  12. seleniumbase/console_scripts/sb_recorder.py +4 -4
  13. seleniumbase/core/browser_launcher.py +179 -108
  14. seleniumbase/core/mysql.py +1 -4
  15. seleniumbase/core/recorder_helper.py +24 -5
  16. seleniumbase/core/sb_driver.py +13 -3
  17. seleniumbase/core/settings_parser.py +4 -0
  18. seleniumbase/fixtures/base_case.py +324 -493
  19. seleniumbase/fixtures/js_utils.py +19 -52
  20. seleniumbase/fixtures/page_actions.py +3 -6
  21. seleniumbase/fixtures/page_utils.py +18 -53
  22. seleniumbase/plugins/base_plugin.py +2 -3
  23. seleniumbase/plugins/driver_manager.py +182 -5
  24. seleniumbase/plugins/pytest_plugin.py +51 -23
  25. seleniumbase/plugins/sb_manager.py +185 -5
  26. seleniumbase/plugins/selenium_plugin.py +71 -8
  27. seleniumbase/undetected/__init__.py +13 -38
  28. seleniumbase/undetected/dprocess.py +4 -6
  29. seleniumbase/undetected/options.py +3 -6
  30. seleniumbase/undetected/patcher.py +2 -3
  31. {seleniumbase-4.30.8.dist-info → seleniumbase-4.31.1.dist-info}/METADATA +111 -125
  32. {seleniumbase-4.30.8.dist-info → seleniumbase-4.31.1.dist-info}/RECORD +36 -47
  33. {seleniumbase-4.30.8.dist-info → seleniumbase-4.31.1.dist-info}/WHEEL +1 -1
  34. sbase/ReadMe.txt +0 -2
  35. seleniumbase/ReadMe.md +0 -25
  36. seleniumbase/common/ReadMe.md +0 -71
  37. seleniumbase/console_scripts/ReadMe.md +0 -734
  38. seleniumbase/drivers/ReadMe.md +0 -27
  39. seleniumbase/extensions/ReadMe.md +0 -12
  40. seleniumbase/masterqa/ReadMe.md +0 -61
  41. seleniumbase/resources/ReadMe.md +0 -31
  42. seleniumbase/resources/favicon.ico +0 -0
  43. seleniumbase/utilities/selenium_grid/ReadMe.md +0 -84
  44. seleniumbase/utilities/selenium_ide/ReadMe.md +0 -111
  45. {seleniumbase-4.30.8.dist-info → seleniumbase-4.31.1.dist-info}/LICENSE +0 -0
  46. {seleniumbase-4.30.8.dist-info → seleniumbase-4.31.1.dist-info}/entry_points.txt +0 -0
  47. {seleniumbase-4.30.8.dist-info → seleniumbase-4.31.1.dist-info}/top_level.txt +0 -0
sbase/__init__.py CHANGED
@@ -11,3 +11,4 @@ from seleniumbase import MasterQA # noqa
11
11
  from seleniumbase import page_actions # noqa
12
12
  from seleniumbase import page_utils # noqa
13
13
  from seleniumbase import SB # noqa
14
+ from seleniumbase import translate # noqa
seleniumbase/__init__.py CHANGED
@@ -10,7 +10,7 @@ from selenium import webdriver
10
10
  from seleniumbase.__version__ import __version__
11
11
  from seleniumbase.common import decorators # noqa
12
12
  from seleniumbase.common import encryption # noqa
13
- from seleniumbase.core import colored_traceback
13
+ from seleniumbase.core import colored_traceback # noqa
14
14
  from seleniumbase.core.browser_launcher import get_driver # noqa
15
15
  from seleniumbase.fixtures import js_utils # noqa
16
16
  from seleniumbase.fixtures import page_actions # noqa
@@ -36,8 +36,7 @@ if sys.version_info[0] < 3 and "pdbp" in locals():
36
36
  pdb.DefaultConfig.sticky_by_default = True
37
37
  colored_traceback.add_hook()
38
38
  os.environ["SE_AVOID_STATS"] = "true" # Disable Selenium Manager stats
39
- if sys.version_info >= (3, 7):
40
- webdriver.TouchActions = None # Lifeline for past selenium-wire versions
39
+ webdriver.TouchActions = None # Lifeline for past selenium-wire versions
41
40
  if sys.version_info >= (3, 10):
42
41
  collections.Callable = collections.abc.Callable # Lifeline for nosetests
43
42
  del collections # Undo "import collections" / Simplify "dir(seleniumbase)"
@@ -1,2 +1,2 @@
1
1
  # seleniumbase package
2
- __version__ = "4.30.8"
2
+ __version__ = "4.31.1"
@@ -44,10 +44,12 @@ behave -D agent="User Agent String" -D demo
44
44
  -D sjw (Skip JS Waits for readyState to be "complete" or Angular to load.)
45
45
  -D wfa (Wait for AngularJS to be done loading after specific web actions.)
46
46
  -D pls=PLS (Set pageLoadStrategy on Chrome: "normal", "eager", or "none".)
47
- -D headless (Run tests in headless mode. The default arg on Linux OS.)
48
- -D headless2 (Use the new headless mode, which supports extensions.)
47
+ -D headless (The default headless mode. Linux uses this mode by default.)
48
+ -D headless1 (Use Chrome's old headless mode. Fast, but has limitations.)
49
+ -D headless2 (Use Chrome's new headless mode, which supports extensions.)
49
50
  -D headed (Run tests in headed/GUI mode on Linux OS, where not default.)
50
51
  -D xvfb (Run tests using the Xvfb virtual display server on Linux OS.)
52
+ -D xvfb-metrics=STRING (Set Xvfb display size on Linux: "Width,Height".)
51
53
  -D locale=LOCALE_CODE (Set the Language Locale Code for the web browser.)
52
54
  -D pdb (Activate Post Mortem Debug Mode if a test fails.)
53
55
  -D interval=SECONDS (The autoplay interval for presentations & tour steps)
@@ -90,6 +92,7 @@ behave -D agent="User Agent String" -D demo
90
92
  -D rcs | -D reuse-class-session (Reuse session for tests in class/feature)
91
93
  -D crumbs (Delete all cookies between tests reusing a session.)
92
94
  -D disable-beforeunload (Disable the "beforeunload" event on Chrome.)
95
+ -D window-position=X,Y (Set the browser's starting window position.)
93
96
  -D window-size=WIDTH,HEIGHT (Set the browser's starting window size.)
94
97
  -D maximize (Start tests with the browser window maximized.)
95
98
  -D screenshot (Save a screenshot at the end of each test.)
@@ -104,6 +107,7 @@ import colorama
104
107
  import os
105
108
  import re
106
109
  import sys
110
+ from contextlib import suppress
107
111
  from seleniumbase import config as sb_config
108
112
  from seleniumbase.config import settings
109
113
  from seleniumbase.core import download_helper
@@ -141,10 +145,12 @@ def get_configured_sb(context):
141
145
  sb.browser = "chrome"
142
146
  sb.is_behave = True
143
147
  sb.headless = False
148
+ sb.headless1 = False
144
149
  sb.headless2 = False
145
150
  sb.headless_active = False
146
151
  sb.headed = False
147
152
  sb.xvfb = False
153
+ sb.xvfb_metrics = None
148
154
  sb.start_page = None
149
155
  sb.locale_code = None
150
156
  sb.pdb_option = False
@@ -193,6 +199,7 @@ def get_configured_sb(context):
193
199
  sb._disable_beforeunload = False
194
200
  sb.visual_baseline = False
195
201
  sb.use_wire = False
202
+ sb.window_position = None
196
203
  sb.window_size = None
197
204
  sb.maximize_option = False
198
205
  sb.is_context_manager = False
@@ -291,6 +298,11 @@ def get_configured_sb(context):
291
298
  sb.headless = True
292
299
  continue
293
300
  # Handle: -D headless2
301
+ if low_key == "headless1":
302
+ sb.headless1 = True
303
+ sb.headless = True
304
+ continue
305
+ # Handle: -D headless2
294
306
  if low_key == "headless2":
295
307
  sb.headless2 = True
296
308
  continue
@@ -302,6 +314,13 @@ def get_configured_sb(context):
302
314
  if low_key == "xvfb":
303
315
  sb.xvfb = True
304
316
  continue
317
+ # Handle: -D xvfb-metrics=STR / xvfb_metrics=STR
318
+ if low_key in ["xvfb-metrics", "xvfb_metrics"]:
319
+ xvfb_metrics = userdata[key]
320
+ if xvfb_metrics == "true":
321
+ xvfb_metrics = sb.xvfb_metrics # revert to default
322
+ sb.xvfb_metrics = xvfb_metrics
323
+ continue
305
324
  # Handle: -D start-page=URL / start_page=URL / url=URL
306
325
  if low_key in ["start-page", "start_page", "url"]:
307
326
  start_page = userdata[key]
@@ -601,6 +620,13 @@ def get_configured_sb(context):
601
620
  if low_key == "wire":
602
621
  sb.use_wire = True
603
622
  continue
623
+ # Handle: -D window-position=X,Y / window_position=X,Y
624
+ if low_key in ["window-position", "window_position"]:
625
+ window_position = userdata[key]
626
+ if window_position == "true":
627
+ window_position = sb.window_position # revert to default
628
+ sb.window_position = window_position
629
+ continue
604
630
  # Handle: -D window-size=Width,Height / window_size=Width,Height
605
631
  if low_key in ["window-size", "window_size"]:
606
632
  window_size = userdata[key]
@@ -845,6 +871,7 @@ def get_configured_sb(context):
845
871
  # Recorder Mode can still optimize scripts in "-D headless2" mode.
846
872
  if sb.recorder_ext and sb.headless:
847
873
  sb.headless = False
874
+ sb.headless1 = False
848
875
  sb.headless2 = True
849
876
  if sb.headless2 and sb.browser == "firefox":
850
877
  sb.headless2 = False # Only for Chromium browsers
@@ -881,11 +908,13 @@ def get_configured_sb(context):
881
908
  # Recorder Mode can still optimize scripts in --headless2 mode.
882
909
  if sb.recorder_mode and sb.headless:
883
910
  sb.headless = False
911
+ sb.headless1 = False
884
912
  sb.headless2 = True
885
913
  if not sb.headless and not sb.headless2:
886
914
  sb.headed = True
887
915
  if sb.browser == "safari" and sb.headless:
888
916
  sb.headless = False # Safari doesn't support headless mode
917
+ sb.headless1 = False
889
918
  if sb.save_screenshot_after_test and sb.no_screenshot_after_test:
890
919
  sb.save_screenshot_after_test = False # "no_screenshot" has priority
891
920
  if sb.servername != "localhost":
@@ -904,6 +933,29 @@ def get_configured_sb(context):
904
933
  else:
905
934
  sb.enable_ws = False
906
935
  sb.disable_ws = True
936
+ if sb.window_position:
937
+ window_position = sb.window_position
938
+ if window_position.count(",") != 1:
939
+ message = (
940
+ '\n\n window_position expects an "x,y" string!'
941
+ '\n (Your input was: "%s")\n' % window_position
942
+ )
943
+ raise Exception(message)
944
+ window_position = window_position.replace(" ", "")
945
+ win_x = None
946
+ win_y = None
947
+ try:
948
+ win_x = int(window_position.split(",")[0])
949
+ win_y = int(window_position.split(",")[1])
950
+ except Exception:
951
+ message = (
952
+ '\n\n Expecting integer values for "x,y"!'
953
+ '\n (window_position input was: "%s")\n'
954
+ % window_position
955
+ )
956
+ raise Exception(message)
957
+ settings.WINDOW_START_X = win_x
958
+ settings.WINDOW_START_Y = win_y
907
959
  if sb.window_size:
908
960
  window_size = sb.window_size
909
961
  if window_size.count(",") != 1:
@@ -938,9 +990,11 @@ def get_configured_sb(context):
938
990
  sb_config.is_pytest = False
939
991
  sb_config.is_nosetest = False
940
992
  sb_config.is_context_manager = False
993
+ sb_config.window_position = sb.window_position
941
994
  sb_config.window_size = sb.window_size
942
995
  sb_config.maximize_option = sb.maximize_option
943
996
  sb_config.xvfb = sb.xvfb
997
+ sb_config.xvfb_metrics = sb.xvfb_metrics
944
998
  sb_config.reuse_class_session = sb._reuse_class_session
945
999
  sb_config.save_screenshot = sb.save_screenshot_after_test
946
1000
  sb_config.no_screenshot = sb.no_screenshot_after_test
@@ -1162,12 +1216,10 @@ def behave_dashboard_prepare():
1162
1216
  sb_config.item_count_untested = sb_config.item_count
1163
1217
  dash_path = os.path.join(os.getcwd(), "dashboard.html")
1164
1218
  star_len = len("Dashboard: ") + len(dash_path)
1165
- try:
1219
+ with suppress(Exception):
1166
1220
  terminal_size = os.get_terminal_size().columns
1167
1221
  if terminal_size > 30 and star_len > terminal_size:
1168
1222
  star_len = terminal_size
1169
- except Exception:
1170
- pass
1171
1223
  stars = "*" * star_len
1172
1224
  c1 = ""
1173
1225
  cr = ""
@@ -1263,7 +1315,7 @@ def _perform_behave_unconfigure_():
1263
1315
 
1264
1316
 
1265
1317
  def do_final_driver_cleanup_as_needed():
1266
- try:
1318
+ with suppress(Exception):
1267
1319
  if hasattr(sb_config, "last_driver") and sb_config.last_driver:
1268
1320
  if (
1269
1321
  not is_windows
@@ -1271,8 +1323,6 @@ def do_final_driver_cleanup_as_needed():
1271
1323
  or sb_config.last_driver.service.process
1272
1324
  ):
1273
1325
  sb_config.last_driver.quit()
1274
- except Exception:
1275
- pass
1276
1326
 
1277
1327
 
1278
1328
  def _perform_behave_terminal_summary_():
@@ -1281,12 +1331,10 @@ def _perform_behave_terminal_summary_():
1281
1331
  )
1282
1332
  dash_path = os.path.join(os.getcwd(), "dashboard.html")
1283
1333
  equals_len = len("Dashboard: ") + len(dash_path)
1284
- try:
1334
+ with suppress(Exception):
1285
1335
  terminal_size = os.get_terminal_size().columns
1286
1336
  if terminal_size > 30 and equals_len > terminal_size:
1287
1337
  equals_len = terminal_size
1288
- except Exception:
1289
- pass
1290
1338
  equals = "=" * (equals_len + 2)
1291
1339
  c2 = ""
1292
1340
  cr = ""
@@ -110,6 +110,10 @@ DISABLE_CSP_ON_CHROME = False
110
110
  # (This applies when using --proxy=[PROXY_STRING] for using a proxy server.)
111
111
  RAISE_INVALID_PROXY_STRING_EXCEPTION = True
112
112
 
113
+ # Default browser coordinates when opening new windows for tests.
114
+ WINDOW_START_X = 20
115
+ WINDOW_START_Y = 54
116
+
113
117
  # Default browser resolutions when opening new windows for tests.
114
118
  # (Headless resolutions take priority, and include all browsers.)
115
119
  # (Firefox starts maximized by default when running in GUI Mode.)
@@ -3,7 +3,9 @@
3
3
  http://www.patorjk.com/software/taag/#p=display&f=Slant&t=SeleniumBase """
4
4
 
5
5
  import colorama
6
+ import os
6
7
  import sys
8
+ from contextlib import suppress
7
9
 
8
10
  r"""
9
11
  ______ __ _ ____
@@ -66,4 +68,49 @@ def get_seleniumbase_logo():
66
68
  sb += " "
67
69
  sb += cr
68
70
  sb += cr
71
+ with suppress(Exception):
72
+ terminal_width = os.get_terminal_size().columns
73
+ if isinstance(terminal_width, int) and terminal_width >= 66:
74
+ return sb
75
+
76
+ # If the logo is wider than the screen width, use a smaller one:
77
+ r"""
78
+ ___ _ _ ___
79
+ / __| ___| |___ _ _ (_)_ _ _ __ | _ ) __ _ ______
80
+ \__ \/ -_) / -_) ' \| | \| | ' \ | _ \/ _` (_-< -_)
81
+ |___/\___|_\___|_||_|_|\_,_|_|_|_\|___/\__,_/__|___|
82
+ """
83
+ sb = " "
84
+ sb += cr
85
+ sb += "\n"
86
+ sb += c1
87
+ sb += " ___ _ _ "
88
+ sb += c2
89
+ sb += " ___ "
90
+ sb += cr
91
+ sb += "\n"
92
+ sb += c1
93
+ sb += "/ __| ___| |___ _ _ (_)_ _ _ __ "
94
+ sb += c2
95
+ sb += "| _ ) __ _ ______ "
96
+ sb += cr
97
+ sb += "\n"
98
+ sb += c1
99
+ sb += "\\__ \\/ -_) / -_) ' \\| | \\| | ' \\ "
100
+ sb += c2
101
+ sb += "| _ \\/ _` (_-< -_)"
102
+ sb += cr
103
+ sb += "\n"
104
+ sb += c1
105
+ sb += "|___/\\___|_\\___|_||_|_|\\_,_|_|_|_\\"
106
+ sb += c2
107
+ sb += "|___/\\__,_/__|___|"
108
+ sb += cr
109
+ sb += "\n"
110
+ sb += c3
111
+ sb += " "
112
+ sb += c4
113
+ sb += " "
114
+ sb += cr
115
+ sb += cr
69
116
  return sb
@@ -54,8 +54,8 @@ else:
54
54
  def show_usage():
55
55
  show_basic_usage()
56
56
  sc = ""
57
- sc += ' Type "sbase help [COMMAND]" for specific command info.\n'
58
- sc += ' For info on all commands, type: "seleniumbase --help".\n'
57
+ sc += ' Type "sbase help [COMMAND]" for specific info.\n'
58
+ sc += ' For all commands, type: "seleniumbase --help".\n'
59
59
  sc += ' Use "pytest" for running tests.\n'
60
60
  if "linux" not in sys.platform:
61
61
  c1 = colorama.Fore.BLUE + colorama.Back.LIGHTCYAN_EX
@@ -76,12 +76,15 @@ def show_basic_usage():
76
76
 
77
77
  seleniumbase_logo = logo_helper.get_seleniumbase_logo()
78
78
  print(seleniumbase_logo)
79
+ time.sleep(0.044)
79
80
  print("")
80
- time.sleep(0.28) # Enough time to see the logo
81
+ time.sleep(0.033)
81
82
  show_package_location()
83
+ time.sleep(0.032)
82
84
  show_version_info()
85
+ time.sleep(0.031)
83
86
  print("")
84
- time.sleep(0.62) # Enough time to see the version
87
+ time.sleep(0.68) # Enough time to see the logo & version
85
88
  sc = ""
86
89
  sc += ' * USAGE: "seleniumbase [COMMAND] [PARAMETERS]"\n'
87
90
  sc += ' * OR: "sbase [COMMAND] [PARAMETERS]"\n'
@@ -16,16 +16,16 @@ Output:
16
16
  import colorama
17
17
  import subprocess
18
18
  import sys
19
+ import tkinter as tk
20
+ from seleniumbase.fixtures import shared_utils
21
+ from tkinter.scrolledtext import ScrolledText
19
22
 
20
- if sys.version_info <= (3, 7):
23
+ if sys.version_info <= (3, 8):
21
24
  current_version = ".".join(str(ver) for ver in sys.version_info[:3])
22
25
  raise Exception(
23
- "\n* SBase Commander requires Python 3.7 or newer!"
26
+ "\n* SBase Commander requires Python 3.8 or newer!"
24
27
  "\n** You are currently using Python %s" % current_version
25
28
  )
26
- from seleniumbase.fixtures import shared_utils
27
- import tkinter as tk # noqa: E402
28
- from tkinter.scrolledtext import ScrolledText # noqa: E402
29
29
 
30
30
 
31
31
  def set_colors(use_colors):
@@ -20,17 +20,17 @@ import colorama
20
20
  import os
21
21
  import subprocess
22
22
  import sys
23
+ import tkinter as tk
24
+ from seleniumbase.fixtures import shared_utils
25
+ from tkinter import messagebox
26
+ from tkinter.scrolledtext import ScrolledText
23
27
 
24
- if sys.version_info <= (3, 7):
28
+ if sys.version_info <= (3, 8):
25
29
  current_version = ".".join(str(ver) for ver in sys.version_info[:3])
26
30
  raise Exception(
27
- "\n* SBase Case Plans Generator requires Python 3.7 or newer!"
31
+ "\n* SBase Case Plans Generator requires Python 3.8 or newer!"
28
32
  "\n** You are currently using Python %s" % current_version
29
33
  )
30
- from seleniumbase.fixtures import shared_utils
31
- import tkinter as tk # noqa: E402
32
- from tkinter import messagebox # noqa: E402
33
- from tkinter.scrolledtext import ScrolledText # noqa: E402
34
34
 
35
35
 
36
36
  def set_colors(use_colors):
@@ -21,16 +21,16 @@ import colorama
21
21
  import os
22
22
  import subprocess
23
23
  import sys
24
+ import tkinter as tk
25
+ from seleniumbase.fixtures import shared_utils
26
+ from tkinter.scrolledtext import ScrolledText
24
27
 
25
- if sys.version_info <= (3, 7):
28
+ if sys.version_info <= (3, 8):
26
29
  current_version = ".".join(str(ver) for ver in sys.version_info[:3])
27
30
  raise Exception(
28
- "\n* SBase Commander requires Python 3.7 or newer!"
31
+ "\n* SBase Commander requires Python 3.8 or newer!"
29
32
  "\n** You are currently using Python %s" % current_version
30
33
  )
31
- from seleniumbase.fixtures import shared_utils
32
- import tkinter as tk # noqa: E402
33
- from tkinter.scrolledtext import ScrolledText # noqa: E402
34
34
 
35
35
 
36
36
  def set_colors(use_colors):
@@ -578,10 +578,18 @@ def main(override=None, intel_for_uc=None, force_uc=None):
578
578
  else:
579
579
  invalid_run_command()
580
580
  if IS_MAC:
581
- file_name = "geckodriver-%s-macos.tar.gz" % use_version
581
+ if IS_ARM_MAC:
582
+ file_name = "geckodriver-%s-macos-aarch64.tar.gz" % use_version
583
+ else:
584
+ file_name = "geckodriver-%s-macos.tar.gz" % use_version
582
585
  elif IS_LINUX:
583
586
  if "64" in ARCH:
584
- file_name = "geckodriver-%s-linux64.tar.gz" % use_version
587
+ if "aarch64" in platform.processor():
588
+ file_name = (
589
+ "geckodriver-%s-linux-aarch64.tar.gz" % use_version
590
+ )
591
+ else:
592
+ file_name = "geckodriver-%s-linux64.tar.gz" % use_version
585
593
  else:
586
594
  file_name = "geckodriver-%s-linux32.tar.gz" % use_version
587
595
  elif IS_WINDOWS:
@@ -18,23 +18,23 @@ import colorama
18
18
  import os
19
19
  import subprocess
20
20
  import sys
21
+ import tkinter as tk
21
22
  from seleniumbase import config as sb_config
22
23
  from seleniumbase.fixtures import page_utils
23
24
  from seleniumbase.fixtures import shared_utils
25
+ from tkinter import messagebox
24
26
 
25
27
  sb_config.rec_subprocess_p = None
26
28
  sb_config.rec_subprocess_used = False
27
29
  sys_executable = sys.executable
28
30
  if " " in sys_executable:
29
31
  sys_executable = "python"
30
- if sys.version_info <= (3, 7):
32
+ if sys.version_info <= (3, 8):
31
33
  current_version = ".".join(str(ver) for ver in sys.version_info[:3])
32
34
  raise Exception(
33
- "\n* Recorder Desktop requires Python 3.7 or newer!"
35
+ "\n* Recorder Desktop requires Python 3.8 or newer!"
34
36
  "\n*** You are currently using Python %s" % current_version
35
37
  )
36
- import tkinter as tk # noqa: E402
37
- from tkinter import messagebox # noqa: E402
38
38
 
39
39
 
40
40
  def set_colors(use_colors):