pynamodb-async 0.1.0__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.
@@ -0,0 +1,21 @@
1
+ # AUTO-GENERATED from pynamodb/asyncio/__init__.py by scripts/make_addon.py - DO NOT EDIT
2
+ """
3
+ Async API for PynamoDB, built on aiobotocore.
4
+
5
+ Install with ``pip install pynamodb-async`` (Python 3.10+). Usage mirrors the
6
+ sync API: ``from pynamodb_async.models import Model``.
7
+ """
8
+ import sys
9
+
10
+ if sys.version_info < (3, 10): # pragma: no cover
11
+ raise ImportError("pynamodb_async requires Python 3.10+; install pynamodb-async")
12
+ try:
13
+ import aiobotocore # noqa: F401
14
+ except ImportError as e:
15
+ raise ImportError(
16
+ "pynamodb_async requires aiobotocore; install pynamodb-async (Python 3.10+)"
17
+ ) from e
18
+
19
+ from pynamodb_async.connection.base import connections # noqa: E402
20
+
21
+ __all__ = ['connections']
@@ -0,0 +1,198 @@
1
+ # AUTO-GENERATED from pynamodb/asyncio/_compat.py by scripts/make_addon.py - DO NOT EDIT
2
+ """
3
+ Async halves of operations that differ between the sync and async APIs.
4
+
5
+ Helpers for operations whose synchronous and asynchronous forms cannot be derived
6
+ from one another by rewriting keywords (sleeping, gathering, list building). This is
7
+ the only module in this package allowed to import asyncio.
8
+
9
+ `alist` is async-only: the generator rewrites `_compat.alist(` to `list(`.
10
+ """
11
+ import asyncio
12
+ import time
13
+ import weakref
14
+ from typing import Any, AsyncIterable, Dict, Hashable, List, TypeVar
15
+
16
+ from aiobotocore.config import AioConfig
17
+
18
+ from pynamodb.constants import SERVICE_NAME
19
+
20
+
21
+ class _AsyncTime:
22
+ """Default clock for RateLimiter: real time, non-blocking sleep."""
23
+
24
+ time = staticmethod(time.time)
25
+
26
+ @staticmethod
27
+ async def sleep(seconds: float) -> None:
28
+ await asyncio.sleep(seconds)
29
+
30
+
31
+ TIME_MODULE: Any = _AsyncTime()
32
+
33
+
34
+ _T = TypeVar('_T')
35
+
36
+
37
+ async def alist(iterable: AsyncIterable[_T]) -> List[_T]:
38
+ """Collects an async iterable; the generator rewrites `await alist(x)` to `list(x)`."""
39
+ return [item async for item in iterable]
40
+
41
+
42
+ async def sleep(seconds: float) -> None:
43
+ await asyncio.sleep(seconds)
44
+
45
+
46
+ def _has_credentials(client: Any) -> bool:
47
+ signer = client._request_signer
48
+ return not (signer and not signer._credentials)
49
+
50
+
51
+ def client_usable(connection: Any) -> bool:
52
+ client = connection._client
53
+ if not client or not _has_credentials(client):
54
+ return False
55
+ try:
56
+ loop = asyncio.get_running_loop()
57
+ except RuntimeError:
58
+ return False
59
+ # aiobotocore clients only work on the loop that created them.
60
+ return _held_loop(connection) is loop
61
+
62
+
63
+ class _Entry:
64
+ __slots__ = ('client', 'refs')
65
+
66
+ def __init__(self, client: Any) -> None:
67
+ self.client = client
68
+ self.refs = 0
69
+
70
+
71
+ # event loop -> {Connection._client_key() -> shared client}. Weak on the loop,
72
+ # but a client that has made a request holds an aiohttp session, which holds
73
+ # the loop, so a finished loop's entry would keep itself alive. open_client
74
+ # therefore prunes entries for closed loops (see _prune_closed_loops).
75
+ _clients: "weakref.WeakKeyDictionary[asyncio.AbstractEventLoop, Dict[Hashable, _Entry]]" = weakref.WeakKeyDictionary()
76
+
77
+
78
+ def _prune_closed_loops() -> None:
79
+ """Drops cache entries of closed loops; their clients cannot be closed any more."""
80
+ for loop in [loop for loop in list(_clients.keys()) if loop.is_closed()]:
81
+ _clients.pop(loop, None)
82
+
83
+
84
+ def _held_loop(connection: Any) -> Any:
85
+ ref = getattr(connection, '_client_loop', None)
86
+ return ref() if ref is not None else None
87
+
88
+
89
+ def _held_entry(connection: Any, loop: Any) -> Any:
90
+ """The usable entry this connection already holds on `loop`, if any."""
91
+ entry = getattr(connection, '_client_entry', None)
92
+ if entry is not None and _held_loop(connection) is loop and _has_credentials(entry.client):
93
+ return entry
94
+ return None
95
+
96
+
97
+ def _make_header_hook(headers: Any) -> Any:
98
+ # Closes over a copy of the headers, not the connection: the client lives in
99
+ # a shared cache and must not keep a connection (and so its loop) alive.
100
+ headers = dict(headers) if headers else None
101
+
102
+ def _before_send(request: Any, **_: Any) -> None:
103
+ if headers:
104
+ request.headers.update(headers)
105
+
106
+ return _before_send
107
+
108
+
109
+ async def open_client(connection: Any, config: Any) -> Any:
110
+ loop = asyncio.get_running_loop()
111
+ held = _held_entry(connection, loop)
112
+ if held is not None:
113
+ return held.client
114
+ _prune_closed_loops()
115
+ per_loop = _clients.setdefault(loop, {})
116
+ key = connection._client_key()
117
+ entry = per_loop.get(key)
118
+ if entry is None or not _has_credentials(entry.client):
119
+ # A poisoned entry is replaced in the cache; connections still holding
120
+ # it release it when they notice (client_usable) or close.
121
+ client = await connection.session.create_client(
122
+ SERVICE_NAME, connection.region, endpoint_url=connection.host, config=AioConfig().merge(config),
123
+ ).__aenter__()
124
+ # Another coroutine may have opened a client while we were suspended.
125
+ held = _held_entry(connection, loop)
126
+ existing = per_loop.get(key)
127
+ if held is not None:
128
+ await client.__aexit__(None, None, None)
129
+ return held.client
130
+ if existing is not None and _has_credentials(existing.client):
131
+ # Take the reference before suspending to close the extra client;
132
+ # otherwise the last other holder could release (and close) the
133
+ # existing one meanwhile, leaving this connection on a closed client.
134
+ _hold(connection, existing, loop)
135
+ await client.__aexit__(None, None, None)
136
+ return existing.client
137
+ # extra_headers is part of the key, so every holder sends the same headers.
138
+ client.meta.events.register_first('before-send.*.*', _make_header_hook(connection._extra_headers))
139
+ entry = _Entry(client)
140
+ per_loop[key] = entry
141
+ _hold(connection, entry, loop)
142
+ return entry.client
143
+
144
+
145
+ def _hold(connection: Any, entry: _Entry, loop: Any) -> None:
146
+ entry.refs += 1
147
+ connection._client_entry = entry
148
+ connection._client_loop = weakref.ref(loop)
149
+
150
+
151
+ async def _release(connection: Any) -> None:
152
+ entry = getattr(connection, '_client_entry', None)
153
+ loop = _held_loop(connection)
154
+ connection._client_entry = None
155
+ connection._client_loop = None
156
+ connection._client = None
157
+ if entry is None:
158
+ return
159
+ entry.refs -= 1
160
+ if entry.refs > 0:
161
+ return
162
+ per_loop = _clients.get(loop) if loop is not None else None
163
+ if per_loop is not None:
164
+ for key, value in list(per_loop.items()):
165
+ if value is entry:
166
+ del per_loop[key]
167
+ try:
168
+ running = asyncio.get_running_loop()
169
+ except RuntimeError:
170
+ running = None
171
+ if running is not None and running is loop:
172
+ await entry.client.__aexit__(None, None, None)
173
+ # Otherwise the owning loop is gone or different; its sockets cannot be
174
+ # closed from here, so the client is dropped.
175
+
176
+
177
+ async def replace_client(connection: Any) -> None:
178
+ await _release(connection)
179
+
180
+
181
+ async def close_client(connection: Any) -> None:
182
+ await _release(connection)
183
+
184
+
185
+ def client_property(connection: Any) -> Any:
186
+ if connection._client is None:
187
+ raise RuntimeError(
188
+ "The async client is not open yet; use `await connection.get_client()` "
189
+ "(any awaited operation opens it)"
190
+ )
191
+ return connection._client
192
+
193
+
194
+ def connection_repr(connection: Any) -> str:
195
+ # repr must never raise, so it cannot go through the (not yet open) client.
196
+ if connection._client is not None:
197
+ return "Connection<{}>".format(connection._client.meta.endpoint_url)
198
+ return "Connection<{}>".format(connection.host or connection.region)
@@ -0,0 +1,24 @@
1
+ # file generated by vcs-versioning
2
+ # don't change, don't track in version control
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
13
+
14
+ version: str
15
+ __version__: str
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '0.1.0'
22
+ __version_tuple__ = version_tuple = (0, 1, 0)
23
+
24
+ __commit_id__ = commit_id = None
@@ -0,0 +1,13 @@
1
+ # AUTO-GENERATED from pynamodb/asyncio/connection/__init__.py by scripts/make_addon.py - DO NOT EDIT
2
+ """
3
+ PynamoDB lowest level connection
4
+ """
5
+
6
+ from pynamodb_async.connection.base import Connection
7
+ from pynamodb_async.connection.table import TableConnection
8
+
9
+
10
+ __all__ = [
11
+ "Connection",
12
+ "TableConnection",
13
+ ]
@@ -0,0 +1,30 @@
1
+ # AUTO-GENERATED from pynamodb/asyncio/connection/_botocore_private.py by scripts/make_addon.py - DO NOT EDIT
2
+ """
3
+ Type-annotates the private aiobotocore APIs that we're currently relying on.
4
+ """
5
+ from typing import Dict
6
+
7
+ import botocore.credentials
8
+ import botocore.endpoint
9
+ import botocore.hooks
10
+ import botocore.signers
11
+ from aiobotocore.client import AioBaseClient
12
+
13
+
14
+ class BotocoreEndpointPrivate(botocore.endpoint.Endpoint):
15
+ _event_emitter: botocore.hooks.HierarchicalEmitter
16
+
17
+
18
+ class BotocoreRequestSignerPrivate(botocore.signers.RequestSigner):
19
+ _credentials: botocore.credentials.Credentials
20
+
21
+
22
+ class BotocoreBaseClientPrivate(AioBaseClient):
23
+ _endpoint: BotocoreEndpointPrivate
24
+ _request_signer: BotocoreRequestSignerPrivate
25
+
26
+ async def _make_api_call( self,
27
+ operation_name: str,
28
+ operation_kwargs: Dict,
29
+ ) -> Dict:
30
+ raise NotImplementedError