Skip to content

Commit 939562f

Browse files
Added typing in tests (#694)
* reverted overloads for activate * Fix matchers typing * Added status and body attributes to BaseResponse
1 parent c46cb06 commit 939562f

File tree

9 files changed

+63
-35
lines changed

9 files changed

+63
-35
lines changed

CHANGES

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
0.24.1
22
------
33

4-
* Reintroduced overloads for better typing in `CallList`.
4+
* Reverted overloads removal
55
* Added typing to `Call` attributes.
66

77

mypy.ini

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
[mypy]
2-
exclude = tests
32
show_column_numbers=True
43
show_error_codes = True
54

@@ -27,3 +26,8 @@ warn_unreachable=False
2726

2827
strict_equality=True
2928
ignore_missing_imports=True
29+
30+
[mypy-responses.tests.*]
31+
disallow_untyped_calls=False
32+
disallow_untyped_defs=False
33+
disable_error_code = union-attr

responses/__init__.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,9 @@ def __init__(
405405
self._calls: CallList = CallList()
406406
self.passthrough = passthrough
407407

408+
self.status: int = 200
409+
self.body: "_Body" = ""
410+
408411
def __eq__(self, other: Any) -> bool:
409412
if not isinstance(other, BaseResponse):
410413
return False
@@ -569,6 +572,8 @@ def __init__(
569572
auto_calculate_content_length: bool = False,
570573
**kwargs: Any,
571574
) -> None:
575+
super().__init__(method, url, **kwargs)
576+
572577
# if we were passed a `json` argument,
573578
# override the body and content_type
574579
if json is not None:
@@ -596,7 +601,6 @@ def __init__(
596601
self.stream: Optional[bool] = stream
597602
self.content_type: str = content_type # type: ignore[assignment]
598603
self.auto_calculate_content_length: bool = auto_calculate_content_length
599-
super().__init__(method, url, **kwargs)
600604

601605
def get_response(self, request: "PreparedRequest") -> HTTPResponse:
602606
if self.body and isinstance(self.body, Exception):
@@ -641,6 +645,8 @@ def __init__(
641645
content_type: Optional[str] = "text/plain",
642646
**kwargs: Any,
643647
) -> None:
648+
super().__init__(method, url, **kwargs)
649+
644650
self.callback = callback
645651

646652
if stream is not None:
@@ -650,7 +656,6 @@ def __init__(
650656
)
651657
self.stream: Optional[bool] = stream
652658
self.content_type: Optional[str] = content_type
653-
super().__init__(method, url, **kwargs)
654659

655660
def get_response(self, request: "PreparedRequest") -> HTTPResponse:
656661
headers = self.get_headers()
@@ -970,6 +975,22 @@ def __exit__(self, type: Any, value: Any, traceback: Any) -> bool:
970975
self.reset()
971976
return success
972977

978+
@overload
979+
def activate(self, func: "_F" = ...) -> "_F":
980+
"""Overload for scenario when 'responses.activate' is used."""
981+
982+
@overload
983+
def activate( # type: ignore[misc]
984+
self,
985+
*,
986+
registry: Type[Any] = ...,
987+
assert_all_requests_are_fired: bool = ...,
988+
) -> Callable[["_F"], "_F"]:
989+
"""Overload for scenario when
990+
'responses.activate(registry=, assert_all_requests_are_fired=True)' is used.
991+
See https://github.com/getsentry/responses/pull/469 for more details
992+
"""
993+
973994
def activate(
974995
self,
975996
func: Optional["_F"] = None,

responses/_recorder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ def _dump(
5050
"response": {
5151
"method": rsp.method,
5252
"url": rsp.url,
53-
"body": rsp.body, # type: ignore[attr-defined]
54-
"status": rsp.status, # type: ignore[attr-defined]
53+
"body": rsp.body,
54+
"status": rsp.status,
5555
"headers": rsp.headers,
5656
"content_type": rsp.content_type,
5757
"auto_calculate_content_length": content_length,

responses/matchers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import Dict
88
from typing import List
99
from typing import Optional
10+
from typing import Pattern
1011
from typing import Tuple
1112
from typing import Union
1213
from urllib.parse import parse_qsl
@@ -391,7 +392,7 @@ def match(request: PreparedRequest) -> Tuple[bool, str]:
391392

392393

393394
def header_matcher(
394-
headers: Dict[str, str], strict_match: bool = False
395+
headers: Dict[str, Union[str, Pattern[str]]], strict_match: bool = False
395396
) -> Callable[..., Any]:
396397
"""
397398
Matcher to match 'headers' argument in request using the responses library.

responses/tests/test_matchers.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import gzip
22
import re
3+
from typing import Any
4+
from typing import List
35
from unittest.mock import Mock
46

57
import pytest
@@ -152,7 +154,7 @@ def test_json_params_matcher_json_list():
152154

153155

154156
def test_json_params_matcher_json_list_empty():
155-
json_a = []
157+
json_a: "List[Any]" = []
156158
json_b = "[]"
157159
mock_request = Mock(body=json_b)
158160
result = matchers.json_params_matcher(json_a)(mock_request)
@@ -457,7 +459,7 @@ def run():
457459
(b"\xacHello World!", b"\xacHello World!"),
458460
],
459461
)
460-
def test_multipart_matcher(req_file, match_file):
462+
def test_multipart_matcher(req_file, match_file): # type: ignore[misc]
461463
@responses.activate
462464
def run():
463465
req_data = {"some": "other", "data": "fields"}
@@ -796,7 +798,7 @@ def test_matchers_create_key_val_str():
796798

797799
class TestHeaderWithRegex:
798800
@property
799-
def url(self):
801+
def url(self): # type: ignore[misc]
800802
return "http://example.com/"
801803

802804
def _register(self):

responses/tests/test_multithreading.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111

1212
@pytest.mark.parametrize("execution_number", range(10))
13-
def test_multithreading_lock(execution_number):
13+
def test_multithreading_lock(execution_number): # type: ignore[misc]
1414
"""Reruns test multiple times since error is random and
1515
depends on CPU and can lead to false positive result.
1616

responses/tests/test_recorder.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ def test_recorder_toml(self, httpserver):
9797

9898
def dump_to_file(file_path, registered):
9999
with open(file_path, "wb") as file:
100-
_dump(registered, file, tomli_w.dump)
100+
_dump(registered, file, tomli_w.dump) # type: ignore[arg-type]
101101

102-
custom_recorder.dump_to_file = dump_to_file
102+
custom_recorder.dump_to_file = dump_to_file # type: ignore[method-assign]
103103

104104
url202, url400, url404, url500 = self.prepare_server(httpserver)
105105

@@ -151,25 +151,25 @@ def teardown_method(self):
151151
assert not self.out_file.exists()
152152

153153
@pytest.mark.parametrize("parser", (yaml, tomli_w))
154-
def test_add_from_file(self, parser):
154+
def test_add_from_file(self, parser): # type: ignore[misc]
155155
if parser == yaml:
156156
with open(self.out_file, "w") as file:
157157
parser.dump(get_data("example.com", "8080"), file)
158158
else:
159-
with open(self.out_file, "wb") as file:
159+
with open(self.out_file, "wb") as file: # type: ignore[assignment]
160160
parser.dump(get_data("example.com", "8080"), file)
161161

162162
@responses.activate
163163
def run():
164164
responses.patch("http://httpbin.org")
165165
if parser == tomli_w:
166166

167-
def _parse_response_file(file_path):
167+
def _parse_resp_f(file_path):
168168
with open(file_path, "rb") as file:
169169
data = _toml.load(file)
170170
return data
171171

172-
responses.mock._parse_response_file = _parse_response_file
172+
responses.mock._parse_response_file = _parse_resp_f # type: ignore[method-assign]
173173

174174
responses._add_from_file(file_path=self.out_file)
175175
responses.post("http://httpbin.org/form")

responses/tests/test_responses.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def run():
123123
),
124124
],
125125
)
126-
def test_replace(original, replacement):
126+
def test_replace(original, replacement): # type: ignore[misc]
127127
@responses.activate
128128
def run():
129129
responses.add(responses.GET, "http://example.com/one", body="test1")
@@ -157,7 +157,7 @@ def run():
157157
(re.compile(r"http://example\.com/one"), "http://example.com/one"),
158158
],
159159
)
160-
def test_replace_error(original, replacement):
160+
def test_replace_error(original, replacement): # type: ignore[misc]
161161
@responses.activate
162162
def run():
163163
responses.add(responses.GET, original)
@@ -203,7 +203,7 @@ def run():
203203
),
204204
],
205205
)
206-
def test_upsert_replace(original, replacement):
206+
def test_upsert_replace(original, replacement): # type: ignore[misc]
207207
@responses.activate
208208
def run():
209209
responses.add(responses.GET, "http://example.com/one", body="test1")
@@ -241,7 +241,7 @@ def run():
241241
),
242242
],
243243
)
244-
def test_upsert_add(original, replacement):
244+
def test_upsert_add(original, replacement): # type: ignore[misc]
245245
@responses.activate
246246
def run():
247247
responses.add(responses.GET, "http://example.com/one", body="test1")
@@ -299,7 +299,7 @@ def run():
299299
),
300300
],
301301
)
302-
def test_response_equality(args1, kwargs1, args2, kwargs2, expected):
302+
def test_response_equality(args1, kwargs1, args2, kwargs2, expected): # type: ignore[misc]
303303
o1 = BaseResponse(*args1, **kwargs1)
304304
o2 = BaseResponse(*args2, **kwargs2)
305305
assert (o1 == o2) is expected
@@ -847,7 +847,7 @@ def send(
847847
"adapter_class",
848848
(CustomAdapter, PositionalArgsAdapter, PositionalArgsIncompleteAdapter),
849849
)
850-
def test_custom_adapter(self, adapter_class):
850+
def test_custom_adapter(self, adapter_class): # type: ignore[misc]
851851
"""Test basic adapter implementation and that responses can patch them properly."""
852852

853853
@responses.activate
@@ -902,12 +902,12 @@ def test_function(a, b=None):
902902

903903

904904
@pytest.fixture
905-
def my_fruit():
905+
def my_fruit(): # type: ignore[misc]
906906
return "apple"
907907

908908

909909
@pytest.fixture
910-
def fruit_basket(my_fruit):
910+
def fruit_basket(my_fruit): # type: ignore[misc]
911911
return ["banana", my_fruit]
912912

913913

@@ -926,7 +926,7 @@ def test_function(self, my_fruit, fruit_basket):
926926

927927
def test_activate_mock_interaction():
928928
@patch("sys.stdout")
929-
def test_function(mock_stdout):
929+
def test_function(mock_stdout): # type: ignore[misc]
930930
return mock_stdout
931931

932932
decorated_test_function = responses.activate(test_function)
@@ -1045,7 +1045,7 @@ def run():
10451045

10461046
@pytest.mark.parametrize("request_stream", (True, False, None))
10471047
@pytest.mark.parametrize("responses_stream", (True, False, None))
1048-
def test_response_cookies_session(request_stream, responses_stream):
1048+
def test_response_cookies_session(request_stream, responses_stream): # type: ignore[misc]
10491049
@responses.activate
10501050
def run():
10511051
url = "https://example.com/path"
@@ -1384,13 +1384,13 @@ def run():
13841384
# Type errors here and on 1250 are ignored because the stubs for requests
13851385
# are off https://github.com/python/typeshed/blob/f8501d33c737482a829c6db557a0be26895c5941
13861386
# /stubs/requests/requests/packages/__init__.pyi#L1
1387-
original_init = getattr(urllib3.HTTPResponse, "__init__") # type: ignore
1387+
original_init = getattr(urllib3.HTTPResponse, "__init__")
13881388

13891389
def patched_init(self, *args, **kwargs):
13901390
kwargs["enforce_content_length"] = True
13911391
original_init(self, *args, **kwargs)
13921392

1393-
monkeypatch.setattr(urllib3.HTTPResponse, "__init__", patched_init) # type: ignore
1393+
monkeypatch.setattr(urllib3.HTTPResponse, "__init__", patched_init)
13941394

13951395
run()
13961396
assert_reset()
@@ -1919,7 +1919,7 @@ def test_custom_target(monkeypatch):
19191919
"http://example.com/other/path/",
19201920
),
19211921
)
1922-
def test_request_param(url):
1922+
def test_request_param(url): # type: ignore[misc]
19231923
@responses.activate
19241924
def run():
19251925
params = {"hello": "world", "example": "params"}
@@ -1962,7 +1962,7 @@ def run():
19621962
@pytest.mark.parametrize(
19631963
"url", ("http://example.com", "http://example.com?hello=world")
19641964
)
1965-
def test_assert_call_count(url):
1965+
def test_assert_call_count(url): # type: ignore[misc]
19661966
@responses.activate
19671967
def run():
19681968
responses.add(responses.GET, url)
@@ -2160,7 +2160,7 @@ def run():
21602160
),
21612161
],
21622162
)
2163-
def test_response_representations(response_params, expected_representation):
2163+
def test_response_representations(response_params, expected_representation): # type: ignore[misc]
21642164
response = Response(**response_params)
21652165

21662166
assert str(response) == expected_representation
@@ -2206,7 +2206,7 @@ def run():
22062206
("http://fizzbuzz/foo", "http://fizzbuzz/foo"),
22072207
],
22082208
)
2209-
def test_rfc_compliance(url, other_url):
2209+
def test_rfc_compliance(url, other_url): # type: ignore[misc]
22102210
@responses.activate
22112211
def run():
22122212
responses.add(method=responses.GET, url=url)
@@ -2314,7 +2314,7 @@ def run_classic():
23142314
run_not_strict()
23152315

23162316
@pytest.mark.parametrize("assert_fired", (True, False, None))
2317-
def test_nested_decorators(self, assert_fired):
2317+
def test_nested_decorators(self, assert_fired): # type: ignore[misc]
23182318
"""Validate if assert_all_requests_are_fired is applied from the correct function.
23192319
23202320
assert_all_requests_are_fired must be applied from the function
@@ -2607,7 +2607,7 @@ def run():
26072607
assert_reset()
26082608

26092609
@pytest.mark.parametrize("raise_on_status", (True, False))
2610-
def test_max_retries_exceed(self, raise_on_status):
2610+
def test_max_retries_exceed(self, raise_on_status): # type: ignore[misc]
26112611
@responses.activate(registry=registries.OrderedRegistry)
26122612
def run():
26132613
url = "https://example.com"

0 commit comments

Comments
 (0)