Skip to content
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

[requests] Sync HttpError stub to implementation #10875

Merged
merged 1 commit into from
Oct 13, 2023

Conversation

ubersan
Copy link
Contributor

@ubersan ubersan commented Oct 13, 2023

The implementation has no restrictions on providing a response. Is there a reason why the stub requires it?

@github-actions
Copy link
Contributor

Diff from mypy_primer, showing the effect of this PR on open source code:

cloud-init (https://github.com/canonical/cloud-init)
+ cloudinit/url_helper.py:343: error: Item "None" of "Response | None" has no attribute "status_code"  [union-attr]
+ cloudinit/url_helper.py:344: error: Item "None" of "Response | None" has no attribute "headers"  [union-attr]
- tests/unittests/sources/azure/test_errors.py:169: error: Missing named argument "response" for "HTTPError"  [call-arg]

paasta (https://github.com/yelp/paasta)
- paasta_tools/mesos_maintenance.py:213: error: Missing named argument "response" for "HTTPError"  [call-arg]

poetry (https://github.com/python-poetry/poetry)
+ src/poetry/publishing/uploader.py:35: error: Item "None" of "Response | None" has no attribute "status_code"  [union-attr]
+ src/poetry/publishing/uploader.py:35: error: Item "None" of "Response | None" has no attribute "reason"  [union-attr]
+ src/poetry/publishing/uploader.py:35: error: Item "None" of "Response | None" has no attribute "content"  [union-attr]

twine (https://github.com/pypa/twine)
+ twine/__main__.py:36: error: Item "None" of "Response | None" has no attribute "status_code"  [union-attr]
+ twine/__main__.py:39: error: Item "None" of "Response | None" has no attribute "url"  [union-attr]
+ twine/__main__.py:39: error: Item "None" of "Response | None" has no attribute "reason"  [union-attr]

schemathesis (https://github.com/schemathesis/schemathesis)
+ src/schemathesis/cli/output/default.py: note: In function "display_service_error":
+ src/schemathesis/cli/output/default.py:368: error: Item "None" of "Optional[Response]" has no attribute "status_code"  [union-attr]
+ src/schemathesis/cli/__init__.py: note: In function "handle_service_error":
+ src/schemathesis/cli/__init__.py:1233: error: Item "None" of "Optional[Response]" has no attribute "status_code"  [union-attr]
+ src/schemathesis/cli/__init__.py:1234: error: Item "None" of "Optional[Response]" has no attribute "json"  [union-attr]
+ src/schemathesis/cli/__init__.py:1235: error: Item "None" of "Optional[Response]" has no attribute "status_code"  [union-attr]
+ src/schemathesis/cli/__init__.py: note: In function "login":
+ src/schemathesis/cli/__init__.py:1357: error: Item "None" of "Optional[Response]" has no attribute "json"  [union-attr]

apprise (https://github.com/caronc/apprise)
- test/helpers/rest.py:63: error: Missing named argument "response" for "HTTPError"  [call-arg]
- test/test_attach_http.py:59: error: Missing named argument "response" for "HTTPError"  [call-arg]
- test/test_config_http.py:54: error: Missing named argument "response" for "HTTPError"  [call-arg]

openlibrary (https://github.com/internetarchive/openlibrary)
+ openlibrary/catalog/get_ia.py: note: In function "urlopen_keep_trying":
+ openlibrary/catalog/get_ia.py:25: error: Item "None" of "Response | None" has no attribute "status_code"  [union-attr]

@srittau
Copy link
Collaborator

srittau commented Oct 13, 2023

Cf #10764

@srittau
Copy link
Collaborator

srittau commented Oct 13, 2023

This PR is problematic, as the primer output shows. A lot of code assumes that HTTPError.response is not None, which is true for the only place in requests that raises an HTTPError:

https://github.com/psf/requests/blob/b55bb15c35132f021fc0997c6a72730abe2216f5/src/requests/models.py#L1019

On the other hand, some code outside requests that constructs HTTPErrors assumes that the response argument is optional. Even requests has a test that asserts that:

https://github.com/psf/requests/blob/b55bb15c35132f021fc0997c6a72730abe2216f5/tests/test_requests.py#L1542

Especially considering the test in requests, I propose to accept this PR, even if it means that some code needs asserts or type ignore. It's also the safer alternative.

Copy link
Collaborator

@srittau srittau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, see my last comment, but I would like another maintainer to chime in.

@AlexWaygood
Copy link
Member

There's no way of making everybody happy here, but this approach does have the advantage that it is, well, correct.

@ubersan
Copy link
Contributor Author

ubersan commented Oct 13, 2023

thanks for the comments, I agree it's not super nice to break quite some apps, but at least we're starting to being aligned again with the implementation going forward

@srittau srittau merged commit e92bfcb into python:main Oct 13, 2023
47 checks passed
geoberle added a commit to geoberle/qontract-reconcile that referenced this pull request Oct 15, 2023
`types-requests` now allows `HTTPError.response` to be `None` and in order to make mypy happy, we need to check for it

see python/typeshed#10875

Signed-off-by: Gerd Oberlechner <goberlec@redhat.com>
geoberle added a commit to geoberle/qontract-reconcile that referenced this pull request Oct 15, 2023
`types-requests` now allows `HTTPError.response` to be `None` and in order to make mypy happy, we need to check for it

see python/typeshed#10875

Signed-off-by: Gerd Oberlechner <goberlec@redhat.com>
geoberle added a commit to app-sre/qontract-reconcile that referenced this pull request Oct 16, 2023
`types-requests` now allows `HTTPError.response` to be `None` and in order to make mypy happy, we need to check for it

see python/typeshed#10875

Signed-off-by: Gerd Oberlechner <goberlec@redhat.com>
andersk added a commit to andersk/python-zulip-api that referenced this pull request Oct 18, 2023
python/typeshed#10875

Signed-off-by: Anders Kaseorg <anders@zulip.com>
andersk added a commit to andersk/python-zulip-api that referenced this pull request Oct 18, 2023
python/typeshed#10875

Signed-off-by: Anders Kaseorg <anders@zulip.com>
andersk added a commit to zulip/python-zulip-api that referenced this pull request Oct 18, 2023
python/typeshed#10875

Signed-off-by: Anders Kaseorg <anders@zulip.com>
@intgr
Copy link
Contributor

intgr commented Oct 20, 2023

FWIW I think this is a step backwards.

@srittau
Copy link
Collaborator

srittau commented Oct 20, 2023

@intgr In the end, this is an issue to be taken up with the requests project. It would make sense to me that HTTPError requires the response to be set, but this isn't the case in the implementation, and in fact there is an explicit test in requests that HTTPError can be used without a response set, so this is clearly intended usage.

@bluetech
Copy link
Contributor

bluetech commented Nov 5, 2023

This change has caused quite a lot of busy work for us as well. I think that in practice, it would have been better to leave response not optional. requests always passes a response to HTTPError, and "HTTP error" itself sort of implies that a response be present (otherwise it's not really an HTTP error...). I think that outweighs type unsafety from some 3rd party packages not passing a response. But I understand @srittau's rationale and I wouldn't change it back at this point.

@asottile-sentry
Copy link
Contributor

is there any way to change this so that by default it has Response -- but when constructed directly it does not? this change is a big step backwards otherwise

@Akuli
Copy link
Collaborator

Akuli commented Dec 28, 2023

I think this should be reverted.

As already mentioned, the only place in requests that raises HTTPError is:

        if http_error_msg:
            raise HTTPError(http_error_msg, response=self)

So practically, when you do except HTTPError, the response will always be set. I think handling an exception with try/except is by far the most important use case for exception type stubs in a library. So making it "just work" should be our main goal.

IMO the unit test that initializes response to None doesn't mean anything. When you write unit tests, you tend to write unit tests for everything, including that dumb feature that seemed like a good idea at the time but was not needed after all. To me, the test would be more meaningful if it was more integration test style than unit test style (for example, if the test actually made requests throw HTTPError with no response set in some obscure corner case).

Is there really a practical problem that this PR solves, and is it really worth solving? If there is, and I'm just unaware of it, I'd suggest using the Any trick (now documented in CONTRIBUTING.md).

@srittau
Copy link
Collaborator

srittau commented Dec 28, 2023

The practical problem is that people initialize HTTPError in their own code.

Akuli added a commit to Akuli/typeshed that referenced this pull request Dec 28, 2023
@Akuli
Copy link
Collaborator

Akuli commented Dec 30, 2023

is there any way to change this so that by default it has Response -- but when constructed directly it does not?

Not really, but we did the next best thing in #11207: you can now assume it has a Response or check whether it's missing without any type checking errors. A new version of types-requests with the fix will be released automatically in about 12 hours.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants