python-arango-async 0.0.1__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,379 @@
1
+ from typing import Optional
2
+
3
+ from arangoasync.request import Request
4
+ from arangoasync.response import Response
5
+
6
+
7
+ class ArangoError(Exception):
8
+ """Base class for all exceptions in python-arango-async."""
9
+
10
+
11
+ class ArangoClientError(ArangoError):
12
+ """Base class for all client-related exceptions.
13
+
14
+ Args:
15
+ msg (str): Error message.
16
+
17
+ Attributes:
18
+ source (str): Source of the error (always set to "client")
19
+ message (str): Error message.
20
+ """
21
+
22
+ source = "client"
23
+
24
+ def __init__(self, msg: str) -> None:
25
+ super().__init__(msg)
26
+ self.message = msg
27
+
28
+
29
+ class ArangoServerError(ArangoError):
30
+ """Base class for all server-related exceptions.
31
+
32
+ Args:
33
+ resp (Response): HTTP response object.
34
+ request (Request): HTTP request object.
35
+ msg (str | None): Error message.
36
+
37
+ Attributes:
38
+ source (str): Source of the error (always set to "server")
39
+ message (str): Error message.
40
+ url (str): URL of the request.
41
+ response (Response): HTTP response object.
42
+ request (Request): HTTP request object.
43
+ http_method (str): HTTP method of the request.
44
+ http_code (int): HTTP status code of the response.
45
+ http_headers (dict): HTTP headers of the response.
46
+ """
47
+
48
+ source = "server"
49
+
50
+ def __init__(
51
+ self, resp: Response, request: Request, msg: Optional[str] = None
52
+ ) -> None:
53
+ if msg is None:
54
+ msg = resp.error_message or resp.status_text
55
+ else:
56
+ msg = f"{msg} ({resp.error_message or resp.status_text})"
57
+ self.error_message = resp.error_message
58
+ self.error_code = resp.error_code
59
+ if self.error_code is not None:
60
+ msg = f"[HTTP {resp.status_code}][ERR {self.error_code}] {msg}"
61
+ else:
62
+ msg = f"[HTTP {resp.status_code}] {msg}"
63
+ self.error_code = resp.status_code
64
+ super().__init__(msg)
65
+ self.message = msg
66
+ self.url = resp.url
67
+ self.response = resp
68
+ self.request = request
69
+ self.http_method = resp.method.name
70
+ self.http_code = resp.status_code
71
+ self.http_headers = resp.headers
72
+
73
+
74
+ class AQLCacheClearError(ArangoServerError):
75
+ """Failed to clear the query cache."""
76
+
77
+
78
+ class AQLCacheConfigureError(ArangoServerError):
79
+ """Failed to configure query cache properties."""
80
+
81
+
82
+ class AQLCacheEntriesError(ArangoServerError):
83
+ """Failed to retrieve AQL cache entries."""
84
+
85
+
86
+ class AQLCachePropertiesError(ArangoServerError):
87
+ """Failed to retrieve query cache properties."""
88
+
89
+
90
+ class AQLFunctionCreateError(ArangoServerError):
91
+ """Failed to create AQL user function."""
92
+
93
+
94
+ class AQLFunctionDeleteError(ArangoServerError):
95
+ """Failed to delete AQL user function."""
96
+
97
+
98
+ class AQLFunctionListError(ArangoServerError):
99
+ """Failed to retrieve AQL user functions."""
100
+
101
+
102
+ class AQLQueryClearError(ArangoServerError):
103
+ """Failed to clear slow AQL queries."""
104
+
105
+
106
+ class AQLQueryExecuteError(ArangoServerError):
107
+ """Failed to execute query."""
108
+
109
+
110
+ class AQLQueryExplainError(ArangoServerError):
111
+ """Failed to parse and explain query."""
112
+
113
+
114
+ class AQLQueryKillError(ArangoServerError):
115
+ """Failed to kill the query."""
116
+
117
+
118
+ class AQLQueryListError(ArangoServerError):
119
+ """Failed to retrieve running AQL queries."""
120
+
121
+
122
+ class AQLQueryRulesGetError(ArangoServerError):
123
+ """Failed to retrieve AQL query rules."""
124
+
125
+
126
+ class AQLQueryTrackingGetError(ArangoServerError):
127
+ """Failed to retrieve AQL tracking properties."""
128
+
129
+
130
+ class AQLQueryTrackingSetError(ArangoServerError):
131
+ """Failed to configure AQL tracking properties."""
132
+
133
+
134
+ class AQLQueryValidateError(ArangoServerError):
135
+ """Failed to parse and validate query."""
136
+
137
+
138
+ class AsyncExecuteError(ArangoServerError):
139
+ """Failed to execute async API request."""
140
+
141
+
142
+ class AsyncJobCancelError(ArangoServerError):
143
+ """Failed to cancel async job."""
144
+
145
+
146
+ class AsyncJobClearError(ArangoServerError):
147
+ """Failed to clear async job results."""
148
+
149
+
150
+ class AsyncJobListError(ArangoServerError):
151
+ """Failed to retrieve async jobs."""
152
+
153
+
154
+ class AsyncJobResultError(ArangoServerError):
155
+ """Failed to retrieve async job result."""
156
+
157
+
158
+ class AsyncJobStatusError(ArangoServerError):
159
+ """Failed to retrieve async job status."""
160
+
161
+
162
+ class AuthHeaderError(ArangoClientError):
163
+ """The authentication header could not be determined."""
164
+
165
+
166
+ class CollectionCreateError(ArangoServerError):
167
+ """Failed to create collection."""
168
+
169
+
170
+ class CollectionDeleteError(ArangoServerError):
171
+ """Failed to delete collection."""
172
+
173
+
174
+ class CollectionListError(ArangoServerError):
175
+ """Failed to retrieve collections."""
176
+
177
+
178
+ class CollectionPropertiesError(ArangoServerError):
179
+ """Failed to retrieve collection properties."""
180
+
181
+
182
+ class ClientConnectionAbortedError(ArangoClientError):
183
+ """The connection was aborted."""
184
+
185
+
186
+ class ClientConnectionError(ArangoClientError):
187
+ """The request was unable to reach the server."""
188
+
189
+
190
+ class CollectionTruncateError(ArangoServerError):
191
+ """Failed to truncate collection."""
192
+
193
+
194
+ class CursorCloseError(ArangoServerError):
195
+ """Failed to delete the cursor result from server."""
196
+
197
+
198
+ class CursorCountError(ArangoClientError, TypeError):
199
+ """The cursor count was not enabled."""
200
+
201
+
202
+ class CursorEmptyError(ArangoClientError):
203
+ """The current batch in cursor was empty."""
204
+
205
+
206
+ class CursorNextError(ArangoServerError):
207
+ """Failed to retrieve the next result batch from server."""
208
+
209
+
210
+ class CursorStateError(ArangoClientError):
211
+ """The cursor object was in a bad state."""
212
+
213
+
214
+ class DatabaseCreateError(ArangoServerError):
215
+ """Failed to create database."""
216
+
217
+
218
+ class DatabaseDeleteError(ArangoServerError):
219
+ """Failed to delete database."""
220
+
221
+
222
+ class DatabaseListError(ArangoServerError):
223
+ """Failed to retrieve databases."""
224
+
225
+
226
+ class DatabasePropertiesError(ArangoServerError):
227
+ """Failed to retrieve database properties."""
228
+
229
+
230
+ class DeserializationError(ArangoClientError):
231
+ """Failed to deserialize the server response."""
232
+
233
+
234
+ class DocumentCountError(ArangoServerError):
235
+ """Failed to retrieve document count."""
236
+
237
+
238
+ class DocumentDeleteError(ArangoServerError):
239
+ """Failed to delete document."""
240
+
241
+
242
+ class DocumentGetError(ArangoServerError):
243
+ """Failed to retrieve document."""
244
+
245
+
246
+ class DocumentInsertError(ArangoServerError):
247
+ """Failed to insert document."""
248
+
249
+
250
+ class DocumentParseError(ArangoClientError):
251
+ """Failed to parse document input."""
252
+
253
+
254
+ class DocumentReplaceError(ArangoServerError):
255
+ """Failed to replace document."""
256
+
257
+
258
+ class DocumentRevisionError(ArangoServerError):
259
+ """The expected and actual document revisions mismatched."""
260
+
261
+
262
+ class DocumentUpdateError(ArangoServerError):
263
+ """Failed to update document."""
264
+
265
+
266
+ class IndexCreateError(ArangoServerError):
267
+ """Failed to create collection index."""
268
+
269
+
270
+ class IndexDeleteError(ArangoServerError):
271
+ """Failed to delete collection index."""
272
+
273
+
274
+ class IndexGetError(ArangoServerError):
275
+ """Failed to retrieve collection index."""
276
+
277
+
278
+ class IndexListError(ArangoServerError):
279
+ """Failed to retrieve collection indexes."""
280
+
281
+
282
+ class IndexLoadError(ArangoServerError):
283
+ """Failed to load indexes into memory."""
284
+
285
+
286
+ class JWTRefreshError(ArangoClientError):
287
+ """Failed to refresh the JWT token."""
288
+
289
+
290
+ class JWTSecretListError(ArangoServerError):
291
+ """Failed to retrieve information on currently loaded JWT secrets."""
292
+
293
+
294
+ class JWTSecretReloadError(ArangoServerError):
295
+ """Failed to reload JWT secrets."""
296
+
297
+
298
+ class PermissionGetError(ArangoServerError):
299
+ """Failed to retrieve user permission."""
300
+
301
+
302
+ class PermissionListError(ArangoServerError):
303
+ """Failed to list user permissions."""
304
+
305
+
306
+ class PermissionResetError(ArangoServerError):
307
+ """Failed to reset user permission."""
308
+
309
+
310
+ class PermissionUpdateError(ArangoServerError):
311
+ """Failed to update user permission."""
312
+
313
+
314
+ class SerializationError(ArangoClientError):
315
+ """Failed to serialize the request."""
316
+
317
+
318
+ class ServerConnectionError(ArangoServerError):
319
+ """Failed to connect to ArangoDB server."""
320
+
321
+
322
+ class ServerStatusError(ArangoServerError):
323
+ """Failed to retrieve server status."""
324
+
325
+
326
+ class ServerVersionError(ArangoServerError):
327
+ """Failed to retrieve server version."""
328
+
329
+
330
+ class SortValidationError(ArangoClientError):
331
+ """Invalid sort parameters."""
332
+
333
+
334
+ class TransactionAbortError(ArangoServerError):
335
+ """Failed to abort transaction."""
336
+
337
+
338
+ class TransactionCommitError(ArangoServerError):
339
+ """Failed to commit transaction."""
340
+
341
+
342
+ class TransactionExecuteError(ArangoServerError):
343
+ """Failed to execute JavaScript transaction."""
344
+
345
+
346
+ class TransactionInitError(ArangoServerError):
347
+ """Failed to initialize transaction."""
348
+
349
+
350
+ class TransactionListError(ArangoServerError):
351
+ """Failed to retrieve transactions."""
352
+
353
+
354
+ class TransactionStatusError(ArangoServerError):
355
+ """Failed to retrieve transaction status."""
356
+
357
+
358
+ class UserCreateError(ArangoServerError):
359
+ """Failed to create user."""
360
+
361
+
362
+ class UserDeleteError(ArangoServerError):
363
+ """Failed to delete user."""
364
+
365
+
366
+ class UserGetError(ArangoServerError):
367
+ """Failed to retrieve user details."""
368
+
369
+
370
+ class UserListError(ArangoServerError):
371
+ """Failed to retrieve users."""
372
+
373
+
374
+ class UserReplaceError(ArangoServerError):
375
+ """Failed to replace user."""
376
+
377
+
378
+ class UserUpdateError(ArangoServerError):
379
+ """Failed to update user."""
@@ -0,0 +1,168 @@
1
+ __all__ = [
2
+ "ApiExecutor",
3
+ "DefaultApiExecutor",
4
+ "NonAsyncExecutor",
5
+ "TransactionApiExecutor",
6
+ "AsyncApiExecutor",
7
+ ]
8
+
9
+ from typing import Callable, Optional, TypeVar
10
+
11
+ from arangoasync.connection import Connection
12
+ from arangoasync.exceptions import AsyncExecuteError
13
+ from arangoasync.job import AsyncJob
14
+ from arangoasync.request import Request
15
+ from arangoasync.response import Response
16
+ from arangoasync.serialization import Deserializer, Serializer
17
+ from arangoasync.typings import Json, Jsons
18
+
19
+ T = TypeVar("T")
20
+
21
+
22
+ class ExecutorContext:
23
+ """Base class for API executors.
24
+
25
+ Not to be exported publicly.
26
+
27
+ Args:
28
+ connection: HTTP connection.
29
+ """
30
+
31
+ def __init__(self, connection: Connection) -> None:
32
+ self._conn = connection
33
+
34
+ @property
35
+ def connection(self) -> Connection:
36
+ return self._conn
37
+
38
+ @property
39
+ def db_name(self) -> str:
40
+ return self._conn.db_name
41
+
42
+ @property
43
+ def serializer(self) -> Serializer[Json]:
44
+ return self._conn.serializer
45
+
46
+ @property
47
+ def deserializer(self) -> Deserializer[Json, Jsons]:
48
+ return self._conn.deserializer
49
+
50
+ def serialize(self, data: Json) -> str:
51
+ return self.serializer.dumps(data)
52
+
53
+ def deserialize(self, data: bytes) -> Json:
54
+ return self.deserializer.loads(data)
55
+
56
+
57
+ class DefaultApiExecutor(ExecutorContext):
58
+ """Default API executor.
59
+
60
+ Responsible for executing requests and handling responses.
61
+
62
+ Args:
63
+ connection: HTTP connection.
64
+ """
65
+
66
+ def __init__(self, connection: Connection) -> None:
67
+ super().__init__(connection)
68
+
69
+ @property
70
+ def context(self) -> str:
71
+ return "default"
72
+
73
+ async def execute(
74
+ self, request: Request, response_handler: Callable[[Response], T]
75
+ ) -> T:
76
+ """Execute the request and handle the response.
77
+
78
+ Args:
79
+ request: HTTP request.
80
+ response_handler: HTTP response handler.
81
+ """
82
+ response = await self._conn.send_request(request)
83
+ return response_handler(response)
84
+
85
+
86
+ class TransactionApiExecutor(ExecutorContext):
87
+ """Executes transaction API requests.
88
+
89
+ Args:
90
+ connection: HTTP connection.
91
+ transaction_id: str: Transaction ID generated by the server.
92
+ """
93
+
94
+ def __init__(self, connection: Connection, transaction_id: str) -> None:
95
+ super().__init__(connection)
96
+ self._id = transaction_id
97
+
98
+ @property
99
+ def context(self) -> str:
100
+ return "transaction"
101
+
102
+ @property
103
+ def id(self) -> str:
104
+ """Return the transaction ID."""
105
+ return self._id
106
+
107
+ async def execute(
108
+ self, request: Request, response_handler: Callable[[Response], T]
109
+ ) -> T:
110
+ """Execute the request and handle the response.
111
+
112
+ Args:
113
+ request: HTTP request.
114
+ response_handler: HTTP response handler.
115
+ """
116
+ request.headers["x-arango-trx-id"] = self.id
117
+ response = await self._conn.send_request(request)
118
+ return response_handler(response)
119
+
120
+
121
+ class AsyncApiExecutor(ExecutorContext):
122
+ """Executes asynchronous API requests (jobs).
123
+
124
+ Args:
125
+ connection: HTTP connection.
126
+ return_result: If set to `True`, API executions return instances of
127
+ :class:`arangoasync.job.AsyncJob` and results can be retrieved from server
128
+ once available. If set to `False`, API executions return `None` and no
129
+ results are stored on server.
130
+ """
131
+
132
+ def __init__(self, connection: Connection, return_result: bool) -> None:
133
+ super().__init__(connection)
134
+ self._return_result = return_result
135
+
136
+ @property
137
+ def context(self) -> str:
138
+ return "async"
139
+
140
+ async def execute(
141
+ self, request: Request, response_handler: Callable[[Response], T]
142
+ ) -> Optional[AsyncJob[T]]:
143
+ """Execute an API request asynchronously.
144
+
145
+ Args:
146
+ request: HTTP request.
147
+ response_handler: HTTP response handler.
148
+
149
+ Returns: `AsyncJob` job or `None` if **return_result** parameter was set to
150
+ `False` during initialization.
151
+ """
152
+ if self._return_result:
153
+ request.headers["x-arango-async"] = "store"
154
+ else:
155
+ request.headers["x-arango-async"] = "true"
156
+
157
+ response = await self._conn.send_request(request)
158
+ if not response.is_success:
159
+ raise AsyncExecuteError(response, request)
160
+ if not self._return_result:
161
+ return None
162
+
163
+ job_id = response.headers["x-arango-async-id"]
164
+ return AsyncJob(self._conn, job_id, response_handler)
165
+
166
+
167
+ ApiExecutor = DefaultApiExecutor | TransactionApiExecutor | AsyncApiExecutor
168
+ NonAsyncExecutor = DefaultApiExecutor | TransactionApiExecutor