Skip to main content

Run performance tests against the mainline code.

Project description

https://img.shields.io/pypi/v/pytest-perf.svg https://img.shields.io/pypi/pyversions/pytest-perf.svg tests Ruff https://img.shields.io/badge/skeleton-2026-informational

Run performance tests against the mainline code.

pytest-perf measures whether a change makes code slower by benchmarking the working copy (the experiment) against the mainline (the control) and reporting the difference. It installs each version into its own environment, runs the same exercise against both, and fails only when a regression exceeds the tolerance.

Installation

Add pytest-perf to your project’s test dependencies. For example, in pyproject.toml:

[project.optional-dependencies]
test = [
    "pytest-perf",
]

The package registers a pytest plugin automatically; no further configuration is required.

Writing performance tests

Create a Python module anywhere pytest will collect it (for example exercises.py at the project root). Two conventions drive collection:

  • The plugin only inspects modules whose source contains the text pytest_perf. Importing something from the package — from pytest_perf.deco import ... — is enough, but even a bare comment mentioning pytest_perf qualifies the module.

  • Within such a module, every function whose name contains perf (or import_time; see Import latency) becomes a benchmark.

A benchmark function is not executed directly. Instead, its source is split into two parts at a # end warmup comment: the warmup runs once as setup, and the exercise (everything after the comment) is the code that gets timed. Both parts are handed to the timeit module:

def dict_construction_perf():
    "constructing a dict"
    from itertools import product

    pairs = list(product(range(100), range(100)))  # end warmup

    dict(pairs)

Here the imports and data setup run once as warmup, and only dict(pairs) is timed. If a function has no # end warmup marker, its whole body is the exercise.

The first line of the docstring, when present, names the benchmark in the report; otherwise the function name is used.

Decorators

The pytest_perf.deco module supplies decorators to control how the benchmark’s environments are built:

@deps('name', ...)

Install additional distributions into both environments before running the exercise. Use this when the exercise imports a package that isn’t otherwise a dependency.

@extras('name', ...)

Install the named extras of the project (e.g. testing) into both environments.

@control('rev')

Pin the control environment to a specific git revision (tag, branch, or commit) instead of the mainline head. Handy for measuring the cumulative change since a released version.

from pytest_perf.deco import control, deps, extras

@extras('testing')
@deps('path')
def deps_and_extras_perf():
    "with deps and extras"
    import path
    import pytest  # end warmup

    assert type(pytest) is type(path)

@control('v0.9.2')
def diff_from_oh_nine_two_perf():
    pass

See the exercises.py module in this repository for more examples.

Running the tests

Run pytest as usual; the benchmarks are collected and executed alongside your other tests:

pytest

Building two isolated environments and installing into them takes time, so restrict a run to the perf module when iterating:

pytest exercises.py

Results are printed in a perf section of the terminal summary, one line per benchmark, showing the experiment timing, the delta from the control, and the percentage change:

------------------------------ perf ------------------------------
exercises.py:simple test: 38.1 nsec (+3.9 nsec, 11%)

A benchmark fails only when the slowdown exceeds the tolerance (a 100% increase by default), so ordinary run-to-run noise won’t break your build.

Options

Two command-line options adjust what is compared:

--perf-baseline URL

The git repository to use as the control. Defaults to the origin remote of the local repository.

--perf-target DIR

The directory or distribution file to use as the experiment. Defaults to the current project (.).

Import latency

timeit cannot measure the cost of importing a module, because after the first loop the module is cached in sys.modules and subsequent loops only measure the cache lookup. To measure import latency instead, name the function with import_time (in place of perf) and let its body perform the import:

def check_import_time():
    import importlib_metadata

Such a function is traced with python -X importtime in a fresh interpreter (sampled a few times, reporting the fastest) rather than timed with timeit, capturing the real cold-import cost against both the control and the experiment.

Import latency cannot be measured on interpreters that don’t emit an -X importtime trace (such as PyPy); those benchmarks are skipped.

Design

pytest-perf works by creating two installs, the control and the experiment, and measuring the performance of some python code against each.

Under the hood, it uses pip-run to install from the upstream main branch (e.g. https://github.com/jaraco/pytest-perf) for the control and from . for the experiment. It then runs each of the experiments against each of the enviroments.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pytest_perf-1.0.0.tar.gz (20.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pytest_perf-1.0.0-py3-none-any.whl (12.6 kB view details)

Uploaded Python 3

File details

Details for the file pytest_perf-1.0.0.tar.gz.

File metadata

  • Download URL: pytest_perf-1.0.0.tar.gz
  • Upload date:
  • Size: 20.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for pytest_perf-1.0.0.tar.gz
Algorithm Hash digest
SHA256 7be0ab10eae69b0c4534af7d94db70995d5709907bae2e4849742a546f52748d
MD5 b843e88efe33cdf734fcc651062c2e12
BLAKE2b-256 aabdf1c2b5f3ff96c303a4e41ae28bdf6def09621935b9ab3918006995da1488

See more details on using hashes here.

File details

Details for the file pytest_perf-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: pytest_perf-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 12.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.6

File hashes

Hashes for pytest_perf-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fc466df5e1a82c172e3f2d445e15e01a37cc78b7b19fa0ec4fdb1324e65fbf63
MD5 8b9aaee86a29b12d80dac513de91d95e
BLAKE2b-256 5ce33ac453324b0eea46ed30e69820376a6d94655075a091f971234d4e2c9034

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page