Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Benchmark

on: [push, pull_request, workflow_dispatch]

permissions: {}

env:
FORCE_COLOR: 1
PIP_DISABLE_PIP_VERSION_CHECK: 1

jobs:
benchmarks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Set up Python 3.14
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.14"
allow-prereleases: true

- name: Install gettext
run: |
sudo apt install gettext

- name: Generate translation binaries
run: |
scripts/generate-translation-binaries.sh

- name: Install dependencies
run: pip install -e ".[tests]"

- name: Run benchmarks
uses: CodSpeedHQ/action@3194d9a39c4d46684cb44bf7207fc56626aad8fd # v4.15.1
with:
mode: simulation
run: pytest tests/test_benchmarks.py --codspeed
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ dynamic = [ "version" ]
optional-dependencies.tests = [
"freezegun",
"pytest>=9",
"pytest-benchmark",
"pytest-codspeed",
"pytest-cov",
]
urls."Issue tracker" = "https://github.com/python-humanize/humanize/issues"
Expand Down
82 changes: 82 additions & 0 deletions tests/test_benchmarks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""Benchmarks run via pytest-codspeed."""

from __future__ import annotations

import datetime as dt

import pytest

import humanize

TYPE_CHECKING = False
if TYPE_CHECKING:
from pytest_codspeed import BenchmarkFixture


@pytest.fixture(scope="session", autouse=True)
def _warmup_i18n() -> None:
# Touch i18n-backed functions once so lazy gettext catalog loading
# is not attributed to the first benchmarked call.
humanize.naturaltime(dt.datetime.now() - dt.timedelta(seconds=1))
humanize.naturalday(dt.date.today())


def test_apnumber(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.apnumber, 7)


def test_clamp(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.clamp, 0.5, "{:.0%}", 0.1, 0.9)


def test_fractional(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.fractional, 1.5)


def test_intcomma(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.intcomma, 1_234_567_890)


def test_intword(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.intword, 1_234_567_890)


def test_metric(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.metric, 1500, "W")


def test_natural_list(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.natural_list, ["one", "two", "three", "four"])


def test_naturaldate(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.naturaldate, dt.date.today() - dt.timedelta(days=30))


def test_naturalday(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.naturalday, dt.date.today() - dt.timedelta(days=1))


def test_naturaldelta(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.naturaldelta, dt.timedelta(hours=3, minutes=27))


def test_naturalsize(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.naturalsize, 1_234_567_890)


def test_naturaltime(benchmark: BenchmarkFixture) -> None:
when = dt.datetime.now() - dt.timedelta(hours=3, minutes=27)
benchmark(humanize.naturaltime, when)


def test_ordinal(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.ordinal, 123)


def test_precisedelta(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.precisedelta, dt.timedelta(days=2, hours=3, seconds=4))


def test_scientific(benchmark: BenchmarkFixture) -> None:
benchmark(humanize.scientific, -1.234e-50)
Loading