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

Make HttpStatusError and RequestError pickleable #3108

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### Fixed

* `HttpStatusError` and `RequestError` are now pickleable. (#3108)
* Fix `app` type signature in `ASGITransport`. (#3109)

## 0.27.0 (21st February, 2024)
Expand Down
7 changes: 7 additions & 0 deletions httpx/_exceptions.py
Expand Up @@ -102,6 +102,13 @@ def request(self) -> Request:
def request(self, request: Request) -> None:
self._request = request

def __reduce__(
self,
) -> typing.Tuple[
typing.Callable[..., Exception], typing.Tuple[typing.Any], dict[str, typing.Any]
]:
return (Exception.__new__, (type(self),) + self.args, self.__dict__)

Comment on lines +105 to +111
Copy link
Member

Choose a reason for hiding this comment

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

Are we able to be consistent with how pickle is supported on Request/Response here?

Copy link
Author

Choose a reason for hiding this comment

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

All of the key word only arguments of Request have default values so that's why it's pickleable. Our choices here are:

  1. Give all kwonly arguments defaults. Classes where all kwonly arguments have defaults mostly have the correct pickle behavior without any special support.
  2. Do something like what I have here.

As an aside, this is a bit of a Python wart, ideally simple classes with required kwonly constructor args should be pickleable out of the box. I wonder if there is any discussion on discuss.python.org about it...

Copy link
Member

Choose a reason for hiding this comment

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

Okay sure thing.
Thanks for the fix. ☺️


class RequestError(HTTPError):
"""
Expand Down
16 changes: 16 additions & 0 deletions tests/test_pickle.py
@@ -0,0 +1,16 @@
import pickle

from httpx import HTTPStatusError, RequestError


def test_pickle():
req_err = RequestError("hi!", request="request") # type:ignore[arg-type]
req_err_clone = pickle.loads(pickle.dumps(req_err))
assert req_err.args == req_err_clone.args
assert req_err.request == req_err_clone.request

status_err = HTTPStatusError("hi", request="request", response="response") # type:ignore[arg-type]
status_err_clone = pickle.loads(pickle.dumps(status_err))
assert status_err.args == status_err_clone.args
assert status_err.request == status_err_clone.request
assert status_err.response == status_err_clone.response