Skip to content

adding benchmarking, currently only for http funcs #247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ coverage.xml
.dmypy.json
.hypothesis/
.idea/
.codspeed
uv.lock
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ allow_untyped_defs = false
# Allow test functions to be untyped
module = "tests.*"
allow_untyped_defs = true
disallow_untyped_calls = false

[tool.pylint.MASTER]
persistent = "no"
Expand Down
60 changes: 60 additions & 0 deletions tests/test_benchmark_http.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from collections import OrderedDict

import pytest

from w3lib.http import headers_dict_to_raw, headers_raw_to_dict

pytest.importorskip("pytest_codspeed", reason="Benchmark tests require pytest-codspeed")

pytestmark = pytest.mark.benchmark


def _header_case_long_headers():
dct = OrderedDict(
[
(b"X-Custom-Header", [b"a" * 1_000]),
(b"X-Custom-Header-2", [b"b" * 1_000]),
]
)
raw = (
b"X-Custom-Header: " + b"a" * 1_000 + b"\r\n"
b"X-Custom-Header-2: " + b"b" * 1_000
) # fmt: off
return "long_headers", dct, raw


def _header_case_many_unique_headers():
dct = OrderedDict(
[(f"Header-{i}".encode(), [f"value-{i}".encode()]) for i in range(100)]
)
raw = b"\r\n".join([f"Header-{i}: value-{i}".encode() for i in range(100)])
return "many_unique_headers", dct, raw


def _header_case_many_repeated_headers():
values = [f"id={i}".encode() for i in range(100)]
dct = OrderedDict([(b"Set-Cookie", values)])
raw = b"\r\n".join([b"Set-Cookie: " + val for val in values])
return "many_repeated_headers", dct, raw


header_cases = [
_header_case_long_headers(),
_header_case_many_unique_headers(),
_header_case_many_repeated_headers(),
]


@pytest.mark.parametrize(
("_id", "dct", "raw"),
header_cases,
ids=[case[0] for case in header_cases],
)
class TestBenchmarkHttp:
def test_bench_dict_to_raw(self, benchmark, _id, dct, raw): # noqa: PT019
result = benchmark(lambda: headers_dict_to_raw(dct))
assert result == raw

def test_bench_raw_to_dict(self, benchmark, _id, dct, raw): # noqa: PT019
result = benchmark(lambda: headers_raw_to_dict(raw))
assert result == dct
5 changes: 4 additions & 1 deletion tests/test_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ def test_headers_dict_to_raw(self):

def test_headers_dict_to_raw_listtuple(self):
dct: HeadersDictInput = OrderedDict(
[(b"Content-type", [b"text/html"]), (b"Accept", [b"gzip"])]
[
(b"Content-type", [b"text/html"]),
(b"Accept", [b"gzip"]),
]
)
assert headers_dict_to_raw(dct) == b"Content-type: text/html\r\nAccept: gzip"

Expand Down
35 changes: 34 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,20 @@
# and then run "tox" from this directory.

[tox]
envlist = py39, py310, py311, py312, py313, py314, pypy3.10, pypy3.11, docs, pylint, typing, pre-commit, twinecheck
envlist =
py39
py310
py311
py312
py313
py314
pypy3.10
pypy3.11
docs
pylint
typing
pre-commit
twinecheck

[testenv]
deps =
Expand Down Expand Up @@ -51,3 +64,23 @@ deps =
commands =
python -m build --sdist
twine check dist/*

[testenv:benchmark-{py39,py310,py311,py312,py313,py314,pypy310,pypy311}]
basepython =
py39: python3.9
py310: python3.10
py311: python3.11
py312: python3.12
py313: python3.13
py314: python3.14
pypy310: pypy3.10
pypy311: pypy3.11
deps =
pytest
pytest-codspeed
commands =
python -m pytest \
--codspeed \
--codspeed-warmup-time=1 \
--codspeed-max-rounds=10000 \
--codspeed-max-time=10