locust 2.29.1.dev31__tar.gz → 2.29.1.dev39__tar.gz

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 (331) hide show
  1. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/PKG-INFO +31 -26
  2. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/README.md +1 -0
  3. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/_version.py +6 -2
  4. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/clients.py +14 -18
  5. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/contrib/fasthttp.py +63 -18
  6. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/dispatch.py +7 -6
  7. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/event.py +32 -0
  8. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/runners.py +13 -22
  9. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/stats.py +4 -17
  10. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/user/sequential_taskset.py +8 -6
  11. locust-2.29.1.dev31/locust/webui/dist/assets/index-84c63e70.js → locust-2.29.1.dev39/locust/webui/dist/assets/index-e9ad42b4.js +2 -2
  12. locust-2.29.1.dev39/pre_build.py +14 -0
  13. locust-2.29.1.dev39/pyproject.toml +209 -0
  14. locust-2.29.1.dev31/.coveragerc +0 -19
  15. locust-2.29.1.dev31/.dockerignore +0 -8
  16. locust-2.29.1.dev31/.git-blame-ignore-revs +0 -15
  17. locust-2.29.1.dev31/.gitattributes +0 -20
  18. locust-2.29.1.dev31/.github/CONTRIBUTING.md +0 -10
  19. locust-2.29.1.dev31/.github/ISSUE_TEMPLATE/bug.yml +0 -63
  20. locust-2.29.1.dev31/.github/ISSUE_TEMPLATE/config.yml +0 -1
  21. locust-2.29.1.dev31/.github/ISSUE_TEMPLATE/feature_request.yml +0 -29
  22. locust-2.29.1.dev31/.github/workflows/stale.yml +0 -26
  23. locust-2.29.1.dev31/.github/workflows/tests.yml +0 -197
  24. locust-2.29.1.dev31/.gitignore +0 -32
  25. locust-2.29.1.dev31/.pre-commit-config.yaml +0 -10
  26. locust-2.29.1.dev31/.readthedocs.yaml +0 -16
  27. locust-2.29.1.dev31/.vscode/extensions.json +0 -6
  28. locust-2.29.1.dev31/.vscode/launch.json +0 -27
  29. locust-2.29.1.dev31/.vscode/launch_locust.json +0 -20
  30. locust-2.29.1.dev31/.vscode/settings.json +0 -48
  31. locust-2.29.1.dev31/CHANGELOG.md +0 -1684
  32. locust-2.29.1.dev31/Dockerfile +0 -33
  33. locust-2.29.1.dev31/MANIFEST.in +0 -3
  34. locust-2.29.1.dev31/Makefile +0 -23
  35. locust-2.29.1.dev31/SECURITY.md +0 -19
  36. locust-2.29.1.dev31/Vagrantfile +0 -5
  37. locust-2.29.1.dev31/benchmarks/dispatch.py +0 -181
  38. locust-2.29.1.dev31/docs/_static/theme-overrides.css +0 -9
  39. locust-2.29.1.dev31/docs/api.rst +0 -161
  40. locust-2.29.1.dev31/docs/changelog.rst +0 -1254
  41. locust-2.29.1.dev31/docs/conf.py +0 -168
  42. locust-2.29.1.dev31/docs/configuration.rst +0 -285
  43. locust-2.29.1.dev31/docs/custom-load-shape.rst +0 -120
  44. locust-2.29.1.dev31/docs/developing-locust.rst +0 -167
  45. locust-2.29.1.dev31/docs/extending-locust.rst +0 -240
  46. locust-2.29.1.dev31/docs/extensions.rst +0 -41
  47. locust-2.29.1.dev31/docs/faq.rst +0 -107
  48. locust-2.29.1.dev31/docs/further-reading.rst +0 -23
  49. locust-2.29.1.dev31/docs/history.rst +0 -29
  50. locust-2.29.1.dev31/docs/images/extend_modern_web_ui_cache_stats.png +0 -0
  51. locust-2.29.1.dev31/docs/images/locust_workers.png +0 -0
  52. locust-2.29.1.dev31/docs/images/number_of_users.png +0 -0
  53. locust-2.29.1.dev31/docs/images/response_times.png +0 -0
  54. locust-2.29.1.dev31/docs/images/total_requests_per_second.png +0 -0
  55. locust-2.29.1.dev31/docs/images/userclass_picker_example.png +0 -0
  56. locust-2.29.1.dev31/docs/images/webui-running-statistics.png +0 -0
  57. locust-2.29.1.dev31/docs/images/webui-splash-screenshot.png +0 -0
  58. locust-2.29.1.dev31/docs/increase-performance.rst +0 -124
  59. locust-2.29.1.dev31/docs/increasing-request-rate.rst +0 -28
  60. locust-2.29.1.dev31/docs/index.rst +0 -82
  61. locust-2.29.1.dev31/docs/installation.rst +0 -103
  62. locust-2.29.1.dev31/docs/logging.rst +0 -60
  63. locust-2.29.1.dev31/docs/quickstart.rst +0 -97
  64. locust-2.29.1.dev31/docs/requirements.txt +0 -17
  65. locust-2.29.1.dev31/docs/retrieving-stats.rst +0 -29
  66. locust-2.29.1.dev31/docs/running-distributed.rst +0 -167
  67. locust-2.29.1.dev31/docs/running-in-debugger.rst +0 -107
  68. locust-2.29.1.dev31/docs/running-in-docker.rst +0 -41
  69. locust-2.29.1.dev31/docs/running-without-web-ui.rst +0 -97
  70. locust-2.29.1.dev31/docs/tasksets.rst +0 -175
  71. locust-2.29.1.dev31/docs/testing-other-systems.rst +0 -64
  72. locust-2.29.1.dev31/docs/use-as-lib.rst +0 -61
  73. locust-2.29.1.dev31/docs/what-is-locust.rst +0 -72
  74. locust-2.29.1.dev31/docs/writing-a-locustfile.rst +0 -696
  75. locust-2.29.1.dev31/examples/add_command_line_argument.py +0 -24
  76. locust-2.29.1.dev31/examples/basic.py +0 -29
  77. locust-2.29.1.dev31/examples/browse_docs_sequence_test.py +0 -47
  78. locust-2.29.1.dev31/examples/browse_docs_test.py +0 -46
  79. locust-2.29.1.dev31/examples/custom_messages.py +0 -70
  80. locust-2.29.1.dev31/examples/custom_shape/double_wave.py +0 -48
  81. locust-2.29.1.dev31/examples/custom_shape/stages.py +0 -48
  82. locust-2.29.1.dev31/examples/custom_shape/staging_user_classes.py +0 -57
  83. locust-2.29.1.dev31/examples/custom_shape/step_load.py +0 -43
  84. locust-2.29.1.dev31/examples/custom_shape/wait_user_count.py +0 -73
  85. locust-2.29.1.dev31/examples/custom_wait_function.py +0 -56
  86. locust-2.29.1.dev31/examples/custom_xmlrpc_client/server.py +0 -20
  87. locust-2.29.1.dev31/examples/custom_xmlrpc_client/xmlrpc_locustfile.py +0 -66
  88. locust-2.29.1.dev31/examples/debugging.py +0 -15
  89. locust-2.29.1.dev31/examples/debugging_advanced.py +0 -30
  90. locust-2.29.1.dev31/examples/dispatch_test_scripts/locustfile.py +0 -80
  91. locust-2.29.1.dev31/examples/dispatch_test_scripts/run-disributed-headless.sh +0 -58
  92. locust-2.29.1.dev31/examples/dispatch_test_scripts/run-disributed-web.sh +0 -57
  93. locust-2.29.1.dev31/examples/dispatch_test_scripts/run-local-headless.sh +0 -20
  94. locust-2.29.1.dev31/examples/dispatch_test_scripts/run-local-web.sh +0 -19
  95. locust-2.29.1.dev31/examples/docker-compose/docker-compose.yml +0 -16
  96. locust-2.29.1.dev31/examples/dynamic_user_credentials.py +0 -26
  97. locust-2.29.1.dev31/examples/events.py +0 -73
  98. locust-2.29.1.dev31/examples/extend_web_ui.py +0 -163
  99. locust-2.29.1.dev31/examples/fast_http_locust.py +0 -24
  100. locust-2.29.1.dev31/examples/grpc/grpc_user.py +0 -63
  101. locust-2.29.1.dev31/examples/grpc/hello.proto +0 -15
  102. locust-2.29.1.dev31/examples/grpc/hello_pb2.py +0 -159
  103. locust-2.29.1.dev31/examples/grpc/hello_pb2_grpc.py +0 -77
  104. locust-2.29.1.dev31/examples/grpc/hello_server.py +0 -29
  105. locust-2.29.1.dev31/examples/grpc/locustfile.py +0 -22
  106. locust-2.29.1.dev31/examples/locustfile.py +0 -21
  107. locust-2.29.1.dev31/examples/manual_stats_reporting.py +0 -78
  108. locust-2.29.1.dev31/examples/multiple_hosts.py +0 -35
  109. locust-2.29.1.dev31/examples/nested_inline_tasksets.py +0 -26
  110. locust-2.29.1.dev31/examples/rest.py +0 -99
  111. locust-2.29.1.dev31/examples/sdk_session_patching/session_patch_locustfile.py +0 -24
  112. locust-2.29.1.dev31/examples/semaphore_wait.py +0 -22
  113. locust-2.29.1.dev31/examples/stop_on_threshold.py +0 -35
  114. locust-2.29.1.dev31/examples/terraform/aws/README.md +0 -94
  115. locust-2.29.1.dev31/examples/terraform/aws/data_subnet.tf +0 -6
  116. locust-2.29.1.dev31/examples/terraform/aws/main.tf +0 -32
  117. locust-2.29.1.dev31/examples/terraform/aws/output.tf +0 -24
  118. locust-2.29.1.dev31/examples/terraform/aws/plan/basic.py +0 -22
  119. locust-2.29.1.dev31/examples/terraform/aws/provisioner.tf +0 -3
  120. locust-2.29.1.dev31/examples/terraform/aws/variables.tf +0 -29
  121. locust-2.29.1.dev31/examples/test_data_management.py +0 -119
  122. locust-2.29.1.dev31/examples/use_as_lib.py +0 -46
  123. locust-2.29.1.dev31/examples/vagrant/README.md +0 -0
  124. locust-2.29.1.dev31/examples/vagrant/supervisord.conf +0 -36
  125. locust-2.29.1.dev31/examples/web_ui_auth.py +0 -83
  126. locust-2.29.1.dev31/examples/web_ui_cache_stats.py +0 -210
  127. locust-2.29.1.dev31/examples/worker_index.py +0 -20
  128. locust-2.29.1.dev31/generate_changelog.py +0 -37
  129. locust-2.29.1.dev31/locust/test/__init__.py +0 -15
  130. locust-2.29.1.dev31/locust/test/fake_module1_for_env_test.py +0 -7
  131. locust-2.29.1.dev31/locust/test/fake_module2_for_env_test.py +0 -7
  132. locust-2.29.1.dev31/locust/test/mock_locustfile.py +0 -56
  133. locust-2.29.1.dev31/locust/test/mock_logging.py +0 -28
  134. locust-2.29.1.dev31/locust/test/test_debugging.py +0 -39
  135. locust-2.29.1.dev31/locust/test/test_dispatch.py +0 -4170
  136. locust-2.29.1.dev31/locust/test/test_env.py +0 -283
  137. locust-2.29.1.dev31/locust/test/test_fasthttp.py +0 -785
  138. locust-2.29.1.dev31/locust/test/test_http.py +0 -325
  139. locust-2.29.1.dev31/locust/test/test_interruptable_task.py +0 -48
  140. locust-2.29.1.dev31/locust/test/test_load_locustfile.py +0 -228
  141. locust-2.29.1.dev31/locust/test/test_locust_class.py +0 -831
  142. locust-2.29.1.dev31/locust/test/test_log.py +0 -237
  143. locust-2.29.1.dev31/locust/test/test_main.py +0 -2264
  144. locust-2.29.1.dev31/locust/test/test_old_wait_api.py +0 -0
  145. locust-2.29.1.dev31/locust/test/test_parser.py +0 -450
  146. locust-2.29.1.dev31/locust/test/test_runners.py +0 -4342
  147. locust-2.29.1.dev31/locust/test/test_sequential_taskset.py +0 -137
  148. locust-2.29.1.dev31/locust/test/test_stats.py +0 -866
  149. locust-2.29.1.dev31/locust/test/test_tags.py +0 -440
  150. locust-2.29.1.dev31/locust/test/test_taskratio.py +0 -94
  151. locust-2.29.1.dev31/locust/test/test_users.py +0 -69
  152. locust-2.29.1.dev31/locust/test/test_util.py +0 -33
  153. locust-2.29.1.dev31/locust/test/test_wait_time.py +0 -79
  154. locust-2.29.1.dev31/locust/test/test_web.py +0 -1257
  155. locust-2.29.1.dev31/locust/test/test_zmqrpc.py +0 -58
  156. locust-2.29.1.dev31/locust/test/testcases.py +0 -248
  157. locust-2.29.1.dev31/locust/test/util.py +0 -88
  158. locust-2.29.1.dev31/locust/webui/.eslintrc +0 -41
  159. locust-2.29.1.dev31/locust/webui/.gitignore +0 -3
  160. locust-2.29.1.dev31/locust/webui/.prettierrc +0 -9
  161. locust-2.29.1.dev31/locust/webui/auth.html +0 -19
  162. locust-2.29.1.dev31/locust/webui/dev.html +0 -39
  163. locust-2.29.1.dev31/locust/webui/dist/assets/favicon.ico +0 -0
  164. locust-2.29.1.dev31/locust/webui/dist/assets/logo.png +0 -0
  165. locust-2.29.1.dev31/locust/webui/dist/auth.html +0 -20
  166. locust-2.29.1.dev31/locust/webui/dist/index.html +0 -20
  167. locust-2.29.1.dev31/locust/webui/dist/report.html +0 -23
  168. locust-2.29.1.dev31/locust/webui/index.html +0 -19
  169. locust-2.29.1.dev31/locust/webui/package.json +0 -55
  170. locust-2.29.1.dev31/locust/webui/public/assets/favicon.ico +0 -0
  171. locust-2.29.1.dev31/locust/webui/public/assets/logo.png +0 -0
  172. locust-2.29.1.dev31/locust/webui/public/report.html +0 -23
  173. locust-2.29.1.dev31/locust/webui/src/App.test.tsx +0 -35
  174. locust-2.29.1.dev31/locust/webui/src/App.tsx +0 -32
  175. locust-2.29.1.dev31/locust/webui/src/components/DataTable/DataTable.test.tsx +0 -42
  176. locust-2.29.1.dev31/locust/webui/src/components/DataTable/DataTable.tsx +0 -44
  177. locust-2.29.1.dev31/locust/webui/src/components/ExceptionsTable/ExceptionsTable.tsx +0 -19
  178. locust-2.29.1.dev31/locust/webui/src/components/FailuresTable/FailuresTable.tsx +0 -20
  179. locust-2.29.1.dev31/locust/webui/src/components/FallbackRender/FallbackRender.test.tsx +0 -37
  180. locust-2.29.1.dev31/locust/webui/src/components/FallbackRender/FallbackRender.tsx +0 -12
  181. locust-2.29.1.dev31/locust/webui/src/components/Form/Form.tsx +0 -57
  182. locust-2.29.1.dev31/locust/webui/src/components/Form/Select.tsx +0 -41
  183. locust-2.29.1.dev31/locust/webui/src/components/Form/tests/Form.test.tsx +0 -98
  184. locust-2.29.1.dev31/locust/webui/src/components/Form/tests/Select.test.tsx +0 -63
  185. locust-2.29.1.dev31/locust/webui/src/components/Layout/Footer/About.tsx +0 -63
  186. locust-2.29.1.dev31/locust/webui/src/components/Layout/Footer/Footer.tsx +0 -19
  187. locust-2.29.1.dev31/locust/webui/src/components/Layout/Layout.tsx +0 -21
  188. locust-2.29.1.dev31/locust/webui/src/components/Layout/Navbar/DarkLightToggle.tsx +0 -30
  189. locust-2.29.1.dev31/locust/webui/src/components/Layout/Navbar/Navbar.tsx +0 -41
  190. locust-2.29.1.dev31/locust/webui/src/components/Layout/Navbar/SwarmMonitor.test.tsx +0 -71
  191. locust-2.29.1.dev31/locust/webui/src/components/Layout/Navbar/SwarmMonitor.tsx +0 -78
  192. locust-2.29.1.dev31/locust/webui/src/components/LineChart/LineChart.test.tsx +0 -30
  193. locust-2.29.1.dev31/locust/webui/src/components/LineChart/LineChart.tsx +0 -210
  194. locust-2.29.1.dev31/locust/webui/src/components/LogViewer/LogViewer.tsx +0 -95
  195. locust-2.29.1.dev31/locust/webui/src/components/LogViewer/logUtils.tsx +0 -2
  196. locust-2.29.1.dev31/locust/webui/src/components/LogViewer/tests/LogViewer.test.tsx +0 -55
  197. locust-2.29.1.dev31/locust/webui/src/components/LogViewer/tests/useLogViewer.test.tsx +0 -41
  198. locust-2.29.1.dev31/locust/webui/src/components/LogViewer/useLogViewer.ts +0 -41
  199. locust-2.29.1.dev31/locust/webui/src/components/Modal/Modal.tsx +0 -43
  200. locust-2.29.1.dev31/locust/webui/src/components/Reports/Reports.test.tsx +0 -97
  201. locust-2.29.1.dev31/locust/webui/src/components/Reports/Reports.tsx +0 -56
  202. locust-2.29.1.dev31/locust/webui/src/components/ResponseTimeTable/ResponseTimeTable.test.tsx +0 -35
  203. locust-2.29.1.dev31/locust/webui/src/components/ResponseTimeTable/ResponseTimeTable.tsx +0 -27
  204. locust-2.29.1.dev31/locust/webui/src/components/StateButtons/EditButton.tsx +0 -20
  205. locust-2.29.1.dev31/locust/webui/src/components/StateButtons/NewTestButton.tsx +0 -20
  206. locust-2.29.1.dev31/locust/webui/src/components/StateButtons/ResetButton.tsx +0 -13
  207. locust-2.29.1.dev31/locust/webui/src/components/StateButtons/StateButtons.tsx +0 -30
  208. locust-2.29.1.dev31/locust/webui/src/components/StateButtons/StopButton.tsx +0 -27
  209. locust-2.29.1.dev31/locust/webui/src/components/StateButtons/tests/ResetButton.test.tsx +0 -28
  210. locust-2.29.1.dev31/locust/webui/src/components/StateButtons/tests/StateButtons.test.tsx +0 -56
  211. locust-2.29.1.dev31/locust/webui/src/components/StateButtons/tests/StopButton.test.tsx +0 -32
  212. locust-2.29.1.dev31/locust/webui/src/components/StatsTable/StatsTable.tsx +0 -51
  213. locust-2.29.1.dev31/locust/webui/src/components/SwarmCharts/SwarmCharts.tsx +0 -56
  214. locust-2.29.1.dev31/locust/webui/src/components/SwarmForm/SwarmCustomParameters.tsx +0 -77
  215. locust-2.29.1.dev31/locust/webui/src/components/SwarmForm/SwarmEditForm.tsx +0 -56
  216. locust-2.29.1.dev31/locust/webui/src/components/SwarmForm/SwarmForm.tsx +0 -185
  217. locust-2.29.1.dev31/locust/webui/src/components/SwarmForm/SwarmUserClassPicker.tsx +0 -216
  218. locust-2.29.1.dev31/locust/webui/src/components/SwarmForm/tests/SwarmCustomParameters.test.tsx +0 -278
  219. locust-2.29.1.dev31/locust/webui/src/components/SwarmForm/tests/SwarmEditForm.test.tsx +0 -52
  220. locust-2.29.1.dev31/locust/webui/src/components/SwarmForm/tests/SwarmForm.test.tsx +0 -246
  221. locust-2.29.1.dev31/locust/webui/src/components/SwarmForm/tests/SwarmUserClassPicker.test.tsx +0 -174
  222. locust-2.29.1.dev31/locust/webui/src/components/SwarmRatios/SwarmRatios.test.tsx +0 -86
  223. locust-2.29.1.dev31/locust/webui/src/components/SwarmRatios/SwarmRatios.tsx +0 -52
  224. locust-2.29.1.dev31/locust/webui/src/components/Table/Table.test.tsx +0 -92
  225. locust-2.29.1.dev31/locust/webui/src/components/Table/Table.tsx +0 -110
  226. locust-2.29.1.dev31/locust/webui/src/components/Tabs/Tabs.constants.tsx +0 -57
  227. locust-2.29.1.dev31/locust/webui/src/components/Tabs/Tabs.test.tsx +0 -63
  228. locust-2.29.1.dev31/locust/webui/src/components/Tabs/Tabs.tsx +0 -97
  229. locust-2.29.1.dev31/locust/webui/src/components/ViewColumnSelector/ViewColumnSelector.test.tsx +0 -57
  230. locust-2.29.1.dev31/locust/webui/src/components/ViewColumnSelector/ViewColumnSelector.tsx +0 -61
  231. locust-2.29.1.dev31/locust/webui/src/components/WorkersTable/WorkersTable.tsx +0 -22
  232. locust-2.29.1.dev31/locust/webui/src/constants/auth.ts +0 -4
  233. locust-2.29.1.dev31/locust/webui/src/constants/logs.ts +0 -1
  234. locust-2.29.1.dev31/locust/webui/src/constants/swarm.ts +0 -29
  235. locust-2.29.1.dev31/locust/webui/src/constants/theme.ts +0 -12
  236. locust-2.29.1.dev31/locust/webui/src/global.d.ts +0 -13
  237. locust-2.29.1.dev31/locust/webui/src/hooks/tests/useNotifications.test.tsx +0 -135
  238. locust-2.29.1.dev31/locust/webui/src/hooks/tests/useSelecteViewColumns.test.tsx +0 -59
  239. locust-2.29.1.dev31/locust/webui/src/hooks/tests/useSortByField.test.tsx +0 -130
  240. locust-2.29.1.dev31/locust/webui/src/hooks/tests/useSwarmUi.test.tsx +0 -83
  241. locust-2.29.1.dev31/locust/webui/src/hooks/useInterval.ts +0 -25
  242. locust-2.29.1.dev31/locust/webui/src/hooks/useNotifications.ts +0 -33
  243. locust-2.29.1.dev31/locust/webui/src/hooks/useSelectViewColumns.ts +0 -28
  244. locust-2.29.1.dev31/locust/webui/src/hooks/useSortByField.ts +0 -88
  245. locust-2.29.1.dev31/locust/webui/src/hooks/useSwarmUi.ts +0 -130
  246. locust-2.29.1.dev31/locust/webui/src/index.tsx +0 -13
  247. locust-2.29.1.dev31/locust/webui/src/pages/Auth.tsx +0 -98
  248. locust-2.29.1.dev31/locust/webui/src/pages/Dashboard.tsx +0 -45
  249. locust-2.29.1.dev31/locust/webui/src/pages/HtmlReport.tsx +0 -116
  250. locust-2.29.1.dev31/locust/webui/src/pages/tests/Auth.test.tsx +0 -68
  251. locust-2.29.1.dev31/locust/webui/src/pages/tests/Dashboard.test.tsx +0 -36
  252. locust-2.29.1.dev31/locust/webui/src/pages/tests/HtmlReport.test.tsx +0 -55
  253. locust-2.29.1.dev31/locust/webui/src/redux/api/swarm.ts +0 -57
  254. locust-2.29.1.dev31/locust/webui/src/redux/hooks.ts +0 -23
  255. locust-2.29.1.dev31/locust/webui/src/redux/slice/logViewer.slice.ts +0 -24
  256. locust-2.29.1.dev31/locust/webui/src/redux/slice/notification.slice.ts +0 -22
  257. locust-2.29.1.dev31/locust/webui/src/redux/slice/root.slice.ts +0 -42
  258. locust-2.29.1.dev31/locust/webui/src/redux/slice/swarm.slice.ts +0 -51
  259. locust-2.29.1.dev31/locust/webui/src/redux/slice/tests/ui.slice.test.ts +0 -113
  260. locust-2.29.1.dev31/locust/webui/src/redux/slice/theme.slice.ts +0 -24
  261. locust-2.29.1.dev31/locust/webui/src/redux/slice/ui.slice.ts +0 -85
  262. locust-2.29.1.dev31/locust/webui/src/redux/slice/url.slice.ts +0 -25
  263. locust-2.29.1.dev31/locust/webui/src/redux/store.ts +0 -12
  264. locust-2.29.1.dev31/locust/webui/src/redux/utils.ts +0 -9
  265. locust-2.29.1.dev31/locust/webui/src/styles/theme.ts +0 -25
  266. locust-2.29.1.dev31/locust/webui/src/test/constants.ts +0 -1
  267. locust-2.29.1.dev31/locust/webui/src/test/mocks/statsRequest.mock.ts +0 -174
  268. locust-2.29.1.dev31/locust/webui/src/test/mocks/swarmState.mock.ts +0 -52
  269. locust-2.29.1.dev31/locust/webui/src/test/setup.ts +0 -37
  270. locust-2.29.1.dev31/locust/webui/src/test/testUtils.tsx +0 -24
  271. locust-2.29.1.dev31/locust/webui/src/types/auth.types.ts +0 -11
  272. locust-2.29.1.dev31/locust/webui/src/types/swarm.types.ts +0 -58
  273. locust-2.29.1.dev31/locust/webui/src/types/tab.types.ts +0 -8
  274. locust-2.29.1.dev31/locust/webui/src/types/table.types.ts +0 -6
  275. locust-2.29.1.dev31/locust/webui/src/types/ui.types.ts +0 -110
  276. locust-2.29.1.dev31/locust/webui/src/utils/array.ts +0 -5
  277. locust-2.29.1.dev31/locust/webui/src/utils/date.ts +0 -5
  278. locust-2.29.1.dev31/locust/webui/src/utils/number.ts +0 -4
  279. locust-2.29.1.dev31/locust/webui/src/utils/object.ts +0 -40
  280. locust-2.29.1.dev31/locust/webui/src/utils/string.ts +0 -63
  281. locust-2.29.1.dev31/locust/webui/src/utils/tests/number.test.ts +0 -13
  282. locust-2.29.1.dev31/locust/webui/src/utils/tests/object.test.ts +0 -142
  283. locust-2.29.1.dev31/locust/webui/src/utils/tests/string.test.ts +0 -249
  284. locust-2.29.1.dev31/locust/webui/src/utils/tests/url.test.ts +0 -44
  285. locust-2.29.1.dev31/locust/webui/src/utils/url.ts +0 -14
  286. locust-2.29.1.dev31/locust/webui/tsconfig.json +0 -27
  287. locust-2.29.1.dev31/locust/webui/vite.config.ts +0 -39
  288. locust-2.29.1.dev31/locust/webui/vitest.config.ts +0 -16
  289. locust-2.29.1.dev31/locust/webui/yarn.lock +0 -4913
  290. locust-2.29.1.dev31/locust.egg-info/PKG-INFO +0 -126
  291. locust-2.29.1.dev31/locust.egg-info/SOURCES.txt +0 -327
  292. locust-2.29.1.dev31/locust.egg-info/dependency_links.txt +0 -1
  293. locust-2.29.1.dev31/locust.egg-info/entry_points.txt +0 -2
  294. locust-2.29.1.dev31/locust.egg-info/not-zip-safe +0 -1
  295. locust-2.29.1.dev31/locust.egg-info/requires.txt +0 -21
  296. locust-2.29.1.dev31/locust.egg-info/top_level.txt +0 -1
  297. locust-2.29.1.dev31/package.json +0 -16
  298. locust-2.29.1.dev31/pyproject.toml +0 -115
  299. locust-2.29.1.dev31/setup.cfg +0 -4
  300. locust-2.29.1.dev31/tox.ini +0 -45
  301. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/LICENSE +0 -0
  302. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/__init__.py +0 -0
  303. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/__main__.py +0 -0
  304. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/argument_parser.py +0 -0
  305. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/contrib/__init__.py +0 -0
  306. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/debug.py +0 -0
  307. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/env.py +0 -0
  308. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/exception.py +0 -0
  309. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/html.py +0 -0
  310. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/input_events.py +0 -0
  311. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/log.py +0 -0
  312. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/main.py +0 -0
  313. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/py.typed +0 -0
  314. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/rpc/__init__.py +0 -0
  315. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/rpc/protocol.py +0 -0
  316. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/rpc/zmqrpc.py +0 -0
  317. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/shape.py +0 -0
  318. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/user/__init__.py +0 -0
  319. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/user/inspectuser.py +0 -0
  320. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/user/task.py +0 -0
  321. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/user/users.py +0 -0
  322. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/user/wait_time.py +0 -0
  323. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/util/__init__.py +0 -0
  324. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/util/cache.py +0 -0
  325. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/util/date.py +0 -0
  326. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/util/deprecation.py +0 -0
  327. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/util/exception_handler.py +0 -0
  328. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/util/load_locustfile.py +0 -0
  329. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/util/rounding.py +0 -0
  330. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/util/timespan.py +0 -0
  331. {locust-2.29.1.dev31 → locust-2.29.1.dev39}/locust/web.py +0 -0
@@ -1,15 +1,15 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: locust
3
- Version: 2.29.1.dev31
3
+ Version: 2.29.1.dev39
4
4
  Summary: Developer-friendly load testing framework
5
+ Home-page: https://locust.io/
5
6
  License: MIT
6
- Project-URL: Homepage, https://github.com/locustio/locust
7
- Project-URL: Documentation, https://docs.locust.io/
8
- Project-URL: Code, https://github.com/locustio/locust
9
- Project-URL: Help/Questions, https://stackoverflow.com/questions/tagged/locust
10
- Project-URL: Issue tracker, https://github.com/locustio/locust/issues
11
- Classifier: Topic :: Software Development :: Testing :: Traffic Generation
7
+ Author: Jonatan Heyman
8
+ Maintainer: Lars Holmberg
9
+ Requires-Python: >=3.9
12
10
  Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: System Administrators
13
13
  Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Operating System :: OS Independent
15
15
  Classifier: Programming Language :: Python
@@ -18,29 +18,32 @@ Classifier: Programming Language :: Python :: 3.9
18
18
  Classifier: Programming Language :: Python :: 3.10
19
19
  Classifier: Programming Language :: Python :: 3.11
20
20
  Classifier: Programming Language :: Python :: 3.12
21
- Classifier: Intended Audience :: Developers
22
- Classifier: Intended Audience :: System Administrators
23
21
  Classifier: Topic :: Software Development :: Testing
24
22
  Classifier: Topic :: Software Development :: Testing :: Traffic Generation
25
23
  Classifier: Topic :: System :: Distributed Computing
26
- Requires-Python: >=3.9
24
+ Requires-Dist: ConfigArgParse (>=1.5.5)
25
+ Requires-Dist: Flask-Cors (>=3.0.10)
26
+ Requires-Dist: Flask-Login (>=0.6.3)
27
+ Requires-Dist: Werkzeug (>=2.0.0)
28
+ Requires-Dist: flask (>=2.0.0)
29
+ Requires-Dist: gevent (>=22.10.2)
30
+ Requires-Dist: geventhttpclient (>=2.3.1)
31
+ Requires-Dist: msgpack (>=1.0.0)
32
+ Requires-Dist: psutil (>=5.9.1)
33
+ Requires-Dist: pywin32 ; sys_platform == "win32"
34
+ Requires-Dist: pyzmq (>=25.0.0)
35
+ Requires-Dist: requests (>=2.26.0) ; python_full_version <= "3.11.0"
36
+ Requires-Dist: requests (>=2.32.2) ; python_full_version > "3.11.0"
37
+ Requires-Dist: tomli (>=1.1.0) ; python_version < "3.11"
38
+ Requires-Dist: typing_extensions (>=4.6.0) ; python_version < "3.11"
39
+ Project-URL: Documentation, https://docs.locust.io/
40
+ Project-URL: Help/Questions, https://github.com/orgs/locustio/discussions/
41
+ Project-URL: Issue Tracker, https://github.com/locustio/locust/issues
42
+ Project-URL: Repository, https://github.com/locustio/locust
43
+ Project-URL: Stack Overflow, https://stackoverflow.com/questions/tagged/locust
44
+ Project-URL: Slack, https://locustio.slack.com/
45
+ Project-URL: Slack/Signup, https://communityinviter.com/apps/locustio/locust
27
46
  Description-Content-Type: text/markdown
28
- License-File: LICENSE
29
- Requires-Dist: gevent>=22.10.2
30
- Requires-Dist: flask>=2.0.0
31
- Requires-Dist: Werkzeug>=2.0.0
32
- Requires-Dist: requests>=2.26.0
33
- Requires-Dist: requests>=2.32.2; python_version > "3.11"
34
- Requires-Dist: msgpack>=1.0.0
35
- Requires-Dist: pyzmq>=25.0.0
36
- Requires-Dist: geventhttpclient>=2.3.1
37
- Requires-Dist: ConfigArgParse>=1.5.5
38
- Requires-Dist: tomli>=1.1.0; python_version < "3.11"
39
- Requires-Dist: typing_extensions>=4.6.0; python_version < "3.11"
40
- Requires-Dist: psutil>=5.9.1
41
- Requires-Dist: Flask-Login>=0.6.3
42
- Requires-Dist: Flask-Cors>=3.0.10
43
- Requires-Dist: pywin32; platform_system == "Windows"
44
47
 
45
48
  # Locust
46
49
 
@@ -112,6 +115,7 @@ Locust's code base is intentionally kept small and doesn't solve everything out
112
115
 
113
116
  * Documentation: [docs.locust.io](https://docs.locust.io)
114
117
  * Support/Questions: [StackOverflow](https://stackoverflow.com/questions/tagged/locust)
118
+ * Github Discussions: [Github Discussions](https://github.com/orgs/locustio/discussions)
115
119
  * Chat/discussion: [Slack](https://locustio.slack.com) [(signup)](https://communityinviter.com/apps/locustio/locust)
116
120
 
117
121
  ## Authors
@@ -124,3 +128,4 @@ Locust's code base is intentionally kept small and doesn't solve everything out
124
128
  ## License
125
129
 
126
130
  Open source licensed under the MIT license (see _LICENSE_ file for details).
131
+
@@ -68,6 +68,7 @@ Locust's code base is intentionally kept small and doesn't solve everything out
68
68
 
69
69
  * Documentation: [docs.locust.io](https://docs.locust.io)
70
70
  * Support/Questions: [StackOverflow](https://stackoverflow.com/questions/tagged/locust)
71
+ * Github Discussions: [Github Discussions](https://github.com/orgs/locustio/discussions)
71
72
  * Chat/discussion: [Slack](https://locustio.slack.com) [(signup)](https://communityinviter.com/apps/locustio/locust)
72
73
 
73
74
  ## Authors
@@ -3,6 +3,7 @@
3
3
  TYPE_CHECKING = False
4
4
  if TYPE_CHECKING:
5
5
  from typing import Tuple, Union
6
+
6
7
  VERSION_TUPLE = Tuple[Union[int, str], ...]
7
8
  else:
8
9
  VERSION_TUPLE = object
@@ -12,5 +13,8 @@ __version__: str
12
13
  __version_tuple__: VERSION_TUPLE
13
14
  version_tuple: VERSION_TUPLE
14
15
 
15
- __version__ = version = '2.29.1.dev31'
16
- __version_tuple__ = version_tuple = (2, 29, 1, 'dev31')
16
+
17
+ __version__ = "2.29.1.dev39"
18
+ version = __version__
19
+ __version_tuple__ = (2, 29, 1, "dev39")
20
+ version_tuple = __version_tuple__
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING
7
7
  from urllib.parse import urlparse, urlunparse
8
8
 
9
9
  import requests
10
- from requests import Request, Response
10
+ from requests import Response
11
11
  from requests.adapters import HTTPAdapter
12
12
  from requests.auth import HTTPBasicAuth
13
13
  from requests.exceptions import InvalidSchema, InvalidURL, MissingSchema, RequestException
@@ -54,8 +54,10 @@ absolute_http_url_regexp = re.compile(r"^https?://", re.I)
54
54
 
55
55
 
56
56
  class LocustResponse(Response):
57
- def raise_for_status(self):
58
- if hasattr(self, "error") and self.error:
57
+ error: Exception | None = None
58
+
59
+ def raise_for_status(self) -> None:
60
+ if self.error:
59
61
  raise self.error
60
62
  Response.raise_for_status(self)
61
63
 
@@ -112,7 +114,7 @@ class HttpSession(requests.Session):
112
114
  self.mount("https://", LocustHttpAdapter(pool_manager=pool_manager))
113
115
  self.mount("http://", LocustHttpAdapter(pool_manager=pool_manager))
114
116
 
115
- def _build_url(self, path):
117
+ def _build_url(self, path) -> str:
116
118
  """prepend url with hostname unless it's already an absolute URL"""
117
119
  if absolute_http_url_regexp.match(path):
118
120
  return path
@@ -191,7 +193,7 @@ class HttpSession(requests.Session):
191
193
  response_time = (time.perf_counter() - start_perf_counter) * 1000
192
194
 
193
195
  request_before_redirect = (response.history and response.history[0] or response).request
194
- url = request_before_redirect.url
196
+ url = request_before_redirect.url # type: ignore
195
197
 
196
198
  if not name:
197
199
  name = request_before_redirect.path_url
@@ -225,7 +227,7 @@ class HttpSession(requests.Session):
225
227
  pass
226
228
  return response
227
229
 
228
- def _send_request_safe_mode(self, method, url, **kwargs):
230
+ def _send_request_safe_mode(self, method, url, **kwargs) -> Response | LocustResponse:
229
231
  """
230
232
  Send an HTTP request, and catch any exception that might occur due to connection problems.
231
233
 
@@ -238,8 +240,8 @@ class HttpSession(requests.Session):
238
240
  except RequestException as e:
239
241
  r = LocustResponse()
240
242
  r.error = e
241
- r.status_code = 0 # with this status_code, content returns None
242
- r.request = Request(method, url).prepare()
243
+ r.status_code = 0
244
+ r.request = e.request # type: ignore
243
245
  return r
244
246
 
245
247
  def get(
@@ -440,17 +442,11 @@ class LocustHttpAdapter(HTTPAdapter):
440
442
 
441
443
 
442
444
  # Monkey patch Response class to give some guidance
443
- def _success(self):
444
- raise LocustError(
445
- "If you want to change the state of the request, you must pass catch_response=True. See http://docs.locust.io/en/stable/writing-a-locustfile.html#validating-responses"
446
- )
447
-
448
-
449
- def _failure(self):
445
+ def _missing_catch_response_True(self, *_args, **_kwargs):
450
446
  raise LocustError(
451
- "If you want to change the state of the request, you must pass catch_response=True. See http://docs.locust.io/en/stable/writing-a-locustfile.html#validating-responses"
447
+ "If you want to change the state of the request using .success() or .failure(), you must pass catch_response=True. See http://docs.locust.io/en/stable/writing-a-locustfile.html#validating-responses"
452
448
  )
453
449
 
454
450
 
455
- Response.success = _success # type: ignore[attr-defined]
456
- Response.failure = _failure # type: ignore[attr-defined]
451
+ Response.success = _missing_catch_response_True # type: ignore[attr-defined]
452
+ Response.failure = _missing_catch_response_True # type: ignore[attr-defined]
@@ -12,12 +12,11 @@ import socket
12
12
  import time
13
13
  import traceback
14
14
  from base64 import b64encode
15
- from collections.abc import Generator
16
15
  from contextlib import contextmanager
17
16
  from http.cookiejar import CookieJar
18
17
  from json.decoder import JSONDecodeError
19
18
  from ssl import SSLError
20
- from typing import Any, Callable, cast
19
+ from typing import TYPE_CHECKING, cast
21
20
  from urllib.parse import urlparse, urlunparse
22
21
 
23
22
  import gevent
@@ -32,6 +31,36 @@ from geventhttpclient.useragent import CompatRequest, CompatResponse, Connection
32
31
  # borrow requests's content-type header parsing
33
32
  from requests.utils import get_encoding_from_headers
34
33
 
34
+ if TYPE_CHECKING:
35
+ import sys
36
+ from collections.abc import Callable, Generator
37
+ from typing import TypedDict
38
+
39
+ if sys.version_info >= (3, 11):
40
+ from typing import Unpack
41
+ else:
42
+ from typing_extensions import Unpack
43
+
44
+ class PostKwargs(TypedDict, total=False):
45
+ name: str | None
46
+ catch_response: bool
47
+ stream: bool
48
+ headers: dict | None
49
+ auth: tuple[str | bytes, str | bytes] | None
50
+ allow_redirects: bool
51
+ context: dict
52
+
53
+ class PutKwargs(PostKwargs, total=False):
54
+ json: dict | None
55
+
56
+ class PatchKwargs(PostKwargs, total=False):
57
+ json: dict | None
58
+
59
+ class RESTKwargs(PostKwargs, total=False):
60
+ data: str | dict | None
61
+ json: dict | None
62
+
63
+
35
64
  # Monkey patch geventhttpclient.useragent.CompatRequest so that Cookiejar works with Python >= 3.3
36
65
  # More info: https://github.com/requests/requests/pull/871
37
66
  CompatRequest.unverifiable = False
@@ -85,7 +114,7 @@ class FastHttpSession:
85
114
  client_pool: HTTPClientPool | None = None,
86
115
  ssl_context_factory: Callable | None = None,
87
116
  **kwargs,
88
- ):
117
+ ) -> None:
89
118
  self.environment = environment
90
119
  self.base_url = base_url
91
120
  self.cookiejar = CookieJar()
@@ -117,14 +146,14 @@ class FastHttpSession:
117
146
  # store authentication header (we construct this by using _basic_auth_str() function from requests.auth)
118
147
  self.auth_header = _construct_basic_auth_str(parsed_url.username, parsed_url.password)
119
148
 
120
- def _build_url(self, path):
149
+ def _build_url(self, path: str) -> str:
121
150
  """prepend url with hostname unless it's already an absolute URL"""
122
151
  if absolute_http_url_regexp.match(path):
123
152
  return path
124
153
  else:
125
154
  return f"{self.base_url}{path}"
126
155
 
127
- def _send_request_safe_mode(self, method, url, **kwargs):
156
+ def _send_request_safe_mode(self, method: str, url: str, **kwargs):
128
157
  """
129
158
  Send an HTTP request, and catch any exception that might occur due to either
130
159
  connection problems, or invalid HTTP status codes
@@ -155,9 +184,9 @@ class FastHttpSession:
155
184
  catch_response: bool = False,
156
185
  stream: bool = False,
157
186
  headers: dict | None = None,
158
- auth=None,
187
+ auth: tuple[str | bytes, str | bytes] | None = None,
159
188
  json: dict | None = None,
160
- allow_redirects=True,
189
+ allow_redirects: bool = True,
161
190
  context: dict = {},
162
191
  **kwargs,
163
192
  ) -> ResponseContextManager | FastResponse:
@@ -187,6 +216,7 @@ class FastHttpSession:
187
216
  and can instead be consumed by accessing the stream attribute on the Response object.
188
217
  Another side effect of setting stream to True is that the time for downloading the response
189
218
  content will not be accounted for in the request time that is reported by Locust.
219
+ :param allow_redirects: (optional) Set to True by default.
190
220
  """
191
221
  # prepend url with hostname unless it's already an absolute URL
192
222
  built_url = self._build_url(url)
@@ -250,7 +280,7 @@ class FastHttpSession:
250
280
  # Record the consumed time
251
281
  # Note: This is intentionally placed after we record the content_size above, since
252
282
  # we'll then trigger fetching of the body (unless stream=True)
253
- request_meta["response_time"] = int((time.perf_counter() - start_perf_counter) * 1000)
283
+ request_meta["response_time"] = (time.perf_counter() - start_perf_counter) * 1000
254
284
 
255
285
  if catch_response:
256
286
  return ResponseContextManager(response, environment=self.environment, request_meta=request_meta)
@@ -263,30 +293,37 @@ class FastHttpSession:
263
293
  self.environment.events.request.fire(**request_meta)
264
294
  return response
265
295
 
266
- def delete(self, url, **kwargs):
296
+ def delete(self, url: str, **kwargs: Unpack[RESTKwargs]) -> ResponseContextManager | FastResponse:
297
+ """Sends a DELETE request"""
267
298
  return self.request("DELETE", url, **kwargs)
268
299
 
269
- def get(self, url, **kwargs):
300
+ def get(self, url: str, **kwargs: Unpack[RESTKwargs]) -> ResponseContextManager | FastResponse:
270
301
  """Sends a GET request"""
271
302
  return self.request("GET", url, **kwargs)
272
303
 
273
- def head(self, url, **kwargs):
304
+ def head(self, url: str, **kwargs: Unpack[RESTKwargs]) -> ResponseContextManager | FastResponse:
274
305
  """Sends a HEAD request"""
275
306
  return self.request("HEAD", url, **kwargs)
276
307
 
277
- def options(self, url, **kwargs):
308
+ def options(self, url: str, **kwargs: Unpack[RESTKwargs]) -> ResponseContextManager | FastResponse:
278
309
  """Sends a OPTIONS request"""
279
310
  return self.request("OPTIONS", url, **kwargs)
280
311
 
281
- def patch(self, url, data=None, **kwargs):
282
- """Sends a POST request"""
312
+ def patch(
313
+ self, url: str, data: str | dict | None = None, **kwargs: Unpack[PatchKwargs]
314
+ ) -> ResponseContextManager | FastResponse:
315
+ """Sends a PATCH request"""
283
316
  return self.request("PATCH", url, data=data, **kwargs)
284
317
 
285
- def post(self, url, data=None, **kwargs):
318
+ def post(
319
+ self, url: str, data: str | dict | None = None, json: dict | None = None, **kwargs: Unpack[PostKwargs]
320
+ ) -> ResponseContextManager | FastResponse:
286
321
  """Sends a POST request"""
287
- return self.request("POST", url, data=data, **kwargs)
322
+ return self.request("POST", url, data=data, json=json, **kwargs)
288
323
 
289
- def put(self, url, data=None, **kwargs):
324
+ def put(
325
+ self, url: str, data: str | dict | None = None, **kwargs: Unpack[PutKwargs]
326
+ ) -> ResponseContextManager | FastResponse:
290
327
  """Sends a PUT request"""
291
328
  return self.request("PUT", url, data=data, **kwargs)
292
329
 
@@ -324,6 +361,12 @@ class FastHttpUser(User):
324
361
  Note that setting this value has no effect when custom client_pool was given, and you need to spawn a your own gevent pool
325
362
  to use it (as Users only have one greenlet). See test_fasthttp.py / test_client_pool_concurrency for an example."""
326
363
 
364
+ proxy_host: str | None = None
365
+ """Parameter passed to FastHttpSession"""
366
+
367
+ proxy_port: int | None = None
368
+ """Parameter passed to FastHttpSession"""
369
+
327
370
  client_pool: HTTPClientPool | None = None
328
371
  """HTTP client pool to use. If not given, a new pool is created per single user."""
329
372
 
@@ -355,6 +398,8 @@ class FastHttpUser(User):
355
398
  client_pool=self.client_pool,
356
399
  ssl_context_factory=self.ssl_context_factory,
357
400
  headers=self.default_headers,
401
+ proxy_host=self.proxy_host,
402
+ proxy_port=self.proxy_port,
358
403
  )
359
404
  """
360
405
  Instance of HttpSession that is created upon instantiation of User.
@@ -438,7 +483,7 @@ class FastResponse(CompatResponse):
438
483
 
439
484
  _response: HTTPSocketPoolResponse | None = None
440
485
 
441
- encoding: str | None = None
486
+ encoding: str | float | None = None
442
487
  """In some cases setting the encoding explicitly is needed. If so, do it before calling .text"""
443
488
 
444
489
  request: FastRequest | None = None
@@ -90,13 +90,13 @@ class UsersDispatcher(Iterator):
90
90
  assert len(user_classes) > 0
91
91
  assert len(set(self._user_classes)) == len(self._user_classes)
92
92
 
93
- self._target_user_count: int = None
93
+ self._target_user_count: int = 0
94
94
 
95
- self._spawn_rate: float = None
95
+ self._spawn_rate: float = 0.0
96
96
 
97
- self._user_count_per_dispatch_iteration: int = None
97
+ self._user_count_per_dispatch_iteration: int = 0
98
98
 
99
- self._wait_between_dispatch: float = None
99
+ self._wait_between_dispatch: float = 0.0
100
100
 
101
101
  self._initial_users_on_workers = {
102
102
  worker_node.id: {user_class.__name__: 0 for user_class in self._user_classes}
@@ -107,7 +107,8 @@ class UsersDispatcher(Iterator):
107
107
 
108
108
  self._current_user_count = self.get_current_user_count()
109
109
 
110
- self._dispatcher_generator: Generator[dict[str, dict[str, int]], None, None] = None
110
+ self._dispatcher_generator: Generator[dict[str, dict[str, int]], None, None] = None # type: ignore
111
+ # a generator is assigned (in new_dispatch()) to _dispatcher_generator before it's used
111
112
 
112
113
  self._user_generator = self._user_gen()
113
114
 
@@ -131,7 +132,7 @@ class UsersDispatcher(Iterator):
131
132
  return sum(map(sum, map(dict.values, self._users_on_workers.values())))
132
133
 
133
134
  @property
134
- def dispatch_in_progress(self):
135
+ def dispatch_in_progress(self) -> bool:
135
136
  return self._dispatch_in_progress
136
137
 
137
138
  @property
@@ -235,6 +235,38 @@ class Events:
235
235
  Fired when the CPU usage exceeds runners.CPU_WARNING_THRESHOLD (90% by default)
236
236
  """
237
237
 
238
+ heartbeat_sent: EventHook
239
+ """
240
+ Fired when a heartbeat is sent by master to a worker.
241
+
242
+ Event arguments:
243
+
244
+ :param client_id: worker client id
245
+ :param timestamp: time in seconds since the epoch (float) when the event occured
246
+ """
247
+
248
+ heartbeat_received: EventHook
249
+ """
250
+ Fired when a heartbeat is received by a worker from master.
251
+
252
+ Event arguments:
253
+
254
+ :param client_id: worker client id
255
+ :param timestamp: time in seconds since the epoch (float) when the event occured
256
+ """
257
+
258
+ usage_monitor: EventHook
259
+ """
260
+ Fired every runners.CPU_MONITOR_INTERVAL (5.0 seconds by default) with information about
261
+ current CPU and memory usage.
262
+
263
+ Event arguments:
264
+
265
+ :param environment: locust environment
266
+ :param cpu_usage: current CPU usage in percent
267
+ :param memory_usage: current memory usage (RSS) in bytes
268
+ """
269
+
238
270
  def __init__(self):
239
271
  # For backward compatibility use also values of class attributes
240
272
  for name, value in vars(type(self)).items():
@@ -15,19 +15,9 @@ import traceback
15
15
  from abc import abstractmethod
16
16
  from collections import defaultdict
17
17
  from collections.abc import Iterator, MutableMapping, ValuesView
18
- from operator import (
19
- itemgetter,
20
- methodcaller,
21
- )
18
+ from operator import itemgetter, methodcaller
22
19
  from types import TracebackType
23
- from typing import (
24
- TYPE_CHECKING,
25
- Any,
26
- Callable,
27
- NoReturn,
28
- TypedDict,
29
- cast,
30
- )
20
+ from typing import TYPE_CHECKING, Any, Callable, NoReturn, TypedDict, cast
31
21
  from uuid import uuid4
32
22
 
33
23
  import gevent
@@ -40,15 +30,8 @@ from . import argument_parser
40
30
  from .dispatch import UsersDispatcher
41
31
  from .exception import RPCError, RPCReceiveError, RPCSendError
42
32
  from .log import get_logs, greenlet_exception_logger
43
- from .rpc import (
44
- Message,
45
- rpc,
46
- )
47
- from .stats import (
48
- RequestStats,
49
- StatsError,
50
- setup_distributed_stats_event_listeners,
51
- )
33
+ from .rpc import Message, rpc
34
+ from .stats import RequestStats, StatsError, setup_distributed_stats_event_listeners
52
35
 
53
36
  if TYPE_CHECKING:
54
37
  from . import User
@@ -106,7 +89,7 @@ class Runner:
106
89
  self.spawning_greenlet: gevent.Greenlet | None = None
107
90
  self.shape_greenlet: gevent.Greenlet | None = None
108
91
  self.shape_last_tick: tuple[int, float] | tuple[int, float, list[type[User]] | None] | None = None
109
- self.current_cpu_usage: int = 0
92
+ self.current_cpu_usage: float = 0.0
110
93
  self.cpu_warning_emitted: bool = False
111
94
  self.worker_cpu_warning_emitted: bool = False
112
95
  self.current_memory_usage: int = 0
@@ -308,6 +291,10 @@ class Runner:
308
291
  f"CPU usage above {CPU_WARNING_THRESHOLD}%! This may constrain your throughput and may even give inconsistent response time measurements! See https://docs.locust.io/en/stable/running-distributed.html for how to distribute the load over multiple CPU cores or machines"
309
292
  )
310
293
  self.cpu_warning_emitted = True
294
+
295
+ self.environment.events.usage_monitor.fire(
296
+ environment=self.environment, cpu_usage=self.current_cpu_usage, memory_usage=self.current_memory_usage
297
+ )
311
298
  gevent.sleep(CPU_MONITOR_INTERVAL)
312
299
 
313
300
  @abstractmethod
@@ -1102,6 +1089,7 @@ class MasterRunner(DistributedRunner):
1102
1089
  )
1103
1090
  if "current_memory_usage" in msg.data:
1104
1091
  c.memory_usage = msg.data["current_memory_usage"]
1092
+ self.environment.events.heartbeat_sent.fire(client_id=msg.node_id, timestamp=time.time())
1105
1093
  self.server.send_to_client(Message("heartbeat", None, msg.node_id))
1106
1094
  else:
1107
1095
  logging.debug(f"Got heartbeat message from unknown worker {msg.node_id}")
@@ -1399,6 +1387,9 @@ class WorkerRunner(DistributedRunner):
1399
1387
  self.reset_connection()
1400
1388
  elif msg.type == "heartbeat":
1401
1389
  self.last_heartbeat_timestamp = time.time()
1390
+ self.environment.events.heartbeat_received.fire(
1391
+ client_id=msg.node_id, timestamp=self.last_heartbeat_timestamp
1392
+ )
1402
1393
  elif msg.type == "update_user_class":
1403
1394
  self.environment.update_user_class(msg.data)
1404
1395
  elif msg.type == "spawning_complete":
@@ -9,25 +9,12 @@ import signal
9
9
  import time
10
10
  from abc import abstractmethod
11
11
  from collections import OrderedDict, defaultdict, namedtuple
12
- from collections import (
13
- OrderedDict as OrderedDictType,
14
- )
15
12
  from collections.abc import Iterable
16
13
  from copy import copy
17
14
  from html import escape
18
15
  from itertools import chain
19
- from tempfile import NamedTemporaryFile
20
16
  from types import FrameType
21
- from typing import (
22
- TYPE_CHECKING,
23
- Any,
24
- Callable,
25
- NoReturn,
26
- Protocol,
27
- TypedDict,
28
- TypeVar,
29
- cast,
30
- )
17
+ from typing import TYPE_CHECKING, Any, Callable, NoReturn, Protocol, TypedDict, TypeVar, cast
31
18
 
32
19
  import gevent
33
20
 
@@ -319,12 +306,12 @@ class StatsEntry:
319
306
  A {response_time => count} dict that holds the response time distribution of all
320
307
  the requests.
321
308
 
322
- The keys (the response time in ms) are rounded to store 1, 2, ... 9, 10, 20. .. 90,
323
- 100, 200 .. 900, 1000, 2000 ... 9000, in order to save memory.
309
+ The keys (the response time in ms) are rounded to store 1, 2, ... 98, 99, 100, 110, 120, ... 980, 990, 1000,
310
+ 1100, 1200, ... 9800, 9900, 10_000, 11_000, 12_000 ... in order to save memory.
324
311
 
325
312
  This dict is used to calculate the median and percentile response times.
326
313
  """
327
- self.response_times_cache: OrderedDictType[int, CachedResponseTimes] | None = None
314
+ self.response_times_cache: OrderedDict[int, CachedResponseTimes] | None = None
328
315
  """
329
316
  If use_response_times_cache is set to True, this will be a {timestamp => CachedResponseTimes()}
330
317
  OrderedDict that holds a copy of the response_times dict for each of the last 20 seconds.
@@ -1,6 +1,6 @@
1
1
  from locust.exception import LocustError
2
2
 
3
- import logging
3
+ from itertools import cycle
4
4
 
5
5
  from .task import TaskSet, TaskSetMeta
6
6
 
@@ -26,8 +26,12 @@ class SequentialTaskSetMeta(TaskSetMeta):
26
26
  # compared to methods declared with @task
27
27
  if isinstance(value, list):
28
28
  new_tasks.extend(value)
29
+ elif isinstance(value, dict):
30
+ for task, weight in value.items():
31
+ for _ in range(weight):
32
+ new_tasks.append(task)
29
33
  else:
30
- raise ValueError("On SequentialTaskSet the task attribute can only be set to a list")
34
+ raise ValueError("The 'tasks' attribute can only be set to list or dict")
31
35
 
32
36
  if "locust_task_weight" in dir(value):
33
37
  # method decorated with @task
@@ -52,13 +56,11 @@ class SequentialTaskSet(TaskSet, metaclass=SequentialTaskSetMeta):
52
56
 
53
57
  def __init__(self, *args, **kwargs):
54
58
  super().__init__(*args, **kwargs)
55
- self._task_index = 0
59
+ self._task_cycle = cycle(self.tasks)
56
60
 
57
61
  def get_next_task(self):
58
62
  if not self.tasks:
59
63
  raise LocustError(
60
64
  "No tasks defined. Use the @task decorator or set the 'tasks' attribute of the SequentialTaskSet"
61
65
  )
62
- task = self.tasks[self._task_index % len(self.tasks)]
63
- self._task_index += 1
64
- return task
66
+ return next(self._task_cycle)