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
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
repos:
- repo: https://github.com/psf/black
rev: 25.1.0
rev: 25.11.0
hooks:
- id: black
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,24 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.36.0] - 2025-12-02
### Changed
- `pytest` required version is now `9`.

### Added
- Explicit support for python `3.14`.
- `match_params` parameter is now available on responses and callbacks registration, as well as request(s) retrieval. Allowing to provide query parameters as a dict instead of being part of the matched URL.
- This parameter allows to perform partial query params matching ([refer to documentation](README.md#matching-on-query-parameters) for more information).

### Fixed
- URL with more than one value for the same parameter were not matched properly (matching was performed on the first value).
- `httpx_mock.add_exception` is now properly documented (accepts `BaseException` instead of `Exception`).

### Removed
- `pytest` `8` is not supported anymore.
- python `3.9` is not supported anymore.

## [0.35.0] - 2024-11-28
### Changed
- Requires [`httpx`](https://www.python-httpx.org)==0.28.\*
Expand Down Expand Up @@ -415,7 +425,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- First release, should be considered as unstable for now as design might change.

[Unreleased]: https://github.com/Colin-b/pytest_httpx/compare/v0.35.0...HEAD
[Unreleased]: https://github.com/Colin-b/pytest_httpx/compare/v0.36.0...HEAD
[0.36.0]: https://github.com/Colin-b/pytest_httpx/compare/v0.35.0...v0.36.0
[0.35.0]: https://github.com/Colin-b/pytest_httpx/compare/v0.34.0...v0.35.0
[0.34.0]: https://github.com/Colin-b/pytest_httpx/compare/v0.33.0...v0.34.0
[0.33.0]: https://github.com/Colin-b/pytest_httpx/compare/v0.32.0...v0.33.0
Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ issues = "https://github.com/Colin-b/pytest_httpx/issues"
[project.optional-dependencies]
testing = [
# Used to check coverage
"pytest-cov==6.*",
"pytest-cov==7.*",
# Used to run async tests
"pytest-asyncio==1.*",
]
Expand All @@ -65,3 +65,6 @@ version = {attr = "pytest_httpx.version.__version__"}
[tool.pytest]
# Silence deprecation warnings about option "asyncio_default_fixture_loop_scope"
asyncio_default_fixture_loop_scope = "function"

[tool.coverage.run]
patch = ["subprocess"]
10 changes: 6 additions & 4 deletions pytest_httpx/_request_matcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,7 @@ def __init__(
"Otherwise, use match_content."
)
if self.params and not self.url:
raise ValueError(
"URL must be provided when match_params is used."
)
raise ValueError("URL must be provided when match_params is used.")
if self.params and isinstance(self.url, re.Pattern):
raise ValueError(
"match_params cannot be used in addition to regex URL. Request this feature via https://github.com/Colin-b/pytest_httpx/issues/new?title=Regex%20URL%20should%20allow%20match_params&body=Hi,%20I%20need%20a%20regex%20to%20match%20the%20non%20query%20part%20of%20the%20URL%20only"
Expand Down Expand Up @@ -124,7 +122,11 @@ def _is_matching_body_more_than_one_way(self) -> bool:
return sum(matching_ways) > 1

def _is_matching_params_more_than_one_way(self) -> bool:
url_has_params = bool(self.url.params) if (self.url and isinstance(self.url, httpx.URL)) else False
url_has_params = (
bool(self.url.params)
if (self.url and isinstance(self.url, httpx.URL))
else False
)
matching_ways = [
self.params is not None,
url_has_params,
Expand Down
2 changes: 1 addition & 1 deletion pytest_httpx/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
# Major should be incremented in case there is a breaking change. (eg: 2.5.8 -> 3.0.0)
# Minor should be incremented in case there is an enhancement. (eg: 2.5.8 -> 2.6.0)
# Patch should be incremented in case there is a bug fix. (eg: 2.5.8 -> 2.5.9)
__version__ = "0.35.0"
__version__ = "0.36.0"
16 changes: 12 additions & 4 deletions tests/test_httpx_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,9 @@ async def test_url_query_params_not_matching(httpx_mock: HTTPXMock) -> None:


@pytest.mark.asyncio
async def test_url_matching_with_more_than_one_value_on_same_param(httpx_mock: HTTPXMock) -> None:
async def test_url_matching_with_more_than_one_value_on_same_param(
httpx_mock: HTTPXMock,
) -> None:
httpx_mock.add_response(url="https://test_url?a=1&a=3", is_optional=True)

async with httpx.AsyncClient() as client:
Expand All @@ -195,7 +197,9 @@ async def test_url_matching_with_more_than_one_value_on_same_param(httpx_mock: H

@pytest.mark.asyncio
@pytest.mark.httpx_mock(assert_all_requests_were_expected=False)
async def test_url_not_matching_with_more_than_one_value_on_same_param_and_diff_value(httpx_mock: HTTPXMock) -> None:
async def test_url_not_matching_with_more_than_one_value_on_same_param_and_diff_value(
httpx_mock: HTTPXMock,
) -> None:
httpx_mock.add_response(url="https://test_url?a=2&a=3", is_optional=True)

async with httpx.AsyncClient() as client:
Expand All @@ -210,7 +214,9 @@ async def test_url_not_matching_with_more_than_one_value_on_same_param_and_diff_

@pytest.mark.asyncio
@pytest.mark.httpx_mock(assert_all_requests_were_expected=False)
async def test_url_not_matching_with_more_than_one_value_on_same_param_and_more_values(httpx_mock: HTTPXMock) -> None:
async def test_url_not_matching_with_more_than_one_value_on_same_param_and_more_values(
httpx_mock: HTTPXMock,
) -> None:
httpx_mock.add_response(url="https://test_url?a=1&a=3", is_optional=True)

async with httpx.AsyncClient() as client:
Expand All @@ -225,7 +231,9 @@ async def test_url_not_matching_with_more_than_one_value_on_same_param_and_more_

@pytest.mark.asyncio
@pytest.mark.httpx_mock(assert_all_requests_were_expected=False)
async def test_url_not_matching_with_more_than_one_value_on_same_param_and_less_values(httpx_mock: HTTPXMock) -> None:
async def test_url_not_matching_with_more_than_one_value_on_same_param_and_less_values(
httpx_mock: HTTPXMock,
) -> None:
httpx_mock.add_response(url="https://test_url?a=1&a=3&a=4", is_optional=True)

async with httpx.AsyncClient() as client:
Expand Down
30 changes: 23 additions & 7 deletions tests/test_httpx_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,21 +156,29 @@ def test_match_params_without_url(httpx_mock: HTTPXMock) -> None:
with pytest.raises(ValueError) as exception_info:
httpx_mock.add_response(match_params={"a": "1"})

assert str(exception_info.value) == "URL must be provided when match_params is used."
assert (
str(exception_info.value) == "URL must be provided when match_params is used."
)


def test_query_params_in_both_url_and_match_params(httpx_mock: HTTPXMock) -> None:
with pytest.raises(ValueError) as exception_info:
httpx_mock.add_response(url="https://test_url?a=1", match_params={"a": "1"})

assert str(exception_info.value) == "Provided URL must not contain any query parameter when match_params is used."
assert (
str(exception_info.value)
== "Provided URL must not contain any query parameter when match_params is used."
)


def test_regex_url_and_match_params(httpx_mock: HTTPXMock) -> None:
with pytest.raises(ValueError) as exception_info:
httpx_mock.add_response(url=re.compile(".*test.*"), match_params={"a": "1"})

assert str(exception_info.value) == "match_params cannot be used in addition to regex URL. Request this feature via https://github.com/Colin-b/pytest_httpx/issues/new?title=Regex%20URL%20should%20allow%20match_params&body=Hi,%20I%20need%20a%20regex%20to%20match%20the%20non%20query%20part%20of%20the%20URL%20only"
assert (
str(exception_info.value)
== "match_params cannot be used in addition to regex URL. Request this feature via https://github.com/Colin-b/pytest_httpx/issues/new?title=Regex%20URL%20should%20allow%20match_params&body=Hi,%20I%20need%20a%20regex%20to%20match%20the%20non%20query%20part%20of%20the%20URL%20only"
)


@pytest.mark.httpx_mock(assert_all_requests_were_expected=False)
Expand All @@ -191,7 +199,9 @@ def test_url_query_params_not_matching(httpx_mock: HTTPXMock) -> None:
)


def test_url_matching_with_more_than_one_value_on_same_param(httpx_mock: HTTPXMock) -> None:
def test_url_matching_with_more_than_one_value_on_same_param(
httpx_mock: HTTPXMock,
) -> None:
httpx_mock.add_response(url="https://test_url?a=1&a=3", is_optional=True)

with httpx.Client() as client:
Expand All @@ -200,7 +210,9 @@ def test_url_matching_with_more_than_one_value_on_same_param(httpx_mock: HTTPXMo


@pytest.mark.httpx_mock(assert_all_requests_were_expected=False)
def test_url_not_matching_with_more_than_one_value_on_same_param_and_diff_value(httpx_mock: HTTPXMock) -> None:
def test_url_not_matching_with_more_than_one_value_on_same_param_and_diff_value(
httpx_mock: HTTPXMock,
) -> None:
httpx_mock.add_response(url="https://test_url?a=2&a=3", is_optional=True)

with httpx.Client() as client:
Expand All @@ -214,7 +226,9 @@ def test_url_not_matching_with_more_than_one_value_on_same_param_and_diff_value(


@pytest.mark.httpx_mock(assert_all_requests_were_expected=False)
def test_url_not_matching_with_more_than_one_value_on_same_param_and_more_values(httpx_mock: HTTPXMock) -> None:
def test_url_not_matching_with_more_than_one_value_on_same_param_and_more_values(
httpx_mock: HTTPXMock,
) -> None:
httpx_mock.add_response(url="https://test_url?a=1&a=3", is_optional=True)

with httpx.Client() as client:
Expand All @@ -228,7 +242,9 @@ def test_url_not_matching_with_more_than_one_value_on_same_param_and_more_values


@pytest.mark.httpx_mock(assert_all_requests_were_expected=False)
def test_url_not_matching_with_more_than_one_value_on_same_param_and_less_values(httpx_mock: HTTPXMock) -> None:
def test_url_not_matching_with_more_than_one_value_on_same_param_and_less_values(
httpx_mock: HTTPXMock,
) -> None:
httpx_mock.add_response(url="https://test_url?a=1&a=3&a=4", is_optional=True)

with httpx.Client() as client:
Expand Down