diff --git a/httpcore/_async/connection_pool.py b/httpcore/_async/connection_pool.py index 96e973d0..5e49e2f5 100644 --- a/httpcore/_async/connection_pool.py +++ b/httpcore/_async/connection_pool.py @@ -9,7 +9,7 @@ from .._backends.base import SOCKET_OPTION, AsyncNetworkBackend from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol from .._models import Origin, Proxy, Request, Response -from .._synchronization import AsyncEvent, AsyncShieldCancellation, AsyncThreadLock +from .._synchronization import AsyncEvent, AsyncShieldCancellation, AsyncThreadRLock from .connection import AsyncHTTPConnection from .interfaces import AsyncConnectionInterface, AsyncRequestInterface @@ -123,7 +123,7 @@ def __init__( # We only mutate the state of the connection pool within an 'optional_thread_lock' # context. This holds a threading lock unless we're running in async mode, # in which case it is a no-op. - self._optional_thread_lock = AsyncThreadLock() + self._optional_thread_lock = AsyncThreadRLock() def create_connection(self, origin: Origin) -> AsyncConnectionInterface: if self._proxy is not None: diff --git a/httpcore/_sync/connection_pool.py b/httpcore/_sync/connection_pool.py index 9ccfa53e..a61493cf 100644 --- a/httpcore/_sync/connection_pool.py +++ b/httpcore/_sync/connection_pool.py @@ -9,7 +9,7 @@ from .._backends.base import SOCKET_OPTION, NetworkBackend from .._exceptions import ConnectionNotAvailable, UnsupportedProtocol from .._models import Origin, Proxy, Request, Response -from .._synchronization import Event, ShieldCancellation, ThreadLock +from .._synchronization import Event, ShieldCancellation, ThreadRLock from .connection import HTTPConnection from .interfaces import ConnectionInterface, RequestInterface @@ -123,7 +123,7 @@ def __init__( # We only mutate the state of the connection pool within an 'optional_thread_lock' # context. This holds a threading lock unless we're running in async mode, # in which case it is a no-op. - self._optional_thread_lock = ThreadLock() + self._optional_thread_lock = ThreadRLock() def create_connection(self, origin: Origin) -> ConnectionInterface: if self._proxy is not None: diff --git a/httpcore/_synchronization.py b/httpcore/_synchronization.py index 2ecc9e9c..0c3859e5 100644 --- a/httpcore/_synchronization.py +++ b/httpcore/_synchronization.py @@ -90,15 +90,16 @@ async def __aexit__( self._anyio_lock.release() -class AsyncThreadLock: +class AsyncThreadRLock: """ This is a threading-only lock for no-I/O contexts. + The lock type is a reentrant lock. - In the sync case `ThreadLock` provides thread locking. - In the async case `AsyncThreadLock` is a no-op. + In the sync case `ThreadRLock` provides thread locking. + In the async case `AsyncThreadRLock` is a no-op. """ - def __enter__(self) -> AsyncThreadLock: + def __enter__(self) -> AsyncThreadRLock: return self def __exit__( @@ -253,18 +254,19 @@ def __exit__( self._lock.release() -class ThreadLock: +class ThreadRLock: """ This is a threading-only lock for no-I/O contexts. + The lock type is a reentrant lock. - In the sync case `ThreadLock` provides thread locking. - In the async case `AsyncThreadLock` is a no-op. + In the sync case `ThreadRLock` provides thread locking. + In the async case `AsyncThreadRLock` is a no-op. """ def __init__(self) -> None: - self._lock = threading.Lock() + self._lock = threading.RLock() - def __enter__(self) -> ThreadLock: + def __enter__(self) -> ThreadRLock: self._lock.acquire() return self