python-arango 7.7.0__tar.gz → 7.8.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.
Files changed (91) hide show
  1. {python-arango-7.7.0 → python-arango-7.8.1}/PKG-INFO +1 -1
  2. {python-arango-7.7.0 → python-arango-7.8.1}/arango/client.py +21 -1
  3. {python-arango-7.7.0 → python-arango-7.8.1}/arango/connection.py +78 -20
  4. {python-arango-7.7.0 → python-arango-7.8.1}/arango/exceptions.py +8 -0
  5. {python-arango-7.7.0 → python-arango-7.8.1}/arango/graph.py +2 -2
  6. {python-arango-7.7.0 → python-arango-7.8.1}/arango/utils.py +1 -1
  7. python-arango-7.8.1/arango/version.py +16 -0
  8. {python-arango-7.7.0 → python-arango-7.8.1}/docs/auth.rst +27 -1
  9. {python-arango-7.7.0 → python-arango-7.8.1}/python_arango.egg-info/PKG-INFO +1 -1
  10. python-arango-7.7.0/arango/version.py +0 -8
  11. {python-arango-7.7.0 → python-arango-7.8.1}/.github/workflows/build.yaml +0 -0
  12. {python-arango-7.7.0 → python-arango-7.8.1}/.github/workflows/codeql.yaml +0 -0
  13. {python-arango-7.7.0 → python-arango-7.8.1}/.github/workflows/pypi.yaml +0 -0
  14. {python-arango-7.7.0 → python-arango-7.8.1}/.gitignore +0 -0
  15. {python-arango-7.7.0 → python-arango-7.8.1}/.pre-commit-config.yaml +0 -0
  16. {python-arango-7.7.0 → python-arango-7.8.1}/.readthedocs.yaml +0 -0
  17. {python-arango-7.7.0 → python-arango-7.8.1}/CONTRIBUTING.md +0 -0
  18. {python-arango-7.7.0 → python-arango-7.8.1}/LICENSE +0 -0
  19. {python-arango-7.7.0 → python-arango-7.8.1}/MANIFEST.in +0 -0
  20. {python-arango-7.7.0 → python-arango-7.8.1}/README.md +0 -0
  21. {python-arango-7.7.0 → python-arango-7.8.1}/arango/__init__.py +0 -0
  22. {python-arango-7.7.0 → python-arango-7.8.1}/arango/api.py +0 -0
  23. {python-arango-7.7.0 → python-arango-7.8.1}/arango/aql.py +0 -0
  24. {python-arango-7.7.0 → python-arango-7.8.1}/arango/backup.py +0 -0
  25. {python-arango-7.7.0 → python-arango-7.8.1}/arango/cluster.py +0 -0
  26. {python-arango-7.7.0 → python-arango-7.8.1}/arango/collection.py +0 -0
  27. {python-arango-7.7.0 → python-arango-7.8.1}/arango/cursor.py +0 -0
  28. {python-arango-7.7.0 → python-arango-7.8.1}/arango/database.py +0 -0
  29. {python-arango-7.7.0 → python-arango-7.8.1}/arango/errno.py +0 -0
  30. {python-arango-7.7.0 → python-arango-7.8.1}/arango/executor.py +0 -0
  31. {python-arango-7.7.0 → python-arango-7.8.1}/arango/formatter.py +0 -0
  32. {python-arango-7.7.0 → python-arango-7.8.1}/arango/foxx.py +0 -0
  33. {python-arango-7.7.0 → python-arango-7.8.1}/arango/http.py +0 -0
  34. {python-arango-7.7.0 → python-arango-7.8.1}/arango/job.py +0 -0
  35. {python-arango-7.7.0 → python-arango-7.8.1}/arango/pregel.py +0 -0
  36. {python-arango-7.7.0 → python-arango-7.8.1}/arango/py.typed +0 -0
  37. {python-arango-7.7.0 → python-arango-7.8.1}/arango/replication.py +0 -0
  38. {python-arango-7.7.0 → python-arango-7.8.1}/arango/request.py +0 -0
  39. {python-arango-7.7.0 → python-arango-7.8.1}/arango/resolver.py +0 -0
  40. {python-arango-7.7.0 → python-arango-7.8.1}/arango/response.py +0 -0
  41. {python-arango-7.7.0 → python-arango-7.8.1}/arango/result.py +0 -0
  42. {python-arango-7.7.0 → python-arango-7.8.1}/arango/typings.py +0 -0
  43. {python-arango-7.7.0 → python-arango-7.8.1}/arango/wal.py +0 -0
  44. {python-arango-7.7.0 → python-arango-7.8.1}/docs/Makefile +0 -0
  45. {python-arango-7.7.0 → python-arango-7.8.1}/docs/admin.rst +0 -0
  46. {python-arango-7.7.0 → python-arango-7.8.1}/docs/analyzer.rst +0 -0
  47. {python-arango-7.7.0 → python-arango-7.8.1}/docs/aql.rst +0 -0
  48. {python-arango-7.7.0 → python-arango-7.8.1}/docs/async.rst +0 -0
  49. {python-arango-7.7.0 → python-arango-7.8.1}/docs/backup.rst +0 -0
  50. {python-arango-7.7.0 → python-arango-7.8.1}/docs/batch.rst +0 -0
  51. {python-arango-7.7.0 → python-arango-7.8.1}/docs/certificates.rst +0 -0
  52. {python-arango-7.7.0 → python-arango-7.8.1}/docs/cluster.rst +0 -0
  53. {python-arango-7.7.0 → python-arango-7.8.1}/docs/collection.rst +0 -0
  54. {python-arango-7.7.0 → python-arango-7.8.1}/docs/conf.py +0 -0
  55. {python-arango-7.7.0 → python-arango-7.8.1}/docs/contributing.rst +0 -0
  56. {python-arango-7.7.0 → python-arango-7.8.1}/docs/cursor.rst +0 -0
  57. {python-arango-7.7.0 → python-arango-7.8.1}/docs/database.rst +0 -0
  58. {python-arango-7.7.0 → python-arango-7.8.1}/docs/document.rst +0 -0
  59. {python-arango-7.7.0 → python-arango-7.8.1}/docs/errno.rst +0 -0
  60. {python-arango-7.7.0 → python-arango-7.8.1}/docs/errors.rst +0 -0
  61. {python-arango-7.7.0 → python-arango-7.8.1}/docs/foxx.rst +0 -0
  62. {python-arango-7.7.0 → python-arango-7.8.1}/docs/graph.rst +0 -0
  63. {python-arango-7.7.0 → python-arango-7.8.1}/docs/http.rst +0 -0
  64. {python-arango-7.7.0 → python-arango-7.8.1}/docs/index.rst +0 -0
  65. {python-arango-7.7.0 → python-arango-7.8.1}/docs/indexes.rst +0 -0
  66. {python-arango-7.7.0 → python-arango-7.8.1}/docs/logging.rst +0 -0
  67. {python-arango-7.7.0 → python-arango-7.8.1}/docs/make.bat +0 -0
  68. {python-arango-7.7.0 → python-arango-7.8.1}/docs/overload.rst +0 -0
  69. {python-arango-7.7.0 → python-arango-7.8.1}/docs/overview.rst +0 -0
  70. {python-arango-7.7.0 → python-arango-7.8.1}/docs/pregel.rst +0 -0
  71. {python-arango-7.7.0 → python-arango-7.8.1}/docs/replication.rst +0 -0
  72. {python-arango-7.7.0 → python-arango-7.8.1}/docs/requirements.txt +0 -0
  73. {python-arango-7.7.0 → python-arango-7.8.1}/docs/schema.rst +0 -0
  74. {python-arango-7.7.0 → python-arango-7.8.1}/docs/serializer.rst +0 -0
  75. {python-arango-7.7.0 → python-arango-7.8.1}/docs/simple.rst +0 -0
  76. {python-arango-7.7.0 → python-arango-7.8.1}/docs/specs.rst +0 -0
  77. {python-arango-7.7.0 → python-arango-7.8.1}/docs/static/logo.png +0 -0
  78. {python-arango-7.7.0 → python-arango-7.8.1}/docs/task.rst +0 -0
  79. {python-arango-7.7.0 → python-arango-7.8.1}/docs/threading.rst +0 -0
  80. {python-arango-7.7.0 → python-arango-7.8.1}/docs/transaction.rst +0 -0
  81. {python-arango-7.7.0 → python-arango-7.8.1}/docs/user.rst +0 -0
  82. {python-arango-7.7.0 → python-arango-7.8.1}/docs/view.rst +0 -0
  83. {python-arango-7.7.0 → python-arango-7.8.1}/docs/wal.rst +0 -0
  84. {python-arango-7.7.0 → python-arango-7.8.1}/pyproject.toml +0 -0
  85. {python-arango-7.7.0 → python-arango-7.8.1}/python_arango.egg-info/SOURCES.txt +0 -0
  86. {python-arango-7.7.0 → python-arango-7.8.1}/python_arango.egg-info/dependency_links.txt +0 -0
  87. {python-arango-7.7.0 → python-arango-7.8.1}/python_arango.egg-info/requires.txt +0 -0
  88. {python-arango-7.7.0 → python-arango-7.8.1}/python_arango.egg-info/top_level.txt +0 -0
  89. {python-arango-7.7.0 → python-arango-7.8.1}/setup.cfg +0 -0
  90. {python-arango-7.7.0 → python-arango-7.8.1}/setup.py +0 -0
  91. {python-arango-7.7.0 → python-arango-7.8.1}/tester.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-arango
3
- Version: 7.7.0
3
+ Version: 7.8.1
4
4
  Summary: Python Driver for ArangoDB
5
5
  Home-page: https://github.com/ArangoDB-Community/python-arango
6
6
  Author: Joohwan Oh
@@ -171,6 +171,7 @@ class ArangoClient:
171
171
  password: str = "",
172
172
  verify: bool = False,
173
173
  auth_method: str = "basic",
174
+ user_token: Optional[str] = None,
174
175
  superuser_token: Optional[str] = None,
175
176
  verify_certificate: bool = True,
176
177
  ) -> StandardDatabase:
@@ -189,9 +190,17 @@ class ArangoClient:
189
190
  refreshed automatically using ArangoDB username and password. This
190
191
  assumes that the clocks of the server and client are synchronized.
191
192
  :type auth_method: str
193
+ :param user_token: User generated token for user access.
194
+ If set, parameters **username**, **password** and **auth_method**
195
+ are ignored. This token is not refreshed automatically. If automatic
196
+ token refresh is required, consider setting **auth_method** to "jwt"
197
+ and using the **username** and **password** parameters instead. Token
198
+ expiry will be checked.
199
+ :type user_token: str
192
200
  :param superuser_token: User generated token for superuser access.
193
201
  If set, parameters **username**, **password** and **auth_method**
194
- are ignored. This token is not refreshed automatically.
202
+ are ignored. This token is not refreshed automatically. Token
203
+ expiry will not be checked.
195
204
  :type superuser_token: str
196
205
  :param verify_certificate: Verify TLS certificates.
197
206
  :type verify_certificate: bool
@@ -213,6 +222,17 @@ class ArangoClient:
213
222
  deserializer=self._deserializer,
214
223
  superuser_token=superuser_token,
215
224
  )
225
+ elif user_token is not None:
226
+ connection = JwtConnection(
227
+ hosts=self._hosts,
228
+ host_resolver=self._host_resolver,
229
+ sessions=self._sessions,
230
+ db_name=name,
231
+ http_client=self._http,
232
+ serializer=self._serializer,
233
+ deserializer=self._deserializer,
234
+ user_token=user_token,
235
+ )
216
236
  elif auth_method.lower() == "basic":
217
237
  connection = BasicConnection(
218
238
  hosts=self._hosts,
@@ -13,10 +13,16 @@ from abc import abstractmethod
13
13
  from typing import Any, Callable, Optional, Sequence, Set, Tuple, Union
14
14
 
15
15
  import jwt
16
+ from jwt.exceptions import ExpiredSignatureError
16
17
  from requests import ConnectionError, Session
17
18
  from requests_toolbelt import MultipartEncoder
18
19
 
19
- from arango.exceptions import JWTAuthError, ServerConnectionError
20
+ from arango.exceptions import (
21
+ JWTAuthError,
22
+ JWTExpiredError,
23
+ JWTRefreshError,
24
+ ServerConnectionError,
25
+ )
20
26
  from arango.http import HTTPClient
21
27
  from arango.request import Request
22
28
  from arango.resolver import HostResolver
@@ -203,7 +209,7 @@ class BaseConnection:
203
209
  request = Request(method="get", endpoint="/_api/collection")
204
210
  resp = self.send_request(request)
205
211
  if resp.status_code in {401, 403}:
206
- raise ServerConnectionError("bad username and/or password")
212
+ raise ServerConnectionError("bad username/password or token is expired")
207
213
  if not resp.is_success: # pragma: no cover
208
214
  raise ServerConnectionError(resp.error_message or "bad server response")
209
215
  return resp.status_code
@@ -300,11 +306,12 @@ class JwtConnection(BaseConnection):
300
306
  host_resolver: HostResolver,
301
307
  sessions: Sequence[Session],
302
308
  db_name: str,
303
- username: str,
304
- password: str,
305
309
  http_client: HTTPClient,
306
310
  serializer: Callable[..., str],
307
311
  deserializer: Callable[[str], Any],
312
+ username: Optional[str] = None,
313
+ password: Optional[str] = None,
314
+ user_token: Optional[str] = None,
308
315
  ) -> None:
309
316
  super().__init__(
310
317
  hosts,
@@ -323,7 +330,13 @@ class JwtConnection(BaseConnection):
323
330
  self._token: Optional[str] = None
324
331
  self._token_exp: int = sys.maxsize
325
332
 
326
- self.refresh_token()
333
+ if user_token is not None:
334
+ self.set_token(user_token)
335
+ elif username is not None and password is not None:
336
+ self.refresh_token()
337
+ else:
338
+ m = "Either **user_token** or **username** & **password** must be set"
339
+ raise ValueError(m)
327
340
 
328
341
  def send_request(self, request: Request) -> Response:
329
342
  """Send an HTTP request to ArangoDB server.
@@ -360,7 +373,12 @@ class JwtConnection(BaseConnection):
360
373
 
361
374
  :return: JWT token.
362
375
  :rtype: str
376
+ :raise arango.exceptions.JWTRefreshError: If missing username & password.
377
+ :raise arango.exceptions.JWTAuthError: If token retrieval fails.
363
378
  """
379
+ if self._username is None or self._password is None:
380
+ raise JWTRefreshError("username and password must be set")
381
+
364
382
  request = Request(
365
383
  method="post",
366
384
  endpoint="/_open/auth",
@@ -374,21 +392,34 @@ class JwtConnection(BaseConnection):
374
392
  if not resp.is_success:
375
393
  raise JWTAuthError(resp, request)
376
394
 
377
- self._token = resp.body["jwt"]
378
- assert self._token is not None
379
-
380
- jwt_payload = jwt.decode(
381
- self._token,
382
- issuer="arangodb",
383
- algorithms=["HS256"],
384
- options={
385
- "require_exp": True,
386
- "require_iat": True,
387
- "verify_iat": True,
388
- "verify_exp": True,
389
- "verify_signature": False,
390
- },
391
- )
395
+ self.set_token(resp.body["jwt"])
396
+
397
+ def set_token(self, token: str) -> None:
398
+ """Set the JWT token.
399
+
400
+ :param token: JWT token.
401
+ :type token: str
402
+ :raise arango.exceptions.JWTExpiredError: If the token is expired.
403
+ """
404
+ assert token is not None
405
+
406
+ try:
407
+ jwt_payload = jwt.decode(
408
+ token,
409
+ issuer="arangodb",
410
+ algorithms=["HS256"],
411
+ options={
412
+ "require_exp": True,
413
+ "require_iat": True,
414
+ "verify_iat": True,
415
+ "verify_exp": True,
416
+ "verify_signature": False,
417
+ },
418
+ )
419
+ except ExpiredSignatureError:
420
+ raise JWTExpiredError("JWT token is expired")
421
+
422
+ self._token = token
392
423
  self._token_exp = jwt_payload["exp"]
393
424
  self._auth_header = f"bearer {self._token}"
394
425
 
@@ -444,3 +475,30 @@ class JwtSuperuserConnection(BaseConnection):
444
475
  request.headers["Authorization"] = self._auth_header
445
476
 
446
477
  return self.process_request(host_index, request)
478
+
479
+ def set_token(self, token: str) -> None:
480
+ """Set the JWT token.
481
+
482
+ :param token: JWT token.
483
+ :type token: str
484
+ :raise arango.exceptions.JWTExpiredError: If the token is expired.
485
+ """
486
+ assert token is not None
487
+
488
+ try:
489
+ jwt.decode(
490
+ token,
491
+ issuer="arangodb",
492
+ algorithms=["HS256"],
493
+ options={
494
+ "require_exp": True,
495
+ "require_iat": True,
496
+ "verify_iat": True,
497
+ "verify_exp": True,
498
+ "verify_signature": False,
499
+ },
500
+ )
501
+ except ExpiredSignatureError:
502
+ raise JWTExpiredError("JWT token is expired")
503
+
504
+ self._auth_header = f"bearer {token}"
@@ -1014,3 +1014,11 @@ class JWTSecretListError(ArangoServerError):
1014
1014
 
1015
1015
  class JWTSecretReloadError(ArangoServerError):
1016
1016
  """Failed to reload JWT secrets."""
1017
+
1018
+
1019
+ class JWTRefreshError(ArangoClientError):
1020
+ """Failed to refresh JWT token."""
1021
+
1022
+
1023
+ class JWTExpiredError(ArangoClientError):
1024
+ """JWT token has expired."""
@@ -107,9 +107,9 @@ class Graph(ApiGroup):
107
107
  return self._execute(request, response_handler)
108
108
 
109
109
  def vertex_collections(self) -> Result[List[str]]:
110
- """Return vertex collections in the graph that are not orphaned.
110
+ """Return vertex collections in the graph.
111
111
 
112
- :return: Names of vertex collections that are not orphaned.
112
+ :return: Names of vertex collections in Edge Definitions and Orphan Collections.
113
113
  :rtype: [str]
114
114
  :raise arango.exceptions.VertexCollectionListError: If retrieval fails.
115
115
  """
@@ -120,5 +120,5 @@ def build_filter_conditions(filters: Json) -> str:
120
120
  if not filters:
121
121
  return ""
122
122
 
123
- conditions = [f"doc.{k} == {json.dumps(v)}" for k, v in filters.items()]
123
+ conditions = [f"doc.`{k}` == {json.dumps(v)}" for k, v in filters.items()]
124
124
  return "FILTER " + " AND ".join(conditions)
@@ -0,0 +1,16 @@
1
+ # file generated by setuptools_scm
2
+ # don't change, don't track in version control
3
+ TYPE_CHECKING = False
4
+ if TYPE_CHECKING:
5
+ from typing import Tuple, Union
6
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
7
+ else:
8
+ VERSION_TUPLE = object
9
+
10
+ version: str
11
+ __version__: str
12
+ __version_tuple__: VERSION_TUPLE
13
+ version_tuple: VERSION_TUPLE
14
+
15
+ __version__ = version = '7.8.1'
16
+ __version_tuple__ = version_tuple = (7, 8, 1)
@@ -59,7 +59,7 @@ to work correctly.
59
59
  # compensate for out-of-sync clocks between the client and server.
60
60
  db.conn.ext_leeway = 2
61
61
 
62
- User generated JWT token can be used for superuser access.
62
+ User generated JWT token can be used for user and superuser access.
63
63
 
64
64
  **Example:**
65
65
 
@@ -89,3 +89,29 @@ User generated JWT token can be used for superuser access.
89
89
 
90
90
  # Connect to "test" database as superuser using the token.
91
91
  db = client.db('test', superuser_token=token)
92
+
93
+ # Connect to "test" database as user using the token.
94
+ db = client.db('test', user_token=token)
95
+
96
+ User and superuser tokens can be set on the connection object as well.
97
+
98
+ **Example:**
99
+
100
+ .. code-block:: python
101
+
102
+ from arango import ArangoClient
103
+
104
+ # Initialize the ArangoDB client.
105
+ client = ArangoClient()
106
+
107
+ # Connect to "test" database as superuser using the token.
108
+ db = client.db('test', user_token='token')
109
+
110
+ # Set the user token on the connection object.
111
+ db.conn.set_token('new token')
112
+
113
+ # Connect to "test" database as superuser using the token.
114
+ db = client.db('test', superuser_token='superuser token')
115
+
116
+ # Set the user token on the connection object.
117
+ db.conn.set_token('new superuser token')
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-arango
3
- Version: 7.7.0
3
+ Version: 7.8.1
4
4
  Summary: Python Driver for ArangoDB
5
5
  Home-page: https://github.com/ArangoDB-Community/python-arango
6
6
  Author: Joohwan Oh
@@ -1,8 +0,0 @@
1
- # file generated by setuptools_scm
2
- # don't change, don't track in version control
3
- TYPE_CHECKING = False
4
- if TYPE_CHECKING:
5
- from typing import Tuple
6
-
7
- __version__ = version = '7.7.0' # type: str
8
- __version_tuple__ = version_tuple = (7, 7, 0) # type: Tuple[int | str, ...]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes