python-arango 8.3.5__tar.gz → 8.3.6__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 (99) hide show
  1. {python_arango-8.3.5 → python_arango-8.3.6}/.circleci/config.yml +9 -2
  2. python_arango-8.3.6/.github/workflows/pypi.yaml +66 -0
  3. python_arango-8.3.6/AGENTS.md +89 -0
  4. {python_arango-8.3.5/python_arango.egg-info → python_arango-8.3.6}/PKG-INFO +1 -1
  5. python_arango-8.3.6/arango/version.py +1 -0
  6. {python_arango-8.3.5 → python_arango-8.3.6}/docs/index.rst +0 -1
  7. {python_arango-8.3.5 → python_arango-8.3.6}/docs/indexes.rst +6 -3
  8. {python_arango-8.3.5 → python_arango-8.3.6/python_arango.egg-info}/PKG-INFO +1 -1
  9. {python_arango-8.3.5 → python_arango-8.3.6}/python_arango.egg-info/SOURCES.txt +2 -2
  10. {python_arango-8.3.5 → python_arango-8.3.6}/python_arango.egg-info/scm_file_list.json +3 -3
  11. python_arango-8.3.6/python_arango.egg-info/scm_version.json +8 -0
  12. {python_arango-8.3.5 → python_arango-8.3.6}/starter.sh +6 -5
  13. python_arango-8.3.6/todo.md +397 -0
  14. python_arango-8.3.5/.github/workflows/pypi.yaml +0 -40
  15. python_arango-8.3.5/CONTRIBUTING.md +0 -28
  16. python_arango-8.3.5/arango/version.py +0 -1
  17. python_arango-8.3.5/docs/contributing.rst +0 -99
  18. python_arango-8.3.5/python_arango.egg-info/scm_version.json +0 -8
  19. {python_arango-8.3.5 → python_arango-8.3.6}/.github/workflows/codeql.yaml +0 -0
  20. {python_arango-8.3.5 → python_arango-8.3.6}/.github/workflows/docs.yaml +0 -0
  21. {python_arango-8.3.5 → python_arango-8.3.6}/.gitignore +0 -0
  22. {python_arango-8.3.5 → python_arango-8.3.6}/.pre-commit-config.yaml +0 -0
  23. {python_arango-8.3.5 → python_arango-8.3.6}/.readthedocs.yaml +0 -0
  24. {python_arango-8.3.5 → python_arango-8.3.6}/LICENSE +0 -0
  25. {python_arango-8.3.5 → python_arango-8.3.6}/MANIFEST.in +0 -0
  26. {python_arango-8.3.5 → python_arango-8.3.6}/README.md +0 -0
  27. {python_arango-8.3.5 → python_arango-8.3.6}/arango/__init__.py +0 -0
  28. {python_arango-8.3.5 → python_arango-8.3.6}/arango/api.py +0 -0
  29. {python_arango-8.3.5 → python_arango-8.3.6}/arango/aql.py +0 -0
  30. {python_arango-8.3.5 → python_arango-8.3.6}/arango/backup.py +0 -0
  31. {python_arango-8.3.5 → python_arango-8.3.6}/arango/client.py +0 -0
  32. {python_arango-8.3.5 → python_arango-8.3.6}/arango/cluster.py +0 -0
  33. {python_arango-8.3.5 → python_arango-8.3.6}/arango/collection.py +0 -0
  34. {python_arango-8.3.5 → python_arango-8.3.6}/arango/connection.py +0 -0
  35. {python_arango-8.3.5 → python_arango-8.3.6}/arango/cursor.py +0 -0
  36. {python_arango-8.3.5 → python_arango-8.3.6}/arango/database.py +0 -0
  37. {python_arango-8.3.5 → python_arango-8.3.6}/arango/errno.py +0 -0
  38. {python_arango-8.3.5 → python_arango-8.3.6}/arango/exceptions.py +0 -0
  39. {python_arango-8.3.5 → python_arango-8.3.6}/arango/executor.py +0 -0
  40. {python_arango-8.3.5 → python_arango-8.3.6}/arango/formatter.py +0 -0
  41. {python_arango-8.3.5 → python_arango-8.3.6}/arango/foxx.py +0 -0
  42. {python_arango-8.3.5 → python_arango-8.3.6}/arango/graph.py +0 -0
  43. {python_arango-8.3.5 → python_arango-8.3.6}/arango/http.py +0 -0
  44. {python_arango-8.3.5 → python_arango-8.3.6}/arango/job.py +0 -0
  45. {python_arango-8.3.5 → python_arango-8.3.6}/arango/pregel.py +0 -0
  46. {python_arango-8.3.5 → python_arango-8.3.6}/arango/py.typed +0 -0
  47. {python_arango-8.3.5 → python_arango-8.3.6}/arango/replication.py +0 -0
  48. {python_arango-8.3.5 → python_arango-8.3.6}/arango/request.py +0 -0
  49. {python_arango-8.3.5 → python_arango-8.3.6}/arango/resolver.py +0 -0
  50. {python_arango-8.3.5 → python_arango-8.3.6}/arango/response.py +0 -0
  51. {python_arango-8.3.5 → python_arango-8.3.6}/arango/result.py +0 -0
  52. {python_arango-8.3.5 → python_arango-8.3.6}/arango/typings.py +0 -0
  53. {python_arango-8.3.5 → python_arango-8.3.6}/arango/utils.py +0 -0
  54. {python_arango-8.3.5 → python_arango-8.3.6}/arango/wal.py +0 -0
  55. {python_arango-8.3.5 → python_arango-8.3.6}/docs/Makefile +0 -0
  56. {python_arango-8.3.5 → python_arango-8.3.6}/docs/admin.rst +0 -0
  57. {python_arango-8.3.5 → python_arango-8.3.6}/docs/analyzer.rst +0 -0
  58. {python_arango-8.3.5 → python_arango-8.3.6}/docs/aql.rst +0 -0
  59. {python_arango-8.3.5 → python_arango-8.3.6}/docs/async.rst +0 -0
  60. {python_arango-8.3.5 → python_arango-8.3.6}/docs/auth.rst +0 -0
  61. {python_arango-8.3.5 → python_arango-8.3.6}/docs/backup.rst +0 -0
  62. {python_arango-8.3.5 → python_arango-8.3.6}/docs/batch.rst +0 -0
  63. {python_arango-8.3.5 → python_arango-8.3.6}/docs/certificates.rst +0 -0
  64. {python_arango-8.3.5 → python_arango-8.3.6}/docs/cluster.rst +0 -0
  65. {python_arango-8.3.5 → python_arango-8.3.6}/docs/collection.rst +0 -0
  66. {python_arango-8.3.5 → python_arango-8.3.6}/docs/compression.rst +0 -0
  67. {python_arango-8.3.5 → python_arango-8.3.6}/docs/conf.py +0 -0
  68. {python_arango-8.3.5 → python_arango-8.3.6}/docs/cursor.rst +0 -0
  69. {python_arango-8.3.5 → python_arango-8.3.6}/docs/database.rst +0 -0
  70. {python_arango-8.3.5 → python_arango-8.3.6}/docs/document.rst +0 -0
  71. {python_arango-8.3.5 → python_arango-8.3.6}/docs/errno.rst +0 -0
  72. {python_arango-8.3.5 → python_arango-8.3.6}/docs/errors.rst +0 -0
  73. {python_arango-8.3.5 → python_arango-8.3.6}/docs/foxx.rst +0 -0
  74. {python_arango-8.3.5 → python_arango-8.3.6}/docs/graph.rst +0 -0
  75. {python_arango-8.3.5 → python_arango-8.3.6}/docs/http.rst +0 -0
  76. {python_arango-8.3.5 → python_arango-8.3.6}/docs/logging.rst +0 -0
  77. {python_arango-8.3.5 → python_arango-8.3.6}/docs/make.bat +0 -0
  78. {python_arango-8.3.5 → python_arango-8.3.6}/docs/overload.rst +0 -0
  79. {python_arango-8.3.5 → python_arango-8.3.6}/docs/overview.rst +0 -0
  80. {python_arango-8.3.5 → python_arango-8.3.6}/docs/pregel.rst +0 -0
  81. {python_arango-8.3.5 → python_arango-8.3.6}/docs/replication.rst +0 -0
  82. {python_arango-8.3.5 → python_arango-8.3.6}/docs/requirements.txt +0 -0
  83. {python_arango-8.3.5 → python_arango-8.3.6}/docs/schema.rst +0 -0
  84. {python_arango-8.3.5 → python_arango-8.3.6}/docs/serializer.rst +0 -0
  85. {python_arango-8.3.5 → python_arango-8.3.6}/docs/simple.rst +0 -0
  86. {python_arango-8.3.5 → python_arango-8.3.6}/docs/specs.rst +0 -0
  87. {python_arango-8.3.5 → python_arango-8.3.6}/docs/static/logo.png +0 -0
  88. {python_arango-8.3.5 → python_arango-8.3.6}/docs/task.rst +0 -0
  89. {python_arango-8.3.5 → python_arango-8.3.6}/docs/threading.rst +0 -0
  90. {python_arango-8.3.5 → python_arango-8.3.6}/docs/transaction.rst +0 -0
  91. {python_arango-8.3.5 → python_arango-8.3.6}/docs/user.rst +0 -0
  92. {python_arango-8.3.5 → python_arango-8.3.6}/docs/view.rst +0 -0
  93. {python_arango-8.3.5 → python_arango-8.3.6}/docs/wal.rst +0 -0
  94. {python_arango-8.3.5 → python_arango-8.3.6}/pyproject.toml +0 -0
  95. {python_arango-8.3.5 → python_arango-8.3.6}/python_arango.egg-info/dependency_links.txt +0 -0
  96. {python_arango-8.3.5 → python_arango-8.3.6}/python_arango.egg-info/requires.txt +0 -0
  97. {python_arango-8.3.5 → python_arango-8.3.6}/python_arango.egg-info/top_level.txt +0 -0
  98. {python_arango-8.3.5 → python_arango-8.3.6}/setup.cfg +0 -0
  99. {python_arango-8.3.5 → python_arango-8.3.6}/setup.py +0 -0
@@ -30,11 +30,18 @@ workflows:
30
30
  parameters:
31
31
  python_version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
32
32
  - integration-test:
33
- name: ArangoDB (enterprise, 3.12 << matrix.arangodb_config >>)
33
+ name: ArangoDB (enterprise, 3.12.10 << matrix.arangodb_config >>)
34
34
  matrix:
35
35
  parameters:
36
36
  arangodb_config: ["single", "cluster"]
37
- arangodb_image: ["arangodb/enterprise:3.12"]
37
+ arangodb_image: ["arangodb/enterprise:3.12.10"]
38
+ arangodb_conf_version: ["3.12"]
39
+ - integration-test:
40
+ name: ArangoDB (enterprise, 3.12.9 << matrix.arangodb_config >>)
41
+ matrix:
42
+ parameters:
43
+ arangodb_config: ["single", "cluster"]
44
+ arangodb_image: ["arangodb/enterprise:3.12.9"]
38
45
  arangodb_conf_version: ["3.12"]
39
46
  - integration-test:
40
47
  name: ArangoDB (core-preview, 4.0-nightly << matrix.arangodb_config >>)
@@ -0,0 +1,66 @@
1
+ name: Publish
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ build:
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - name: Checkout repository
16
+ uses: actions/checkout@v7
17
+ with:
18
+ fetch-depth: 0
19
+ fetch-tags: true
20
+ persist-credentials: false
21
+
22
+ - uses: actions/setup-python@v7
23
+ with:
24
+ python-version: "3.12"
25
+
26
+ - name: Install dependencies
27
+ run: python -m pip install build
28
+
29
+ - name: Build distribution
30
+ run: python -m build
31
+
32
+ - uses: actions/upload-artifact@v5
33
+ with:
34
+ name: dist
35
+ path: dist/
36
+ if-no-files-found: error
37
+
38
+ testpypi:
39
+ needs: build
40
+ runs-on: ubuntu-latest
41
+ environment: testpypi
42
+ permissions:
43
+ id-token: write
44
+ steps:
45
+ - uses: actions/download-artifact@v6
46
+ with:
47
+ name: dist
48
+ path: dist/
49
+ - name: Publish to TestPyPI
50
+ uses: pypa/gh-action-pypi-publish@release/v1
51
+ with:
52
+ repository-url: https://test.pypi.org/legacy/
53
+
54
+ pypi:
55
+ needs: testpypi
56
+ runs-on: ubuntu-latest
57
+ environment: pypi
58
+ permissions:
59
+ id-token: write
60
+ steps:
61
+ - uses: actions/download-artifact@v6
62
+ with:
63
+ name: dist
64
+ path: dist/
65
+ - name: Publish to PyPI
66
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,89 @@
1
+ # Quickstart
2
+
3
+ python-arango is a Python driver for ArangoDB. Run the commands below from the
4
+ repository root.
5
+
6
+ ## Repository layout
7
+
8
+ - `arango/`: driver implementation, public APIs, and type annotations.
9
+ - `tests/`: pytest tests; `conftest.py` defines database fixtures and CLI options.
10
+ - `tests/static/`: server configurations and test data used by `starter.sh`.
11
+ - `docs/`: Sphinx documentation in reStructuredText.
12
+ - `pyproject.toml`, `setup.cfg`, `.pre-commit-config.yaml`: packaging and tooling.
13
+ - `.circleci/`, `.github/workflows/`: CI checks, documentation, and publishing.
14
+
15
+ ## Development setup
16
+
17
+ Use Python 3.10 or newer. Create a virtual environment, or use an existing one:
18
+
19
+ ```bash
20
+ python3 -m venv .venv # Create an isolated Python environment.
21
+ source .venv/bin/activate # Use its interpreter and tools.
22
+ python -m pip install -e '.[dev]' # Install the editable driver and dev tools.
23
+ pre-commit install # Enable checks before each commit.
24
+ ```
25
+
26
+ Examples use `python` from the activated environment. If it is unavailable on
27
+ PATH, invoke your environment's interpreter directly.
28
+
29
+ ## Local cluster and tests
30
+
31
+ The starter requires Docker, Bash, `wget`, and `jq`. To replace an existing test
32
+ container, run `docker stop arango` and `docker rm arango` first.
33
+
34
+ ```bash
35
+ version="latest" # Or pin a supported version, such as 3.12.10.
36
+ ./starter.sh cluster enterprise "$version" # Start a local test cluster.
37
+ python -m pytest --cluster # Run the full suite against the cluster.
38
+ # Run one test while developing a document change.
39
+ python -m pytest --cluster tests/test_document.py::test_document_insert
40
+ # Generate an HTML coverage report.
41
+ python -m pytest --cluster --cov=arango --cov-report=html
42
+ ```
43
+
44
+ Defaults are `127.0.0.1:8529`, user `root`, password `passwd`, and JWT secret
45
+ `secret`, matching the starter configuration. Override them with `--host`,
46
+ `--port`, `--root`, `--password`, and `--secret`. Use a disposable development
47
+ database: tests create and delete databases, users, jobs, and backups. If a
48
+ sandbox blocks localhost access, rerun with the required sandbox permission.
49
+
50
+ For a single server, use `./starter.sh single enterprise "$version"` and omit
51
+ `--cluster`. Import tests can run without ArangoDB:
52
+
53
+ ```bash
54
+ python -m pytest tests/test_imports.py --skip-arango-setup # Check imports offline.
55
+ ```
56
+
57
+ ## Style and documentation
58
+
59
+ Run the configured hooks for formatting, import ordering, linting, and type
60
+ checks. Build and test documentation separately:
61
+
62
+ ```bash
63
+ pre-commit run --all-files # Run hooks; formatters may modify files.
64
+ python -m sphinx -b html docs docs/_build # Build the HTML documentation.
65
+ python -m sphinx -b doctest docs docs/_build # Test documentation examples.
66
+ ```
67
+
68
+ The Sphinx doctests require a running ArangoDB server. Open
69
+ `docs/_build/index.html` for the HTML documentation or `htmlcov/index.html` for
70
+ the coverage report.
71
+
72
+ ## Changes and pull requests
73
+
74
+ - Agents must work on a branch other than `main`; never commit directly to `main`.
75
+ Check the current branch before editing or committing. If on `main` or a
76
+ detached HEAD, create a branch first:
77
+
78
+ ```bash
79
+ git branch --show-current # Check the current branch.
80
+ git switch -c fix/describe-change # Choose a descriptive branch name.
81
+ ```
82
+
83
+ - Preserve public API compatibility unless a breaking change is intentional.
84
+ - Follow existing code patterns, type annotations, and Sphinx docstrings.
85
+ - Add regression tests for fixes and tests for new behavior; update user documentation.
86
+ - Run relevant tests and checks; report anything skipped and why.
87
+ - Keep test coverage up and squash changes into one commit for submission.
88
+ - Use present-tense commit messages, such as `Fix cursor retry`.
89
+ - Explain what changed, why, and any compatibility impact in the pull request.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-arango
3
- Version: 8.3.5
3
+ Version: 8.3.6
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>
@@ -0,0 +1 @@
1
+ __version__ = "8.3.6"
@@ -94,7 +94,6 @@ Development
94
94
  .. toctree::
95
95
  :maxdepth: 1
96
96
 
97
- contributing
98
97
  specs
99
98
 
100
99
  .. _ArangoDB: https://www.arangodb.com
@@ -88,7 +88,7 @@ on fields ``_from`` and ``_to``. For more information on indexes, refer to
88
88
  },
89
89
  })
90
90
 
91
- # Index creation may succeed even if vector training fails.
91
+ # Index creation may succeed even if there is insufficient training data.
92
92
  if vector_index.get('trainingState') != 'ready':
93
93
  raise RuntimeError(
94
94
  vector_index.get('errorMessage', 'Vector index is not ready')
@@ -98,7 +98,10 @@ Omitted or scaling-object ``nLists``, ``numberOfDocsPerCentroid``, factory
98
98
  placeholders such as ``IVF{},Flat``, and successful-but-unusable creation
99
99
  behavior require ArangoDB 3.12.10 or later. A successful creation response
100
100
  means that the index exists, but callers should check ``trainingState`` before
101
- using it. If training fails permanently, the state is ``"unusable"`` and
102
- ``errorMessage`` describes the failure.
101
+ using it. If there is insufficient data to train the index, the state is
102
+ ``"unusable"`` and ``errorMessage`` describes the failure. Invalid index
103
+ definitions, such as an ``nLists`` value that disagrees with the number of
104
+ centroids in the factory string, are rejected during creation with
105
+ ``IndexCreateError`` and no index is created.
103
106
 
104
107
  See :ref:`StandardCollection` for API specification.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-arango
3
- Version: 8.3.5
3
+ Version: 8.3.6
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>
@@ -1,7 +1,7 @@
1
1
  .gitignore
2
2
  .pre-commit-config.yaml
3
3
  .readthedocs.yaml
4
- CONTRIBUTING.md
4
+ AGENTS.md
5
5
  LICENSE
6
6
  MANIFEST.in
7
7
  README.md
@@ -9,6 +9,7 @@ pyproject.toml
9
9
  setup.cfg
10
10
  setup.py
11
11
  starter.sh
12
+ todo.md
12
13
  .circleci/config.yml
13
14
  .github/workflows/codeql.yaml
14
15
  .github/workflows/docs.yaml
@@ -55,7 +56,6 @@ docs/cluster.rst
55
56
  docs/collection.rst
56
57
  docs/compression.rst
57
58
  docs/conf.py
58
- docs/contributing.rst
59
59
  docs/cursor.rst
60
60
  docs/database.rst
61
61
  docs/document.rst
@@ -7,7 +7,7 @@
7
7
  ".gitignore",
8
8
  ".pre-commit-config.yaml",
9
9
  ".readthedocs.yaml",
10
- "CONTRIBUTING.md",
10
+ "AGENTS.md",
11
11
  "LICENSE",
12
12
  "MANIFEST.in",
13
13
  "README.md",
@@ -53,7 +53,6 @@
53
53
  "docs/collection.rst",
54
54
  "docs/compression.rst",
55
55
  "docs/conf.py",
56
- "docs/contributing.rst",
57
56
  "docs/cursor.rst",
58
57
  "docs/database.rst",
59
58
  "docs/document.rst",
@@ -124,6 +123,7 @@
124
123
  "tests/test_transaction.py",
125
124
  "tests/test_user.py",
126
125
  "tests/test_view.py",
127
- "tests/test_wal.py"
126
+ "tests/test_wal.py",
127
+ "todo.md"
128
128
  ]
129
129
  }
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "8.3.6",
3
+ "distance": 0,
4
+ "node": "gc019d8643272db4621ffd7d20795a387618705a8",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-04"
8
+ }
@@ -4,15 +4,16 @@
4
4
  # Useful for testing the python-arango driver against a local ArangoDB setup.
5
5
 
6
6
  # Usage:
7
- # ./starter.sh [single|cluster] [community|enterprise|enterprise-preview] [version]
7
+ # ./starter.sh [single|cluster] [core-preview|enterprise|enterprise-preview] [version]
8
8
  # ./starter.sh [single|cluster] [image[:tag]]
9
9
  # Example:
10
10
  # ./starter.sh cluster enterprise 3.12.4
11
11
  # ./starter.sh single core-preview 4.0-nightly
12
12
  # ./starter.sh single arangodb/enterprise-preview:3.12-nightly
13
+ # Defaults: single server, enterprise image, latest version.
13
14
 
14
15
  setup="${1:-single}"
15
- image="${2:-community}"
16
+ image="${2:-enterprise}"
16
17
  version="${3:-latest}"
17
18
 
18
19
  extra_ports=""
@@ -35,14 +36,14 @@ if [[ "$image" == */* ]]; then
35
36
  else
36
37
  image_ref="$image:$version"
37
38
  fi
38
- elif [ "$image" == "community" ]; then
39
- image_ref="arangodb/arangodb:$version"
39
+ elif [ "$image" == "core-preview" ]; then
40
+ image_ref="arangodb/core-preview:$version"
40
41
  elif [ "$image" == "enterprise" ]; then
41
42
  image_ref="arangodb/enterprise:$version"
42
43
  elif [ "$image" == "enterprise-preview" ]; then
43
44
  image_ref="arangodb/enterprise-preview:$version"
44
45
  else
45
- echo "Invalid argument. Please provide 'community', 'enterprise', 'enterprise-preview', or a full image reference."
46
+ echo "Invalid argument. Please provide 'core-preview', 'enterprise', 'enterprise-preview', or a full image reference."
46
47
  exit 1
47
48
  fi
48
49
 
@@ -0,0 +1,397 @@
1
+ # Painpoints to address with the next major release
2
+
3
+ ## JWT authentication
4
+
5
+ The driver supports JWTs, but renewal is reactive, unsynchronized, and can fail for expired tokens. Application-managed
6
+ tokens can incorrectly enter credential-based refresh. Reliable renewal needs clearer authentication ownership, while
7
+ changing the Basic authentication default requires a migration path.
8
+
9
+ a. Define disabled, driver-managed, and application-managed authentication modes. Make JWT the default, allow an initial
10
+ JWT alongside credentials in driver-managed mode, and document migration.
11
+
12
+ b. Add proactive renewal with bounded retries and one acquisition shared by concurrent requests. Define renewal worker
13
+ ownership and cleanup.
14
+
15
+ c. Fix expired-token recovery and retry rejected requests once. Reuse newer tokens after delayed 401s, and never refresh
16
+ application-managed tokens using credentials.
17
+
18
+ d. Test expiration, concurrent renewal, failed acquisition, and application-managed replacement. Correct the expiry test
19
+ to update both the token and its recorded expiration.
20
+
21
+ e. Add `db.update_jwt(token)` for application-managed tokens, delegating to the connection's token replacement. Scope
22
+ updates to that authentication context, not the entire ArangoClient: separate database connections can use different
23
+ credentials. Make replacement safe during concurrent requests, without recreating connections or triggering renewal.
24
+ Subsequent requests through the database and its existing collection wrappers must use the replacement token;
25
+ requests already in progress may finish with the previous token. Other authentication contexts remain unaffected.
26
+
27
+ f. Keep renewal state per authentication context. Track contexts created by the client so `client.close()` stops all
28
+ associated renewal activity, including preventing in-progress renewals from scheduling new tasks after shutdown.
29
+
30
+ `alice_db.update_jwt(new_alice_token)` is a proposed public API; the current equivalent is
31
+ `alice_db.conn.set_token(new_alice_token)`. A separate `bob_db` connection remains unaffected, even when both were
32
+ created through the same client. The specification's "root instance" should therefore mean the authentication context
33
+ for this operation, rather than requiring a single client-wide token.
34
+
35
+ ## Concurrency
36
+
37
+ Using the driver across threads lacks clear guarantees around shared sessions, mutable connection state, and JWT
38
+ renewal. Both a shared ArangoClient and separate clients per thread should support parallel requests. Stateful cursors
39
+ also need explicit ownership rules to prevent overlapping fetches and inconsistent iteration.
40
+
41
+ a. Support both client usage patterns and document which database and collection wrappers can be shared. Define session
42
+ ownership without serializing all requests.
43
+
44
+ b. Make pool sizing and acquisition timeouts predictable. Verify and fix the suspected pool_timeout wiring issue, then
45
+ test pool exhaustion.
46
+
47
+ c. Synchronize shared resolver and JWT state, and define shutdown behavior during active requests. Keep separate clients
48
+ independent.
49
+
50
+ d. Support independent cursors for concurrent queries. Document each cursor as having one consumer, including iteration,
51
+ fetching, batch access, and closing.
52
+
53
+ e. Test both client usage patterns with overlapping requests, independent cursors, JWT renewal, and shutdown. Check for
54
+ deadlocks and blocked threads after failures.
55
+
56
+ ## API versioning
57
+
58
+ Versioned APIs can change accepted parameters, response fields, and endpoint behavior. Supporting them requires more
59
+ than changing URL prefixes: the driver must preserve existing Python calls while exposing incompatible contracts through
60
+ clear method signatures and accurate type hints.
61
+
62
+ a. Add optional API version selection to client.db(), retaining legacy behavior when omitted. Keep the selected policy
63
+ fixed on the connection and propagate it through cursors and execution contexts.
64
+
65
+ b. Group operation-specific request builders and response decoders into adapters selected by each version policy. Reuse
66
+ unchanged adapters and keep authentication, transport, and retries separate.
67
+
68
+ c. Preserve StandardCollection as the legacy interface. Share unchanged methods through a common base and introduce
69
+ sibling version-specific wrappers where signatures or result contracts differ.
70
+
71
+ d. Use Literal overloads to select typed database and collection wrappers, and TypedDict definitions for
72
+ version-specific results. Preserve missing legacy fields only when they can be derived accurately.
73
+
74
+ e. Validate version support and reject unsupported operations explicitly. Test legacy compatibility, version-specific
75
+ requests and results, type inference, and version propagation across execution contexts.
76
+
77
+ ### Examples
78
+
79
+ These sketches describe proposed interfaces, not current driver features. The index parameters and result fields are
80
+ hypothetical; omitted implementations use `...`.
81
+
82
+ Existing calls retain their behavior, while callers explicitly opt into a new contract:
83
+
84
+ ```python
85
+ legacy = client.db("example", **credentials)
86
+ modern = client.db("example", api_version="v1", **credentials)
87
+
88
+ legacy.collection("docs").index(foo="bar")
89
+ result = modern.collection("docs").index(foo={"bar": "bar"})
90
+ ```
91
+
92
+ Each policy groups adapters for its contract. Adapters build complete requests and decode successful responses;
93
+ existing response handlers retain operation-specific exceptions and use `_execute()` to preserve execution contexts.
94
+
95
+ ```python
96
+ legacy_policy = ApiPolicy(
97
+ indexes=LegacyIndexAdapter(),
98
+ aql=LegacyAqlAdapter(),
99
+ cursors=LegacyCursorAdapter(),
100
+ )
101
+ v1_policy = ApiPolicy(
102
+ indexes=V1IndexAdapter(),
103
+ aql=V1AqlAdapter(),
104
+ cursors=V1CursorAdapter(),
105
+ )
106
+
107
+ class V1IndexAdapter:
108
+ def build_create_request(self, collection, definition) -> Request:
109
+ ...
110
+
111
+ def decode_create_response(self, body) -> dict:
112
+ ...
113
+ ```
114
+
115
+ Unchanged public methods share a base implementation. Incompatible methods belong to sibling classes, with separate
116
+ parameter and result types. Here, StandardCollection retains the legacy role discussed as V0Collection.
117
+
118
+ ```python
119
+ from typing import TypedDict
120
+
121
+ from arango.api import ApiGroup
122
+ from arango.result import Result
123
+
124
+
125
+ class V1IndexOptions(TypedDict):
126
+ bar: str
127
+
128
+
129
+ class V0IndexResult(TypedDict):
130
+ id: str
131
+ legacy_field: str
132
+
133
+
134
+ class V1IndexResult(TypedDict):
135
+ id: str
136
+
137
+
138
+ class CommonCollection(ApiGroup):
139
+ def count(self) -> Result[int]:
140
+ ...
141
+
142
+
143
+ class StandardCollection(CommonCollection):
144
+ def index(self, *, foo: str) -> Result[V0IndexResult]:
145
+ ...
146
+
147
+
148
+ class V1Collection(CommonCollection):
149
+ def index(self, *, foo: V1IndexOptions) -> Result[V1IndexResult]:
150
+ ...
151
+ ```
152
+
153
+ Both collection classes inherit `count()`. Their `index()` implementations delegate to version-specific adapters;
154
+ V1Collection does not override StandardCollection with an incompatible signature. V1IndexResult has no legacy_field.
155
+
156
+ Overloads connect version selection to the returned wrapper type. This sketch abbreviates existing arguments;
157
+ the actual signatures must preserve them and append `api_version` as a keyword-only parameter.
158
+
159
+ ```python
160
+ from typing import Literal, overload
161
+
162
+
163
+ class ArangoClient:
164
+ @overload
165
+ def db(self, name: str, *, api_version: None = None) -> StandardDatabase: ...
166
+
167
+ @overload
168
+ def db(self, name: str, *, api_version: Literal["v1"]) -> V1Database: ...
169
+
170
+ def db(self, name: str, *, api_version: str | None = None):
171
+ ...
172
+ ```
173
+
174
+ StandardDatabase.collection() returns StandardCollection; V1Database.collection() returns V1Collection.
175
+ This lets type checkers reject a string passed to the v1 index method without widening both signatures to a union.
176
+
177
+ ## Types
178
+
179
+ Generic dictionaries and long parameter lists make driver APIs difficult to discover and check statically. Typed inputs,
180
+ results, and query configuration objects should provide clearer signatures and property access while preserving existing
181
+ dictionary operations, JSON serialization, and method calls.
182
+
183
+ a. Add dictionary-based input and result models with typed constructors and explicit properties. Keep dictionary storage
184
+ authoritative, preserve existing keys, and retain unknown fields where current behavior does.
185
+
186
+ b. Accept typed index definitions alongside existing dictionaries. Return models such as Result[ServerVersion], wrapping
187
+ existing formatted responses and preserving asynchronous and batch execution behavior.
188
+
189
+ c. Add a Query object accepted by AQL.execute() alongside the full existing signature. Normalize both forms through one
190
+ execution path without mutating reusable query configuration.
191
+
192
+ d. Describe both execute() forms with overloads and one runtime implementation. Capture extra arguments to reject mixed
193
+ configuration, preserving existing defaults and positional arguments for string calls.
194
+
195
+ e. Test dictionary operations, properties, JSON serialization, custom serializers, and both query forms. Document
196
+ mutation limits and use opt-in typed responses where exact dictionary types must remain compatible.
197
+
198
+ ### Examples
199
+
200
+ These are proposed interfaces and abbreviated implementation sketches. Models are instances passed to methods, not
201
+ classes. The earlier TypedDict examples describe schemas; dictionary subclasses additionally provide runtime accessors.
202
+
203
+ Typed index definitions supplement existing dictionary inputs. Request definitions and returned index descriptions
204
+ should use separate models because their required fields differ.
205
+
206
+ ```python
207
+ collection.add_index(VectorIndex(fields=["embedding"], params=vector_params))
208
+ collection.add_index(InvertedIndex(fields=["title"]))
209
+ collection.add_index({"type": "inverted", "fields": ["title"]})
210
+ ```
211
+
212
+ A response model keeps property and dictionary access consistent, without storing a second copy of each value:
213
+
214
+ ```python
215
+ import json
216
+ from typing import Any, cast
217
+
218
+
219
+ class ServerVersion(dict[str, Any]):
220
+ @property
221
+ def version(self) -> str:
222
+ return cast(str, self["version"])
223
+
224
+ @version.setter
225
+ def version(self, value: str) -> None:
226
+ self["version"] = value
227
+
228
+
229
+ result = ServerVersion(version="3.12.11", server="arango")
230
+ assert result.version == result["version"]
231
+ result.version = "3.12.12"
232
+ assert result["version"] == "3.12.12"
233
+ plain = dict(result)
234
+ encoded = json.dumps(result)
235
+ ```
236
+
237
+ server_version() would return Result[ServerVersion], wrapping format_body(resp.body) in ServerVersion on success.
238
+ Keep existing formatting before wrapping; version adapters select different models when needed.
239
+
240
+ dict(result) makes a shallow copy. Nested values must also be JSON-compatible; a recursive to_dict() can provide plain
241
+ nested dictionaries if required. Unknown keys remain accessible through dictionary syntax.
242
+
243
+ Dictionary subclasses pass isinstance(result, dict), but not type(result) is dict. Custom serializers need compatibility
244
+ checks. Explicit properties avoid collisions with dictionary methods such as items() and keys().
245
+
246
+ cast() provides a static hint, not runtime validation. Direct dictionary mutation can still introduce invalid values or
247
+ remove required fields. Validate typed constructors or provide explicit validation without restricting legacy dictionary
248
+ operations; optional accessors should not insert absent fields into the response.
249
+
250
+ A Query object groups the text, bind variables, and execution options without replacing the existing call form:
251
+
252
+ ```python
253
+ text = "FOR doc IN documents FILTER doc.active == @active RETURN doc"
254
+
255
+ cursor = db.aql.execute(text, bind_vars={"active": True}, batch_size=100)
256
+
257
+ query = Query(text=text, bind_vars={"active": True}, batch_size=100)
258
+ cursor = db.aql.execute(query=query)
259
+ ```
260
+
261
+ Overloads describe the accepted forms to type checkers. One implementation dispatches on the query type; two ordinary
262
+ execute() definitions would replace one another. This sketch shows only count and batch_size; retain all existing
263
+ parameters in the actual string overload and the helper handling legacy calls.
264
+
265
+ ```python
266
+ from typing import overload
267
+
268
+
269
+ class AQL:
270
+ @overload
271
+ def execute(self, query: Query) -> Result[Cursor]: ...
272
+
273
+ @overload
274
+ def execute(
275
+ self, query: str, count: bool = False, batch_size: int | None = None
276
+ ) -> Result[Cursor]: ...
277
+
278
+ def execute(self, query: str | Query, *args, **kwargs) -> Result[Cursor]:
279
+ if isinstance(query, Query):
280
+ if args or kwargs:
281
+ raise TypeError("A Query object cannot be combined with other arguments")
282
+ return self._execute_query(query)
283
+ return self._execute_legacy(query, *args, **kwargs)
284
+ ```
285
+
286
+ The _execute_legacy() helper retains the full existing signature and defaults, then normalizes its arguments into the
287
+ same execution path as _execute_query(). Capturing arguments before defaults are applied distinguishes every explicit
288
+ extra argument, including None and False, without sentinels.
289
+
290
+ ```python
291
+ db.aql.execute(query) # Accepted.
292
+ db.aql.execute(query=query) # Accepted.
293
+ db.aql.execute(query, batch_size=None) # TypeError: explicit extra keyword argument.
294
+ db.aql.execute(query, False) # TypeError: explicit extra positional argument.
295
+ ```
296
+
297
+ The existing Sphinx autodoc configuration rendered both overloads, including their defaults and type hints, in a
298
+ temporary build with Sphinx 8.2.3. No additional extension or configuration was needed. Keep overloads complete for IDEs
299
+ and generated API documentation; documentation dependencies currently do not pin Sphinx.
300
+
301
+ Runtime inspect.signature() still exposes (self, query, *args, **kwargs). Overloads improve static tooling and this
302
+ project's generated documentation, but do not change runtime argument binding or enforce the mixed-argument rule.
303
+
304
+ The shared execution path must preserve more than the JSON body: allow_dirty_read controls a request header, while
305
+ allow_retry also configures the returned cursor. Keep cursor state separate and snapshot mutable query configuration
306
+ as needed so executing a Query does not change it.
307
+
308
+ ## Response format
309
+
310
+ Response formatting inconsistently renames keys, drops unknown fields, and changes values such as index identifiers.
311
+ Disabling formatting does not reliably preserve server data. Responses need predictable dictionary representations and
312
+ stable snake_case properties, with a compatibility mode for applications relying on historical transformations.
313
+
314
+ a. Add fixed server and legacy response formats per database wrapper, independently of API version. Make server the
315
+ next major release's default and retain legacy indefinitely.
316
+
317
+ b. Preserve server resource keys, values, and unknown fields in server mode. Isolate historical transformations in
318
+ legacy adapters; define unchanged server names for new fields without historical mappings.
319
+
320
+ c. Implement response models as dict subclasses with explicit snake_case properties. Store only the selected
321
+ representation, and use sibling legacy implementations where property mappings differ.
322
+
323
+ d. Separate envelope extraction from resource formatting. Avoid mutating input dictionaries or renaming user data;
324
+ document copying, optional properties, and value differences between representations.
325
+
326
+ e. Audit formatter.py and inline cursor transformations. Test both formats, property synchronization, serialization, and
327
+ execution contexts; document migration, existing formatter options, and exact-dict compatibility limits.
328
+
329
+ ### Examples
330
+
331
+ These are proposed interfaces. Select the format once; collections, cursors, and asynchronous or batch results inherit
332
+ that selection. API version and response format remain independent choices.
333
+
334
+ ```python
335
+ modern = client.db("example", response_format="server", **credentials)
336
+ legacy = client.db("example", response_format="legacy", **credentials)
337
+ ```
338
+
339
+ Both representations offer the same snake_case property names. Dictionary access and JSON serialization use the selected
340
+ keys, without storing duplicate aliases. This simplified model illustrates a required field of a TTL index:
341
+
342
+ ```python
343
+ import json
344
+ from typing import Any, ClassVar, cast
345
+
346
+
347
+ class IndexInfo(dict[str, Any]):
348
+ _expiry_key: ClassVar[str] = "expireAfter"
349
+
350
+ @property
351
+ def expire_after(self) -> int:
352
+ return cast(int, self[self._expiry_key])
353
+
354
+ @expire_after.setter
355
+ def expire_after(self, value: int) -> None:
356
+ self[self._expiry_key] = value
357
+
358
+
359
+ class LegacyIndexInfo(IndexInfo):
360
+ _expiry_key = "expiry_time"
361
+
362
+
363
+ server = IndexInfo({"expireAfter": 60})
364
+ legacy = LegacyIndexInfo({"expiry_time": 60})
365
+ assert server.expire_after == legacy.expire_after
366
+
367
+ legacy.expire_after = 120
368
+ assert legacy["expiry_time"] == 120
369
+ assert dict(server) == {"expireAfter": 60}
370
+ assert json.loads(json.dumps(legacy)) == {"expiry_time": 120}
371
+ ```
372
+
373
+ The response adapter prepares the selected representation and constructs its model. Actual models must reflect the
374
+ field's numeric range and optionality. Properties read dictionary storage directly, including changes made through
375
+ update() or item assignment; unrestricted dictionary mutation still cannot guarantee valid field types.
376
+
377
+ Keep legacy value and structure conversions explicit: shortening an index ID is not a key alias. Document whether
378
+ properties expose the selected stored value or a separately derived value. Do not reconstruct lost information from
379
+ legacy data or retain a second mutable dictionary that can drift out of sync.
380
+
381
+ Use the async driver's JsonWrapper properties as a reference, but inherit standard dictionary behavior instead of
382
+ reimplementing it. Its current wrapper lacks several dictionary methods, cannot be serialized directly by json.dumps(),
383
+ mutates constructor input, and exposes internal storage through to_dict().
384
+
385
+ Copy input mappings during construction. dict(model) and a basic to_dict() should return shallow copies; document nested
386
+ sharing or provide explicit recursive conversion. Envelope removal belongs in endpoint response handling, not the model
387
+ base class. Never apply generic recursive key conversion to documents, bind variables, or user-defined names.
388
+
389
+ Retaining legacy indefinitely requires permanent compatibility tests. Freeze historical mappings and document handling
390
+ of new fields; preserve existing formatter options in legacy mode and reject conflicting options in server mode.
391
+ Dictionary subclasses preserve isinstance(result, dict), but change type(result) is dict; include this and custom
392
+ serializer compatibility in the major-release migration notes.
393
+
394
+
395
+ ## Documentation tests
396
+
397
+ This could be done better, especially for the async driver.
@@ -1,40 +0,0 @@
1
- name: Upload to PyPI
2
-
3
- on:
4
- release:
5
- types: [published]
6
-
7
- jobs:
8
- upload:
9
- runs-on: ubuntu-latest
10
-
11
- steps:
12
- - name: Checkout repository
13
- uses: actions/checkout@v7
14
- with:
15
- fetch-depth: 0
16
- fetch-tags: true
17
-
18
- - uses: actions/setup-python@v7
19
- with:
20
- python-version: "3.12"
21
-
22
- - name: Install dependencies
23
- run: |
24
- python -m pip install --upgrade pip
25
- pip install build twine
26
-
27
- - name: Build distribution
28
- run: python -m build
29
-
30
- - name: Publish to PyPI Test
31
- env:
32
- TWINE_USERNAME: __token__
33
- TWINE_PASSWORD: ${{ secrets.PYPI_TEST_TOKEN }}
34
- run: twine upload --verbose --repository testpypi dist/*
35
-
36
- - name: Publish to PyPI
37
- env:
38
- TWINE_USERNAME: __token__
39
- TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
40
- run: twine upload --verbose --repository pypi dist/*
@@ -1,28 +0,0 @@
1
- # Contributing
2
-
3
- Set up dev environment:
4
- ```shell
5
- cd ~/your/repository/fork # Activate venv if you have one (recommended)
6
- pip install -e .[dev] # Install dev dependencies (e.g. black, mypy, pre-commit)
7
- pre-commit install # Install git pre-commit hooks
8
- ```
9
-
10
- Run unit tests with coverage:
11
-
12
- ```shell
13
- pytest --cov=arango --cov-report=html # Open htmlcov/index.html in your browser
14
- ```
15
-
16
- To start and ArangoDB instance locally, run:
17
-
18
- ```shell
19
- ./starter.sh # Requires docker
20
- ```
21
-
22
- Build and test documentation:
23
-
24
- ```shell
25
- python -m sphinx docs docs/_build # Open docs/_build/index.html in your browser
26
- ```
27
-
28
- Thank you for your contribution!
@@ -1 +0,0 @@
1
- __version__ = "8.3.5"
@@ -1,99 +0,0 @@
1
- Contributing
2
- ------------
3
-
4
- Requirements
5
- ============
6
-
7
- Before submitting a pull request on GitHub_, please make sure you meet the
8
- following requirements:
9
-
10
- * The pull request points to main_ branch.
11
- * Changes are squashed into a single commit. I like to use git rebase for this.
12
- * Commit message is in present tense. For example, "Fix bug" is good while
13
- "Fixed bug" is not.
14
- * Sphinx_-compatible docstrings.
15
- * PEP8_ compliance.
16
- * No missing docstrings or commented-out lines.
17
- * Test coverage remains at %100. If a piece of code is trivial and does not
18
- need unit tests, use this_ to exclude it from coverage.
19
- * No build failures. Builds automatically trigger on pull
20
- request submissions.
21
- * Documentation is kept up-to-date with the new changes (see below).
22
-
23
- .. warning::
24
- The dev branch is occasionally rebased, and its commit history may be
25
- overwritten in the process. Before you begin your feature work, git fetch
26
- or pull to ensure that your local branch has not diverged. If you see git
27
- conflicts and want to start with a clean slate, run the following commands:
28
-
29
- .. code-block:: bash
30
-
31
- ~$ git checkout dev
32
- ~$ git fetch origin
33
- ~$ git reset --hard origin/dev # THIS WILL WIPE ALL LOCAL CHANGES
34
-
35
- Style
36
- =====
37
-
38
- To ensure PEP8_ compliance, run flake8_:
39
-
40
- .. code-block:: bash
41
-
42
- ~$ pip install flake8
43
- ~$ git clone https://github.com/arangodb/python-arango.git
44
- ~$ cd python-arango
45
- ~$ flake8
46
-
47
- If there is a good reason to ignore a warning, see here_ on how to exclude it.
48
-
49
- Testing
50
- =======
51
-
52
- To test your changes, you can run the integration test suite that comes with
53
- **python-arango**. It uses pytest_ and requires an actual ArangoDB instance.
54
-
55
- To run the test suite (use your own host, port and root password):
56
-
57
- .. code-block:: bash
58
-
59
- ~$ pip install pytest
60
- ~$ git clone https://github.com/arangodb/python-arango.git
61
- ~$ cd python-arango
62
- ~$ pytest --cluster --host=127.0.0.1 --port=8529 --password=passwd
63
-
64
- To run the test suite with coverage report:
65
-
66
- .. code-block:: bash
67
-
68
- ~$ pip install coverage pytest pytest-cov
69
- ~$ git clone https://github.com/arangodb/python-arango.git
70
- ~$ cd python-arango
71
- ~$ pytest --cluster --host=127.0.0.1 --port=8529 --password=passwd --cov=kq
72
-
73
- As the test suite creates real databases and jobs, it should only be run in
74
- development environments.
75
-
76
- Documentation
77
- =============
78
-
79
- The documentation including the README is written in reStructuredText_ and uses
80
- Sphinx_. To build an HTML version on your local machine:
81
-
82
- .. code-block:: bash
83
-
84
- ~$ pip install sphinx sphinx_rtd_theme
85
- ~$ git clone https://github.com/arangodb/python-arango.git
86
- ~$ cd python-arango
87
- ~$ python -m sphinx -b html -W docs docs/_build/ # Open build/index.html in a browser
88
-
89
- As always, thank you for your contribution!
90
-
91
- .. _main: https://github.com/arangodb/python-arango/tree/main
92
- .. _GitHub: https://github.com/arangodb/python-arango
93
- .. _PEP8: https://www.python.org/dev/peps/pep-0008/
94
- .. _this: http://coverage.readthedocs.io/en/latest/excluding.html
95
- .. _Sphinx: https://github.com/sphinx-doc/sphinx
96
- .. _flake8: http://flake8.pycqa.org
97
- .. _here: http://flake8.pycqa.org/en/latest/user/violations.html#in-line-ignoring-errors
98
- .. _pytest: https://github.com/pytest-dev/pytest
99
- .. _reStructuredText: https://en.wikipedia.org/wiki/ReStructuredText
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "8.3.5",
3
- "distance": 0,
4
- "node": "ga90d0b72830ee6a7db388833e77110a53fe59708",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-08-31"
8
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes