locust 2.27.0__py3-none-any.whl → 2.27.1.dev10__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 (42) hide show
  1. locust/_version.py +2 -2
  2. locust/argument_parser.py +13 -16
  3. locust/env.py +0 -2
  4. locust/html.py +37 -83
  5. locust/log.py +2 -1
  6. locust/main.py +8 -12
  7. locust/stats.py +3 -10
  8. locust/test/test_fasthttp.py +6 -4
  9. locust/test/test_main.py +6 -15
  10. locust/test/test_web.py +53 -199
  11. locust/web.py +18 -56
  12. {locust-2.27.0.dist-info → locust-2.27.1.dev10.dist-info}/METADATA +1 -1
  13. {locust-2.27.0.dist-info → locust-2.27.1.dev10.dist-info}/RECORD +17 -42
  14. locust/static/chart.js +0 -133
  15. locust/static/css/application.css +0 -491
  16. locust/static/css/application.css.map +0 -1
  17. locust/static/css/tables.css +0 -74
  18. locust/static/css/tables.css.map +0 -1
  19. locust/static/echarts.common.min.js +0 -22
  20. locust/static/img/favicon.ico +0 -0
  21. locust/static/img/logo.png +0 -0
  22. locust/static/img/ui-screenshot-charts.png +0 -0
  23. locust/static/img/ui-screenshot-start-test.png +0 -0
  24. locust/static/img/ui-screenshot-stats.png +0 -0
  25. locust/static/img/ui-screenshot-workers.png +0 -0
  26. locust/static/jquery-1.11.3.min.js +0 -5
  27. locust/static/jquery.jqote2.min.js +0 -14
  28. locust/static/jquery.tools.min.js +0 -17
  29. locust/static/locust.js +0 -324
  30. locust/static/sass/_base.sass +0 -27
  31. locust/static/sass/_mixins.sass +0 -3
  32. locust/static/sass/application.sass +0 -320
  33. locust/static/sass/tables.sass +0 -61
  34. locust/static/tasks.js +0 -48
  35. locust/static/vintage.js +0 -35
  36. locust/templates/index.html +0 -370
  37. locust/templates/report.html +0 -265
  38. locust/templates/stats_data.html +0 -10
  39. {locust-2.27.0.dist-info → locust-2.27.1.dev10.dist-info}/LICENSE +0 -0
  40. {locust-2.27.0.dist-info → locust-2.27.1.dev10.dist-info}/WHEEL +0 -0
  41. {locust-2.27.0.dist-info → locust-2.27.1.dev10.dist-info}/entry_points.txt +0 -0
  42. {locust-2.27.0.dist-info → locust-2.27.1.dev10.dist-info}/top_level.txt +0 -0
locust/test/test_web.py CHANGED
@@ -79,13 +79,19 @@ class TestWebUI(LocustTestCase, _HeaderCheckMixin):
79
79
  web_ui.stop()
80
80
 
81
81
  def test_index(self):
82
- self.assertEqual(200, requests.get("http://127.0.0.1:%i/" % self.web_port).status_code)
82
+ self.assertEqual(self.web_ui, self.environment.web_ui)
83
83
 
84
- def test_index_with_spawn_options(self):
85
84
  html_to_option = {
86
- "user_count": ["-u", "100"],
85
+ "num_users": ["-u", "100"],
87
86
  "spawn_rate": ["-r", "10.0"],
88
87
  }
88
+
89
+ response = requests.get("http://127.0.0.1:%i/" % self.web_port)
90
+ d = pq(response.content.decode("utf-8"))
91
+
92
+ self.assertEqual(200, response.status_code)
93
+ self.assertTrue(d("#root"))
94
+
89
95
  for html_name_to_test in html_to_option.keys():
90
96
  # Test that setting each spawn option individually populates the corresponding field in the html, and none of the others
91
97
  self.environment.parsed_options = parse_options(html_to_option[html_name_to_test])
@@ -95,15 +101,23 @@ class TestWebUI(LocustTestCase, _HeaderCheckMixin):
95
101
 
96
102
  d = pq(response.content.decode("utf-8"))
97
103
 
98
- for html_name in html_to_option.keys():
99
- start_value = d(f".start [name={html_name}]").attr("value")
100
- edit_value = d(f".edit [name={html_name}]").attr("value")
101
- if html_name_to_test == html_name:
102
- self.assertEqual(html_to_option[html_name][1], start_value)
103
- self.assertEqual(html_to_option[html_name][1], edit_value)
104
- else:
105
- self.assertEqual("1", start_value, msg=f"start value was {start_value} for {html_name}")
106
- self.assertEqual("1", edit_value, msg=f"edit value was {edit_value} for {html_name}")
104
+ self.assertIn(f'"{html_name_to_test}": {html_to_option[html_name_to_test][1]}', str(d("script")))
105
+
106
+ def test_index_with_spawn_options(self):
107
+ html_to_option = {
108
+ "num_users": ["-u", "100"],
109
+ "spawn_rate": ["-r", "10.0"],
110
+ }
111
+
112
+ for html_name_to_test in html_to_option.keys():
113
+ self.environment.parsed_options = parse_options(html_to_option[html_name_to_test])
114
+
115
+ response = requests.get("http://127.0.0.1:%i/" % self.web_port)
116
+ self.assertEqual(200, response.status_code)
117
+
118
+ d = pq(response.content.decode("utf-8"))
119
+
120
+ self.assertIn(f'"{html_name_to_test}": {html_to_option[html_name_to_test][1]}', str(d))
107
121
 
108
122
  def test_stats_no_data(self):
109
123
  self.assertEqual(200, requests.get("http://127.0.0.1:%i/stats/requests" % self.web_port).status_code)
@@ -771,30 +785,6 @@ class TestWebUI(LocustTestCase, _HeaderCheckMixin):
771
785
  self.assertEqual(200, response.status_code)
772
786
  self.assertEqual(my_dict["val"], 42)
773
787
 
774
- def test_custom_argument_dropdown(self):
775
- class MyUser(User):
776
- host = "http://example.com"
777
-
778
- @locust.events.init_command_line_parser.add_listener
779
- def _(parser, **kw):
780
- parser.add_argument("--my-argument", default="a", choices=["a", "b"], help="Pick one")
781
-
782
- parsed_options = parse_options(args=["--my-argument", "b"])
783
- self.environment.user_classes = [MyUser]
784
- self.environment.parsed_options = parsed_options
785
- self.environment.web_ui.parsed_options = parsed_options
786
-
787
- response = requests.get("http://127.0.0.1:%i/" % self.web_port)
788
- self.assertEqual(200, response.status_code)
789
-
790
- # regex to match the intended select tag with id from the custom argument
791
- dropdown_pattern = re.compile(r"<select[^>]*id=\"my_argument\"[^>]*>", flags=re.I)
792
- self.assertRegex(response.text, dropdown_pattern)
793
-
794
- # regex to match the input that generates if it fails to find the choices
795
- textfield_pattern = re.compile(r"<input[^>]*id=\"my_argument\"[^>]*>", flags=re.I)
796
- self.assertNotRegex(response.text, textfield_pattern)
797
-
798
788
  def test_swarm_host_value_not_specified(self):
799
789
  class MyUser(User):
800
790
  wait_time = constant(1)
@@ -922,40 +912,42 @@ class TestWebUI(LocustTestCase, _HeaderCheckMixin):
922
912
  response = requests.get("http://127.0.0.1:%i/" % self.web_port)
923
913
  self.assertEqual(200, response.status_code)
924
914
  self.assertNotIn("http://example.com", response.content.decode("utf-8"))
925
- self.assertIn("setting this will override the host on all User classes", response.content.decode("utf-8"))
926
915
 
927
916
  def test_report_page(self):
928
917
  self.stats.log_request("GET", "/test", 120, 5612)
929
918
  r = requests.get("http://127.0.0.1:%i/stats/report" % self.web_port)
919
+
920
+ d = pq(r.content.decode("utf-8"))
921
+
930
922
  self.assertEqual(200, r.status_code)
931
- self.assertIn("<title>Test Report for None</title>", r.text)
932
- self.assertIn("<p>Script: <span>None</span></p>", r.text)
933
- self.assertIn("charts-container", r.text)
934
- self.assertIn(
935
- '<a href="?download=1">Download the Report</a>',
936
- r.text,
937
- "Download report link not found in HTML content",
938
- )
923
+ self.assertIn('"host": "None"', str(d))
924
+ self.assertIn('"num_requests": 1', str(d))
925
+ self.assertIn('"is_report": true', str(d))
926
+ self.assertIn('"show_download_link": true', str(d))
939
927
 
940
928
  def test_report_page_empty_stats(self):
941
929
  r = requests.get("http://127.0.0.1:%i/stats/report" % self.web_port)
942
930
  self.assertEqual(200, r.status_code)
943
- self.assertIn("<title>Test Report for None</title>", r.text)
944
- self.assertIn("charts-container", r.text)
945
931
 
946
932
  def test_report_download(self):
947
933
  self.stats.log_request("GET", "/test", 120, 5612)
948
934
  r = requests.get("http://127.0.0.1:%i/stats/report?download=1" % self.web_port)
935
+
936
+ d = pq(r.content.decode("utf-8"))
937
+
949
938
  self.assertEqual(200, r.status_code)
950
939
  self.assertIn("attachment", r.headers.get("Content-Disposition", ""))
951
- self.assertNotIn("Download the Report", r.text, "Download report link found in HTML content")
940
+ self.assertIn('"show_download_link": false', str(d))
952
941
 
953
942
  def test_report_host(self):
954
943
  self.environment.host = "http://test.com"
955
944
  self.stats.log_request("GET", "/test", 120, 5612)
956
945
  r = requests.get("http://127.0.0.1:%i/stats/report" % self.web_port)
946
+
947
+ d = pq(r.content.decode("utf-8"))
948
+
957
949
  self.assertEqual(200, r.status_code)
958
- self.assertIn("http://test.com", r.text)
950
+ self.assertIn('"host": "http://test.com"', str(d))
959
951
 
960
952
  def test_report_host2(self):
961
953
  class MyUser(User):
@@ -969,8 +961,11 @@ class TestWebUI(LocustTestCase, _HeaderCheckMixin):
969
961
  self.environment.user_classes = [MyUser]
970
962
  self.stats.log_request("GET", "/test", 120, 5612)
971
963
  r = requests.get("http://127.0.0.1:%i/stats/report" % self.web_port)
964
+
965
+ d = pq(r.content.decode("utf-8"))
966
+
972
967
  self.assertEqual(200, r.status_code)
973
- self.assertIn("http://test2.com", r.text)
968
+ self.assertIn('"host": "http://test2.com"', str(d))
974
969
 
975
970
  def test_report_exceptions(self):
976
971
  try:
@@ -981,8 +976,10 @@ class TestWebUI(LocustTestCase, _HeaderCheckMixin):
981
976
  self.runner.log_exception("local", str(e), "".join(traceback.format_tb(tb)))
982
977
  self.stats.log_request("GET", "/test", 120, 5612)
983
978
  r = requests.get("http://127.0.0.1:%i/stats/report" % self.web_port)
984
- # self.assertEqual(200, r.status_code)
985
- self.assertIn("<h2>Exceptions Statistics</h2>", r.text)
979
+
980
+ d = pq(r.content.decode("utf-8"))
981
+
982
+ self.assertIn('exceptions_statistics": [{"count": 2', str(d))
986
983
 
987
984
  # Prior to 088a98bf8ff4035a0de3becc8cd4e887d618af53, the "nodes" field for each exception in
988
985
  # "self.runner.exceptions" was accidentally mutated in "get_html_report" to a string.
@@ -992,54 +989,6 @@ class TestWebUI(LocustTestCase, _HeaderCheckMixin):
992
989
  isinstance(next(iter(self.runner.exceptions.values()))["nodes"], set), "exception object has been mutated"
993
990
  )
994
991
 
995
- def test_custom_shape_deactivate_num_users_and_spawn_rate(self):
996
- class TestShape(LoadTestShape):
997
- def tick(self):
998
- return None
999
-
1000
- self.environment.shape_class = TestShape
1001
-
1002
- response = requests.get("http://127.0.0.1:%i/" % self.web_port)
1003
- self.assertEqual(200, response.status_code)
1004
-
1005
- # regex to match the intended select tag with id from the custom argument
1006
- re_disabled_user_count = re.compile(
1007
- r"<input[^>]*id=\"(new_)?user_count\"[^>]*disabled=\"disabled\"[^>]*>", flags=re.I
1008
- )
1009
- self.assertRegex(response.text, re_disabled_user_count)
1010
-
1011
- re_disabled_spawn_rate = re.compile(
1012
- r"<input[^>]*id=\"(new_)?spawn_rate\"[^>]*disabled=\"disabled\"[^>]*>", flags=re.I
1013
- )
1014
- self.assertRegex(response.text, re_disabled_spawn_rate)
1015
-
1016
- def test_custom_shape_with_use_common_options_keep_num_users_and_spawn_rate(self):
1017
- class TestShape(LoadTestShape):
1018
- use_common_options = True
1019
-
1020
- def tick(self):
1021
- return None
1022
-
1023
- self.environment.shape_class = TestShape
1024
-
1025
- response = requests.get("http://127.0.0.1:%i/" % self.web_port)
1026
- self.assertEqual(200, response.status_code)
1027
-
1028
- # regex to match the intended select tag with id from the custom argument
1029
- re_user_count = re.compile(r"<input[^>]*id=\"(new_)?user_count\"[^>]*>", flags=re.I)
1030
- re_disabled_user_count = re.compile(
1031
- r"<input[^>]*id=\"(new_)?user_count\"[^>]*disabled=\"disabled\"[^>]*>", flags=re.I
1032
- )
1033
- self.assertRegex(response.text, re_user_count)
1034
- self.assertNotRegex(response.text, re_disabled_user_count)
1035
-
1036
- re_spawn_rate = re.compile(r"<input[^>]*id=\"(new_)?spawn_rate\"[^>]*>", flags=re.I)
1037
- re_disabled_spawn_rate = re.compile(
1038
- r"<input[^>]*id=\"(new_)?spawn_rate\"[^>]*disabled=\"disabled\"[^>]*>", flags=re.I
1039
- )
1040
- self.assertRegex(response.text, re_spawn_rate)
1041
- self.assertNotRegex(response.text, re_disabled_spawn_rate)
1042
-
1043
992
  def test_html_stats_report(self):
1044
993
  self.environment.locustfile = "locust.py"
1045
994
  self.environment.host = "http://localhost"
@@ -1049,8 +998,9 @@ class TestWebUI(LocustTestCase, _HeaderCheckMixin):
1049
998
 
1050
999
  d = pq(response.content.decode("utf-8"))
1051
1000
 
1052
- self.assertIn("Script: <span>locust.py</span>", str(d))
1053
- self.assertIn("Target Host: <span>http://localhost</span>", str(d))
1001
+ self.assertTrue(d("#root"))
1002
+ self.assertIn('"locustfile": "locust.py"', str(d))
1003
+ self.assertIn('"host": "http://localhost"', str(d))
1054
1004
 
1055
1005
  def test_logs(self):
1056
1006
  log_handler = LogReader()
@@ -1128,7 +1078,7 @@ class TestWebUIAuth(LocustTestCase):
1128
1078
  parser = get_parser(default_config_files=[])
1129
1079
  self.environment.parsed_options = parser.parse_args(["--web-login"])
1130
1080
 
1131
- self.web_ui = self.environment.create_web_ui("127.0.0.1", 0, modern_ui=True, web_login=True)
1081
+ self.web_ui = self.environment.create_web_ui("127.0.0.1", 0, web_login=True)
1132
1082
 
1133
1083
  self.web_ui.app.secret_key = "secret!"
1134
1084
  gevent.sleep(0.01)
@@ -1280,99 +1230,3 @@ class TestWebUIFullHistory(LocustTestCase, _HeaderCheckMixin):
1280
1230
  self.assertEqual("/test2", rows[2][3])
1281
1231
  self.assertEqual("", rows[3][2])
1282
1232
  self.assertEqual("Aggregated", rows[3][3])
1283
-
1284
-
1285
- class TestModernWebUI(LocustTestCase, _HeaderCheckMixin):
1286
- def setUp(self):
1287
- super().setUp()
1288
-
1289
- get_parser(default_config_files=[])
1290
- self.stats = self.environment.stats
1291
-
1292
- self.web_ui = self.environment.create_web_ui("127.0.0.1", 0, modern_ui=True)
1293
- self.web_ui.app.view_functions["request_stats"].clear_cache()
1294
- gevent.sleep(0.01)
1295
- self.web_port = self.web_ui.server.server_port
1296
-
1297
- def tearDown(self):
1298
- super().tearDown()
1299
- self.web_ui.stop()
1300
- self.runner.quit()
1301
-
1302
- def test_index_with_modern_ui(self):
1303
- self.assertEqual(self.web_ui, self.environment.web_ui)
1304
-
1305
- html_to_option = {
1306
- "num_users": ["-u", "100"],
1307
- "spawn_rate": ["-r", "10.0"],
1308
- }
1309
-
1310
- response = requests.get("http://127.0.0.1:%i/" % self.web_port)
1311
- d = pq(response.content.decode("utf-8"))
1312
-
1313
- self.assertEqual(200, response.status_code)
1314
- self.assertTrue(d("#root"))
1315
-
1316
- for html_name_to_test in html_to_option.keys():
1317
- # Test that setting each spawn option individually populates the corresponding field in the html, and none of the others
1318
- self.environment.parsed_options = parse_options(html_to_option[html_name_to_test])
1319
-
1320
- response = requests.get("http://127.0.0.1:%i/" % self.web_port)
1321
- self.assertEqual(200, response.status_code)
1322
-
1323
- d = pq(response.content.decode("utf-8"))
1324
-
1325
- self.assertIn(f'"{html_name_to_test}": {html_to_option[html_name_to_test][1]}', str(d("script")))
1326
-
1327
- def test_web_ui_no_runner(self):
1328
- env = Environment()
1329
- web_ui = WebUI(env, "127.0.0.1", 0)
1330
- gevent.sleep(0.01)
1331
- try:
1332
- response = requests.get("http://127.0.0.1:%i/" % web_ui.server.server_port)
1333
- self.assertEqual(500, response.status_code)
1334
- self.assertEqual("Error: Locust Environment does not have any runner", response.text)
1335
- finally:
1336
- web_ui.stop()
1337
-
1338
- def test_html_stats_report(self):
1339
- self.environment.locustfile = "locust.py"
1340
- self.environment.host = "http://localhost"
1341
-
1342
- response = requests.get("http://127.0.0.1:%i/stats/report" % self.web_port)
1343
- self.assertEqual(200, response.status_code)
1344
-
1345
- d = pq(response.content.decode("utf-8"))
1346
-
1347
- self.assertTrue(d("#root"))
1348
- self.assertIn('"locustfile": "locust.py"', str(d))
1349
- self.assertIn('"host": "http://localhost"', str(d))
1350
-
1351
- def test_update_user(self):
1352
- class MyUser1(User):
1353
- @task
1354
- def my_task(self):
1355
- pass
1356
-
1357
- @task
1358
- def my_task_2(self):
1359
- pass
1360
-
1361
- class MyUser2(User):
1362
- @task
1363
- def my_task(self):
1364
- pass
1365
-
1366
- self.environment.user_classes = [MyUser1, MyUser2]
1367
- self.environment.available_user_classes = {"User1": MyUser1, "User2": MyUser2}
1368
- self.environment.available_user_tasks = {"User1": MyUser1.tasks, "User2": MyUser2.tasks}
1369
-
1370
- requests.post(
1371
- "http://127.0.0.1:%i/user" % self.web_port,
1372
- json={"user_class_name": "User1", "host": "http://localhost", "tasks": ["my_task_2"]},
1373
- )
1374
-
1375
- self.assertEqual(
1376
- self.environment.available_user_classes["User1"].json(),
1377
- {"host": "http://localhost", "tasks": ["my_task_2"], "fixed_count": 0, "weight": 1},
1378
- )
locust/web.py CHANGED
@@ -32,7 +32,7 @@ from gevent import pywsgi
32
32
  from . import __version__ as version
33
33
  from . import argument_parser
34
34
  from . import stats as stats_module
35
- from .html import get_html_report
35
+ from .html import BUILD_PATH, ROOT_PATH, STATIC_PATH, get_html_report
36
36
  from .log import greenlet_exception_logger
37
37
  from .runners import STATE_MISSING, STATE_RUNNING, MasterRunner
38
38
  from .stats import StatsCSV, StatsCSVFileWriter, StatsErrorDict, sort_stats
@@ -95,7 +95,6 @@ class WebUI:
95
95
  stats_csv_writer: StatsCSV | None = None,
96
96
  delayed_start=False,
97
97
  userclass_picker_is_active=False,
98
- modern_ui=False,
99
98
  ):
100
99
  """
101
100
  Create WebUI instance and start running the web server in a separate greenlet (self.greenlet)
@@ -118,20 +117,21 @@ class WebUI:
118
117
  self.tls_cert = tls_cert
119
118
  self.tls_key = tls_key
120
119
  self.userclass_picker_is_active = userclass_picker_is_active
121
- self.modern_ui = modern_ui
122
120
  self.web_login = web_login
123
121
  app = Flask(__name__)
124
122
  CORS(app)
125
123
  self.app = app
126
124
  app.jinja_env.add_extension("jinja2.ext.do")
127
125
  app.debug = True
128
- root_path = os.path.dirname(os.path.abspath(__file__))
129
- app.root_path = root_path
130
- self.webui_build_path = os.path.join(root_path, "webui", "dist")
126
+ app.root_path = ROOT_PATH
127
+ self.webui_build_path = BUILD_PATH
131
128
  self.greenlet: gevent.Greenlet | None = None
132
129
  self._swarm_greenlet: gevent.Greenlet | None = None
133
130
  self.template_args = {}
134
131
  self.auth_args = {}
132
+ self.app.template_folder = BUILD_PATH
133
+ self.app.static_folder = STATIC_PATH
134
+ self.app.static_url_path = "/assets/"
135
135
 
136
136
  if self.web_login:
137
137
  self.login_manager = LoginManager()
@@ -160,11 +160,7 @@ class WebUI:
160
160
  return make_response("Error: Locust Environment does not have any runner", 500)
161
161
  self.update_template_args()
162
162
 
163
- if self.modern_ui:
164
- self.set_static_modern_ui()
165
-
166
- return render_template("index.html", template_args=self.template_args)
167
- return render_template("index.html", **self.template_args)
163
+ return render_template("index.html", template_args=self.template_args)
168
164
 
169
165
  @app.route("/swarm", methods=["POST"])
170
166
  @self.auth_required_if_enabled
@@ -302,7 +298,6 @@ class WebUI:
302
298
  res = get_html_report(
303
299
  self.environment,
304
300
  show_download_link=not request.args.get("download"),
305
- use_modern_ui=self.modern_ui,
306
301
  theme=theme,
307
302
  )
308
303
  if request.args.get("download"):
@@ -416,25 +411,12 @@ class WebUI:
416
411
  report["total_fail_per_sec"] = total_stats["current_fail_per_sec"]
417
412
  report["total_avg_response_time"] = total_stats["avg_response_time"]
418
413
  report["fail_ratio"] = environment.runner.stats.total.fail_ratio
419
-
420
- if self.modern_ui:
421
- report["current_response_time_percentiles"] = {
422
- f"response_time_percentile_{percentile}": environment.runner.stats.total.get_current_response_time_percentile(
423
- percentile
424
- )
425
- for percentile in stats_module.MODERN_UI_PERCENTILES_TO_CHART
426
- }
427
- else:
428
- report["current_response_time_percentile_1"] = (
429
- environment.runner.stats.total.get_current_response_time_percentile(
430
- stats_module.PERCENTILES_TO_CHART[0]
431
- )
432
- )
433
- report["current_response_time_percentile_2"] = (
434
- environment.runner.stats.total.get_current_response_time_percentile(
435
- stats_module.PERCENTILES_TO_CHART[1]
436
- )
414
+ report["current_response_time_percentiles"] = {
415
+ f"response_time_percentile_{percentile}": environment.runner.stats.total.get_current_response_time_percentile(
416
+ percentile
437
417
  )
418
+ for percentile in stats_module.PERCENTILES_TO_CHART
419
+ }
438
420
 
439
421
  if isinstance(environment.runner, MasterRunner):
440
422
  workers = []
@@ -520,15 +502,10 @@ class WebUI:
520
502
  if not self.web_login:
521
503
  return redirect(url_for("index"))
522
504
 
523
- if self.modern_ui:
524
- self.set_static_modern_ui()
525
-
526
- return render_template(
527
- "auth.html",
528
- auth_args=self.auth_args,
529
- )
530
- else:
531
- return "Web Auth is only available on the modern web ui."
505
+ return render_template(
506
+ "auth.html",
507
+ auth_args=self.auth_args,
508
+ )
532
509
 
533
510
  @app.route("/user", methods=["POST"])
534
511
  def update_user():
@@ -581,11 +558,6 @@ class WebUI:
581
558
 
582
559
  return wrapper
583
560
 
584
- def set_static_modern_ui(self):
585
- self.app.template_folder = self.webui_build_path
586
- self.app.static_folder = os.path.join(self.webui_build_path, "assets")
587
- self.app.static_url_path = "/assets/"
588
-
589
561
  def update_template_args(self):
590
562
  override_host_warning = False
591
563
  if self.environment.host:
@@ -634,17 +606,6 @@ class WebUI:
634
606
  else None
635
607
  )
636
608
 
637
- if self.modern_ui:
638
- percentiles = {
639
- "percentiles_to_chart": stats_module.MODERN_UI_PERCENTILES_TO_CHART,
640
- "percentiles_to_statistics": stats_module.PERCENTILES_TO_STATISTICS,
641
- }
642
- else:
643
- percentiles = {
644
- "percentile1": stats_module.PERCENTILES_TO_CHART[0],
645
- "percentile2": stats_module.PERCENTILES_TO_CHART[1],
646
- }
647
-
648
609
  self.template_args = {
649
610
  "locustfile": self.environment.locustfile,
650
611
  "state": self.environment.runner.state,
@@ -670,7 +631,8 @@ class WebUI:
670
631
  "available_shape_classes": available_shape_classes,
671
632
  "available_user_tasks": available_user_tasks,
672
633
  "users": users,
673
- **percentiles,
634
+ "percentiles_to_chart": stats_module.PERCENTILES_TO_CHART,
635
+ "percentiles_to_statistics": stats_module.PERCENTILES_TO_STATISTICS,
674
636
  }
675
637
 
676
638
  def _update_shape_class(self, shape_class_name):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: locust
3
- Version: 2.27.0
3
+ Version: 2.27.1.dev10
4
4
  Summary: Developer friendly load testing framework
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/locustio/locust
@@ -1,52 +1,27 @@
1
1
  locust/__init__.py,sha256=g6oA-Ba_hs3gLWVf5MKJ1mvfltI8MFnDWG8qslqm8yg,1402
2
2
  locust/__main__.py,sha256=vBQ82334kX06ImDbFlPFgiBRiLIinwNk3z8Khs6hd74,31
3
- locust/_version.py,sha256=vkYXgVuvNk95khotVUCWC2ZuRgmRVBQCyElfrt6rGnE,413
4
- locust/argument_parser.py,sha256=izMXLuMZWUpS6m8SrGRmOjLfPPuYWXCvQFicRmn-a90,28774
3
+ locust/_version.py,sha256=x-6utjIw1UHmNtiFZdMNr3K5tbCgtWach4_LBPlvVEI,428
4
+ locust/argument_parser.py,sha256=5gUvJ6zLTscX1fUP25oAj_VemKl11Hm2aTm86cIlzWs,28680
5
5
  locust/clients.py,sha256=YKuAyMAbxs8_-w7XJw0hc67KFBNNLxibsw6FwiS01Q8,14781
6
6
  locust/debug.py,sha256=We6Z9W0btkKSc7PxWmrZx-xMynvOOsKhG6jmDgQin0g,5134
7
7
  locust/dispatch.py,sha256=vYh0QEDFgJ3hY0HgSk-EiNO7IP9ffzXF_Et8wB9JvsI,16995
8
- locust/env.py,sha256=jgXA4N8X1cGYZ48F16CbVAuhEo1zolJ65qqZyOzP1Dc,12510
8
+ locust/env.py,sha256=SLtUQCYaiv_oq_Nz1xaB0OD8RkTdESt2b71vz_qohpo,12452
9
9
  locust/event.py,sha256=xgNKbcejxy1TNUfIdgV75KgD2_BOwQmvjrJ4hWuydRw,7740
10
10
  locust/exception.py,sha256=jGgJ32ubuf4pWdlaVOkbh2Y0LlG0_DHi-lv3ib8ppOE,1791
11
- locust/html.py,sha256=f0coiIkRXSRV-MSLPhxLDT3xjmoqQxUxbAGtmDcPMXI,5754
11
+ locust/html.py,sha256=Qz3Php454f5QwIdJyP2ckJ2L9aNkdZQCVahFELfMBIc,3983
12
12
  locust/input_events.py,sha256=ZIyePyAMuA_YFYWg18g_pE4kwuQV3RbEB250MzXRwjY,3314
13
- locust/log.py,sha256=2IVp9YL4ZPfWdj3sBFuOHfgneg3g7m7tUGR-sy2s3E8,3155
14
- locust/main.py,sha256=LooX1HPmUd6TKxV-p3xrWTMkPUoU5LtIGVPQvPMPT6U,28111
13
+ locust/log.py,sha256=cqLt7nnxnQuM4vWFB5EpJpNUTxGBVEkUJuaJPI1S7_Y,3186
14
+ locust/main.py,sha256=FM8mkO3HGXJCaUbXZNXn1Yy37fuUaiS3VuLEk7pbbwQ,27831
15
15
  locust/py.typed,sha256=gkWLl8yD4mIZnNYYAIRM8g9VarLvWmTAFeUfEbxJLBw,65
16
16
  locust/runners.py,sha256=Go8b8fpOAfFy6JuNcot7KyguHuExA6eoPHVmcgx3RoI,67813
17
17
  locust/shape.py,sha256=t-lwBS8LOjWcKXNL7j2U3zroIXJ1b0fazUwpRYQOKXw,1973
18
- locust/stats.py,sha256=l2cxxVre8dvA4MIOD_ZKNj_fYySz5gTGC2f9Rc4-CL0,46134
19
- locust/web.py,sha256=zj0Lm3tQq0MhbeJ1oKROnvauNibwUSBXsTehw2q2nAA,28251
18
+ locust/stats.py,sha256=dulIckrNr3t01LSOFvpr7LdBHj1YXHlEoK7q3b79z0A,45581
19
+ locust/web.py,sha256=_7uelOUgnBJA80ZKjcIQ67zSxz0uEH5hoQDcZ8mP6XU,26720
20
20
  locust/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  locust/contrib/fasthttp.py,sha256=vByPepw35DF84qZ2xK89yHgjOA_8btV0wig_rSR6p4g,26757
22
22
  locust/rpc/__init__.py,sha256=nVGoHWFQxZjnhCDWjbgXIbmFbN9sizAjkhvSs9_642c,58
23
23
  locust/rpc/protocol.py,sha256=n-rb3GZQcAlldYDj4E4GuFGylYj_26GSS5U29meft5Y,1282
24
24
  locust/rpc/zmqrpc.py,sha256=7DLIXzkQr7992zmZwAqNgcqzm7LOQAOQtz0tUGv5-Gg,2637
25
- locust/static/chart.js,sha256=Aue4SxJZhv9I3k0Nr2uXTrdrLxsrX7x_a0d4u3a1e_Q,4796
26
- locust/static/echarts.common.min.js,sha256=2h6zIZeHk-eGAiC-qYvxv7uW5S1HcyM72K5FbcVhky4,620458
27
- locust/static/jquery-1.11.3.min.js,sha256=7LkWEzqTdpEfELxcZZlS6wAx5Ff13zZ83lYO2_ujj7g,95957
28
- locust/static/jquery.jqote2.min.js,sha256=kkYnMvNSQ0_h-YsHCRzBF3v4yEfRdcEacMusrnW4BK0,3381
29
- locust/static/jquery.tools.min.js,sha256=elDu82RR_6K-TWXb2qTSxAz96-upLyHBrnypvQSIu3c,2981
30
- locust/static/locust.js,sha256=3Z-7JNT9t46dYFXUxRd-wDrfj1VrWbeuMmQu16GVqy0,10264
31
- locust/static/tasks.js,sha256=Gi999xLri5s_x_Xr_o_Xo-zsXsgaDSyWNcctmZySnZs,1370
32
- locust/static/vintage.js,sha256=aNBHBqGMT-oTINb5wVaeRykd3tFI-FWV8C46qAHcx40,1137
33
- locust/static/css/application.css,sha256=XoDwPgPsnLiF-RlCFR4Pipuz2diy1oimXW0pPs6xq4s,9550
34
- locust/static/css/application.css.map,sha256=mwJQ10Tc5HzQ71JFPn1BtoULU7pBi91wX5DDoDvBtM0,2089
35
- locust/static/css/tables.css,sha256=KZDZbn_DEM0pkuUWPTu0ogEwCUU4bWXWfIeShXNCIW0,1403
36
- locust/static/css/tables.css.map,sha256=7FqJQhCK0Q_EgNGUc-1BEqfs0Z7N8Jk_Aw0GKd4OtNY,411
37
- locust/static/img/favicon.ico,sha256=IUl-rYqfpHdV38e-s0bkmFIeLS-n3Ug0DQxk-h202hI,8348
38
- locust/static/img/logo.png,sha256=iEdgwYwXapNPY1BeAn2qSCAk4rsEeYecYbN7GjNpr9A,24553
39
- locust/static/img/ui-screenshot-charts.png,sha256=eK5hVgKM9uSZJd87BhimZMCspH03R1fuIfYeac2g0kQ,79701
40
- locust/static/img/ui-screenshot-start-test.png,sha256=sQJB4V9FQ3VXiWZVVweh7lkK-0NuBeEMUNoqbIJ_pv8,64670
41
- locust/static/img/ui-screenshot-stats.png,sha256=l6COjiS31ceox6kqdFs_7YKs1QgvwSQB0-VlwunD6Qk,95837
42
- locust/static/img/ui-screenshot-workers.png,sha256=5MapSjLOBcieRMxeJAmAqszhwu72sE4PIHD9UzLVFFg,151806
43
- locust/static/sass/_base.sass,sha256=UaC1ViXp-Sz_5S6ggjctxurevfaGx8RdFdG6VEZK-lc,458
44
- locust/static/sass/_mixins.sass,sha256=Sy5r_1WTWM0k646SYm0XF1WNN2HJxtQ4QO7rVVkIfoI,69
45
- locust/static/sass/application.sass,sha256=v_S916UmdCOno4A0cGfDpVmFFxZxSQ4XOU_0MqjvotU,8512
46
- locust/static/sass/tables.sass,sha256=mG3RXKJRU2NTI6jz__1RUEwjAGdJzgzYpuRCP8jLT1I,1361
47
- locust/templates/index.html,sha256=7Qe69jYG7Vv9G0xWNtbALcqgl_m79GeHSYJxmlaQoBA,21651
48
- locust/templates/report.html,sha256=Q1NmZWZL61-tLzJaR8kKG2tkjMjI6ry-OXEFvgM4PHM,10667
49
- locust/templates/stats_data.html,sha256=MoBvJE41VtG3eriHkP4qWgQs3QNTsFTvS03aCenh0j0,1264
50
25
  locust/test/__init__.py,sha256=CaVC4yA4DnCO8EY3LbedPHFg86a9Lqlpe92JuiX3THw,396
51
26
  locust/test/fake_module1_for_env_test.py,sha256=dzGYWCr1SSkd8Yyo68paUNrCNW7YY_QgjRb7sM37gG0,164
52
27
  locust/test/fake_module2_for_env_test.py,sha256=dzGYWCr1SSkd8Yyo68paUNrCNW7YY_QgjRb7sM37gG0,164
@@ -55,13 +30,13 @@ locust/test/mock_logging.py,sha256=qapKrKhTdlVc8foJB2Hxjn7SB6soaLeAj3VF4A6kZtw,8
55
30
  locust/test/test_debugging.py,sha256=omQ0w5_Xh1xuTBzkd3VavEIircwtlmoOEHcMInY67vU,1053
56
31
  locust/test/test_dispatch.py,sha256=RjoncanN4FFt-aiTl4G8XRoc81n6fwfO8CacbjzpvP8,168856
57
32
  locust/test/test_env.py,sha256=l0fLl9nubdgzxwFNajmBkJvQc5cO5rOTE4p12lbCbs0,8919
58
- locust/test/test_fasthttp.py,sha256=jVA5wWjZxXYW6emzy-lfPC0AOabzT6rDCX0N7DPP9mc,30727
33
+ locust/test/test_fasthttp.py,sha256=cuWsS9t875Mrik0xTXlsfHde90F6_cgKWKJ3_Dr0ldw,30723
59
34
  locust/test/test_http.py,sha256=VQCVY0inLC0RS-V3E9WHL3vBLGokZjQt0zKSrTNlQmM,12536
60
35
  locust/test/test_interruptable_task.py,sha256=LZKSV-aJNnwfvAxguz6SckBEuGEnfGimoIgVfJ2wQTA,1377
61
36
  locust/test/test_load_locustfile.py,sha256=v-muHoM-CYu8t7DXm4AQtFP2q8RYfnTTUBqj7uVqhig,8494
62
37
  locust/test/test_locust_class.py,sha256=oGhhOX848jHRQnIfFlhLlW-kHGYLyYsfDX8hM07Ro7g,25506
63
38
  locust/test/test_log.py,sha256=YPY6vgTAy1KaNU2qoVvQrTH5x_mzRrljEHrkSBy3yxs,7553
64
- locust/test/test_main.py,sha256=Ae3F8KTj65YakX_S8eckhJNbqKrRsivoPkFoZaHeyWI,85344
39
+ locust/test/test_main.py,sha256=R2akeBreg6aXC2Dhs-HxvFq_0EE64hzEaIZmAVALW4w,84866
65
40
  locust/test/test_old_wait_api.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
41
  locust/test/test_parser.py,sha256=-2VO5Dopg-VoWvIgXrmr7GN40cqrnjUoctBHmVlyewg,17826
67
42
  locust/test/test_runners.py,sha256=xfBdRPOH1CiNk4Rwqmbx6S1e2BDuWdtqDw9omDJ50Ec,159395
@@ -72,7 +47,7 @@ locust/test/test_taskratio.py,sha256=SQ-sBqeFm2GhkfCD_57-fPzQrk1ilSw3DRb0_nwyxAI
72
47
  locust/test/test_users.py,sha256=lp6yAKGK9_MIs9F7s1Vc3561P4oRavhpeVo2y9w3SUU,2135
73
48
  locust/test/test_util.py,sha256=DmFTgNSWWx8zrsx9_ZGO6MsySmBV1H_GzNIVzzyapCM,1229
74
49
  locust/test/test_wait_time.py,sha256=3evSEp6amMWFrzmSYs71MCeIsu7Rtarldb_HnwgSrU0,2353
75
- locust/test/test_web.py,sha256=5EL7j8iAZSWlF2t4iGln8euWhC2HQmX6eKbjTSpkq1Q,52413
50
+ locust/test/test_web.py,sha256=8v1RFeF7GDXDv616uzI3adSxoYSxctoZinmwupX5-K8,45767
76
51
  locust/test/test_zmqrpc.py,sha256=kONaZ11hwnneLwaVn7lIDVV7KHpEP2nkxuKhfb9ba3o,2173
77
52
  locust/test/testcases.py,sha256=ZaPYNxSSChAs0nts_13mCGY7WFW8AjXQZdPOvwAK0TY,6961
78
53
  locust/test/util.py,sha256=98HXLClkycNTxLiuy1d3W_tM6dBU9bA-p5ZXMfncaWE,2754
@@ -95,9 +70,9 @@ locust/webui/dist/report.html,sha256=sOdZZVgZbqgu86BBCSQf3uQUYXgmgSnXF32JpnyAII8
95
70
  locust/webui/dist/assets/favicon.ico,sha256=IUl-rYqfpHdV38e-s0bkmFIeLS-n3Ug0DQxk-h202hI,8348
96
71
  locust/webui/dist/assets/index-941b6e82.js,sha256=G3n5R81Svt0HzbWaV3AV20jLWGLr4X50UZ-Adu2KcxU,1645614
97
72
  locust/webui/dist/assets/logo.png,sha256=EIVPqr6wE_yqguHaqFHIsH0ZACLSrvNWyYO7PbyIj4w,19299
98
- locust-2.27.0.dist-info/LICENSE,sha256=78XGpIn3fHVBfaxlPNUfjVufSN7QsdhpJMRJHv2AFpo,1095
99
- locust-2.27.0.dist-info/METADATA,sha256=rgvv8R6VL0Mgxks71BzEI1tx76m1MiSjfmUAV_KjC80,7261
100
- locust-2.27.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
101
- locust-2.27.0.dist-info/entry_points.txt,sha256=RAdt8Ku-56m7bFjmdj-MBhbF6h4NX7tVODR9QNnOg0E,44
102
- locust-2.27.0.dist-info/top_level.txt,sha256=XSsjgPA8Ggf9TqKVbkwSqZFuPlZ085X13M9orDycE20,7
103
- locust-2.27.0.dist-info/RECORD,,
73
+ locust-2.27.1.dev10.dist-info/LICENSE,sha256=78XGpIn3fHVBfaxlPNUfjVufSN7QsdhpJMRJHv2AFpo,1095
74
+ locust-2.27.1.dev10.dist-info/METADATA,sha256=xeNVqd1FFYrUgwcw6LApa2He11RWfeEav4cFdpWlH_s,7267
75
+ locust-2.27.1.dev10.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
76
+ locust-2.27.1.dev10.dist-info/entry_points.txt,sha256=RAdt8Ku-56m7bFjmdj-MBhbF6h4NX7tVODR9QNnOg0E,44
77
+ locust-2.27.1.dev10.dist-info/top_level.txt,sha256=XSsjgPA8Ggf9TqKVbkwSqZFuPlZ085X13M9orDycE20,7
78
+ locust-2.27.1.dev10.dist-info/RECORD,,