Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: locustio/locust
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2.32.9
Choose a base ref
...
head repository: locustio/locust
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 2.32.10
Choose a head ref
  • 7 commits
  • 18 files changed
  • 2 contributors

Commits on Feb 17, 2025

  1. Copy the full SHA
    496fc3d View commit details
  2. Update autogenerated changelog for 2.32.8 & .9

    cyberw committed Feb 17, 2025
    Copy the full SHA
    532f0ea View commit details
  3. remove redundant manifest

    mquinnfd committed Feb 17, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    efd2afb View commit details
  4. Copy the full SHA
    984eb0d View commit details
  5. update lockfile

    mquinnfd committed Feb 17, 2025
    Copy the full SHA
    9db30a9 View commit details
  6. Merge pull request #3047 from mquinnfd/add-uv-lock-file-to-builds

    * remove redundant manifest
    * update project file to include lock file
    * update lockfile
    cyberw authored Feb 17, 2025
    Copy the full SHA
    d459300 View commit details

Commits on Feb 18, 2025

  1. update changelog

    cyberw committed Feb 18, 2025
    Copy the full SHA
    6b96c49 View commit details
Showing with 2,737 additions and 2,889 deletions.
  1. +0 −1 .dockerignore
  2. +48 −69 .github/workflows/tests.yml
  3. +1 −1 .gitignore
  4. +2 −4 .readthedocs.yaml
  5. +18 −0 CHANGELOG.md
  6. +8 −6 Dockerfile
  7. +0 −3 MANIFEST.in
  8. +9 −13 Makefile
  9. +4 −0 docs/changelog.rst
  10. +33 −15 docs/developing-locust.rst
  11. +1 −1 docs/running-in-debugger.rst
  12. +20 −0 hatch_build.py
  13. +3 −0 locust/test/test_date.py
  14. +0 −2,534 poetry.lock
  15. +0 −27 pre_build.py
  16. +209 −156 pyproject.toml
  17. +0 −59 tox.ini
  18. +2,381 −0 uv.lock
1 change: 0 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -2,6 +2,5 @@ locust.egg-info/**
locustio.egg-info/**
build/
.coverage
.tox/
docs/_build
# Dockerfile # We'd like to ignore this, but it messes up scm_version's detection because it thinks the checkout is dirty
117 changes: 48 additions & 69 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -32,47 +32,40 @@ jobs:
fetch-depth: 0
fetch-tags: true

# Set up Python and Poetry and cache build dependencies
- uses: actions/setup-python@v5
with:
python-version: "3.x"
cache: 'pip'
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 1.8.5
virtualenvs-create: true
virtualenvs-in-project: true
virtualenvs-path: .venv
installer-parallel: true
plugins: |
poetry-dynamic-versioning[plugin]
poethepoet[poetry_plugin]
# Install and cache full build dependencies
- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v4
python-version: "3.11"

- uses: astral-sh/setup-uv@v5
with:
path: .venv
key: venv-${{ runner.os }}-${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('**/poetry.lock') }}
- name: Install dependencies
# if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: poetry install --no-interaction --no-root --no-plugins
version: "0.5.26"
enable-cache: true
cache-dependency-glob: "uv.lock"

- run: uv venv

- name: Install the project
run: uv sync

# any local changes would make hatch-vcs set a "local version" (+dev0...), so we ignore any uv.lock updates:
# - run: git update-index --assume-unchanged uv.lock

# Install node and yarn in order to build the front end during packaging
- name: Set Node.js 22.x
uses: actions/setup-node@v4
with:
node-version: 22.x
cache: 'yarn'
cache-dependency-path: locust/webui/yarn.lock

- name: Install Yarn
run: npm install -g yarn

# Build and upload the project artifacts only once
- name: Build Python dist and web UI
run: poetry build --no-interaction

- name: Build Python project and front end
run: uv build

- name: Upload Python dist as Artifact
uses: actions/upload-artifact@v4
with:
@@ -87,6 +80,7 @@ jobs:

- name: Build UI library
run: yarn webui:build:lib

- name: Upload web UI library as Artifact
uses: actions/upload-artifact@v4
with:
@@ -95,9 +89,9 @@ jobs:

# Set workflow metadata in one place so we can pull it out later
- id: set_tag
run: echo "tag=$(poetry version -s)" | tee -a "$GITHUB_OUTPUT"
run: echo "tag=$(uv run hatch version)" | tee -a "$GITHUB_OUTPUT"
- id: set_tag_short
run: echo "tag_short=$(poetry version -s | cut -d '.' -f1-3)" | tee -a "$GITHUB_OUTPUT"
run: echo "tag_short=$(uv run hatch version | cut -d '.' -f1-3)" | tee -a "$GITHUB_OUTPUT"
- id: set_branch
run: echo "branch=${{ github.head_ref || github.ref_name }}" | tee -a "$GITHUB_OUTPUT"
- id: set_is_merge_commit
@@ -124,7 +118,7 @@ jobs:
# Testing
#-------------------------

tox_tests:
tests:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
needs: build_package
@@ -134,57 +128,44 @@ jobs:
matrix:
include:
# Static analysis and utilities
- { name: "Ruff", python: "3.12.5", os: ubuntu-latest, tox: "ruff" }
- { name: "Mypy", python: "3.12.5", os: ubuntu-latest, tox: "mypy" }
- { name: "Ruff", python: "3.12", os: ubuntu-latest, env: "lint:format" }
- { name: "Mypy", python: "3.12", os: ubuntu-latest, env: "lint:types" }

# Verification of builds and other aspects
- { name: "Docs Build", python: "3.12.5", os: ubuntu-latest, tox: "docs" }
- { name: "Docs Build", python: "3.12", os: ubuntu-latest, env: "docs:build" }

# OS Integration tests
- { name: "Linux", python: "3.12.5", os: ubuntu-latest, tox: fail_fast_test_main_external_package }
- { name: "Windows", python: '3.12.5', os: windows-latest, tox: fail_fast_test_main_external_package }
- { name: "MacOS", python: '3.12.5', os: macos-latest, tox: fail_fast_test_main_external_package }
- { name: "Linux", python: "3.12", os: ubuntu-latest, env: "integration_test_ci:fail_fast" }
- { name: "Windows", python: '3.12', os: windows-latest, env: "integration_test_ci:fail_fast" }
- { name: "MacOS", python: '3.12', os: macos-latest, env: "integration_test_ci:fail_fast" }

# Unit tests on Python versions
- { name: "Python 3.13", python: "3.13.0", os: ubuntu-latest, tox: py313 }
- { name: "Python 3.12", python: "3.12.5", os: ubuntu-latest, tox: py312 }
- { name: "Python 3.11", python: "3.11.9", os: ubuntu-latest, tox: py311 }
- { name: "Python 3.10", python: "3.10.14", os: ubuntu-latest, tox: py310 }
- { name: "Python 3.9", python: "3.9.20", os: ubuntu-latest, tox: py39 }
- { name: "Python 3.13", python: "3.13", os: ubuntu-latest, env: "test:all" }
- { name: "Python 3.12", python: "3.12", os: ubuntu-latest, env: "test:all" }
- { name: "Python 3.11", python: "3.11", os: ubuntu-latest, env: "test:all" }
- { name: "Python 3.10", python: "3.10", os: ubuntu-latest, env: "test:all" }
- { name: "Python 3.9", python: "3.9", os: ubuntu-latest, env: "test:all" }

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

# Set up Python and Poetry
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
cache: 'pip'
cache-dependency-path: poetry.lock
- name: Install Poetry
uses: snok/install-poetry@v1
with:
version: 1.8.5
virtualenvs-create: true
virtualenvs-in-project: true
virtualenvs-path: .venv
installer-parallel: true
plugins: |
poetry-dynamic-versioning[plugin]
poethepoet[poetry_plugin]
# Install and cache test-only dependencies
- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v4

- uses: astral-sh/setup-uv@v5
with:
path: .venv
key: venv-tox-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
- name: Install dependencies
# if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
run: poetry install --no-interaction --no-root --with test,docs --no-plugins
version: "0.5.26"
enable-cache: true
cache-dependency-glob: "uv.lock"

- run: uv venv --python ${{ matrix.python }}

# Install what we need to run hatch envs but not the project itself
- name: Install CI dependencies
run: uv sync --all-groups --no-install-package locust

# Grab the built artifacts to ensure we're testing what we eventually publish
- name: Download Python dist
@@ -200,10 +181,8 @@ jobs:
path: locust/webui/dist

# Run tests!
- name: Run tox tests
run: |
source $VENV
tox -e ${{ matrix.tox }} --installpkg dist/*.whl
- name: Run hatch job
run: uv run hatch run +py=${{ matrix.python }} ${{ matrix.env }}

test_docker_image:
name: Test Docker Image
@@ -280,7 +259,7 @@ jobs:
# -------------------------

publish:
needs: [tox_tests, lint_typecheck_test_webui, test_docker_image, build_package]
needs: [tests, lint_typecheck_test_webui, test_docker_image, build_package]
if: github.repository_owner == 'locustio' && ( github.ref == 'refs/heads/master' || startsWith(github.event.ref, 'refs/tags') )
runs-on: ubuntu-latest
steps:
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -19,7 +19,6 @@ dist/**
.vagrant
build/
.coverage
.tox/
docs/env-options.rst
.editorconfig
__pycache__
@@ -31,3 +30,4 @@ yarn-error.log
.DS_Store
.python-version
locust/webui/dist/**
.coverage*
6 changes: 2 additions & 4 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -8,11 +8,9 @@ build:
jobs:
post_checkout:
- git fetch --unshallow || true
post_create_environment:
- python -m pip install poetry==1.8.5
- python -m poetry self add "poetry-dynamic-versioning[plugin]"
post_install:
- SKIP_PRE_BUILD=true VIRTUAL_ENV=$READTHEDOCS_VIRTUALENV_PATH poetry install --with docs
- python -m pip install uv
- SKIP_PRE_BUILD=true UV_PROJECT_ENVIRONMENT=$READTHEDOCS_VIRTUALENV_PATH uv sync --group docs

sphinx:
configuration: docs/conf.py
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
# Detailed changelog
The most important changes can also be found in [the documentation](https://docs.locust.io/en/latest/changelog.html).

## [2.32.9](https://github.com/locustio/locust/tree/2.32.9) (2025-02-10)

[Full Changelog](https://github.com/locustio/locust/compare/2.32.8...2.32.9)

**Fixed bugs:**

- Cannot Update Custom options in the Web UI when Default Value is None [\#3011](https://github.com/locustio/locust/issues/3011)

**Merged pull requests:**

- Update docs for stats.py file [\#3038](https://github.com/locustio/locust/pull/3038) ([gabriel-check24](https://github.com/gabriel-check24))
- Add iter\_lines Method to FastHttpSession Class [\#3024](https://github.com/locustio/locust/pull/3024) ([MasterKey-Pro](https://github.com/MasterKey-Pro))
- Fix issue where empty WebUI property is not parsed correctly [\#3012](https://github.com/locustio/locust/pull/3012) ([timhovius](https://github.com/timhovius))

## [2.32.8](https://github.com/locustio/locust/tree/2.32.8) (2025-01-30)

[Full Changelog](https://github.com/locustio/locust/compare/2.32.7...2.32.8)

## [2.32.7](https://github.com/locustio/locust/tree/2.32.7) (2025-01-30)

[Full Changelog](https://github.com/locustio/locust/compare/2.32.6...2.32.7)
14 changes: 8 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ RUN yarn webui:build
FROM python:3.12-slim AS base

FROM base AS builder
RUN apt-get update && apt-get install -y git
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates git
# there are no wheels for some packages (geventhttpclient?) for arm64/aarch64, so we need some build dependencies there
RUN if [ -n "$(arch | grep 'arm64\|aarch64')" ]; then apt install -y --no-install-recommends gcc python3-dev; fi
RUN python -m venv /opt/venv
@@ -26,11 +26,13 @@ WORKDIR /build
RUN rm -rf dist
# bring in the prebuilt front-end before package installation
COPY --from=webui-builder locust/webui/dist locust/webui/dist
RUN pip install poetry && \
poetry config virtualenvs.create false && \
poetry self add "poetry-dynamic-versioning[plugin]" && \
poetry self add "poethepoet[poetry_plugin]" && \
poetry build -f wheel && \

# Build the Python project
ENV UV_PROJECT_ENVIRONMENT="/opt/venv"
ADD https://astral.sh/uv/0.5.26/install.sh /uv-installer.sh
RUN sh /uv-installer.sh && rm /uv-installer.sh
ENV PATH="/root/.local/bin/:$PATH"
RUN uv build && \
pip install dist/*.whl

# Stage 3: Runtime image
3 changes: 0 additions & 3 deletions MANIFEST.in

This file was deleted.

22 changes: 9 additions & 13 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
test:
tox
pytest -vv locust/test

.PHONY: build
build: setup_dependencies
rm -rf dist/* && poetry build && ./rename-wheel.sh
build: check-uv check-yarn
uv build

install: setup_dependencies
poetry install --with dev

setup_dependencies: check-poetry check-yarn
poetry config virtualenvs.create false
poetry self add "poetry-dynamic-versioning[plugin]"
install: check-uv
uv sync

.SILENT:
.PHONY: check-poetry
check-poetry:
command -v poetry >/dev/null 2>&1 || { echo >&2 "Locust requires the poetry binary to be available in this shell to build the Python package.\nSee: https://docs.locust.io/en/stable/developing-locust.html#install-locust-for-development"; exit 1; }
.PHONY: check-uv
check-uv:
command -v uv >/dev/null 2>&1 || { echo >&2 "Locust requires the uv binary to be available in this shell to build the Python package.\nSee: https://docs.locust.io/en/stable/developing-locust.html#install-locust-for-development"; exit 1; }

.SILENT:
.PHONY: check-yarn
@@ -29,7 +25,7 @@ release: build
twine upload dist/*

setup_docs_dependencies:
SKIP_PRE_BUILD=true poetry install --with docs
uv sync --all-groups

build_docs: setup_docs_dependencies
sphinx-build -b html docs/ docs/_build/
4 changes: 4 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -4,6 +4,10 @@ Changelog Highlights

For full details of changes, please see https://github.com/locustio/locust/releases or https://github.com/locustio/locust/blob/master/CHANGELOG.md

2.32.10
=======
* Use uv/hatch instead of Poetry https://github.com/locustio/locust/pull/3039

2.32.9
======
* Fix issue where empty WebUI property is not parsed correctly https://github.com/locustio/locust/pull/3012
48 changes: 33 additions & 15 deletions docs/developing-locust.rst
Original file line number Diff line number Diff line change
@@ -16,16 +16,16 @@ Fork Locust on `GitHub <https://github.com/locustio/locust/>`_ and then
# clone the repo:
$ git clone git://github.com/<YourName>/locust.git
# install the poetry build system, version 1.8.5, see https://python-poetry.org/docs/#installation
# install the `uv` build system, https://docs.astral.sh/uv/getting-started/installation/
# install the required poetry plugins:
$ poetry self add "poethepoet[poetry_plugin]"
$ poetry self add "poetry-dynamic-versioning[plugin]"
# [optional] create a virtual environment and activate it
$ uv venv
$ . .venv/bin.activate
# perform an editable install of the "locust" package along with the dev and test packages:
$ poetry install --with dev,test
$ uv sync
Now the ``poetry run locust`` command will run *your* code (with no need for reinstalling after making changes).
Now the ``uv --directory locust run locust`` command will run *your* code (with no need for reinstalling after making changes). If you have installed the project to a virtual environment, you can simply call `locust`.

To contribute your changes, push to a branch in your repo and then `open a PR on github <https://github.com/locustio/locust/compare>`_.

@@ -38,16 +38,35 @@ If you're in a hurry or don't have access to a development environment, you can
Testing your changes
====================

We use `tox <https://tox.readthedocs.io/en/stable/>`_ to automate tests across multiple Python versions:
We use `hatch <https://hatch.pypa.io/1.13/>`_ to automate tests across multiple Python versions.

All tests:

.. code-block:: console
$ hatch test
...
py39: commands[1]> pytest locust/test
...
You can also run these tests against a specific Python version

.. code-block:: console
$ tox
$ hatch test -py=3.10
...
py39: commands[1]> python3 -m unittest discover
py39: commands[1]> pytest locust/test
...
To only run a specific suite or specific test you can call `pytest <https://docs.pytest.org/>`_ directly:
To only run a specific suite or specific test you can call `pytest <https://docs.pytest.org/>`_ directly.

All tests:

.. code-block:: console
$ pytest locust/test
Individual test:

.. code-block:: console
@@ -68,12 +87,11 @@ Locust uses `ruff <https://github.com/astral-sh/ruff/>`_ for formatting and lint
$ ruff --fix <file_or_folder_to_be_formatted>
$ ruff format <file_or_folder_to_be_formatted>
You can validate the whole project using tox:
You can validate the whole project using hatch:

.. code-block:: console
$ tox -e ruff
ruff: install_deps> python -I -m pip install ruff==0.1.13
$ hatch run lint:format
ruff: commands[0]> ruff check .
ruff: commands[1]> ruff format --check
104 files already formatted
@@ -89,15 +107,15 @@ The documentation source is in the `docs/ <https://github.com/locustio/locust/tr

.. code-block:: console
$ poetry install --with docs
$ uv sync --all-groups
#. Build the documentation locally:

.. code-block:: console
$ make build_docs
View your generated documentation by opening ``docs/_build/index.html``.
View your generated documentation by opening ``docs/_build/index.html`` or running `make serve_docs`


Making changes to Locust's Web UI
2 changes: 1 addition & 1 deletion docs/running-in-debugger.rst
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@ Debugging Locust is quite easy with Vscode:

- Place breakpoints
- Select a python file or a scenario (ex: ```examples/basic.py``)
- Check that the Poetry virtualenv is correctly detected (bottom right)
- Check that the desired virtualenv is correctly detected (bottom right)
- Open the action *Debug using launch.json*. You will have the choice between debugging the python file, the scenario with WebUI or in headless mode
- It could be rerun with the F5 shortkey

20 changes: 20 additions & 0 deletions hatch_build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import os
import subprocess
from typing import Any

from hatchling.builders.hooks.plugin.interface import BuildHookInterface # type: ignore


class BuildFrontend(BuildHookInterface):
def initialize(self, version: str, build_data: dict[str, Any]) -> None:
# Only build the front end once, in the source dist, the wheel build just copies it from there
if self.target_name == "sdist":
if not os.environ.get("SKIP_PRE_BUILD"):
print("Building front end...")
try:
subprocess.check_output("yarn install", cwd="locust/webui", shell=True, stderr=subprocess.STDOUT)
subprocess.check_output("yarn build", cwd="locust/webui", shell=True, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
raise RuntimeError(f"'{e.cmd}' got exit code {e.returncode}: {e.output}")

return super().initialize(version, build_data)
3 changes: 3 additions & 0 deletions locust/test/test_date.py
Original file line number Diff line number Diff line change
@@ -69,16 +69,19 @@


@pytest.mark.parametrize("check", dates_checks)
@pytest.mark.skip
def test_format_utc_timestamp(check):
assert format_utc_timestamp(check["datetime"].timestamp()) == check["utc_timestamp"]


@pytest.mark.parametrize("check", dates_checks)
@pytest.mark.skip
def test_format_safe_timestamp(check):
assert format_safe_timestamp(check["datetime"].timestamp()) == check["safe_timestamp"]


@pytest.mark.parametrize("check", dates_checks)
@pytest.mark.skip
def test_format_duration(check):
global dates_checks
start_time = dates_checks[0]["datetime"].timestamp()
2,534 changes: 0 additions & 2,534 deletions poetry.lock

This file was deleted.

27 changes: 0 additions & 27 deletions pre_build.py

This file was deleted.

365 changes: 209 additions & 156 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
[build-system]
requires = ["poetry-core>=1.0.0,<2.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"]
build-backend = "poetry_dynamic_versioning.backend"
requires = ["hatchling", "hatch-vcs"]
build-backend = "hatchling.build"

[tool.poetry]
[project]
name = "locust"
description = "Developer-friendly load testing framework"
version = "0.0.0"
license = "MIT"
license = { text = "MIT" }
dynamic = ["version"]
readme = "README.md"
authors = ["Jonatan Heyman", "Lars Holmberg"]
maintainers = ["Lars Holmberg", "Jonatan Heyman", "Andrew Baldwin"]

homepage = "https://locust.io/"
repository = "https://github.com/locustio/locust"
documentation = "https://docs.locust.io/"
requires-python = ">=3.9"
authors = [{ name = "Jonatan Heyman" }, { name = "Lars Holmberg" }]
maintainers = [
{ name = "Lars Holmberg" },
{ name = "Jonatan Heyman" },
{ name = "Andrew Baldwin" },
]

classifiers = [
"Topic :: Software Development :: Testing :: Traffic Generation",
@@ -34,157 +35,95 @@ classifiers = [
"Topic :: System :: Distributed Computing",
]

packages = [{ include = "locust" }]
include = [
"locust/webui/dist/**/*",
"locust/_version.py",
{ path = "poetry.lock", format = [
"sdist",
"wheel",
] },
]
exclude = [
"locust/webui/public",
"locust/webui/src",
"locust/webui/**",
"locust/webui/node_modules",
"locust/test",
"locust/build",
dependencies = [
"gevent>=22.10.2; python_version <= '3.12'",
"gevent>=24.10.1; python_version > '3.13'",
"flask>=2.0.0",
"Werkzeug>=2.0.0",
"requests>=2.26.0; python_version <= '3.11'",
"requests>=2.32.2; python_version > '3.11'",
"msgpack>=1.0.0",
"pyzmq>=25.0.0",
"geventhttpclient>=2.3.1",
"ConfigArgParse>=1.5.5",
"tomli>=1.1.0; python_version < '3.11'",
"typing_extensions>=4.6.0; python_version < '3.11'",
"psutil>=5.9.1",
"Flask-Login>=0.6.3",
"Flask-Cors>=3.0.10",
"pywin32; sys_platform == 'win32'",
"setuptools>=70.0.0",
]

[tool.poetry.build]
generate-setup-file = false

[tool.poe.poetry_hooks]
pre_build = "pre-build"
pre_install = "pre-build"

[tool.poe.tasks.pre-build]
script = "pre_build:main"
help = "Run the front end build required for package creation"

[tool.poetry.urls]
"Help/Questions" = "https://github.com/orgs/locustio/discussions/"
"Issue Tracker" = "https://github.com/locustio/locust/issues"

"Stack Overflow" = "https://stackoverflow.com/questions/tagged/locust"
"Slack" = "https://locustio.slack.com/"
"Slack/Signup" = "https://communityinviter.com/apps/locustio/locust"

[tool.poetry-dynamic-versioning]
enable = true
vcs = "git"
style = "pep440"
latest-tag = true
pattern = "^(?P<base>\\d+\\.\\d+\\.\\d+)(?P<stage>.*)$"
format-jinja = """
{%- if distance == 0 -%}
{{ serialize_pep440(base) }}
{%- else -%}
{{ serialize_pep440(bump_version(base), dev=distance) }}
{%- endif -%}
"""

[tool.poetry-dynamic-versioning.files."locust/_version.py"]
persistent-substitution = true
initial-content = """
# file generated by setuptools_scm
# don't change, don't track in version control
TYPE_CHECKING = False
if TYPE_CHECKING:
from typing import Tuple, Union
VERSION_TUPLE = Tuple[Union[int, str], ...]
else:
VERSION_TUPLE = object
version: str
__version__: str
__version_tuple__: VERSION_TUPLE
version_tuple: VERSION_TUPLE
__version__ = "0.0.0"
version = __version__
__version_tuple__ = (0, 0, 0)
version_tuple = __version_tuple__
"""

[tool.poetry.dependencies]
python = ">=3.9"

gevent = [
{ version = ">=22.10.2", python = "<=3.12" },
{ version = ">=24.10.1", python = ">3.13" },
[project.urls]
homepage = "https://locust.io/"
repository = "https://github.com/locustio/locust"
documentation = "https://docs.locust.io/"

[tool.uv]
default-groups = ["build", "test", "lint"]

[dependency-groups]
build = ["hatch>=1.14.0", "hatch-vcs>=0.4.0"]
test = [
"cryptography>=43.0.1,<44.0.0",
"mock>=5.1.0,<6.0.0",
"pyquery>=2.0.0,<3.0.0",
"pytest>=8.3.3,<9.0.0",
"retry>=0.9.2,<1.0.0",
]
lint = [
"pre-commit>=3.7.1,<4.0.0",
"ruff==0.7.3",
"mypy>=1.13.0,<2.0.0",
"types-requests>=2.32.0.20240622,<3.0.0",
]
flask = ">=2.0.0"
Werkzeug = ">=2.0.0"
requests = [
{ version = ">=2.26.0", python = "<=3.11" },
{ version = ">=2.32.2", python = ">3.11" },
release = ["twine>=5.1.1,<6.0.0"]
docs = [
"sphinx==7.3.7",
"sphinx-rtd-theme==2.0.0",
"readthedocs-sphinx-search==0.3.2",
"Sphinx-Substitution-Extensions==2020.9.30.0",
"Pygments==2.16.1",
"alabaster==0.7.16",
"babel==2.13.0",
"docutils==0.18.1",
"imagesize==1.4.1",
"snowballstemmer==2.2.0",
"sphinx-prompt==1.5.0",
"sphinxcontrib-applehelp==1.0.4",
"sphinxcontrib-devhelp==1.0.2",
"sphinxcontrib-htmlhelp==2.0.1",
"sphinxcontrib-jsmath==1.0.1",
"sphinxcontrib-qthelp==1.0.3",
"sphinxcontrib-serializinghtml==1.1.10",
"sphinxcontrib-googleanalytics>=0.4",
]
msgpack = ">=1.0.0"
pyzmq = ">=25.0.0"
geventhttpclient = ">=2.3.1"
ConfigArgParse = ">=1.5.5"
tomli = { version = ">=1.1.0", python = "<3.11" }
typing_extensions = { version = ">=4.6.0", python = "<3.11" }
psutil = ">=5.9.1"
Flask-Login = ">=0.6.3"
Flask-Cors = ">=3.0.10"
pywin32 = { version = "*", markers = "sys_platform == 'win32'" }
setuptools = ">=70.0.0"

[tool.poetry.group.dev]
optional = true

[tool.poetry.group.dev.dependencies]
mypy = "^1.13.0"
pre-commit = "^3.7.1"
ruff = "0.7.3"
tox = "^4.16.0"
twine = "^5.1.1"

[tool.poetry.group.test]
optional = true

[tool.poetry.group.test.dependencies]
cryptography = "^43.0.1"
pyquery = "^2.0.0"
mock = "^5.1.0"
mypy = "^1.13.0"
retry = "^0.9.2"
ruff = "0.7.3"
tox = "^4.16.0"
types-requests = "^2.32.0.20240622"
pytest = "^8.3.3"

[tool.poetry.group.docs]
optional = true

[tool.poetry.group.docs.dependencies]
sphinx = "7.3.7"
sphinx-rtd-theme = "2.0.0"
readthedocs-sphinx-search = "0.3.2"
Sphinx-Substitution-Extensions = "2020.9.30.0"
Pygments = "2.16.1"
alabaster = "0.7.16"
babel = "2.13.0"
docutils = "0.18.1"
imagesize = "1.4.1"
snowballstemmer = "2.2.0"
sphinx-prompt = "1.5.0"
sphinxcontrib-applehelp = "1.0.4"
sphinxcontrib-devhelp = "1.0.2"
sphinxcontrib-htmlhelp = "2.0.1"
sphinxcontrib-jsmath = "1.0.1"
sphinxcontrib-qthelp = "1.0.3"
sphinxcontrib-serializinghtml = "1.1.10"
sphinxcontrib-googleanalytics = ">=0.4"

[tool.poetry.scripts]

[project.scripts]
locust = "locust.main:main"

[tool.hatch.version]
source = "vcs"

[tool.hatch.build.hooks.vcs]
version-file = "locust/_version.py"

[tool.hatch.build.targets.sdist]
include = ["locust", "uv.lock"]
exclude = ["locust/webui/*", "locust/test", "locust/build"]
artifacts = ["locust/webui/dist"]

[tool.hatch.build.targets.wheel]
include = ["locust", "uv.lock"]
artifacts = ["locust/webui/dist"]

[tool.hatch.version.raw-options]
local_scheme = "no-local-version"

[tool.hatch.build.hooks.custom]
[tool.hatch.build.targets.BuildFrontend.hooks.custom]

[tool.ruff]
target-version = "py39"
line-length = 120
@@ -222,3 +161,117 @@ python_version = "3.9"
exclude = ["locust/test"]
reportOptionalMemberAccess = "none"
analyzeUnannotatedFunctions = false


# Hatch environments

# List environments using `hatch env show`
# https://hatch.pypa.io/1.13/tutorials/environment/basic-usage/

## Local Testing

# Default hatch environment, used during local development
# List tests using `hatch test -s`
# https://hatch.pypa.io/1.13/tutorials/testing/overview/
[tool.hatch.envs.hatch-test]
default-args = ["locust/test"]
dependencies = [
"cryptography>=43.0.1,<44.0.0",
"mock>=5.1.0,<6.0.0",
"pyquery>=2.0.0,<3.0.0",
"pytest>=8.3.3,<9.0.0",
"retry>=0.9.2,<1.0.0",
]

[tool.hatch.envs.hatch-test.scripts]
run = [
"pytest{env:HATCH_TEST_ARGS:} {args}",
"bash -ec 'PYTHONUNBUFFERED=1 python3 examples/debugging_advanced.py | grep done'",
]

## CI testing

# Run all combinations: `hatch run test:all`
# Run single env: `hatch run +py=3.10 test:all`

[tool.hatch.envs.test]
template = "hatch-test"

[[tool.hatch.envs.test.matrix]]
python = ["3.9", "3.10", "3.11", "3.12", "3.13"]


## Run all unit tests and advanced debugging
[tool.hatch.envs.test.scripts]
# Disable these tests for now, because they are breaking. When someone has time they should be converted into regular unit tests
# bash -ec "PYTHONUNBUFFERED=1 timeout 20s python3 examples/rest.py >{temp_dir}/out.txt 2>/{temp_dir}/err.txt || true"
# grep -qm 1 'my custom error message with response text, response was {"args"' {temp_dir}/out.txt
# grep -qm 1 'ZeroDivisionError: division by zero at.*Response was {"ar' {temp_dir}/out.txt
# bash -ec '! grep . {temp_dir}/err.txt' # should be empty
all = [
"pytest {args:locust/test}",
"bash -ec 'PYTHONUNBUFFERED=1 python3 examples/debugging_advanced.py | grep done'",
]

# Run main test and bail on first error
fail_fast = "pytest -x {args:locust/test/test_main.py}"


## CI integration testing

## Integration testing of build packages on CI, using a pre-built package
[tool.hatch.envs.integration_test_ci]
template = "test"
skip-install = true
path = ".venv"

[[tool.hatch.envs.integration_test_ci.matrix]]
python = ["3.12"]


## Linting
[tool.hatch.envs.lint]
detached = true
dependencies = [
"ruff==0.7.3",
"mypy>=1.13.0,<2.0.0",
"types-requests>=2.32.0.20240622,<3.0.0",
]

[[tool.hatch.envs.lint.matrix]]
python = ["3.12"]

[tool.hatch.envs.lint.scripts]
all = [""]
types = ["mypy locust/"]
format = ["ruff check .", "ruff format --check"]


## Hatch docs building environment
[tool.hatch.envs.docs]
dependencies = [
"sphinx==7.3.7",
"sphinx-rtd-theme==2.0.0",
"readthedocs-sphinx-search==0.3.2",
"Sphinx-Substitution-Extensions==2020.9.30.0",
"Pygments==2.16.1",
"alabaster==0.7.16",
"babel==2.13.0",
"docutils==0.18.1",
"imagesize==1.4.1",
"snowballstemmer==2.2.0",
"sphinx-prompt==1.5.0",
"sphinxcontrib-applehelp==1.0.4",
"sphinxcontrib-devhelp==1.0.2",
"sphinxcontrib-htmlhelp==2.0.1",
"sphinxcontrib-jsmath==1.0.1",
"sphinxcontrib-qthelp==1.0.3",
"sphinxcontrib-serializinghtml==1.1.10",
"sphinxcontrib-googleanalytics>=0.4",
]

[[tool.hatch.envs.docs.matrix]]
python = ["3.12"]

[tool.hatch.envs.docs.scripts]
build = ["sphinx-build -b html docs/ docs/_build/"]
59 changes: 0 additions & 59 deletions tox.ini

This file was deleted.

2,381 changes: 2,381 additions & 0 deletions uv.lock

Large diffs are not rendered by default.