@@ -67,7 +67,7 @@ def __init__(
6767
6868 self ._access_token : str | None = None
6969 self ._expires_at : float | None = None
70- self ._lock = asyncio .Lock ()
70+ self ._lock : asyncio .Lock | None = None
7171
7272 def _determine_auth_endpoint (
7373 self ,
@@ -97,6 +97,23 @@ def _determine_auth_endpoint(
9797
9898 return VERSION_ENDPOINTS [version ]
9999
100+ @property
101+ def lock (self ) -> asyncio .Lock :
102+ """Lazy initialization of the asyncio.Lock.
103+
104+ The lock must be created lazily to support Python 3.9, where
105+ asyncio.Lock() requires an event loop to exist. By creating it
106+ on first access (which happens in an async context), we ensure
107+ an event loop is available.
108+
109+ Returns:
110+ The asyncio.Lock instance.
111+
112+ """
113+ if self ._lock is None :
114+ self ._lock = asyncio .Lock ()
115+ return self ._lock
116+
100117 async def get_token (self ) -> str :
101118 """Get a valid OAuth2 access token, refreshing if necessary.
102119
@@ -115,7 +132,7 @@ async def get_token(self) -> str:
115132 return self ._access_token
116133
117134 # Need to refresh - use lock to prevent concurrent refreshes
118- async with self ._lock :
135+ async with self .lock :
119136 # Double-check after acquiring lock
120137 if self .is_token_valid ():
121138 if self ._access_token is None :
@@ -191,6 +208,10 @@ async def refresh_token(self) -> str:
191208 msg = f"OAuth2 token request failed: { exc } "
192209 raise AuthenticationError (msg ) from exc
193210
211+ # At this point, self._access_token is guaranteed to be a string
212+ if self ._access_token is None :
213+ msg = "Token should be set at this point"
214+ raise AuthenticationError (msg )
194215 return self ._access_token
195216
196217 def clear_token (self ) -> None :
0 commit comments