pattern-agentic-messaging 0.9.0__tar.gz → 0.9.2__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.
Files changed (20) hide show
  1. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/CHANGELOG.md +4 -0
  2. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/PKG-INFO +1 -1
  3. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/pyproject.toml +1 -1
  4. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/src/pattern_agentic_messaging/app.py +21 -38
  5. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/src/pattern_agentic_messaging/session.py +12 -16
  6. pattern_agentic_messaging-0.9.2/src/pattern_agentic_messaging/utils.py +9 -0
  7. pattern_agentic_messaging-0.9.0/uv.lock +0 -132
  8. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/.claude/settings.local.json +0 -0
  9. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/.gitignore +0 -0
  10. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/LICENSE.md +0 -0
  11. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/README.md +0 -0
  12. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/src/pattern_agentic_messaging/__init__.py +0 -0
  13. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/src/pattern_agentic_messaging/auth.py +0 -0
  14. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/src/pattern_agentic_messaging/config.py +0 -0
  15. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/src/pattern_agentic_messaging/exceptions.py +0 -0
  16. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/src/pattern_agentic_messaging/messages.py +0 -0
  17. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/src/pattern_agentic_messaging/messaging.py +0 -0
  18. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/src/pattern_agentic_messaging/types.py +0 -0
  19. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/tests/test_config.py +0 -0
  20. {pattern_agentic_messaging-0.9.0 → pattern_agentic_messaging-0.9.2}/tests/test_messages.py +0 -0
@@ -1,5 +1,9 @@
1
1
 
2
2
 
3
+ ## v0.9.1
4
+
5
+ - improved logging for exceptions in on_connect
6
+
3
7
  ## v0.9.0
4
8
 
5
9
  - upgraded slim-bindings to 0.7.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pattern_agentic_messaging
3
- Version: 0.9.0
3
+ Version: 0.9.2
4
4
  Summary: SLIM-powered messaging
5
5
  Author-email: Amos Joshua <amos@patternagentic.ai>
6
6
  License-File: LICENSE.md
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pattern_agentic_messaging"
7
- version = "0.9.0"
7
+ version = "0.9.2"
8
8
  description = "SLIM-powered messaging"
9
9
  authors = [
10
10
  { name="Amos Joshua", email="amos@patternagentic.ai" }
@@ -1,5 +1,5 @@
1
1
  import asyncio
2
- import inspect
2
+ import logging
3
3
  import slim_bindings
4
4
  from typing import AsyncIterator, Optional, Literal, get_type_hints, get_origin, get_args
5
5
  from .config import PASlimConfig
@@ -7,6 +7,9 @@ from .session import PASlimSession, PASlimP2PSession, PASlimGroupSession
7
7
  from .auth import create_shared_secret_auth
8
8
  from .types import MessagePayload
9
9
  from .exceptions import AuthenticationError
10
+ from .utils import parse_name
11
+
12
+ logger = logging.getLogger(__name__)
10
13
 
11
14
  try:
12
15
  from pydantic import BaseModel, ValidationError
@@ -44,6 +47,7 @@ def _get_pydantic_model_from_handler(func) -> Optional[type]:
44
47
  pass
45
48
  return None
46
49
 
50
+
47
51
  class PASlimApp:
48
52
  def __init__(self, config: PASlimConfig):
49
53
  self.config = config
@@ -64,14 +68,7 @@ class PASlimApp:
64
68
  self.config.auth_secret
65
69
  )
66
70
 
67
- parts = self.config.local_name.split('/')
68
- if len(parts) == 3:
69
- local_name = slim_bindings.Name(*parts)
70
- elif len(parts) == 4:
71
- local_name = slim_bindings.Name(parts[0], parts[1], parts[2])
72
- else:
73
- raise ValueError(f"local_name must be org/namespace/app or org/namespace/app/instance")
74
-
71
+ local_name = parse_name(self.config.local_name)
75
72
  self._app = slim_bindings.Slim(local_name, auth_provider, auth_verifier)
76
73
 
77
74
  slim_config = {"endpoint": self.config.endpoint}
@@ -242,8 +239,6 @@ class PASlimApp:
242
239
 
243
240
  async def _run_async(self):
244
241
  """Internal async runner for the decorator pattern."""
245
- import logging
246
-
247
242
  if not self._message_handlers:
248
243
  raise ValueError("No message handlers registered. Use @app.on_message decorator.")
249
244
 
@@ -254,7 +249,6 @@ class PASlimApp:
254
249
  catch_all_info = handler_info
255
250
  break
256
251
 
257
- logger = logging.getLogger(__name__)
258
252
  disc_field = self.config.message_discriminator
259
253
 
260
254
  async with self:
@@ -284,7 +278,8 @@ class PASlimApp:
284
278
  try:
285
279
  await handler(session, parsed)
286
280
  except Exception as exc:
287
- logger.error(f"Error in message handler: {exc}", exc_info=True)
281
+ model_name = model.__name__ if model else "untyped"
282
+ logger.error(f"Error in handler '{handler.__name__}' for message type '{model_name}': {exc}", exc_info=True)
288
283
  break
289
284
  except ValidationError as e:
290
285
  matched = True
@@ -301,7 +296,7 @@ class PASlimApp:
301
296
  try:
302
297
  await handler(session, msg)
303
298
  except Exception as exc:
304
- logger.error(f"Error in message handler: {exc}", exc_info=True)
299
+ logger.error(f"Error in handler '{handler.__name__}' for discriminator {disc}={val}: {exc}", exc_info=True)
305
300
  break
306
301
 
307
302
  # Fall back to catch-all if no specific handler matched
@@ -320,7 +315,7 @@ class PASlimApp:
320
315
  "details": e.errors()
321
316
  })
322
317
  except Exception as exc:
323
- logger.error(f"Error in catch-all handler: {exc}", exc_info=True)
318
+ logger.error(f"Error in fallback message handler '{handler.__name__}': {exc}", exc_info=True)
324
319
  elif not matched:
325
320
  logger.warning(f"No handler for message: {msg}")
326
321
 
@@ -334,12 +329,7 @@ class PASlimApp:
334
329
  Returns:
335
330
  PASlimP2PSession for communicating with the peer
336
331
  """
337
- parts = peer_name.split('/')
338
- if len(parts) >= 3:
339
- peer = slim_bindings.Name(parts[0], parts[1], parts[2])
340
- else:
341
- raise ValueError(f"peer_name must be org/namespace/app or org/namespace/app/instance")
342
-
332
+ peer = parse_name(peer_name)
343
333
  await self._app.set_route(peer)
344
334
 
345
335
  session_config = slim_bindings.SessionConfiguration.PointToPoint(
@@ -375,12 +365,7 @@ class PASlimApp:
375
365
  if invites is None:
376
366
  invites = []
377
367
 
378
- parts = channel_name.split('/')
379
- if len(parts) >= 3:
380
- channel = slim_bindings.Name(parts[0], parts[1], parts[2])
381
- else:
382
- raise ValueError(f"channel_name must be org/namespace/channel")
383
-
368
+ channel = parse_name(channel_name)
384
369
  session_config = slim_bindings.SessionConfiguration.Group(
385
370
  max_retries=self.config.max_retries,
386
371
  timeout=self.config.timeout,
@@ -391,11 +376,7 @@ class PASlimApp:
391
376
  session = PASlimGroupSession(slim_session)
392
377
 
393
378
  for invite in invites:
394
- parts = invite.split('/')
395
- if len(parts) >= 3:
396
- participant = slim_bindings.Name(parts[0], parts[1], parts[2])
397
- else:
398
- raise ValueError(f"invite name must be org/namespace/app")
379
+ participant = parse_name(invite)
399
380
  await self._app.set_route(participant)
400
381
  await session.invite(invite)
401
382
 
@@ -448,21 +429,23 @@ class PASlimApp:
448
429
  if self._session_connect_handler:
449
430
  try:
450
431
  await self._session_connect_handler(session)
451
- except Exception:
452
- pass # Don't let handler errors prevent session
432
+ except Exception as e:
433
+ logger.error(f"Error in session connect handler: {e}", exc_info=True)
453
434
 
454
435
  async with session:
455
436
  async for msg in session:
456
437
  await message_queue.put((session, msg))
457
- except Exception:
458
- pass # Session ended or errored - normal behavior
438
+ except (StopAsyncIteration, asyncio.CancelledError):
439
+ pass
440
+ except Exception as e:
441
+ logger.error(f"Session reader error: {e}", exc_info=True)
459
442
  finally:
460
443
  # Call session disconnect handler if registered
461
444
  if self._session_disconnect_handler:
462
445
  try:
463
446
  await self._session_disconnect_handler(session)
464
- except Exception:
465
- pass # Don't let handler errors prevent cleanup
447
+ except Exception as e:
448
+ logger.error(f"Error in session disconnect handler: {e}", exc_info=True)
466
449
 
467
450
  async def session_listener():
468
451
  """Listen for new sessions and spawn reader tasks."""
@@ -1,10 +1,14 @@
1
1
  import asyncio
2
+ import logging
2
3
  import uuid
3
4
  from typing import Optional, Callable, Any, Dict
4
5
  from datetime import timedelta
5
6
  from .types import MessagePayload
6
7
  from .messages import encode_message, decode_message
7
8
  from .exceptions import SessionClosedError, TimeoutError as PATimeoutError
9
+ from .utils import parse_name
10
+
11
+ logger = logging.getLogger(__name__)
8
12
 
9
13
  class PASlimSession:
10
14
  def __init__(self, slim_session):
@@ -40,13 +44,15 @@ class PASlimSession:
40
44
  await callback(decoded)
41
45
  else:
42
46
  callback(decoded)
43
- except Exception:
44
- pass
47
+ except Exception as e:
48
+ callback_name = getattr(callback, '__name__', repr(callback))
49
+ logger.error(f"Error in callback '{callback_name}': {e}", exc_info=True)
45
50
 
46
51
  await self._queue.put((msg_ctx, decoded))
47
- except Exception:
52
+ except Exception as e:
48
53
  if not self._closed:
49
- break
54
+ logger.error(f"Read loop error: {e}", exc_info=True)
55
+ break
50
56
 
51
57
  async def __aenter__(self):
52
58
  self._read_task = asyncio.create_task(self._read_loop())
@@ -116,21 +122,11 @@ class PASlimP2PSession(PASlimSession):
116
122
 
117
123
  class PASlimGroupSession(PASlimSession):
118
124
  async def invite(self, participant_name: str):
119
- import slim_bindings
120
- parts = participant_name.split('/')
121
- if len(parts) >= 3:
122
- name = slim_bindings.Name(parts[0], parts[1], parts[2])
123
- else:
124
- raise ValueError(f"participant_name must be org/namespace/app")
125
+ name = parse_name(participant_name)
125
126
  handle = await self._session.invite(name)
126
127
  await handle
127
128
 
128
129
  async def remove(self, participant_name: str):
129
- import slim_bindings
130
- parts = participant_name.split('/')
131
- if len(parts) >= 3:
132
- name = slim_bindings.Name(parts[0], parts[1], parts[2])
133
- else:
134
- raise ValueError(f"participant_name must be org/namespace/app")
130
+ name = parse_name(participant_name)
135
131
  handle = await self._session.remove(name)
136
132
  await handle
@@ -0,0 +1,9 @@
1
+ import slim_bindings
2
+
3
+
4
+ def parse_name(name_str: str) -> slim_bindings.Name:
5
+ """Parse 'org/namespace/app' string into slim_bindings.Name."""
6
+ parts = name_str.split('/')
7
+ if len(parts) >= 3:
8
+ return slim_bindings.Name(parts[0], parts[1], parts[2])
9
+ raise ValueError(f"Name must be org/namespace/app format, got: {name_str}")
@@ -1,132 +0,0 @@
1
- version = 1
2
- revision = 3
3
- requires-python = ">=3.11"
4
-
5
- [[package]]
6
- name = "colorama"
7
- version = "0.4.6"
8
- source = { registry = "https://pypi.org/simple" }
9
- sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
10
- wheels = [
11
- { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
12
- ]
13
-
14
- [[package]]
15
- name = "iniconfig"
16
- version = "2.3.0"
17
- source = { registry = "https://pypi.org/simple" }
18
- sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
19
- wheels = [
20
- { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
21
- ]
22
-
23
- [[package]]
24
- name = "packaging"
25
- version = "25.0"
26
- source = { registry = "https://pypi.org/simple" }
27
- sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
28
- wheels = [
29
- { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
30
- ]
31
-
32
- [[package]]
33
- name = "pattern-agentic-messaging"
34
- version = "0.8.0"
35
- source = { editable = "." }
36
- dependencies = [
37
- { name = "slim-bindings" },
38
- ]
39
-
40
- [package.dev-dependencies]
41
- dev = [
42
- { name = "pytest" },
43
- { name = "pytest-asyncio" },
44
- ]
45
-
46
- [package.metadata]
47
- requires-dist = [{ name = "slim-bindings", specifier = ">=0.6.3" }]
48
-
49
- [package.metadata.requires-dev]
50
- dev = [
51
- { name = "pytest", specifier = ">=9.0.1" },
52
- { name = "pytest-asyncio", specifier = ">=0.21.1" },
53
- ]
54
-
55
- [[package]]
56
- name = "pluggy"
57
- version = "1.6.0"
58
- source = { registry = "https://pypi.org/simple" }
59
- sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
60
- wheels = [
61
- { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
62
- ]
63
-
64
- [[package]]
65
- name = "pygments"
66
- version = "2.19.2"
67
- source = { registry = "https://pypi.org/simple" }
68
- sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" }
69
- wheels = [
70
- { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" },
71
- ]
72
-
73
- [[package]]
74
- name = "pytest"
75
- version = "9.0.1"
76
- source = { registry = "https://pypi.org/simple" }
77
- dependencies = [
78
- { name = "colorama", marker = "sys_platform == 'win32'" },
79
- { name = "iniconfig" },
80
- { name = "packaging" },
81
- { name = "pluggy" },
82
- { name = "pygments" },
83
- ]
84
- sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" }
85
- wheels = [
86
- { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" },
87
- ]
88
-
89
- [[package]]
90
- name = "pytest-asyncio"
91
- version = "1.3.0"
92
- source = { registry = "https://pypi.org/simple" }
93
- dependencies = [
94
- { name = "pytest" },
95
- { name = "typing-extensions", marker = "python_full_version < '3.13'" },
96
- ]
97
- sdist = { url = "https://files.pythonhosted.org/packages/90/2c/8af215c0f776415f3590cac4f9086ccefd6fd463befeae41cd4d3f193e5a/pytest_asyncio-1.3.0.tar.gz", hash = "sha256:d7f52f36d231b80ee124cd216ffb19369aa168fc10095013c6b014a34d3ee9e5", size = 50087, upload-time = "2025-11-10T16:07:47.256Z" }
98
- wheels = [
99
- { url = "https://files.pythonhosted.org/packages/e5/35/f8b19922b6a25bc0880171a2f1a003eaeb93657475193ab516fd87cac9da/pytest_asyncio-1.3.0-py3-none-any.whl", hash = "sha256:611e26147c7f77640e6d0a92a38ed17c3e9848063698d5c93d5aa7aa11cebff5", size = 15075, upload-time = "2025-11-10T16:07:45.537Z" },
100
- ]
101
-
102
- [[package]]
103
- name = "slim-bindings"
104
- version = "0.6.3"
105
- source = { registry = "https://pypi.org/simple" }
106
- sdist = { url = "https://files.pythonhosted.org/packages/9b/09/0b33770d5389000151c032d96b61c6957ad90331179ad02601c57e8686c8/slim_bindings-0.6.3.tar.gz", hash = "sha256:bd9e272640527c7ef51e90e69c4268cd5712fa65b2fe1d9deb4f7de29122916e", size = 394752, upload-time = "2025-10-31T16:16:32.75Z" }
107
- wheels = [
108
- { url = "https://files.pythonhosted.org/packages/72/ed/9ace6f64460dd8d381b4ff7ce58fc063853c6a7571d598f26db70b901585/slim_bindings-0.6.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:01d04a307c8befdd6667262f74c85e1f8e69c36187f5772ed6822718d3b6a647", size = 8242169, upload-time = "2025-10-31T16:15:45.396Z" },
109
- { url = "https://files.pythonhosted.org/packages/60/cb/52bee40860d13dcc158b8e98c099768276383b94450404948459d49a36ee/slim_bindings-0.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cbd3d21bb140ce6837a99145ab4c4336efed658e624bec8710471c237ed082dd", size = 7912501, upload-time = "2025-10-31T16:15:47.598Z" },
110
- { url = "https://files.pythonhosted.org/packages/dc/23/8dfa1489fef922ded4d9855ecb8caca7f1e17041a690055b3bab15b8cb09/slim_bindings-0.6.3-cp311-cp311-manylinux_2_34_aarch64.whl", hash = "sha256:89e026a28a84318dc3cb1e7526d81915ad069e9d89a35e462d9e466b92170008", size = 8744989, upload-time = "2025-10-31T16:15:49.686Z" },
111
- { url = "https://files.pythonhosted.org/packages/4a/cf/5d5a27c10b0a4c04e05fa5a6a19f4cf663a3b4e90fc506e078b1358977a1/slim_bindings-0.6.3-cp311-cp311-manylinux_2_34_x86_64.whl", hash = "sha256:50c0d8427f99a558b0ff980f19a17390876076119f12c91d3e23cd0e4bca7c55", size = 8882953, upload-time = "2025-10-31T16:15:51.524Z" },
112
- { url = "https://files.pythonhosted.org/packages/f5/43/517f2144a9fc5d248571d14ff81f93f3a9a15de2362058c5471c77bca41a/slim_bindings-0.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:72281ef20250d3ba85af547888f5c1f9831a422a5ede1bb7c878d3b2b537d2fd", size = 7292432, upload-time = "2025-10-31T16:15:53.787Z" },
113
- { url = "https://files.pythonhosted.org/packages/05/62/74ca0c91c3379bc8e072ffec8ee012105f3e47bc5c84549cac346c83760b/slim_bindings-0.6.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a8af60585e2488434a50a8dfc46a0f7e32a858925cd6eb25329248b6d3c02fe5", size = 8237044, upload-time = "2025-10-31T16:16:01.952Z" },
114
- { url = "https://files.pythonhosted.org/packages/20/64/b9264200cd5bfbaa5077953fc406232fd8bc9e26aa3bc8bf5dd96de6e6fa/slim_bindings-0.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d7eaeb154294744ae0c087d1bda235f6794bb351108448a38bf5ffe18d5f8fd0", size = 7905819, upload-time = "2025-10-31T16:16:04.911Z" },
115
- { url = "https://files.pythonhosted.org/packages/ce/6b/e701bc4a44e9ba5292557baee205d453890ab989225c9842b05b3440ddf8/slim_bindings-0.6.3-cp312-cp312-manylinux_2_34_aarch64.whl", hash = "sha256:dac66eb1d6e619d8dba7d8ea75781883457a40cc85159eaac4401d044c9934d2", size = 8756849, upload-time = "2025-10-31T16:16:07.403Z" },
116
- { url = "https://files.pythonhosted.org/packages/05/2a/6197e2cfb9c2ff55ade9ef1a545cb006171296e474ccfc52e909cf8055ca/slim_bindings-0.6.3-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:bd7ee891a08da0dd1c96c8fa825ae60eab99356c052870cbd490f52bef0147ac", size = 8891589, upload-time = "2025-10-31T16:16:09.139Z" },
117
- { url = "https://files.pythonhosted.org/packages/0e/32/e1dbb223a7ed65c6e28fe714f888dff725a16a42eecdde993999d281665a/slim_bindings-0.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:1e3cde1d33db1e3bace6c5b80d79f3031f9a8cce0896495873a481b80372882c", size = 7302666, upload-time = "2025-10-31T16:16:10.812Z" },
118
- { url = "https://files.pythonhosted.org/packages/f0/f5/69737a3d263396a18eb84a70483f924f3356be3f81b6660710e84e2ae04d/slim_bindings-0.6.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e24a2ff9ef307790ec114f4bfa158c49dfe0c988ec70c1fe315b4733c672cf69", size = 8237490, upload-time = "2025-10-31T16:16:12.433Z" },
119
- { url = "https://files.pythonhosted.org/packages/31/ff/cab83e16d0595c6ff3a0bbc3e42eaf69a328b183dc5197a150c599c25468/slim_bindings-0.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b55894c30ea608d44eaa5f008ccd016428e2fbdf3b161b073889cd9dbc9c12d5", size = 7906161, upload-time = "2025-10-31T16:16:14.002Z" },
120
- { url = "https://files.pythonhosted.org/packages/6e/16/2cbdedab433e9349ef58263db5843e864554de4d203b993ebe1930d7ce44/slim_bindings-0.6.3-cp313-cp313-manylinux_2_34_aarch64.whl", hash = "sha256:d73069dfdbff0ac0e651ba9b5b76cb6932e633d652467bec66e8e22ec79a7228", size = 8756685, upload-time = "2025-10-31T16:16:15.72Z" },
121
- { url = "https://files.pythonhosted.org/packages/aa/ef/bc746c42162f8611309dab09c11f3d5d063a2f664c27826c8775e6503d5a/slim_bindings-0.6.3-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:27c6bd7b18128eb449d01c92ac0f2c5c28dde83c8173c6cb55950fe921834790", size = 8891357, upload-time = "2025-10-31T16:16:17.517Z" },
122
- { url = "https://files.pythonhosted.org/packages/62/4c/3d2a141c56440b5c065106cf6a57f44f22ed8543dba35d06c766c8ff01a2/slim_bindings-0.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:0e928d4cac235f942794ebace44245de4384c3fe9fc74f4889846964707ebc90", size = 7302378, upload-time = "2025-10-31T16:16:20.009Z" },
123
- ]
124
-
125
- [[package]]
126
- name = "typing-extensions"
127
- version = "4.15.0"
128
- source = { registry = "https://pypi.org/simple" }
129
- sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
130
- wheels = [
131
- { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
132
- ]