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
Improve type hints for copy() and replace() in Request and Response. #6143
base: master
Are you sure you want to change the base?
Changes from 6 commits
a6cee78
5d55e4f
204d6e1
8776b4a
db5a73f
ebdea40
1fab844
a72394a
f56b5fc
2534a28
b658757
706eb8d
032e6a0
6b75d8f
d97d32c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,7 @@ def _build_redirect_request( | |
redirect_request = source_request.replace( | ||
url=url, | ||
**kwargs, | ||
cls=None, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Without this line the type of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you please add a test for this case? I guess it's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's because it cannot know that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, what test do you mean? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If kwargs are passed, what's the reveal_type of the result There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added tests that check that the result is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if it's a useful thing to check :) |
||
cookies=None, | ||
) | ||
if "Cookie" in redirect_request.headers: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import pytest | ||
|
||
from scrapy import Request | ||
from scrapy.http import JsonRequest | ||
|
||
|
||
class MyRequest(Request): | ||
pass | ||
|
||
|
||
class MyRequest2(Request): | ||
pass | ||
|
||
|
||
@pytest.mark.mypy_testing | ||
def mypy_test_headers(): | ||
Request("data:,", headers=1) # E: Argument "headers" to "Request" has incompatible type "int"; expected "Union[Mapping[str, Any], Iterable[Tuple[str, Any]], None]" | ||
Request("data:,", headers=None) | ||
Request("data:,", headers={}) | ||
Request("data:,", headers=[]) | ||
Request("data:,", headers={"foo": "bar"}) | ||
Request("data:,", headers={b"foo": "bar"}) | ||
Request("data:,", headers={"foo": b"bar"}) | ||
Request("data:,", headers=[("foo", "bar")]) | ||
Request("data:,", headers=[(b"foo", "bar")]) | ||
Request("data:,", headers=[("foo", b"bar")]) | ||
|
||
|
||
@pytest.mark.mypy_testing | ||
def mypy_test_copy(): | ||
req = Request("data:,") | ||
reveal_type(req) # R: scrapy.http.request.Request | ||
req_copy = req.copy() | ||
reveal_type(req_copy) # R: scrapy.http.request.Request | ||
|
||
req = MyRequest("data:,") | ||
reveal_type(req) # R: __main__.MyRequest | ||
req_copy = req.copy() | ||
reveal_type(req_copy) # R: __main__.MyRequest | ||
|
||
|
||
@pytest.mark.mypy_testing | ||
def mypy_test_replace(): | ||
req = Request("data:,") | ||
reveal_type(req) # R: scrapy.http.request.Request | ||
req_copy = req.replace(body=b"a") | ||
reveal_type(req_copy) # R: scrapy.http.request.Request | ||
|
||
req = MyRequest("data:,") | ||
reveal_type(req) # R: __main__.MyRequest | ||
req_copy = req.replace(body=b"a") | ||
reveal_type(req_copy) # R: __main__.MyRequest | ||
req_copy2 = req.replace(body=b"a", cls=MyRequest2) | ||
reveal_type(req_copy2) # R: __main__.MyRequest2 | ||
|
||
|
||
@pytest.mark.mypy_testing | ||
def mypy_test_jsonrequest_copy_replace(): | ||
req = JsonRequest("data:,") | ||
reveal_type(req) # R: scrapy.http.request.json_request.JsonRequest | ||
req_copy = req.copy() | ||
reveal_type(req_copy) # R: scrapy.http.request.json_request.JsonRequest | ||
req_copy = req.replace(body=b"a") | ||
reveal_type(req_copy) # R: scrapy.http.request.json_request.JsonRequest | ||
req_copy_my = req.replace(body=b"a", cls=MyRequest) | ||
reveal_type(req_copy_my) # R: __main__.MyRequest |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import pytest | ||
|
||
from scrapy.http import HtmlResponse, Response, TextResponse | ||
|
||
|
||
@pytest.mark.mypy_testing | ||
def mypy_test_headers(): | ||
Response("data:,", headers=1) # E: Argument "headers" to "Response" has incompatible type "int"; expected "Union[Mapping[str, Any], Iterable[Tuple[str, Any]], None]" | ||
Response("data:,", headers=None) | ||
Response("data:,", headers={}) | ||
Response("data:,", headers=[]) | ||
Response("data:,", headers={"foo": "bar"}) | ||
Response("data:,", headers={b"foo": "bar"}) | ||
Response("data:,", headers={"foo": b"bar"}) | ||
Response("data:,", headers=[("foo", "bar")]) | ||
Response("data:,", headers=[(b"foo", "bar")]) | ||
Response("data:,", headers=[("foo", b"bar")]) | ||
|
||
|
||
@pytest.mark.mypy_testing | ||
def mypy_test_copy(): | ||
resp = Response("data:,") | ||
reveal_type(resp) # R: scrapy.http.response.Response | ||
resp_copy = resp.copy() | ||
reveal_type(resp_copy) # R: scrapy.http.response.Response | ||
|
||
resp = HtmlResponse("data:,") | ||
reveal_type(resp) # R: scrapy.http.response.html.HtmlResponse | ||
resp_copy = resp.copy() | ||
reveal_type(resp_copy) # R: scrapy.http.response.html.HtmlResponse | ||
|
||
|
||
@pytest.mark.mypy_testing | ||
def mypy_test_replace(): | ||
resp = Response("data:,") | ||
reveal_type(resp) # R: scrapy.http.response.Response | ||
resp_copy = resp.replace(body=b"a") | ||
reveal_type(resp_copy) # R: scrapy.http.response.Response | ||
|
||
resp = HtmlResponse("data:,") | ||
reveal_type(resp) # R: scrapy.http.response.html.HtmlResponse | ||
resp_copy = resp.replace(body=b"a") | ||
reveal_type(resp_copy) # R: scrapy.http.response.html.HtmlResponse | ||
resp_copy2 = resp.replace(body=b"a", cls=TextResponse) | ||
reveal_type(resp_copy2) # R: scrapy.http.response.text.TextResponse |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should run it in the latest Python instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also run the
typing
check on the latest Python then, as I think they check the same thing? In that case we will stop checking (and so supporting) that the type hints work as expected on older Python versions and I thought it's a nice thing to support.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I mean, for users that use Scrapy on older Python versions and run mypy on their code)