aiohttp-msal 1.0.6__py3-none-any.whl → 1.0.7__py3-none-any.whl

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.
aiohttp_msal/__init__.py CHANGED
@@ -1,11 +1,10 @@
1
1
  """aiohttp_msal."""
2
2
 
3
- import json
4
3
  import logging
5
4
  from collections.abc import Awaitable, Callable
6
5
  from functools import wraps
7
6
  from inspect import getfullargspec, iscoroutinefunction
8
- from typing import Any, TypeVar, TypeVarTuple, cast
7
+ from typing import TypeVar, TypeVarTuple, cast
9
8
 
10
9
  from aiohttp import ClientSession, web
11
10
  from aiohttp_session import get_session
@@ -92,8 +91,6 @@ async def app_init_redis_session(
92
91
  app: web.Application,
93
92
  max_age: int = 3600 * 24 * 90,
94
93
  check_proxy_cb: Callable[[], Awaitable[None]] | None = None,
95
- encoder: Callable[[object], str] = json.dumps,
96
- decoder: Callable[[str], Any] = json.loads,
97
94
  ) -> None:
98
95
  """Init an aiohttp_session with Redis storage helper.
99
96
 
@@ -123,8 +120,8 @@ async def app_init_redis_session(
123
120
  secure=True,
124
121
  domain=ENV.DOMAIN,
125
122
  cookie_name=ENV.COOKIE_NAME,
126
- encoder=encoder,
127
- decoder=decoder,
123
+ encoder=ENV.dumps,
124
+ decoder=ENV.loads,
128
125
  )
129
126
  _setup(app, storage)
130
127
 
@@ -6,7 +6,6 @@ Once you have the OAuth tokens store in the session, you are free to make reques
6
6
  """
7
7
 
8
8
  import asyncio
9
- import json
10
9
  import logging
11
10
  from collections.abc import Callable
12
11
  from functools import cached_property, partialmethod
@@ -43,7 +42,7 @@ T = TypeVar("T")
43
42
 
44
43
  @attrs.define(slots=False)
45
44
  class AsyncMSAL:
46
- """AsycMSAL class.
45
+ """AsyncMSAL class.
47
46
 
48
47
  Authorization Code Flow Helper. Learn more about auth-code-flow at
49
48
  https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow
@@ -220,7 +219,7 @@ class AsyncMSAL:
220
219
  elif method in [HTTP_POST, HTTP_PUT, HTTP_PATCH]:
221
220
  headers["Content-type"] = "application/json"
222
221
  if "data" in kwargs:
223
- kwargs["data"] = json.dumps(kwargs["data"]) # auto convert to json
222
+ kwargs["data"] = ENV.dumps(kwargs["data"]) # auto convert to json
224
223
 
225
224
  if not AsyncMSAL.client_session:
226
225
  AsyncMSAL.client_session = ClientSession(trust_env=True)
@@ -1,7 +1,6 @@
1
1
  """Redis tools for sessions."""
2
2
 
3
3
  import asyncio
4
- import json
5
4
  import logging
6
5
  import time
7
6
  from collections.abc import AsyncGenerator
@@ -11,7 +10,7 @@ from typing import Any, TypeVar
11
10
  from redis.asyncio import Redis, from_url
12
11
 
13
12
  from aiohttp_msal.msal_async import AsyncMSAL
14
- from aiohttp_msal.settings import ENV as MENV
13
+ from aiohttp_msal.settings import ENV
15
14
 
16
15
  _LOG = logging.getLogger(__name__)
17
16
 
@@ -21,17 +20,17 @@ SES_KEYS = ("mail", "name", "m_mail", "m_name")
21
20
  @asynccontextmanager
22
21
  async def get_redis() -> AsyncGenerator[Redis, None]:
23
22
  """Get a Redis connection."""
24
- if MENV.database:
23
+ if ENV.database:
25
24
  _LOG.debug("Using redis from environment")
26
- yield MENV.database
25
+ yield ENV.database
27
26
  return
28
- _LOG.info("Connect to Redis %s", MENV.REDIS)
29
- redis = from_url(MENV.REDIS) # decode_responses=True not allowed aiohttp_session
30
- MENV.database = redis
27
+ _LOG.info("Connect to Redis %s", ENV.REDIS)
28
+ redis = from_url(ENV.REDIS) # decode_responses=True not allowed aiohttp_session
29
+ ENV.database = redis
31
30
  try:
32
31
  yield redis
33
32
  finally:
34
- MENV.database = None # type:ignore[assignment]
33
+ ENV.database = None # type:ignore[assignment]
35
34
  await redis.close()
36
35
 
37
36
 
@@ -50,14 +49,14 @@ async def session_iter(
50
49
  if match and not all(isinstance(v, str) for v in match.values()):
51
50
  raise ValueError("match values must be strings")
52
51
  async for key in redis.scan_iter(
53
- count=100, match=key_match or f"{MENV.COOKIE_NAME}*"
52
+ count=100, match=key_match or f"{ENV.COOKIE_NAME}*"
54
53
  ):
55
54
  if not isinstance(key, str):
56
55
  key = key.decode()
57
56
  sval = await redis.get(key)
58
57
  created, ses = 0, {}
59
58
  try:
60
- val = json.loads(sval) # type: ignore[arg-type]
59
+ val = ENV.loads(sval) # type: ignore[arg-type]
61
60
  created = int(val["created"])
62
61
  ses = val["session"]
63
62
  except Exception:
@@ -97,14 +96,14 @@ async def session_clean(
97
96
 
98
97
  async def invalid_sessions(redis: Redis, /) -> None:
99
98
  """Find & clean invalid sessions."""
100
- async for key in redis.scan_iter(count=100, match=f"{MENV.COOKIE_NAME}*"):
99
+ async for key in redis.scan_iter(count=100, match=f"{ENV.COOKIE_NAME}*"):
101
100
  if not isinstance(key, str):
102
101
  key = key.decode()
103
102
  sval = await redis.get(key)
104
103
  if sval is None:
105
104
  continue
106
105
  try:
107
- val: dict = json.loads(sval)
106
+ val: dict = ENV.loads(sval)
108
107
  assert isinstance(val["created"], int)
109
108
  assert isinstance(val["session"], dict)
110
109
  except Exception as err:
@@ -127,7 +126,7 @@ def async_msal_factory(
127
126
  async def async_save_cache(_: dict) -> None:
128
127
  """Save the token cache to Redis."""
129
128
  async with get_redis() as rd2:
130
- await rd2.set(key, json.dumps({"created": created, "session": session}))
129
+ await rd2.set(key, ENV.dumps({"created": created, "session": session}))
131
130
 
132
131
  def save_cache(*args: Any) -> None:
133
132
  """Save the token cache to Redis."""
@@ -163,11 +162,11 @@ async def get_session(
163
162
  raise ValueError(f"{msg} with scope {scope} not found ({cnt} checked)")
164
163
 
165
164
 
166
- async def redis_get_json(key: str) -> list[str] | dict[str, Any] | None:
165
+ async def redis_get_json(key: str) -> list[Any] | dict[str, Any] | None:
167
166
  """Get a key from redis."""
168
- res = await MENV.database.get(key)
167
+ res = await ENV.database.get(key)
169
168
  if isinstance(res, str | bytes | bytearray):
170
- return json.loads(res)
169
+ return ENV.loads(res)
171
170
  if res is not None:
172
171
  _LOG.warning("Unexpected type for %s: %s", key, type(res))
173
172
  return None
@@ -175,7 +174,7 @@ async def redis_get_json(key: str) -> list[str] | dict[str, Any] | None:
175
174
 
176
175
  async def redis_get(key: str) -> str | None:
177
176
  """Get a key from redis."""
178
- res = await MENV.database.get(key)
177
+ res = await ENV.database.get(key)
179
178
  if isinstance(res, str):
180
179
  return res
181
180
  if isinstance(res, bytes | bytearray):
@@ -189,22 +188,22 @@ async def redis_set_set(key: str, new_set: set[str]) -> None:
189
188
  """Set the value of a set in redis."""
190
189
  cur_set = set(
191
190
  s if isinstance(s, str) else s.decode()
192
- for s in await MENV.database.smembers(key)
191
+ for s in await ENV.database.smembers(key)
193
192
  )
194
193
  dif = list(cur_set - new_set)
195
194
  if dif:
196
195
  _LOG.warning("%s: removing %s", key, dif)
197
- await MENV.database.srem(key, *dif)
196
+ await ENV.database.srem(key, *dif)
198
197
 
199
198
  dif = list(new_set - cur_set)
200
199
  if dif:
201
200
  _LOG.info("%s: adding %s", key, dif)
202
- await MENV.database.sadd(key, *dif)
201
+ await ENV.database.sadd(key, *dif)
203
202
 
204
203
 
205
204
  async def redis_scan_keys(match_str: str) -> list[str]:
206
205
  """Return a list of matching keys."""
207
206
  return [
208
207
  s if isinstance(s, str) else s.decode()
209
- async for s in MENV.database.scan_iter(match=match_str)
208
+ async for s in ENV.database.scan_iter(match=match_str)
210
209
  ]
aiohttp_msal/settings.py CHANGED
@@ -1,5 +1,6 @@
1
1
  """Settings."""
2
2
 
3
+ import json
3
4
  from collections.abc import Awaitable, Callable
4
5
  from typing import TYPE_CHECKING, Any
5
6
 
@@ -39,8 +40,11 @@ class MSALSettings(SettingsBase):
39
40
 
40
41
  REDIS: str = "redis://redis1:6379"
41
42
  """OPTIONAL: Redis database connection used by app_init_redis_session()."""
42
- database: "Redis" = attrs.field(init=False)
43
+ database: "Redis" = attrs.field(init=False, default=None)
43
44
  """Store the Redis connection when using app_init_redis_session()."""
44
45
 
46
+ dumps: Callable[[Any], str] = attrs.field(default=json.dumps)
47
+ loads: Callable[[str | bytes | bytearray], Any] = attrs.field(default=json.loads)
48
+
45
49
 
46
50
  ENV = MSALSettings()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: aiohttp-msal
3
- Version: 1.0.6
3
+ Version: 1.0.7
4
4
  Summary: Helper Library to use the Microsoft Authentication Library (MSAL) with aiohttp
5
5
  Keywords: aiohttp,asyncio,msal,oauth
6
6
  Author: Johann Kellerman
@@ -0,0 +1,11 @@
1
+ aiohttp_msal/__init__.py,sha256=FTo4VtVno6TMEk9ZoE0tG7Apn6r-ZCa2qbAIs0cYD7U,4257
2
+ aiohttp_msal/helpers.py,sha256=L0DFIZD9OfCepckfk64ZtxrVX0-y0aAqRFowBYipepE,2474
3
+ aiohttp_msal/msal_async.py,sha256=UJgIjIie4gLpfsvDFd3iLp3-aauuOnNLlZPB1wF74Cs,11690
4
+ aiohttp_msal/redis_tools.py,sha256=4INqYzNyedXyVmrrFASGo_kCiZ9Pp-fbemkuDkfdcx0,6634
5
+ aiohttp_msal/routes.py,sha256=Cc6FHqs8dyHSTCC6AaT-yPttSDyBlsngoiz7j9QCKRU,5143
6
+ aiohttp_msal/settings.py,sha256=kQpWXMohpiWjejTnP7lvkjqUDpwd6O33K920UgQEFu0,1738
7
+ aiohttp_msal/settings_base.py,sha256=WBI7HS780i9zKWUy1ZnztDbRsfoDMVr3K-otHZOhNCc,3026
8
+ aiohttp_msal/utils.py,sha256=ll303J58nwCEB9QCAm13urUOa6cPqsAE7z_iP9OlRJw,2390
9
+ aiohttp_msal-1.0.7.dist-info/WHEEL,sha256=Jb20R3Ili4n9P1fcwuLup21eQ5r9WXhs4_qy7VTrgPI,79
10
+ aiohttp_msal-1.0.7.dist-info/METADATA,sha256=Q378idVSWz3aMHc14ebsok-F1RR70XA6bx0YsxmKv8U,4572
11
+ aiohttp_msal-1.0.7.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- aiohttp_msal/__init__.py,sha256=bCBQhbjM5IHKnHKzSDkHQ8Lk_YgW3flO11dgaDn8-Yg,4369
2
- aiohttp_msal/helpers.py,sha256=L0DFIZD9OfCepckfk64ZtxrVX0-y0aAqRFowBYipepE,2474
3
- aiohttp_msal/msal_async.py,sha256=VG5L6PGBHzRBNg_XfIqvfU1V-Snznv_Srd_kXzBgTts,11702
4
- aiohttp_msal/redis_tools.py,sha256=vAA3pvMT8jXd1sDL7wUZ8Z1FWO0xfHTWzi3_pnA_f8E,6672
5
- aiohttp_msal/routes.py,sha256=Cc6FHqs8dyHSTCC6AaT-yPttSDyBlsngoiz7j9QCKRU,5143
6
- aiohttp_msal/settings.py,sha256=sArlq9vBDMsikLf9sTRw-UXE2_QRK_G-kzmtHvZcbwA,1559
7
- aiohttp_msal/settings_base.py,sha256=WBI7HS780i9zKWUy1ZnztDbRsfoDMVr3K-otHZOhNCc,3026
8
- aiohttp_msal/utils.py,sha256=ll303J58nwCEB9QCAm13urUOa6cPqsAE7z_iP9OlRJw,2390
9
- aiohttp_msal-1.0.6.dist-info/WHEEL,sha256=Jb20R3Ili4n9P1fcwuLup21eQ5r9WXhs4_qy7VTrgPI,79
10
- aiohttp_msal-1.0.6.dist-info/METADATA,sha256=YvbKSl1STeQhHmyb9n9vKpsoHfalctOKStQIA_NZHNk,4572
11
- aiohttp_msal-1.0.6.dist-info/RECORD,,