Skip to content

Commit c4ba619

Browse files
committed
Retire map_exceptions
`try: except:` blocks are free on modern Pythons when exceptions aren't raised. Entering a `@contextmanager`'d block is much less free, and there are hot paths (e.g. reading from a sync socket) where it's worth avoiding that overhead. For consistency, this retires the use of `map_exceptions` everywhere.
1 parent 5974b03 commit c4ba619

File tree

7 files changed

+108
-117
lines changed

7 files changed

+108
-117
lines changed

httpcore/_async/http11.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
LocalProtocolError,
1616
RemoteProtocolError,
1717
WriteError,
18-
map_exceptions,
1918
)
2019
from .._models import Origin, Request, Response
2120
from .._synchronization import AsyncLock, AsyncShieldCancellation
@@ -141,12 +140,14 @@ async def _send_request_headers(self, request: Request) -> None:
141140
timeouts = request.extensions.get("timeout", {})
142141
timeout = timeouts.get("write", None)
143142

144-
with map_exceptions({h11.LocalProtocolError: LocalProtocolError}):
143+
try:
145144
event = h11.Request(
146145
method=request.method,
147146
target=request.url.target,
148147
headers=request.headers,
149148
)
149+
except h11.LocalProtocolError as exc:
150+
raise LocalProtocolError(exc) from exc
150151
await self._send_event(event, timeout=timeout)
151152

152153
async def _send_request_body(self, request: Request) -> None:
@@ -210,8 +211,10 @@ async def _receive_event(
210211
self, timeout: float | None = None
211212
) -> h11.Event | type[h11.PAUSED]:
212213
while True:
213-
with map_exceptions({h11.RemoteProtocolError: RemoteProtocolError}):
214+
try:
214215
event = self._h11_state.next_event()
216+
except h11.RemoteProtocolError as exc:
217+
raise RemoteProtocolError(exc) from exc
215218

216219
if event is h11.NEED_DATA:
217220
data = await self._network_stream.read(

httpcore/_backends/anyio.py

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
ReadTimeout,
1313
WriteError,
1414
WriteTimeout,
15-
map_exceptions,
1615
)
1716
from .._utils import is_socket_readable
1817
from .base import SOCKET_OPTION, AsyncNetworkBackend, AsyncNetworkStream
@@ -23,31 +22,32 @@ def __init__(self, stream: anyio.abc.ByteStream) -> None:
2322
self._stream = stream
2423

2524
async def read(self, max_bytes: int, timeout: float | None = None) -> bytes:
26-
exc_map = {
27-
TimeoutError: ReadTimeout,
28-
anyio.BrokenResourceError: ReadError,
29-
anyio.ClosedResourceError: ReadError,
30-
anyio.EndOfStream: ReadError,
31-
}
32-
with map_exceptions(exc_map):
25+
try:
3326
with anyio.fail_after(timeout):
3427
try:
3528
return await self._stream.receive(max_bytes=max_bytes)
3629
except anyio.EndOfStream: # pragma: nocover
3730
return b""
31+
except TimeoutError as exc:
32+
raise ReadTimeout(exc) from exc
33+
except (
34+
anyio.BrokenResourceError,
35+
anyio.ClosedResourceError,
36+
anyio.EndOfStream,
37+
) as exc:
38+
raise ReadError(exc) from exc
3839

3940
async def write(self, buffer: bytes, timeout: float | None = None) -> None:
4041
if not buffer:
4142
return
4243

43-
exc_map = {
44-
TimeoutError: WriteTimeout,
45-
anyio.BrokenResourceError: WriteError,
46-
anyio.ClosedResourceError: WriteError,
47-
}
48-
with map_exceptions(exc_map):
44+
try:
4945
with anyio.fail_after(timeout):
5046
await self._stream.send(item=buffer)
47+
except TimeoutError as exc:
48+
raise WriteTimeout(exc) from exc
49+
except (anyio.BrokenResourceError, anyio.ClosedResourceError) as exc:
50+
raise WriteError(exc) from exc
5151

5252
async def aclose(self) -> None:
5353
await self._stream.aclose()
@@ -58,13 +58,7 @@ async def start_tls(
5858
server_hostname: str | None = None,
5959
timeout: float | None = None,
6060
) -> AsyncNetworkStream:
61-
exc_map = {
62-
TimeoutError: ConnectTimeout,
63-
anyio.BrokenResourceError: ConnectError,
64-
anyio.EndOfStream: ConnectError,
65-
ssl.SSLError: ConnectError,
66-
}
67-
with map_exceptions(exc_map):
61+
try:
6862
try:
6963
with anyio.fail_after(timeout):
7064
ssl_stream = await anyio.streams.tls.TLSStream.wrap(
@@ -77,6 +71,10 @@ async def start_tls(
7771
except Exception as exc: # pragma: nocover
7872
await self.aclose()
7973
raise exc
74+
except TimeoutError as exc:
75+
raise ConnectTimeout(exc) from exc
76+
except (anyio.BrokenResourceError, anyio.EndOfStream, ssl.SSLError) as exc:
77+
raise ConnectError(exc) from exc
8078
return AnyIOStream(ssl_stream)
8179

8280
def get_extra_info(self, info: str) -> typing.Any:
@@ -105,12 +103,7 @@ async def connect_tcp(
105103
) -> AsyncNetworkStream: # pragma: nocover
106104
if socket_options is None:
107105
socket_options = []
108-
exc_map = {
109-
TimeoutError: ConnectTimeout,
110-
OSError: ConnectError,
111-
anyio.BrokenResourceError: ConnectError,
112-
}
113-
with map_exceptions(exc_map):
106+
try:
114107
with anyio.fail_after(timeout):
115108
stream: anyio.abc.ByteStream = await anyio.connect_tcp(
116109
remote_host=host,
@@ -120,6 +113,10 @@ async def connect_tcp(
120113
# By default TCP sockets opened in `asyncio` include TCP_NODELAY.
121114
for option in socket_options:
122115
stream._raw_socket.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover
116+
except TimeoutError as exc:
117+
raise ConnectTimeout(exc) from exc
118+
except (OSError, anyio.BrokenResourceError) as exc:
119+
raise ConnectError(exc) from exc
123120
return AnyIOStream(stream)
124121

125122
async def connect_unix_socket(
@@ -130,16 +127,15 @@ async def connect_unix_socket(
130127
) -> AsyncNetworkStream: # pragma: nocover
131128
if socket_options is None:
132129
socket_options = []
133-
exc_map = {
134-
TimeoutError: ConnectTimeout,
135-
OSError: ConnectError,
136-
anyio.BrokenResourceError: ConnectError,
137-
}
138-
with map_exceptions(exc_map):
130+
try:
139131
with anyio.fail_after(timeout):
140132
stream: anyio.abc.ByteStream = await anyio.connect_unix(path)
141133
for option in socket_options:
142134
stream._raw_socket.setsockopt(*option) # type: ignore[attr-defined] # pragma: no cover
135+
except TimeoutError as exc:
136+
raise ConnectTimeout(exc) from exc
137+
except (OSError, anyio.BrokenResourceError) as exc:
138+
raise ConnectError(exc) from exc
143139
return AnyIOStream(stream)
144140

145141
async def sleep(self, seconds: float) -> None:

httpcore/_backends/sync.py

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@
99
from .._exceptions import (
1010
ConnectError,
1111
ConnectTimeout,
12-
ExceptionMapping,
1312
ReadError,
1413
ReadTimeout,
1514
WriteError,
1615
WriteTimeout,
17-
map_exceptions,
1816
)
1917
from .._utils import is_socket_readable
2018
from .base import SOCKET_OPTION, NetworkBackend, NetworkStream
@@ -77,20 +75,26 @@ def _perform_io(
7775
return ret
7876

7977
def read(self, max_bytes: int, timeout: float | None = None) -> bytes:
80-
exc_map: ExceptionMapping = {socket.timeout: ReadTimeout, OSError: ReadError}
81-
with map_exceptions(exc_map):
78+
try:
8279
self._sock.settimeout(timeout)
8380
return typing.cast(
8481
bytes, self._perform_io(functools.partial(self.ssl_obj.read, max_bytes))
8582
)
83+
except socket.timeout as exc:
84+
raise ReadTimeout(exc) from exc
85+
except OSError as exc:
86+
raise ReadError(exc) from exc
8687

8788
def write(self, buffer: bytes, timeout: float | None = None) -> None:
88-
exc_map: ExceptionMapping = {socket.timeout: WriteTimeout, OSError: WriteError}
89-
with map_exceptions(exc_map):
89+
try:
9090
self._sock.settimeout(timeout)
9191
while buffer:
9292
nsent = self._perform_io(functools.partial(self.ssl_obj.write, buffer))
9393
buffer = buffer[nsent:]
94+
except socket.timeout as exc:
95+
raise WriteTimeout(exc) from exc
96+
except OSError as exc:
97+
raise WriteError(exc) from exc
9498

9599
def close(self) -> None:
96100
self._sock.close()
@@ -122,21 +126,27 @@ def __init__(self, sock: socket.socket) -> None:
122126
self._sock = sock
123127

124128
def read(self, max_bytes: int, timeout: float | None = None) -> bytes:
125-
exc_map: ExceptionMapping = {socket.timeout: ReadTimeout, OSError: ReadError}
126-
with map_exceptions(exc_map):
129+
try:
127130
self._sock.settimeout(timeout)
128131
return self._sock.recv(max_bytes)
132+
except socket.timeout as exc:
133+
raise ReadTimeout(exc) from exc
134+
except OSError as exc:
135+
raise ReadError(exc) from exc
129136

130137
def write(self, buffer: bytes, timeout: float | None = None) -> None:
131138
if not buffer:
132139
return
133140

134-
exc_map: ExceptionMapping = {socket.timeout: WriteTimeout, OSError: WriteError}
135-
with map_exceptions(exc_map):
141+
try:
136142
while buffer:
137143
self._sock.settimeout(timeout)
138144
n = self._sock.send(buffer)
139145
buffer = buffer[n:]
146+
except socket.timeout as exc:
147+
raise WriteTimeout(exc) from exc
148+
except OSError as exc:
149+
raise WriteError(exc) from exc
140150

141151
def close(self) -> None:
142152
self._sock.close()
@@ -147,11 +157,7 @@ def start_tls(
147157
server_hostname: str | None = None,
148158
timeout: float | None = None,
149159
) -> NetworkStream:
150-
exc_map: ExceptionMapping = {
151-
socket.timeout: ConnectTimeout,
152-
OSError: ConnectError,
153-
}
154-
with map_exceptions(exc_map):
160+
try:
155161
try:
156162
if isinstance(self._sock, ssl.SSLSocket): # pragma: no cover
157163
# If the underlying socket has already been upgraded
@@ -168,6 +174,10 @@ def start_tls(
168174
except Exception as exc: # pragma: nocover
169175
self.close()
170176
raise exc
177+
except socket.timeout as exc:
178+
raise ConnectTimeout(exc) from exc
179+
except OSError as exc:
180+
raise ConnectError(exc) from exc
171181
return SyncStream(sock)
172182

173183
def get_extra_info(self, info: str) -> typing.Any:
@@ -199,12 +209,8 @@ def connect_tcp(
199209
socket_options = [] # pragma: no cover
200210
address = (host, port)
201211
source_address = None if local_address is None else (local_address, 0)
202-
exc_map: ExceptionMapping = {
203-
socket.timeout: ConnectTimeout,
204-
OSError: ConnectError,
205-
}
206212

207-
with map_exceptions(exc_map):
213+
try:
208214
sock = socket.create_connection(
209215
address,
210216
timeout,
@@ -213,6 +219,10 @@ def connect_tcp(
213219
for option in socket_options:
214220
sock.setsockopt(*option) # pragma: no cover
215221
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
222+
except socket.timeout as exc:
223+
raise ConnectTimeout(exc) from exc
224+
except OSError as exc:
225+
raise ConnectError(exc) from exc
216226
return SyncStream(sock)
217227

218228
def connect_unix_socket(
@@ -228,14 +238,14 @@ def connect_unix_socket(
228238
if socket_options is None:
229239
socket_options = []
230240

231-
exc_map: ExceptionMapping = {
232-
socket.timeout: ConnectTimeout,
233-
OSError: ConnectError,
234-
}
235-
with map_exceptions(exc_map):
241+
try:
236242
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
237243
for option in socket_options:
238244
sock.setsockopt(*option)
239245
sock.settimeout(timeout)
240246
sock.connect(path)
247+
except socket.timeout as exc:
248+
raise ConnectTimeout(exc) from exc
249+
except OSError as exc:
250+
raise ConnectError(exc) from exc
241251
return SyncStream(sock)

0 commit comments

Comments
 (0)