Skip to content

Commit 535bc57

Browse files
authored
Better can_handle_fun documentation (#322)
* Better `can_handle_fun` documentation. * Pre-commit bump hooks.
1 parent 56e8d47 commit 535bc57

3 files changed

Lines changed: 70 additions & 2 deletions

File tree

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repos:
1515
exclude: helm/
1616
args: [ --unsafe ]
1717
- repo: https://github.com/charliermarsh/ruff-pre-commit
18-
rev: "v0.15.13"
18+
rev: "v0.15.18"
1919
hooks:
2020
- id: ruff
2121
args: [--fix, --exit-non-zero-on-fix]

README.rst

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,19 @@ It's very important that we test non-happy paths.
231231
232232
Example of how to mock a call with a custom request matching logic
233233
==================================================================
234+
``can_handle_fun`` lets you define matching logic beyond the default
235+
``path + querystring`` behavior.
236+
237+
The callback receives:
238+
239+
- ``path``: request path (for example ``/ip``)
240+
- ``qs_dict``: parsed query string as returned by ``urllib.parse.parse_qs(..., keep_blank_values=True)``
241+
242+
.. note::
243+
244+
When ``can_handle_fun`` is provided, it fully defines matching behavior.
245+
In this case ``match_querystring`` is not used.
246+
234247
.. code-block:: python
235248
236249
import json
@@ -239,8 +252,11 @@ Example of how to mock a call with a custom request matching logic
239252
from mocket.mocks.mockhttp import Entry
240253
import requests
241254
255+
242256
@mocketize
243257
def test_can_handle():
258+
url = "https://httpbin.org"
259+
244260
Entry.single_register(
245261
Entry.GET,
246262
url,
@@ -255,10 +271,59 @@ Example of how to mock a call with a custom request matching logic
255271
headers={"content-type": "application/json"},
256272
can_handle_fun=lambda path, qs_dict: path == "/ip" and not qs_dict,
257273
)
274+
258275
resp = requests.get("https://httpbin.org/ip")
259276
assert resp.status_code == 200
260277
assert resp.json() == {"message": "There you go!"}
261278
279+
Useful patterns
280+
---------------
281+
282+
Regex path matching:
283+
284+
.. code-block:: python
285+
286+
import re
287+
288+
Entry.single_register(
289+
Entry.GET,
290+
"https://api.example.com",
291+
body="ok",
292+
can_handle_fun=lambda path, qs_dict: bool(re.match(r"^/users/\d+$", path)),
293+
)
294+
295+
Query parameter checks:
296+
297+
.. code-block:: python
298+
299+
Entry.single_register(
300+
Entry.GET,
301+
"https://api.example.com",
302+
body="ok",
303+
can_handle_fun=lambda path, qs_dict: (
304+
path == "/search"
305+
and qs_dict.get("q") == ["mocket"]
306+
and qs_dict.get("limit", ["10"])[0].isdigit()
307+
),
308+
)
309+
310+
Case-insensitive path checks:
311+
312+
.. code-block:: python
313+
314+
Entry.single_register(
315+
Entry.GET,
316+
"https://api.example.com",
317+
body="ok",
318+
can_handle_fun=lambda path, qs_dict: path.lower() == "/healthz",
319+
)
320+
321+
Troubleshooting tips
322+
--------------------
323+
324+
- ``parse_qs`` values are lists, so compare against ``["value"]``.
325+
- Use ``qs_dict.get("key")`` instead of ``qs_dict["key"]`` when parameters are optional.
326+
- Keep callbacks side-effect free; they may run multiple times during request processing.
262327

263328
Example of how to record real socket traffic
264329
============================================

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ test = [
5151
"pytest-asyncio",
5252
"asgiref",
5353
"requests",
54-
"redis",
54+
"redis<8",
5555
"gevent",
5656
"sure",
5757
"flake8>5",
@@ -126,6 +126,9 @@ select = [
126126
# https://en.wikipedia.org/wiki/Cyclomatic_complexity#Limiting_complexity_during_development
127127
max-complexity = 8
128128

129+
[tool.ruff.lint.isort]
130+
known-first-party = ["mocket"]
131+
129132
[tool.mypy]
130133
python_version = "3.13"
131134
files = [

0 commit comments

Comments
 (0)