locust 2.30.1.dev17__py3-none-any.whl → 2.30.1.dev20__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.
- locust/_version.py +2 -2
- locust/argument_parser.py +7 -0
- locust/env.py +2 -0
- locust/html.py +6 -18
- locust/main.py +6 -1
- locust/web.py +15 -7
- locust/webui/dist/assets/index-7dcacb4b.js +240 -0
- locust/webui/dist/auth.html +1 -1
- locust/webui/dist/index.html +1 -1
- locust/webui/dist/report.html +233 -3
- {locust-2.30.1.dev17.dist-info → locust-2.30.1.dev20.dist-info}/METADATA +1 -1
- {locust-2.30.1.dev17.dist-info → locust-2.30.1.dev20.dist-info}/RECORD +16 -16
- locust/webui/dist/assets/index-d9c29bed.js +0 -250
- /locust/webui/dist/assets/{logo.png → logo-10854faa.png} +0 -0
- {locust-2.30.1.dev17.dist-info → locust-2.30.1.dev20.dist-info}/LICENSE +0 -0
- {locust-2.30.1.dev17.dist-info → locust-2.30.1.dev20.dist-info}/WHEEL +0 -0
- {locust-2.30.1.dev17.dist-info → locust-2.30.1.dev20.dist-info}/entry_points.txt +0 -0
locust/_version.py
CHANGED
@@ -14,7 +14,7 @@ __version_tuple__: VERSION_TUPLE
|
|
14
14
|
version_tuple: VERSION_TUPLE
|
15
15
|
|
16
16
|
|
17
|
-
__version__ = "2.30.1.
|
17
|
+
__version__ = "2.30.1.dev20"
|
18
18
|
version = __version__
|
19
|
-
__version_tuple__ = (2, 30, 1, "
|
19
|
+
__version_tuple__ = (2, 30, 1, "dev20")
|
20
20
|
version_tuple = __version_tuple__
|
locust/argument_parser.py
CHANGED
@@ -496,6 +496,13 @@ def setup_parser_arguments(parser):
|
|
496
496
|
help="Enable select boxes in the web interface to choose from all available User classes and Shape classes",
|
497
497
|
env_var="LOCUST_USERCLASS_PICKER",
|
498
498
|
)
|
499
|
+
web_ui_group.add_argument(
|
500
|
+
"--build-path",
|
501
|
+
type=str,
|
502
|
+
default="",
|
503
|
+
help=configargparse.SUPPRESS,
|
504
|
+
env_var="LOCUST_BUILD_PATH",
|
505
|
+
)
|
499
506
|
web_ui_group.add_argument(
|
500
507
|
"--legacy-ui",
|
501
508
|
default=False,
|
locust/env.py
CHANGED
@@ -171,6 +171,7 @@ class Environment:
|
|
171
171
|
stats_csv_writer: StatsCSV | None = None,
|
172
172
|
delayed_start=False,
|
173
173
|
userclass_picker_is_active=False,
|
174
|
+
build_path: str | None = None,
|
174
175
|
) -> WebUI:
|
175
176
|
"""
|
176
177
|
Creates a :class:`WebUI <locust.web.WebUI>` instance for this Environment and start running the web server
|
@@ -197,6 +198,7 @@ class Environment:
|
|
197
198
|
stats_csv_writer=stats_csv_writer,
|
198
199
|
delayed_start=delayed_start,
|
199
200
|
userclass_picker_is_active=userclass_picker_is_active,
|
201
|
+
build_path=build_path,
|
200
202
|
)
|
201
203
|
return self.web_ui
|
202
204
|
|
locust/html.py
CHANGED
@@ -5,7 +5,8 @@ from html import escape
|
|
5
5
|
from itertools import chain
|
6
6
|
from json import dumps
|
7
7
|
|
8
|
-
from jinja2 import Environment
|
8
|
+
from jinja2 import Environment as JinjaEnvironment
|
9
|
+
from jinja2 import FileSystemLoader
|
9
10
|
|
10
11
|
from . import stats as stats_module
|
11
12
|
from .runners import STATE_STOPPED, STATE_STOPPING, MasterRunner
|
@@ -14,13 +15,11 @@ from .user.inspectuser import get_ratio
|
|
14
15
|
from .util.date import format_utc_timestamp
|
15
16
|
|
16
17
|
PERCENTILES_FOR_HTML_REPORT = [0.50, 0.6, 0.7, 0.8, 0.9, 0.95, 0.99, 1.0]
|
17
|
-
|
18
|
-
BUILD_PATH = os.path.join(ROOT_PATH, "webui", "dist")
|
19
|
-
STATIC_PATH = os.path.join(BUILD_PATH, "assets")
|
18
|
+
DEFAULT_BUILD_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "webui", "dist")
|
20
19
|
|
21
20
|
|
22
|
-
def
|
23
|
-
env =
|
21
|
+
def render_template_from(file, build_path=DEFAULT_BUILD_PATH, **kwargs):
|
22
|
+
env = JinjaEnvironment(loader=FileSystemLoader(build_path))
|
24
23
|
template = env.get_template(file)
|
25
24
|
return template.render(**kwargs)
|
26
25
|
|
@@ -56,16 +55,6 @@ def get_html_report(
|
|
56
55
|
update_stats_history(environment.runner)
|
57
56
|
history = stats.history
|
58
57
|
|
59
|
-
static_js = []
|
60
|
-
js_files = [os.path.basename(filepath) for filepath in glob.glob(os.path.join(STATIC_PATH, "*.js"))]
|
61
|
-
|
62
|
-
for js_file in js_files:
|
63
|
-
path = os.path.join(STATIC_PATH, js_file)
|
64
|
-
static_js.append("// " + js_file + "\n")
|
65
|
-
with open(path, encoding="utf8") as f:
|
66
|
-
static_js.append(f.read())
|
67
|
-
static_js.extend(["", ""])
|
68
|
-
|
69
58
|
is_distributed = isinstance(environment.runner, MasterRunner)
|
70
59
|
user_spawned = (
|
71
60
|
environment.runner.reported_user_classes_count if is_distributed else environment.runner.user_classes_count
|
@@ -79,7 +68,7 @@ def get_html_report(
|
|
79
68
|
"total": get_ratio(environment.user_classes, user_spawned, True),
|
80
69
|
}
|
81
70
|
|
82
|
-
return
|
71
|
+
return render_template_from(
|
83
72
|
"report.html",
|
84
73
|
template_args={
|
85
74
|
"is_report": True,
|
@@ -107,5 +96,4 @@ def get_html_report(
|
|
107
96
|
"percentiles_to_chart": stats_module.PERCENTILES_TO_CHART,
|
108
97
|
},
|
109
98
|
theme=theme,
|
110
|
-
static_js="\n".join(static_js),
|
111
99
|
)
|
locust/main.py
CHANGED
@@ -36,11 +36,15 @@ from .user.inspectuser import print_task_ratio, print_task_ratio_json
|
|
36
36
|
from .util.load_locustfile import load_locustfile
|
37
37
|
from .util.timespan import parse_timespan
|
38
38
|
|
39
|
+
# import external plugins if installed to allow for registering custom arguments etc
|
39
40
|
try:
|
40
|
-
# import locust_plugins if it is installed, to allow it to register custom arguments etc
|
41
41
|
import locust_plugins # pyright: ignore[reportMissingImports]
|
42
42
|
except ModuleNotFoundError:
|
43
43
|
pass
|
44
|
+
try:
|
45
|
+
import locust_cloud # pyright: ignore[reportMissingImports]
|
46
|
+
except ModuleNotFoundError:
|
47
|
+
pass
|
44
48
|
|
45
49
|
version = locust.__version__
|
46
50
|
|
@@ -482,6 +486,7 @@ See https://github.com/locustio/locust/wiki/Installation#increasing-maximum-numb
|
|
482
486
|
stats_csv_writer=stats_csv_writer,
|
483
487
|
delayed_start=True,
|
484
488
|
userclass_picker_is_active=options.class_picker,
|
489
|
+
build_path=options.build_path,
|
485
490
|
)
|
486
491
|
else:
|
487
492
|
web_ui = None
|
locust/web.py
CHANGED
@@ -33,12 +33,13 @@ from gevent import pywsgi
|
|
33
33
|
from . import __version__ as version
|
34
34
|
from . import argument_parser
|
35
35
|
from . import stats as stats_module
|
36
|
-
from .html import
|
36
|
+
from .html import DEFAULT_BUILD_PATH, get_html_report, render_template_from
|
37
37
|
from .log import get_logs, greenlet_exception_logger
|
38
38
|
from .runners import STATE_MISSING, STATE_RUNNING, MasterRunner
|
39
39
|
from .stats import StatsCSV, StatsCSVFileWriter, StatsErrorDict, sort_stats
|
40
40
|
from .user.inspectuser import get_ratio
|
41
41
|
from .util.cache import memoize
|
42
|
+
from .util.date import format_utc_timestamp
|
42
43
|
from .util.timespan import parse_timespan
|
43
44
|
|
44
45
|
if TYPE_CHECKING:
|
@@ -96,6 +97,7 @@ class WebUI:
|
|
96
97
|
stats_csv_writer: StatsCSV | None = None,
|
97
98
|
delayed_start=False,
|
98
99
|
userclass_picker_is_active=False,
|
100
|
+
build_path: str | None = None,
|
99
101
|
):
|
100
102
|
"""
|
101
103
|
Create WebUI instance and start running the web server in a separate greenlet (self.greenlet)
|
@@ -124,14 +126,11 @@ class WebUI:
|
|
124
126
|
self.app = app
|
125
127
|
app.jinja_env.add_extension("jinja2.ext.do")
|
126
128
|
app.debug = True
|
127
|
-
app.root_path = ROOT_PATH
|
128
|
-
self.webui_build_path = BUILD_PATH
|
129
129
|
self.greenlet: gevent.Greenlet | None = None
|
130
130
|
self._swarm_greenlet: gevent.Greenlet | None = None
|
131
131
|
self.template_args = {}
|
132
132
|
self.auth_args = {}
|
133
|
-
self.app.template_folder =
|
134
|
-
self.app.static_folder = STATIC_PATH
|
133
|
+
self.app.template_folder = build_path or DEFAULT_BUILD_PATH
|
135
134
|
self.app.static_url_path = "/assets/"
|
136
135
|
# ensures static js files work on Windows
|
137
136
|
mimetypes.add_type("application/javascript", ".js")
|
@@ -158,7 +157,13 @@ class WebUI:
|
|
158
157
|
|
159
158
|
@app.route("/assets/<path:path>")
|
160
159
|
def send_assets(path):
|
161
|
-
|
160
|
+
directory = (
|
161
|
+
os.path.join(self.app.template_folder, "assets")
|
162
|
+
if os.path.exists(os.path.join(app.template_folder, "assets", path))
|
163
|
+
else os.path.join(DEFAULT_BUILD_PATH, "assets")
|
164
|
+
)
|
165
|
+
|
166
|
+
return send_from_directory(directory, path)
|
162
167
|
|
163
168
|
@app.route("/")
|
164
169
|
@self.auth_required_if_enabled
|
@@ -499,7 +504,7 @@ class WebUI:
|
|
499
504
|
if not self.web_login:
|
500
505
|
return redirect(url_for("index"))
|
501
506
|
|
502
|
-
return
|
507
|
+
return render_template_from(
|
503
508
|
"auth.html",
|
504
509
|
auth_args=self.auth_args,
|
505
510
|
)
|
@@ -613,6 +618,8 @@ class WebUI:
|
|
613
618
|
else None
|
614
619
|
)
|
615
620
|
|
621
|
+
start_time = format_utc_timestamp(stats.start_time)
|
622
|
+
|
616
623
|
self.template_args = {
|
617
624
|
"locustfile": self.environment.locustfile,
|
618
625
|
"state": self.environment.runner.state,
|
@@ -630,6 +637,7 @@ class WebUI:
|
|
630
637
|
and not (self.userclass_picker_is_active or self.environment.shape_class.use_common_options)
|
631
638
|
),
|
632
639
|
"stats_history_enabled": options and options.stats_history_enabled,
|
640
|
+
"start_time": start_time,
|
633
641
|
"tasks": dumps({}),
|
634
642
|
"extra_options": extra_options,
|
635
643
|
"run_time": options and options.run_time,
|