nextlayer-sdk-python 1.1.0__tar.gz → 1.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nextlayer-sdk-python
3
- Version: 1.1.0
3
+ Version: 1.2.1
4
4
  Summary: Client utilities to interact with next layer public APIs
5
5
  Author: Wolfgang Powisch
6
6
  Author-email: wolfgang.powisch@nextlayer.at
@@ -3,7 +3,7 @@ name = "nextlayer-sdk-python"
3
3
  packages = [
4
4
  { include = "nextlayer", from="src" }
5
5
  ]
6
- version = "v1.1.0"
6
+ version = "1.2.1"
7
7
  description = "Client utilities to interact with next layer public APIs"
8
8
  readme = "README.md"
9
9
  authors = ["Wolfgang Powisch <wolfgang.powisch@nextlayer.at>"]
@@ -1,2 +1,2 @@
1
1
  # do not edit this version line, it will be updated in CI-Pipeline!
2
- __version__ = "v1.1.0"
2
+ __version__ = "v1.2.1"
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env python3
2
+ import asyncio
2
3
  import datetime
3
4
  import getpass
4
5
  import json
@@ -160,6 +161,13 @@ class NlAuth(object):
160
161
  verify=True,
161
162
  )
162
163
 
164
+ # shared by NlHttpxAuth.async_auth_flow() so that multiple async Auth
165
+ # wrappers around the same NlAuth instance (e.g. one per API client,
166
+ # all backed by one shared NlAuth singleton) serialize their
167
+ # get_access_token() calls instead of racing concurrent
168
+ # do_refresh()/do_login() calls against Keycloak.
169
+ self.async_lock = asyncio.Lock()
170
+
163
171
  def token_expired(self) -> bool:
164
172
  now = int(time.time())
165
173
  exp_at = self.store.config.expires_at
@@ -0,0 +1,37 @@
1
+ import asyncio
2
+ from typing import AsyncGenerator, Generator
3
+
4
+ import httpx
5
+
6
+ from .auth import NlAuth
7
+
8
+
9
+ class NlHttpxAuth(httpx.Auth):
10
+ def __init__(self, *args, **kwargs):
11
+ if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], NlAuth):
12
+ # pass an existing NlAuth instance directly
13
+ self.nlauth = args[0]
14
+ else:
15
+ # pass all arguments to NlAuth constructor and create NlAuth instance internally
16
+ self.nlauth = NlAuth(*args, **kwargs)
17
+
18
+ def auth_flow(
19
+ self, request: httpx.Request
20
+ ) -> Generator[httpx.Request, httpx.Response, None]:
21
+ request.headers["Authorization"] = "Bearer " + self.nlauth.get_access_token()
22
+ yield request
23
+
24
+ async def async_auth_flow(
25
+ self, request: httpx.Request
26
+ ) -> AsyncGenerator[httpx.Request, httpx.Response]:
27
+ # NlAuth.get_access_token() does blocking file I/O and, on refresh/login,
28
+ # a blocking HTTP call to Keycloak - offload it so it doesn't stall the
29
+ # event loop. The lock lives on the NlAuth instance (not here) so that
30
+ # multiple NlHttpxAuth wrappers sharing one NlAuth (e.g. one per API
31
+ # client, backed by a shared NlAuth singleton) also share the lock -
32
+ # otherwise they could still race concurrent refresh/login calls
33
+ # against Keycloak, which the lock is meant to prevent.
34
+ async with self.nlauth.async_lock:
35
+ access_token = await asyncio.to_thread(self.nlauth.get_access_token)
36
+ request.headers["Authorization"] = "Bearer " + access_token
37
+ yield request
@@ -1,21 +0,0 @@
1
- from typing import Generator
2
-
3
- import httpx
4
-
5
- from .auth import NlAuth
6
-
7
-
8
- class NlHttpxAuth(httpx.Auth):
9
- def __init__(self, *args, **kwargs):
10
- if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], NlAuth):
11
- # pass an existing NlAuth instance directly
12
- self.nlauth = args[0]
13
- else:
14
- # pass all arguments to NlAuth constructor and create NlAuth instance internally
15
- self.nlauth = NlAuth(*args, **kwargs)
16
-
17
- def auth_flow(
18
- self, request: httpx.Request
19
- ) -> Generator[httpx.Request, httpx.Response, None]:
20
- request.headers["Authorization"] = "Bearer " + self.nlauth.get_access_token()
21
- yield request