python-arango 8.1.3__tar.gz → 8.1.5__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 (92) hide show
  1. {python_arango-8.1.3 → python_arango-8.1.5}/.circleci/config.yml +1 -2
  2. {python_arango-8.1.3 → python_arango-8.1.5}/.gitignore +3 -0
  3. {python_arango-8.1.3 → python_arango-8.1.5}/PKG-INFO +4 -5
  4. {python_arango-8.1.3 → python_arango-8.1.5}/README.md +1 -1
  5. {python_arango-8.1.3 → python_arango-8.1.5}/arango/aql.py +44 -5
  6. {python_arango-8.1.3 → python_arango-8.1.5}/arango/collection.py +9 -1
  7. {python_arango-8.1.3 → python_arango-8.1.5}/arango/cursor.py +19 -1
  8. python_arango-8.1.5/arango/errno.py +1168 -0
  9. {python_arango-8.1.3 → python_arango-8.1.5}/arango/exceptions.py +7 -0
  10. {python_arango-8.1.3 → python_arango-8.1.5}/arango/request.py +1 -1
  11. {python_arango-8.1.3 → python_arango-8.1.5}/arango/utils.py +42 -3
  12. {python_arango-8.1.3 → python_arango-8.1.5}/docs/conf.py +1 -1
  13. {python_arango-8.1.3 → python_arango-8.1.5}/docs/document.rst +6 -0
  14. {python_arango-8.1.3 → python_arango-8.1.5}/docs/index.rst +1 -1
  15. {python_arango-8.1.3 → python_arango-8.1.5}/pyproject.toml +1 -2
  16. {python_arango-8.1.3 → python_arango-8.1.5}/python_arango.egg-info/PKG-INFO +4 -5
  17. {python_arango-8.1.3 → python_arango-8.1.5}/setup.cfg +1 -1
  18. python_arango-8.1.3/arango/errno.py +0 -1339
  19. {python_arango-8.1.3 → python_arango-8.1.5}/.github/workflows/codeql.yaml +0 -0
  20. {python_arango-8.1.3 → python_arango-8.1.5}/.github/workflows/docs.yaml +0 -0
  21. {python_arango-8.1.3 → python_arango-8.1.5}/.github/workflows/pypi.yaml +0 -0
  22. {python_arango-8.1.3 → python_arango-8.1.5}/.pre-commit-config.yaml +0 -0
  23. {python_arango-8.1.3 → python_arango-8.1.5}/.readthedocs.yaml +0 -0
  24. {python_arango-8.1.3 → python_arango-8.1.5}/CONTRIBUTING.md +0 -0
  25. {python_arango-8.1.3 → python_arango-8.1.5}/LICENSE +0 -0
  26. {python_arango-8.1.3 → python_arango-8.1.5}/MANIFEST.in +0 -0
  27. {python_arango-8.1.3 → python_arango-8.1.5}/arango/__init__.py +0 -0
  28. {python_arango-8.1.3 → python_arango-8.1.5}/arango/api.py +0 -0
  29. {python_arango-8.1.3 → python_arango-8.1.5}/arango/backup.py +0 -0
  30. {python_arango-8.1.3 → python_arango-8.1.5}/arango/client.py +0 -0
  31. {python_arango-8.1.3 → python_arango-8.1.5}/arango/cluster.py +0 -0
  32. {python_arango-8.1.3 → python_arango-8.1.5}/arango/connection.py +0 -0
  33. {python_arango-8.1.3 → python_arango-8.1.5}/arango/database.py +0 -0
  34. {python_arango-8.1.3 → python_arango-8.1.5}/arango/executor.py +0 -0
  35. {python_arango-8.1.3 → python_arango-8.1.5}/arango/formatter.py +0 -0
  36. {python_arango-8.1.3 → python_arango-8.1.5}/arango/foxx.py +0 -0
  37. {python_arango-8.1.3 → python_arango-8.1.5}/arango/graph.py +0 -0
  38. {python_arango-8.1.3 → python_arango-8.1.5}/arango/http.py +0 -0
  39. {python_arango-8.1.3 → python_arango-8.1.5}/arango/job.py +0 -0
  40. {python_arango-8.1.3 → python_arango-8.1.5}/arango/pregel.py +0 -0
  41. {python_arango-8.1.3 → python_arango-8.1.5}/arango/py.typed +0 -0
  42. {python_arango-8.1.3 → python_arango-8.1.5}/arango/replication.py +0 -0
  43. {python_arango-8.1.3 → python_arango-8.1.5}/arango/resolver.py +0 -0
  44. {python_arango-8.1.3 → python_arango-8.1.5}/arango/response.py +0 -0
  45. {python_arango-8.1.3 → python_arango-8.1.5}/arango/result.py +0 -0
  46. {python_arango-8.1.3 → python_arango-8.1.5}/arango/typings.py +0 -0
  47. {python_arango-8.1.3 → python_arango-8.1.5}/arango/wal.py +0 -0
  48. {python_arango-8.1.3 → python_arango-8.1.5}/docs/Makefile +0 -0
  49. {python_arango-8.1.3 → python_arango-8.1.5}/docs/admin.rst +0 -0
  50. {python_arango-8.1.3 → python_arango-8.1.5}/docs/analyzer.rst +0 -0
  51. {python_arango-8.1.3 → python_arango-8.1.5}/docs/aql.rst +0 -0
  52. {python_arango-8.1.3 → python_arango-8.1.5}/docs/async.rst +0 -0
  53. {python_arango-8.1.3 → python_arango-8.1.5}/docs/auth.rst +0 -0
  54. {python_arango-8.1.3 → python_arango-8.1.5}/docs/backup.rst +0 -0
  55. {python_arango-8.1.3 → python_arango-8.1.5}/docs/batch.rst +0 -0
  56. {python_arango-8.1.3 → python_arango-8.1.5}/docs/certificates.rst +0 -0
  57. {python_arango-8.1.3 → python_arango-8.1.5}/docs/cluster.rst +0 -0
  58. {python_arango-8.1.3 → python_arango-8.1.5}/docs/collection.rst +0 -0
  59. {python_arango-8.1.3 → python_arango-8.1.5}/docs/compression.rst +0 -0
  60. {python_arango-8.1.3 → python_arango-8.1.5}/docs/contributing.rst +0 -0
  61. {python_arango-8.1.3 → python_arango-8.1.5}/docs/cursor.rst +0 -0
  62. {python_arango-8.1.3 → python_arango-8.1.5}/docs/database.rst +0 -0
  63. {python_arango-8.1.3 → python_arango-8.1.5}/docs/errno.rst +0 -0
  64. {python_arango-8.1.3 → python_arango-8.1.5}/docs/errors.rst +0 -0
  65. {python_arango-8.1.3 → python_arango-8.1.5}/docs/foxx.rst +0 -0
  66. {python_arango-8.1.3 → python_arango-8.1.5}/docs/graph.rst +0 -0
  67. {python_arango-8.1.3 → python_arango-8.1.5}/docs/http.rst +0 -0
  68. {python_arango-8.1.3 → python_arango-8.1.5}/docs/indexes.rst +0 -0
  69. {python_arango-8.1.3 → python_arango-8.1.5}/docs/logging.rst +0 -0
  70. {python_arango-8.1.3 → python_arango-8.1.5}/docs/make.bat +0 -0
  71. {python_arango-8.1.3 → python_arango-8.1.5}/docs/overload.rst +0 -0
  72. {python_arango-8.1.3 → python_arango-8.1.5}/docs/overview.rst +0 -0
  73. {python_arango-8.1.3 → python_arango-8.1.5}/docs/pregel.rst +0 -0
  74. {python_arango-8.1.3 → python_arango-8.1.5}/docs/replication.rst +0 -0
  75. {python_arango-8.1.3 → python_arango-8.1.5}/docs/requirements.txt +0 -0
  76. {python_arango-8.1.3 → python_arango-8.1.5}/docs/schema.rst +0 -0
  77. {python_arango-8.1.3 → python_arango-8.1.5}/docs/serializer.rst +0 -0
  78. {python_arango-8.1.3 → python_arango-8.1.5}/docs/simple.rst +0 -0
  79. {python_arango-8.1.3 → python_arango-8.1.5}/docs/specs.rst +0 -0
  80. {python_arango-8.1.3 → python_arango-8.1.5}/docs/static/logo.png +0 -0
  81. {python_arango-8.1.3 → python_arango-8.1.5}/docs/task.rst +0 -0
  82. {python_arango-8.1.3 → python_arango-8.1.5}/docs/threading.rst +0 -0
  83. {python_arango-8.1.3 → python_arango-8.1.5}/docs/transaction.rst +0 -0
  84. {python_arango-8.1.3 → python_arango-8.1.5}/docs/user.rst +0 -0
  85. {python_arango-8.1.3 → python_arango-8.1.5}/docs/view.rst +0 -0
  86. {python_arango-8.1.3 → python_arango-8.1.5}/docs/wal.rst +0 -0
  87. {python_arango-8.1.3 → python_arango-8.1.5}/python_arango.egg-info/SOURCES.txt +0 -0
  88. {python_arango-8.1.3 → python_arango-8.1.5}/python_arango.egg-info/dependency_links.txt +0 -0
  89. {python_arango-8.1.3 → python_arango-8.1.5}/python_arango.egg-info/requires.txt +0 -0
  90. {python_arango-8.1.3 → python_arango-8.1.5}/python_arango.egg-info/top_level.txt +0 -0
  91. {python_arango-8.1.3 → python_arango-8.1.5}/setup.py +0 -0
  92. {python_arango-8.1.3 → python_arango-8.1.5}/starter.sh +0 -0
@@ -11,8 +11,7 @@ workflows:
11
11
  name: Python (<< matrix.python_version >>) - ArangoDB (<< matrix.arangodb_license >>, << matrix.arangodb_version >> << matrix.arangodb_config >>)
12
12
  matrix:
13
13
  parameters:
14
- # TODO: Revisit why pyenv doesn't recognize 3.12
15
- python_version: ["3.8", "3.9", "3.10", "3.11"] # "3.12"
14
+ python_version: ["3.9", "3.10", "3.11", "3.12"]
16
15
  arangodb_config: ["single", "cluster"]
17
16
  arangodb_license: ["community", "enterprise"]
18
17
  arangodb_version: ["3.11", "latest"]
@@ -124,3 +124,6 @@ arango/version.py
124
124
 
125
125
  # test results
126
126
  *_results.txt
127
+
128
+ # devcontainers
129
+ .devcontainer
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: python-arango
3
- Version: 8.1.3
3
+ Version: 8.1.5
4
4
  Summary: Python Driver for ArangoDB
5
5
  Author-email: Joohwan Oh <joohwan.oh@outlook.com>
6
6
  Maintainer-email: Joohwan Oh <joohwan.oh@outlook.com>, Alexandru Petenchea <alex.petenchea@gmail.com>, Anthony Mahanna <anthony.mahanna@arangodb.com>
@@ -33,14 +33,13 @@ Classifier: License :: OSI Approved :: MIT License
33
33
  Classifier: Natural Language :: English
34
34
  Classifier: Operating System :: OS Independent
35
35
  Classifier: Programming Language :: Python :: 3
36
- Classifier: Programming Language :: Python :: 3.8
37
36
  Classifier: Programming Language :: Python :: 3.9
38
37
  Classifier: Programming Language :: Python :: 3.10
39
38
  Classifier: Programming Language :: Python :: 3.11
40
39
  Classifier: Programming Language :: Python :: 3.12
41
40
  Classifier: Topic :: Documentation :: Sphinx
42
41
  Classifier: Typing :: Typed
43
- Requires-Python: >=3.8
42
+ Requires-Python: >=3.9
44
43
  Description-Content-Type: text/markdown
45
44
  License-File: LICENSE
46
45
  Requires-Dist: urllib3>=1.26.0
@@ -88,7 +87,7 @@ database natively supporting documents, graphs and search.
88
87
  ## Requirements
89
88
 
90
89
  - ArangoDB version 3.11+
91
- - Python version 3.8+
90
+ - Python version 3.9+
92
91
 
93
92
  ## Installation
94
93
 
@@ -22,7 +22,7 @@ database natively supporting documents, graphs and search.
22
22
  ## Requirements
23
23
 
24
24
  - ArangoDB version 3.11+
25
- - Python version 3.8+
25
+ - Python version 3.9+
26
26
 
27
27
  ## Installation
28
28
 
@@ -144,6 +144,36 @@ class AQLQueryCache(ApiGroup):
144
144
 
145
145
  return self._execute(request, response_handler)
146
146
 
147
+ def plan_entries(self) -> Result[Jsons]:
148
+ """Return a list of all AQL query plan cache entries.
149
+
150
+ :return: List of AQL query plan cache entries.
151
+ :rtype: list
152
+ :raise arango.exceptions.AQLCacheEntriesError: If retrieval fails.
153
+ """
154
+ request = Request(method="get", endpoint="/_api/query-plan-cache")
155
+
156
+ def response_handler(resp: Response) -> Jsons:
157
+ if not resp.is_success:
158
+ raise AQLCacheEntriesError(resp, request)
159
+ result: Jsons = resp.body
160
+ return result
161
+
162
+ return self._execute(request, response_handler)
163
+
164
+ def clear_plan(self) -> Result[None]:
165
+ """Clear the AQL query plan cache.
166
+
167
+ :raises arango.exceptions.AQLCacheClearError: If clearing the cache fails.
168
+ """
169
+ request = Request(method="delete", endpoint="/_api/query-plan-cache")
170
+
171
+ def response_handler(resp: Response) -> None:
172
+ if not resp.is_success:
173
+ raise AQLCacheClearError(resp, request)
174
+
175
+ return self._execute(request, response_handler)
176
+
147
177
 
148
178
  class AQL(ApiGroup):
149
179
  """AQL (ArangoDB Query Language) API wrapper.
@@ -264,7 +294,7 @@ class AQL(ApiGroup):
264
294
  cache: Optional[bool] = None,
265
295
  memory_limit: int = 0,
266
296
  fail_on_warning: Optional[bool] = None,
267
- profile: Optional[bool] = None,
297
+ profile: Optional[Union[bool, int]] = None,
268
298
  max_transaction_size: Optional[int] = None,
269
299
  max_warning_count: Optional[int] = None,
270
300
  intermediate_commit_count: Optional[int] = None,
@@ -277,6 +307,7 @@ class AQL(ApiGroup):
277
307
  allow_dirty_read: bool = False,
278
308
  allow_retry: bool = False,
279
309
  force_one_shard_attribute_value: Optional[str] = None,
310
+ use_plan_cache: Optional[bool] = None,
280
311
  ) -> Result[Cursor]:
281
312
  """Execute the query and return the result cursor.
282
313
 
@@ -317,8 +348,12 @@ class AQL(ApiGroup):
317
348
  this behaviour, so it does not need to be set per-query.
318
349
  :type fail_on_warning: bool
319
350
  :param profile: Return additional profiling details in the cursor,
320
- unless the query cache is used.
321
- :type profile: bool
351
+ unless the query cache is used. If set to True or 1, then query profiling
352
+ information can be fetched with `cursor.profile()`. If set to 2, additional
353
+ execution stats per query plan node are included via "nodes" in
354
+ `cursor.statistics()`, as well as a the query plan which can be fetched
355
+ with `cursor.plan()`.
356
+ :type profile: bool | int
322
357
  :param max_transaction_size: Transaction size limit in bytes.
323
358
  :type max_transaction_size: int
324
359
  :param max_warning_count: Max number of warnings returned.
@@ -384,6 +419,8 @@ class AQL(ApiGroup):
384
419
  shipped to a wrong DB server and may not return results
385
420
  (i.e. empty result set). Use at your own risk.
386
421
  :param force_one_shard_attribute_value: str | None
422
+ :param use_plan_cache: If set to True, the query plan cache is used.
423
+ :param use_plan_cache: bool | None
387
424
  :return: Result cursor.
388
425
  :rtype: arango.cursor.Cursor
389
426
  :raise arango.exceptions.AQLQueryExecuteError: If execute fails.
@@ -395,8 +432,6 @@ class AQL(ApiGroup):
395
432
  data["ttl"] = ttl
396
433
  if bind_vars is not None:
397
434
  data["bindVars"] = bind_vars
398
- if cache is not None:
399
- data["cache"] = cache
400
435
  if memory_limit is not None:
401
436
  data["memoryLimit"] = memory_limit
402
437
 
@@ -433,6 +468,10 @@ class AQL(ApiGroup):
433
468
  options["allowRetry"] = allow_retry
434
469
  if force_one_shard_attribute_value is not None:
435
470
  options["forceOneShardAttributeValue"] = force_one_shard_attribute_value
471
+ if cache is not None:
472
+ options["cache"] = cache
473
+ if use_plan_cache is not None:
474
+ options["usePlanCache"] = use_plan_cache
436
475
 
437
476
  if options:
438
477
  data["options"] = options
@@ -50,11 +50,13 @@ from arango.result import Result
50
50
  from arango.typings import Fields, Headers, Json, Jsons, Params
51
51
  from arango.utils import (
52
52
  build_filter_conditions,
53
+ build_sort_expression,
53
54
  get_batches,
54
55
  get_doc_id,
55
56
  is_none_or_bool,
56
57
  is_none_or_int,
57
58
  is_none_or_str,
59
+ validate_sort_parameters,
58
60
  )
59
61
 
60
62
 
@@ -753,6 +755,7 @@ class Collection(ApiGroup):
753
755
  skip: Optional[int] = None,
754
756
  limit: Optional[int] = None,
755
757
  allow_dirty_read: bool = False,
758
+ sort: Optional[Jsons] = None,
756
759
  ) -> Result[Cursor]:
757
760
  """Return all documents that match the given filters.
758
761
 
@@ -764,13 +767,18 @@ class Collection(ApiGroup):
764
767
  :type limit: int | None
765
768
  :param allow_dirty_read: Allow reads from followers in a cluster.
766
769
  :type allow_dirty_read: bool
770
+ :param sort: Document sort parameters
771
+ :type sort: Jsons | None
767
772
  :return: Document cursor.
768
773
  :rtype: arango.cursor.Cursor
769
774
  :raise arango.exceptions.DocumentGetError: If retrieval fails.
775
+ :raise arango.exceptions.SortValidationError: If sort parameters are invalid.
770
776
  """
771
777
  assert isinstance(filters, dict), "filters must be a dict"
772
778
  assert is_none_or_int(skip), "skip must be a non-negative int"
773
779
  assert is_none_or_int(limit), "limit must be a non-negative int"
780
+ if sort:
781
+ validate_sort_parameters(sort)
774
782
 
775
783
  skip_val = skip if skip is not None else 0
776
784
  limit_val = limit if limit is not None else "null"
@@ -778,9 +786,9 @@ class Collection(ApiGroup):
778
786
  FOR doc IN @@collection
779
787
  {build_filter_conditions(filters)}
780
788
  LIMIT {skip_val}, {limit_val}
789
+ {build_sort_expression(sort)}
781
790
  RETURN doc
782
791
  """
783
-
784
792
  bind_vars = {"@collection": self.name}
785
793
 
786
794
  request = Request(
@@ -40,6 +40,7 @@ class Cursor:
40
40
  "_count",
41
41
  "_cached",
42
42
  "_stats",
43
+ "_plan",
43
44
  "_profile",
44
45
  "_warnings",
45
46
  "_has_more",
@@ -63,6 +64,7 @@ class Cursor:
63
64
  self._count: Optional[int] = None
64
65
  self._cached = None
65
66
  self._stats = None
67
+ self._plan = None
66
68
  self._profile = None
67
69
  self._warnings = None
68
70
  self._next_batch_id: Optional[str] = None
@@ -132,12 +134,18 @@ class Cursor:
132
134
  self._warnings = extra["warnings"]
133
135
  result["warnings"] = extra["warnings"]
134
136
 
137
+ if "plan" in extra:
138
+ self._plan = extra["plan"]
139
+ result["plan"] = extra["plan"]
140
+
135
141
  if "stats" in extra:
136
142
  stats = extra["stats"]
137
143
  if "writesExecuted" in stats:
138
144
  stats["modified"] = stats.pop("writesExecuted")
139
145
  if "writesIgnored" in stats:
140
146
  stats["ignored"] = stats.pop("writesIgnored")
147
+ if "documentLookups" in stats:
148
+ stats["lookups"] = stats.pop("documentLookups")
141
149
  if "scannedFull" in stats:
142
150
  stats["scanned_full"] = stats.pop("scannedFull")
143
151
  if "scannedIndex" in stats:
@@ -159,6 +167,9 @@ class Cursor:
159
167
  if "peakMemoryUsage" in stats:
160
168
  stats["peak_memory_usage"] = stats.pop("peakMemoryUsage")
161
169
 
170
+ if "intermediateCommits" in stats:
171
+ stats["intermediate_commits"] = stats.pop("intermediateCommits")
172
+
162
173
  self._stats = stats
163
174
  result["statistics"] = stats
164
175
 
@@ -239,6 +250,14 @@ class Cursor:
239
250
  """
240
251
  return self._warnings
241
252
 
253
+ def plan(self) -> Optional[Json]:
254
+ """Return query execution plan.
255
+
256
+ :return: Query execution plan.
257
+ :rtype: dict
258
+ """
259
+ return self._plan
260
+
242
261
  def empty(self) -> bool:
243
262
  """Check if the current batch is empty.
244
263
 
@@ -313,7 +332,6 @@ class Cursor:
313
332
  smaller than the batch size).
314
333
  :rtype: bool | None
315
334
  :raise arango.exceptions.CursorCloseError: If operation fails.
316
- :raise arango.exceptions.CursorStateError: If cursor ID is not set.
317
335
  """
318
336
  if self._id is None:
319
337
  return None