Skip to content

Commit c46cb06

Browse files
authored
Fix/calllist typing (#690)
* fix: Reintroduce `overload`s in `CallList` * test: Add coverage to ensure we can differentiate between indexing and slicing into `CallList`s * feat: Better typing for `Call`
1 parent a0df27d commit c46cb06

File tree

3 files changed

+55
-2
lines changed

3 files changed

+55
-2
lines changed

CHANGES

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
0.24.1
2+
------
3+
4+
* Reintroduced overloads for better typing in `CallList`.
5+
* Added typing to `Call` attributes.
6+
7+
18
0.24.0
29
------
310

responses/__init__.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import json as json_module
44
import logging
55
import socket
6-
from collections import namedtuple
76
from functools import partialmethod
87
from functools import wraps
98
from http import client
@@ -18,12 +17,14 @@
1817
from typing import Iterator
1918
from typing import List
2019
from typing import Mapping
20+
from typing import NamedTuple
2121
from typing import Optional
2222
from typing import Sequence
2323
from typing import Sized
2424
from typing import Tuple
2525
from typing import Type
2626
from typing import Union
27+
from typing import overload
2728
from warnings import warn
2829

2930
import yaml
@@ -96,7 +97,11 @@ def __call__(
9697
]
9798

9899

99-
Call = namedtuple("Call", ["request", "response"])
100+
class Call(NamedTuple):
101+
request: "PreparedRequest"
102+
response: "_Body"
103+
104+
100105
_real_send = HTTPAdapter.send
101106
_UNSET = object()
102107

@@ -241,6 +246,14 @@ def __iter__(self) -> Iterator[Call]:
241246
def __len__(self) -> int:
242247
return len(self._calls)
243248

249+
@overload
250+
def __getitem__(self, idx: int) -> Call:
251+
...
252+
253+
@overload
254+
def __getitem__(self, idx: slice) -> List[Call]:
255+
...
256+
244257
def __getitem__(self, idx: Union[int, slice]) -> Union[Call, List[Call]]:
245258
return self._calls[idx]
246259

responses/tests/test_responses.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from io import BufferedReader
66
from io import BytesIO
77
from typing import Any
8+
from typing import List
89
from typing import Optional
910
from unittest.mock import Mock
1011
from unittest.mock import patch
@@ -20,6 +21,7 @@
2021

2122
import responses
2223
from responses import BaseResponse
24+
from responses import Call
2325
from responses import CallbackResponse
2426
from responses import PassthroughResponse
2527
from responses import Response
@@ -2035,6 +2037,37 @@ def run():
20352037
assert_reset()
20362038

20372039

2040+
def test_response_calls_indexing_and_slicing():
2041+
@responses.activate
2042+
def run():
2043+
responses.add(responses.GET, "http://www.example.com")
2044+
responses.add(responses.GET, "http://www.example.com/1")
2045+
responses.add(responses.GET, "http://www.example.com/2")
2046+
2047+
requests.get("http://www.example.com")
2048+
requests.get("http://www.example.com/1")
2049+
requests.get("http://www.example.com/2")
2050+
requests.get("http://www.example.com/1")
2051+
requests.get("http://www.example.com")
2052+
2053+
# Use of a type hints here ensures mypy knows the difference between index and slice.
2054+
individual_call: Call = responses.calls[0]
2055+
call_slice: List[Call] = responses.calls[1:-1]
2056+
2057+
assert individual_call.request.url == "http://www.example.com"
2058+
2059+
assert call_slice == [
2060+
responses.calls[1],
2061+
responses.calls[2],
2062+
responses.calls[3],
2063+
]
2064+
assert [c.request.url for c in call_slice] == [
2065+
"http://www.example.com/1",
2066+
"http://www.example.com/2",
2067+
"http://www.example.com/1",
2068+
]
2069+
2070+
20382071
def test_response_calls_and_registry_calls_are_equal():
20392072
@responses.activate
20402073
def run():

0 commit comments

Comments
 (0)