Skip to content

Commit 08b3eee

Browse files
authored
Raise a neater RuntimeError when the correct async deps are not installed. (#826)
* Raise a neater RuntimeError when the correct async deps are not installed * Run scripts/unasync * Update CHANGELOG
1 parent 66aa1c1 commit 08b3eee

File tree

4 files changed

+35
-62
lines changed

4 files changed

+35
-62
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
77
## Unreleased
88

99
- Fix pool timeout to account for the total time spent retrying. (#823)
10-
- Fix synchronous TLS-in-TLS streams. (#840)
10+
- Raise a neater RuntimeError when the correct async deps are not installed. (#826)
11+
- Add support for synchronous TLS-in-TLS streams. (#840)
1112

1213
## 1.0.0 (October 6th, 2023)
1314

httpcore/_async/connection_pool.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,10 @@ async def aclose(self) -> None:
326326
self._requests = []
327327

328328
async def __aenter__(self) -> "AsyncConnectionPool":
329+
# Acquiring the pool lock here ensures that we have the
330+
# correct dependencies installed as early as possible.
331+
async with self._pool_lock:
332+
pass
329333
return self
330334

331335
async def __aexit__(

httpcore/_sync/connection_pool.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,10 @@ def close(self) -> None:
326326
self._requests = []
327327

328328
def __enter__(self) -> "ConnectionPool":
329+
# Acquiring the pool lock here ensures that we have the
330+
# correct dependencies installed as early as possible.
331+
with self._pool_lock:
332+
pass
329333
return self
330334

331335
def __exit__(

httpcore/_synchronization.py

Lines changed: 25 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,23 @@ def current_async_library() -> str:
2424
try:
2525
import sniffio
2626
except ImportError: # pragma: nocover
27-
return "asyncio"
28-
29-
environment = sniffio.current_async_library()
27+
environment = "asyncio"
28+
else:
29+
environment = sniffio.current_async_library()
3030

3131
if environment not in ("asyncio", "trio"): # pragma: nocover
3232
raise RuntimeError("Running under an unsupported async environment.")
3333

34+
if environment == "asyncio" and anyio is None: # pragma: nocover
35+
raise RuntimeError(
36+
"Running with asyncio requires installation of 'httpcore[asyncio]'."
37+
)
38+
39+
if environment == "trio" and trio is None: # pragma: nocover
40+
raise RuntimeError(
41+
"Running with trio requires installation of 'httpcore[trio]'."
42+
)
43+
3444
return environment
3545

3646

@@ -45,16 +55,8 @@ def setup(self) -> None:
4555
"""
4656
self._backend = current_async_library()
4757
if self._backend == "trio":
48-
if trio is None: # pragma: nocover
49-
raise RuntimeError(
50-
"Running with trio requires installation of 'httpcore[trio]'."
51-
)
5258
self._trio_lock = trio.Lock()
53-
else:
54-
if anyio is None: # pragma: nocover
55-
raise RuntimeError(
56-
"Running with asyncio requires installation of 'httpcore[asyncio]'."
57-
)
59+
elif self._backend == "asyncio":
5860
self._anyio_lock = anyio.Lock()
5961

6062
async def __aenter__(self) -> "AsyncLock":
@@ -63,7 +65,7 @@ async def __aenter__(self) -> "AsyncLock":
6365

6466
if self._backend == "trio":
6567
await self._trio_lock.acquire()
66-
else:
68+
elif self._backend == "asyncio":
6769
await self._anyio_lock.acquire()
6870

6971
return self
@@ -76,7 +78,7 @@ async def __aexit__(
7678
) -> None:
7779
if self._backend == "trio":
7880
self._trio_lock.release()
79-
else:
81+
elif self._backend == "asyncio":
8082
self._anyio_lock.release()
8183

8284

@@ -91,16 +93,8 @@ def setup(self) -> None:
9193
"""
9294
self._backend = current_async_library()
9395
if self._backend == "trio":
94-
if trio is None: # pragma: nocover
95-
raise RuntimeError(
96-
"Running with trio requires installation of 'httpcore[trio]'."
97-
)
9896
self._trio_event = trio.Event()
99-
else:
100-
if anyio is None: # pragma: nocover
101-
raise RuntimeError(
102-
"Running with asyncio requires installation of 'httpcore[asyncio]'."
103-
)
97+
elif self._backend == "asyncio":
10498
self._anyio_event = anyio.Event()
10599

106100
def set(self) -> None:
@@ -109,30 +103,20 @@ def set(self) -> None:
109103

110104
if self._backend == "trio":
111105
self._trio_event.set()
112-
else:
106+
elif self._backend == "asyncio":
113107
self._anyio_event.set()
114108

115109
async def wait(self, timeout: Optional[float] = None) -> None:
116110
if not self._backend:
117111
self.setup()
118112

119113
if self._backend == "trio":
120-
if trio is None: # pragma: nocover
121-
raise RuntimeError(
122-
"Running with trio requires installation of 'httpcore[trio]'."
123-
)
124-
125114
trio_exc_map: ExceptionMapping = {trio.TooSlowError: PoolTimeout}
126115
timeout_or_inf = float("inf") if timeout is None else timeout
127116
with map_exceptions(trio_exc_map):
128117
with trio.fail_after(timeout_or_inf):
129118
await self._trio_event.wait()
130-
else:
131-
if anyio is None: # pragma: nocover
132-
raise RuntimeError(
133-
"Running with asyncio requires installation of 'httpcore[asyncio]'."
134-
)
135-
119+
elif self._backend == "asyncio":
136120
anyio_exc_map: ExceptionMapping = {TimeoutError: PoolTimeout}
137121
with map_exceptions(anyio_exc_map):
138122
with anyio.fail_after(timeout):
@@ -151,20 +135,10 @@ def setup(self) -> None:
151135
"""
152136
self._backend = current_async_library()
153137
if self._backend == "trio":
154-
if trio is None: # pragma: nocover
155-
raise RuntimeError(
156-
"Running with trio requires installation of 'httpcore[trio]'."
157-
)
158-
159138
self._trio_semaphore = trio.Semaphore(
160139
initial_value=self._bound, max_value=self._bound
161140
)
162-
else:
163-
if anyio is None: # pragma: nocover
164-
raise RuntimeError(
165-
"Running with asyncio requires installation of 'httpcore[asyncio]'."
166-
)
167-
141+
elif self._backend == "asyncio":
168142
self._anyio_semaphore = anyio.Semaphore(
169143
initial_value=self._bound, max_value=self._bound
170144
)
@@ -175,13 +149,13 @@ async def acquire(self) -> None:
175149

176150
if self._backend == "trio":
177151
await self._trio_semaphore.acquire()
178-
else:
152+
elif self._backend == "asyncio":
179153
await self._anyio_semaphore.acquire()
180154

181155
async def release(self) -> None:
182156
if self._backend == "trio":
183157
self._trio_semaphore.release()
184-
else:
158+
elif self._backend == "asyncio":
185159
self._anyio_semaphore.release()
186160

187161

@@ -201,24 +175,14 @@ def __init__(self) -> None:
201175
self._backend = current_async_library()
202176

203177
if self._backend == "trio":
204-
if trio is None: # pragma: nocover
205-
raise RuntimeError(
206-
"Running with trio requires installation of 'httpcore[trio]'."
207-
)
208-
209178
self._trio_shield = trio.CancelScope(shield=True)
210-
else:
211-
if anyio is None: # pragma: nocover
212-
raise RuntimeError(
213-
"Running with asyncio requires installation of 'httpcore[asyncio]'."
214-
)
215-
179+
elif self._backend == "asyncio":
216180
self._anyio_shield = anyio.CancelScope(shield=True)
217181

218182
def __enter__(self) -> "AsyncShieldCancellation":
219183
if self._backend == "trio":
220184
self._trio_shield.__enter__()
221-
else:
185+
elif self._backend == "asyncio":
222186
self._anyio_shield.__enter__()
223187
return self
224188

@@ -230,7 +194,7 @@ def __exit__(
230194
) -> None:
231195
if self._backend == "trio":
232196
self._trio_shield.__exit__(exc_type, exc_value, traceback)
233-
else:
197+
elif self._backend == "asyncio":
234198
self._anyio_shield.__exit__(exc_type, exc_value, traceback)
235199

236200

0 commit comments

Comments
 (0)