polygres-sdk 0.2.0__tar.gz → 0.3.0__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.
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/CONTRIBUTING.md +8 -5
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/PKG-INFO +28 -4
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/README.md +26 -2
- polygres_sdk-0.3.0/compatibility/0.2.1/README.md +8 -0
- {polygres_sdk-0.2.0/src/polygres/spec → polygres_sdk-0.3.0/compatibility/0.2.1}/python-sdk-v1.methods.json +24 -5
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/docs/reference-v1.md +49 -1
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/pyproject.toml +1 -1
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/__init__.py +8 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/auth/enums.py +2 -0
- polygres_sdk-0.3.0/src/polygres/_vendor/polygres_lib/auth/errors.py +230 -0
- polygres_sdk-0.3.0/src/polygres/_vendor/polygres_lib/context/errors.py +103 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/context/models.py +3 -3
- polygres_sdk-0.3.0/src/polygres/_vendor/polygres_lib/errors/__init__.py +27 -0
- polygres_sdk-0.3.0/src/polygres/_vendor/polygres_lib/errors/catalog.py +205 -0
- polygres_sdk-0.3.0/src/polygres/_vendor/polygres_lib/errors/generated.py +9385 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/client.py +57 -5
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/context.py +110 -2
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/context_wait.py +23 -14
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/errors.py +15 -32
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/models.py +101 -0
- polygres_sdk-0.3.0/src/polygres/rows.py +384 -0
- polygres_sdk-0.3.0/src/polygres/spec/python-sdk-v1.methods.json +4892 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/spec/runtime-v1.openapi.json +3805 -2057
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/version_notices.py +72 -0
- polygres_sdk-0.3.0/tests/conftest.py +11 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tests/fixtures/context/contract-fixtures.json +20 -15
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tests/test_client.py +32 -4
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tests/test_context.py +208 -13
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tests/test_method_spec.py +2 -2
- polygres_sdk-0.3.0/tests/test_release_workflow.py +95 -0
- polygres_sdk-0.3.0/tests/test_rows.py +279 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tests/test_version.py +6 -6
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tests/test_version_notices.py +60 -7
- polygres_sdk-0.3.0/tools/extract_release_notes.py +57 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tools/generate_sdk_method_spec.py +14 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tools/runtime_operation_exclusions.json +12 -0
- polygres_sdk-0.2.0/src/polygres/_vendor/polygres_lib/auth/errors.py +0 -895
- polygres_sdk-0.2.0/src/polygres/_vendor/polygres_lib/context/errors.py +0 -266
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/.gitignore +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/LICENSE +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/compatibility/0.1.0/README.md +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/compatibility/0.1.0/python-sdk-v1.methods.json +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/migrations/README.md +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/migrations/vector-configuration-creation.md +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_api_version.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_method_metadata.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/__init__.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/__init__.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/api_versions.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/auth/__init__.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/auth/api_keys.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/auth/models.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/auth/ports.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/auth/principals.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/auth/records.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/auth/types.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/context/__init__.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/context/enums.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/context/validation.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/core/__init__.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/core/models.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_vendor/polygres_lib/core/types.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/_version.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/context_models.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/context_validation.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/py.typed +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/spec/__init__.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/src/polygres/spec/python-sdk-v1.methods.schema.json +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tests/test_compatibility.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tests/test_packaged_resources.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tools/check_sdk_compatibility.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tools/generate_runtime_openapi_snapshot.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tools/run_context_live_test.sh +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tools/test_context_live.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tools/verify_distribution.py +0 -0
- {polygres_sdk-0.2.0 → polygres_sdk-0.3.0}/tools/verify_release_version.py +0 -0
|
@@ -23,7 +23,7 @@ python tools/generate_runtime_openapi_snapshot.py --check
|
|
|
23
23
|
python tools/generate_sdk_method_spec.py --check
|
|
24
24
|
python tools/generate_sdk_method_spec.py --validate-only
|
|
25
25
|
python tools/check_sdk_compatibility.py \
|
|
26
|
-
--baseline compatibility/0.1
|
|
26
|
+
--baseline compatibility/0.2.1/python-sdk-v1.methods.json
|
|
27
27
|
python -m build
|
|
28
28
|
python tools/verify_distribution.py dist/*.whl dist/*.tar.gz
|
|
29
29
|
```
|
|
@@ -60,7 +60,7 @@ Release rehearsal happens first on TestPyPI:
|
|
|
60
60
|
/tmp/polygres-sdk-testpypi/bin/python -m pip install \
|
|
61
61
|
--index-url https://test.pypi.org/simple/ \
|
|
62
62
|
--extra-index-url https://pypi.org/simple/ \
|
|
63
|
-
polygres-sdk==0.
|
|
63
|
+
polygres-sdk==0.3.0
|
|
64
64
|
/tmp/polygres-sdk-testpypi/bin/python - <<'PY'
|
|
65
65
|
import importlib.metadata
|
|
66
66
|
from polygres import Polygres
|
|
@@ -74,12 +74,15 @@ Publish to PyPI only after the same commit has passed TestPyPI validation. Push
|
|
|
74
74
|
a release tag from the public repository:
|
|
75
75
|
|
|
76
76
|
```bash
|
|
77
|
-
git tag polygres-sdk-v0.
|
|
78
|
-
git push origin polygres-sdk-v0.
|
|
77
|
+
git tag polygres-sdk-v0.3.0
|
|
78
|
+
git push origin polygres-sdk-v0.3.0
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
The `pypi` GitHub environment must be approved before the upload proceeds.
|
|
82
|
-
|
|
82
|
+
After PyPI accepts the package, the workflow creates the matching GitHub
|
|
83
|
+
Release from the version's changelog entry and attaches the wheel and source
|
|
84
|
+
distribution. Project URLs in `pyproject.toml` must use valid HTTPS URLs
|
|
85
|
+
accepted by PyPI.
|
|
83
86
|
|
|
84
87
|
## Scope
|
|
85
88
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: polygres-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Python SDK for Polygres
|
|
5
5
|
Project-URL: Homepage, https://polygres.com
|
|
6
6
|
Project-URL: Documentation, https://docs.polygres.com/sdk
|
|
@@ -285,13 +285,37 @@ print(connection.direct_url_without_password)
|
|
|
285
285
|
|
|
286
286
|
Use a PostgreSQL driver such as psycopg or SQLAlchemy when your application needs a database connection. The Polygres SDK is an HTTP retrieval client and does not bundle a PostgreSQL driver.
|
|
287
287
|
|
|
288
|
+
## Single-row writes
|
|
289
|
+
|
|
290
|
+
Use `project.rows` for one JSON-native row. Context reconciliation is explicit:
|
|
291
|
+
omit both Context options for a generic table, or select one collection so the
|
|
292
|
+
same operation writes the row and creates its pgContext point.
|
|
293
|
+
|
|
294
|
+
```python
|
|
295
|
+
result = project.rows.upsert(
|
|
296
|
+
schema="public",
|
|
297
|
+
table="memories",
|
|
298
|
+
row={"id": "memory_123", "content": "Remember the deployment window."},
|
|
299
|
+
conflict_columns=["id"],
|
|
300
|
+
returning=["id"],
|
|
301
|
+
context_collection_id="2e172638-bd77-4a2c-bc42-406f4f2938d7",
|
|
302
|
+
idempotency_key="memory-123-v1",
|
|
303
|
+
wait_for_context=True,
|
|
304
|
+
)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
UUIDs and timestamps are JSON strings. Arrays and vectors are JSON arrays.
|
|
308
|
+
Never automatically retry a row-only write after a timeout; its outcome may be
|
|
309
|
+
ambiguous. A Context-backed request may be resumed only with the exact same
|
|
310
|
+
payload and idempotency key.
|
|
311
|
+
|
|
288
312
|
## Version and support
|
|
289
313
|
|
|
290
|
-
Package version: [`0.
|
|
314
|
+
Package version: [`0.3.0`](https://github.com/Evokoa/polygres-sdk/releases/tag/polygres-sdk-v0.3.0).
|
|
291
315
|
|
|
292
316
|
When contacting support, include the installed SDK version and the request ID.
|
|
293
317
|
|
|
294
|
-
See the [SDK 0.
|
|
318
|
+
See the [SDK 0.3.0 release notes](https://github.com/Evokoa/polygres-sdk/releases/tag/polygres-sdk-v0.3.0) for release changes.
|
|
295
319
|
|
|
296
320
|
## Optional Agent Skill
|
|
297
321
|
|
|
@@ -243,13 +243,37 @@ print(connection.direct_url_without_password)
|
|
|
243
243
|
|
|
244
244
|
Use a PostgreSQL driver such as psycopg or SQLAlchemy when your application needs a database connection. The Polygres SDK is an HTTP retrieval client and does not bundle a PostgreSQL driver.
|
|
245
245
|
|
|
246
|
+
## Single-row writes
|
|
247
|
+
|
|
248
|
+
Use `project.rows` for one JSON-native row. Context reconciliation is explicit:
|
|
249
|
+
omit both Context options for a generic table, or select one collection so the
|
|
250
|
+
same operation writes the row and creates its pgContext point.
|
|
251
|
+
|
|
252
|
+
```python
|
|
253
|
+
result = project.rows.upsert(
|
|
254
|
+
schema="public",
|
|
255
|
+
table="memories",
|
|
256
|
+
row={"id": "memory_123", "content": "Remember the deployment window."},
|
|
257
|
+
conflict_columns=["id"],
|
|
258
|
+
returning=["id"],
|
|
259
|
+
context_collection_id="2e172638-bd77-4a2c-bc42-406f4f2938d7",
|
|
260
|
+
idempotency_key="memory-123-v1",
|
|
261
|
+
wait_for_context=True,
|
|
262
|
+
)
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
UUIDs and timestamps are JSON strings. Arrays and vectors are JSON arrays.
|
|
266
|
+
Never automatically retry a row-only write after a timeout; its outcome may be
|
|
267
|
+
ambiguous. A Context-backed request may be resumed only with the exact same
|
|
268
|
+
payload and idempotency key.
|
|
269
|
+
|
|
246
270
|
## Version and support
|
|
247
271
|
|
|
248
|
-
Package version: [`0.
|
|
272
|
+
Package version: [`0.3.0`](https://github.com/Evokoa/polygres-sdk/releases/tag/polygres-sdk-v0.3.0).
|
|
249
273
|
|
|
250
274
|
When contacting support, include the installed SDK version and the request ID.
|
|
251
275
|
|
|
252
|
-
See the [SDK 0.
|
|
276
|
+
See the [SDK 0.3.0 release notes](https://github.com/Evokoa/polygres-sdk/releases/tag/polygres-sdk-v0.3.0) for release changes.
|
|
253
277
|
|
|
254
278
|
## Optional Agent Skill
|
|
255
279
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# SDK compatibility baseline 0.2.1
|
|
2
|
+
|
|
3
|
+
`python-sdk-v1.methods.json` is the explicit released 0.2.1 public network
|
|
4
|
+
surface used by CI and release checks for 0.3.0. It is copied byte-for-byte
|
|
5
|
+
from the generated method contract at the 0.2.1 release boundary.
|
|
6
|
+
|
|
7
|
+
Release automation must name this file with `--baseline`; the compatibility
|
|
8
|
+
tool refuses to infer a baseline from an arbitrary local artifact.
|
|
@@ -178,6 +178,14 @@
|
|
|
178
178
|
"reason": "Readiness checks are operational endpoints; the SDK uses retrieval readiness instead.",
|
|
179
179
|
"review_date": "2027-02-04"
|
|
180
180
|
},
|
|
181
|
+
{
|
|
182
|
+
"method": "POST",
|
|
183
|
+
"operation_id": "reindex_text_configuration_v1_text_configurations__config_id__reindex_post",
|
|
184
|
+
"owner": "Runtime Platform",
|
|
185
|
+
"path": "/v1/text/configurations/{config_id}/reindex",
|
|
186
|
+
"reason": "Text reindexing is a setup operation managed outside the retrieval SDK.",
|
|
187
|
+
"review_date": "2027-02-04"
|
|
188
|
+
},
|
|
181
189
|
{
|
|
182
190
|
"method": "POST",
|
|
183
191
|
"operation_id": "reindex_vector_configuration_v1_vector_configurations__config_id__reindex_post",
|
|
@@ -201,6 +209,14 @@
|
|
|
201
209
|
"path": "/v1/vector/configurations/{config_id}/compatibility-engine/{target_engine}",
|
|
202
210
|
"reason": "Per-configuration compatibility engine selection is an operator rollback control, not an application retrieval method.",
|
|
203
211
|
"review_date": "2027-02-04"
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
"method": "GET",
|
|
215
|
+
"operation_id": "text_configuration_diagnostics_v1_text_configurations__config_id__diagnostics_get",
|
|
216
|
+
"owner": "Runtime Platform",
|
|
217
|
+
"path": "/v1/text/configurations/{config_id}/diagnostics",
|
|
218
|
+
"reason": "Text index diagnostics are managed through the dashboard and control-plane workflow.",
|
|
219
|
+
"review_date": "2027-02-04"
|
|
204
220
|
}
|
|
205
221
|
],
|
|
206
222
|
"methods": [
|
|
@@ -3637,7 +3653,8 @@
|
|
|
3637
3653
|
"limit",
|
|
3638
3654
|
"max_depth",
|
|
3639
3655
|
"relationship_types",
|
|
3640
|
-
"start"
|
|
3656
|
+
"start",
|
|
3657
|
+
"target_table"
|
|
3641
3658
|
],
|
|
3642
3659
|
"required_fields": [
|
|
3643
3660
|
"start"
|
|
@@ -3707,7 +3724,8 @@
|
|
|
3707
3724
|
"limit",
|
|
3708
3725
|
"max_depth",
|
|
3709
3726
|
"relationship_types",
|
|
3710
|
-
"start"
|
|
3727
|
+
"start",
|
|
3728
|
+
"target_table"
|
|
3711
3729
|
],
|
|
3712
3730
|
"required_fields": [
|
|
3713
3731
|
"start"
|
|
@@ -3846,7 +3864,8 @@
|
|
|
3846
3864
|
"limit",
|
|
3847
3865
|
"max_depth",
|
|
3848
3866
|
"relationship_types",
|
|
3849
|
-
"start"
|
|
3867
|
+
"start",
|
|
3868
|
+
"target_table"
|
|
3850
3869
|
],
|
|
3851
3870
|
"required_fields": [
|
|
3852
3871
|
"start"
|
|
@@ -4438,8 +4457,8 @@
|
|
|
4438
4457
|
"stability": "stable"
|
|
4439
4458
|
}
|
|
4440
4459
|
],
|
|
4441
|
-
"openapi_sha256": "
|
|
4460
|
+
"openapi_sha256": "7dac7258e9dd8e7c92019025effee85ec71a19bca98154d20d7c00f7d8450f8a",
|
|
4442
4461
|
"schema_version": 1,
|
|
4443
4462
|
"sdk": "polygres-sdk",
|
|
4444
|
-
"sdk_version": "0.2.
|
|
4463
|
+
"sdk_version": "0.2.1"
|
|
4445
4464
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
This file is generated. Edit Python method metadata, docstrings, or the Runtime OpenAPI contract instead.
|
|
4
4
|
|
|
5
|
-
- SDK package version: `0.
|
|
5
|
+
- SDK package version: `0.3.0`
|
|
6
6
|
- HTTP API family: `v1`
|
|
7
7
|
- Default API behavior version: `2026-08-04`
|
|
8
8
|
- Method specification schema: `1`
|
|
@@ -190,6 +190,13 @@ Return pgContext capabilities for this Runtime.
|
|
|
190
190
|
capabilities = project.context.get_capabilities()
|
|
191
191
|
```
|
|
192
192
|
|
|
193
|
+
Context retrieval methods fetch this response lazily on their first call and
|
|
194
|
+
cache it on the project Context namespace. They validate the requested mode,
|
|
195
|
+
dimensions, result and candidate limits, graph depth, and relationship-type
|
|
196
|
+
count before sending the retrieval request. Calling `get_capabilities()`
|
|
197
|
+
explicitly refreshes the cache. Cached capabilities expire after 60 seconds,
|
|
198
|
+
and an unavailable capability is refreshed on the next attempted call.
|
|
199
|
+
|
|
193
200
|
### `project.context.get_collection()`
|
|
194
201
|
|
|
195
202
|
Return one Context collection by UUID.
|
|
@@ -496,6 +503,47 @@ Run vector-first hybrid retrieval.
|
|
|
496
503
|
page = project.hybrid.vector_first(embedding)
|
|
497
504
|
```
|
|
498
505
|
|
|
506
|
+
## `project.rows`
|
|
507
|
+
|
|
508
|
+
| SDK method | HTTP operation | Since | Retry | Pagination | Deprecated |
|
|
509
|
+
| --- | --- | --- | --- | --- | --- |
|
|
510
|
+
| `project.rows.ignore()` | `POST /v1/tables/{schema_name}/{table_name}/rows` (`runtime_write_row`) | `0.3.0` | `none` | `none` | No |
|
|
511
|
+
| `project.rows.insert()` | `POST /v1/tables/{schema_name}/{table_name}/rows` (`runtime_write_row`) | `0.3.0` | `none` | `none` | No |
|
|
512
|
+
| `project.rows.upsert()` | `POST /v1/tables/{schema_name}/{table_name}/rows` (`runtime_write_row`) | `0.3.0` | `none` | `none` | No |
|
|
513
|
+
| `project.rows.validate()` | `POST /v1/tables/{schema_name}/{table_name}/rows/validate` (`runtime_validate_row_write`) | `0.3.0` | `read_only_post` | `none` | No |
|
|
514
|
+
|
|
515
|
+
### `project.rows.ignore()`
|
|
516
|
+
|
|
517
|
+
Insert one row and ignore a matching primary or unique conflict.
|
|
518
|
+
|
|
519
|
+
```python
|
|
520
|
+
result = project.rows.ignore(schema="public", table="events", row={"id": "1"}, conflict_columns=["id"])
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### `project.rows.insert()`
|
|
524
|
+
|
|
525
|
+
Insert one row into an eligible project-owned table.
|
|
526
|
+
|
|
527
|
+
```python
|
|
528
|
+
result = project.rows.insert(schema="public", table="events", row={"id": "1"})
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
### `project.rows.upsert()`
|
|
532
|
+
|
|
533
|
+
Upsert one row through a primary or unique constraint.
|
|
534
|
+
|
|
535
|
+
```python
|
|
536
|
+
result = project.rows.upsert(schema="public", table="events", row={"id": "1"}, conflict_columns=["id"])
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
### `project.rows.validate()`
|
|
540
|
+
|
|
541
|
+
Validate a single-row write without executing it.
|
|
542
|
+
|
|
543
|
+
```python
|
|
544
|
+
validation = project.rows.validate(schema="public", table="events", row={"id": "1"})
|
|
545
|
+
```
|
|
546
|
+
|
|
499
547
|
## `project.text`
|
|
500
548
|
|
|
501
549
|
| SDK method | HTTP operation | Since | Retry | Pagination | Deprecated |
|
|
@@ -3,6 +3,7 @@ from polygres.client import Polygres
|
|
|
3
3
|
from polygres.context_models import * # noqa: F403
|
|
4
4
|
from polygres.context_models import __all__ as _context_model_exports
|
|
5
5
|
from polygres.errors import (
|
|
6
|
+
PolygresAmbiguousWriteError,
|
|
6
7
|
PolygresAPIError,
|
|
7
8
|
PolygresAuthError,
|
|
8
9
|
PolygresError,
|
|
@@ -23,6 +24,9 @@ from polygres.models import (
|
|
|
23
24
|
HybridResult,
|
|
24
25
|
Page,
|
|
25
26
|
RetrievalReadiness,
|
|
27
|
+
RowContextReconciliationResult,
|
|
28
|
+
RowWriteResult,
|
|
29
|
+
RowWriteValidation,
|
|
26
30
|
TextResult,
|
|
27
31
|
VectorResult,
|
|
28
32
|
)
|
|
@@ -39,6 +43,7 @@ __all__ = [
|
|
|
39
43
|
"Page",
|
|
40
44
|
"Polygres",
|
|
41
45
|
"PolygresAPIError",
|
|
46
|
+
"PolygresAmbiguousWriteError",
|
|
42
47
|
"PolygresAuthError",
|
|
43
48
|
"PolygresError",
|
|
44
49
|
"PolygresMaintenanceError",
|
|
@@ -50,6 +55,9 @@ __all__ = [
|
|
|
50
55
|
"PolygresVersionNotice",
|
|
51
56
|
"PolygresVersionWarning",
|
|
52
57
|
"RetrievalReadiness",
|
|
58
|
+
"RowContextReconciliationResult",
|
|
59
|
+
"RowWriteResult",
|
|
60
|
+
"RowWriteValidation",
|
|
53
61
|
"TextResult",
|
|
54
62
|
"VectorResult",
|
|
55
63
|
"__version__",
|
|
@@ -233,6 +233,7 @@ class RuntimeScope(str, Enum):
|
|
|
233
233
|
HYBRID_READ = "hybrid:read"
|
|
234
234
|
CONTEXT_READ = "context:read"
|
|
235
235
|
CONTEXT_MANAGE = "context:manage"
|
|
236
|
+
ROWS_WRITE = "rows:write"
|
|
236
237
|
|
|
237
238
|
|
|
238
239
|
class RuntimeClientKind(str, Enum):
|
|
@@ -366,6 +367,7 @@ class PolicyId(str, Enum):
|
|
|
366
367
|
PROJECT_PERMISSION = "project_permission"
|
|
367
368
|
PROJECT_API_KEY = "project_api_key"
|
|
368
369
|
GATEWAY_RUNTIME = "gateway_runtime"
|
|
370
|
+
RUNTIME_ROW_WRITE = "runtime_row_write"
|
|
369
371
|
CLI_FLOW = "cli_flow"
|
|
370
372
|
RECOVERY_SESSION = "recovery_session"
|
|
371
373
|
LEGACY_DEMO = "legacy_demo"
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from collections.abc import Mapping
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from types import MappingProxyType
|
|
9
|
+
from uuid import UUID
|
|
10
|
+
|
|
11
|
+
from ..errors import ERROR_CATALOG, PolygresError, error_record
|
|
12
|
+
from .enums import (
|
|
13
|
+
CliExitCode,
|
|
14
|
+
PasswordRequirement,
|
|
15
|
+
ProjectStatus,
|
|
16
|
+
ResetClass,
|
|
17
|
+
RetryClass,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AuthErrorCategory(str, Enum):
|
|
22
|
+
VALIDATION = "validation"
|
|
23
|
+
AUTHENTICATION = "authentication"
|
|
24
|
+
AUTHORIZATION = "authorization"
|
|
25
|
+
ACCOUNT_GATE = "account_gate"
|
|
26
|
+
CONFLICT = "conflict"
|
|
27
|
+
RATE_LIMIT = "rate_limit"
|
|
28
|
+
DEPENDENCY = "dependency"
|
|
29
|
+
TERMINAL_SESSION = "terminal_session"
|
|
30
|
+
UNEXPECTED = "unexpected"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class AuthErrorCode(str, Enum):
|
|
34
|
+
AUTH_REQUIRED = "AUTH_REQUIRED"
|
|
35
|
+
AUTH_MODE_NOT_ALLOWED = "AUTH_MODE_NOT_ALLOWED"
|
|
36
|
+
AUTH_NOT_CONFIGURED = "AUTH_NOT_CONFIGURED"
|
|
37
|
+
AUTH_INVALID_CREDENTIALS = "AUTH_INVALID_CREDENTIALS"
|
|
38
|
+
AUTH_EMAIL_REQUIRED = "AUTH_EMAIL_REQUIRED"
|
|
39
|
+
INVALID_TOKEN = "INVALID_TOKEN"
|
|
40
|
+
TOKEN_EXPIRED = "TOKEN_EXPIRED"
|
|
41
|
+
LOCAL_SESSION_CORRUPT = "LOCAL_SESSION_CORRUPT"
|
|
42
|
+
LOCAL_SESSION_RESET_LIMIT_REACHED = "LOCAL_SESSION_RESET_LIMIT_REACHED"
|
|
43
|
+
AUTH_PROVIDER_UNAVAILABLE = "AUTH_PROVIDER_UNAVAILABLE"
|
|
44
|
+
AUTH_PKCE_EXCHANGE_FAILED = "AUTH_PKCE_EXCHANGE_FAILED"
|
|
45
|
+
AUTH_PKCE_VERIFIER_MISSING = "AUTH_PKCE_VERIFIER_MISSING"
|
|
46
|
+
AUTH_ACTION_INVALID = "AUTH_ACTION_INVALID"
|
|
47
|
+
AUTH_ACTION_EXPIRED = "AUTH_ACTION_EXPIRED"
|
|
48
|
+
AUTH_RECOVERY_REQUIRED = "AUTH_RECOVERY_REQUIRED"
|
|
49
|
+
RECOVERY_GRANT_INVALID = "RECOVERY_GRANT_INVALID"
|
|
50
|
+
AUTH_REAUTHENTICATION_REQUIRED = "AUTH_REAUTHENTICATION_REQUIRED"
|
|
51
|
+
AUTH_REAUTHENTICATION_INVALID = "AUTH_REAUTHENTICATION_INVALID"
|
|
52
|
+
AUTH_PASSWORD_MODE_MISMATCH = "AUTH_PASSWORD_MODE_MISMATCH"
|
|
53
|
+
AUTH_WEAK_PASSWORD = "AUTH_WEAK_PASSWORD"
|
|
54
|
+
AUTH_IDENTITY_CHANGED = "AUTH_IDENTITY_CHANGED"
|
|
55
|
+
EMAIL_NOT_VERIFIED = "EMAIL_NOT_VERIFIED"
|
|
56
|
+
ACCOUNT_NOT_ELIGIBLE = "ACCOUNT_NOT_ELIGIBLE"
|
|
57
|
+
APPROVAL_REQUIRED = "APPROVAL_REQUIRED"
|
|
58
|
+
ADMIN_NOT_ALLOWED = "ADMIN_NOT_ALLOWED"
|
|
59
|
+
PERMISSION_DENIED = "PERMISSION_DENIED"
|
|
60
|
+
NOT_FOUND = "NOT_FOUND"
|
|
61
|
+
PROJECT_NOT_READY = "PROJECT_NOT_READY"
|
|
62
|
+
INVITATION_NOT_FOUND = "INVITATION_NOT_FOUND"
|
|
63
|
+
INVITATION_EMAIL_MISMATCH = "INVITATION_EMAIL_MISMATCH"
|
|
64
|
+
INVITATION_EXISTS = "INVITATION_EXISTS"
|
|
65
|
+
INVITATION_EXPIRED = "INVITATION_EXPIRED"
|
|
66
|
+
INVITATION_NOT_PENDING = "INVITATION_NOT_PENDING"
|
|
67
|
+
INVITATION_NOT_RESENDABLE = "INVITATION_NOT_RESENDABLE"
|
|
68
|
+
INVITATION_RESEND_TOO_SOON = "INVITATION_RESEND_TOO_SOON"
|
|
69
|
+
INVITATION_DELIVERY_FAILED = "INVITATION_DELIVERY_FAILED"
|
|
70
|
+
SELF_INVITE_NOT_ALLOWED = "SELF_INVITE_NOT_ALLOWED"
|
|
71
|
+
INVALID_INVITATION_ROLE = "INVALID_INVITATION_ROLE"
|
|
72
|
+
ORG_MEMBERSHIP_LIMIT_EXCEEDED = "ORG_MEMBERSHIP_LIMIT_EXCEEDED"
|
|
73
|
+
LEGAL_ACCEPTANCE_REQUIRED = "LEGAL_ACCEPTANCE_REQUIRED"
|
|
74
|
+
VALIDATION_ERROR = "VALIDATION_ERROR"
|
|
75
|
+
CLI_AUTH_NOT_CONFIGURED = "CLI_AUTH_NOT_CONFIGURED"
|
|
76
|
+
CLI_AUTH_SESSION_CREATE_FAILED = "CLI_AUTH_SESSION_CREATE_FAILED"
|
|
77
|
+
CLI_AUTH_SESSION_INVALID = "CLI_AUTH_SESSION_INVALID"
|
|
78
|
+
CLI_AUTH_SESSION_NOT_FOUND = "CLI_AUTH_SESSION_NOT_FOUND"
|
|
79
|
+
CLI_AUTH_SESSION_TERMINAL = "CLI_AUTH_SESSION_TERMINAL"
|
|
80
|
+
CLI_AUTH_DENIED = "CLI_AUTH_DENIED"
|
|
81
|
+
CLI_AUTH_EXPIRED = "CLI_AUTH_EXPIRED"
|
|
82
|
+
CLI_AUTH_TIMEOUT = "CLI_AUTH_TIMEOUT"
|
|
83
|
+
CLI_AUTH_RESPONSE_INVALID = "CLI_AUTH_RESPONSE_INVALID"
|
|
84
|
+
API_KEY_INVALID = "API_KEY_INVALID"
|
|
85
|
+
API_KEY_NOT_FOUND = "API_KEY_NOT_FOUND"
|
|
86
|
+
PROJECT_HEADER_REQUIRED = "PROJECT_HEADER_REQUIRED"
|
|
87
|
+
RUNTIME_API_KEY_SNAPSHOT_UNAVAILABLE = "RUNTIME_API_KEY_SNAPSHOT_UNAVAILABLE"
|
|
88
|
+
GATEWAY_RUNTIME_JWT_REQUIRED = "GATEWAY_RUNTIME_JWT_REQUIRED"
|
|
89
|
+
GATEWAY_RUNTIME_JWT_INVALID = "GATEWAY_RUNTIME_JWT_INVALID"
|
|
90
|
+
GATEWAY_RUNTIME_PROJECT_MISMATCH = "GATEWAY_RUNTIME_PROJECT_MISMATCH"
|
|
91
|
+
GATEWAY_RUNTIME_SCOPE_INVALID = "GATEWAY_RUNTIME_SCOPE_INVALID"
|
|
92
|
+
GATEWAY_RUNTIME_SCOPE_DENIED = "GATEWAY_RUNTIME_SCOPE_DENIED"
|
|
93
|
+
GATEWAY_RUNTIME_JWKS_UNAVAILABLE = "GATEWAY_RUNTIME_JWKS_UNAVAILABLE"
|
|
94
|
+
RUNTIME_HOST_INVALID = "RUNTIME_HOST_INVALID"
|
|
95
|
+
RUNTIME_ROUTING_HEADER_REJECTED = "RUNTIME_ROUTING_HEADER_REJECTED"
|
|
96
|
+
RUNTIME_PROJECT_NOT_FOUND = "RUNTIME_PROJECT_NOT_FOUND"
|
|
97
|
+
RUNTIME_PROJECT_NOT_READY = "RUNTIME_PROJECT_NOT_READY"
|
|
98
|
+
EMAIL_DELIVERY_FAILED = "EMAIL_DELIVERY_FAILED"
|
|
99
|
+
RATE_LIMITED = "RATE_LIMITED"
|
|
100
|
+
RATE_LIMIT_UNAVAILABLE = "RATE_LIMIT_UNAVAILABLE"
|
|
101
|
+
INTERNAL_ERROR = "INTERNAL_ERROR"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@dataclass(frozen=True, slots=True)
|
|
105
|
+
class AuthErrorDescriptor:
|
|
106
|
+
code: AuthErrorCode
|
|
107
|
+
category: AuthErrorCategory
|
|
108
|
+
safe_message: str
|
|
109
|
+
message_key: str
|
|
110
|
+
http_status: int | None
|
|
111
|
+
cli_exit_code: CliExitCode
|
|
112
|
+
retry_class: RetryClass
|
|
113
|
+
reset_class: ResetClass
|
|
114
|
+
safe_detail_keys: frozenset[str]
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
AUTH_ERROR_CATALOG: Mapping[AuthErrorCode, AuthErrorDescriptor] = MappingProxyType(
|
|
118
|
+
{
|
|
119
|
+
code: AuthErrorDescriptor(
|
|
120
|
+
code=code,
|
|
121
|
+
category=AuthErrorCategory(ERROR_CATALOG[code.value].category),
|
|
122
|
+
safe_message=ERROR_CATALOG[code.value].message,
|
|
123
|
+
message_key=ERROR_CATALOG[code.value].message_key,
|
|
124
|
+
http_status=ERROR_CATALOG[code.value].http_status,
|
|
125
|
+
cli_exit_code=CliExitCode(ERROR_CATALOG[code.value].cli_exit_code),
|
|
126
|
+
retry_class=RetryClass(ERROR_CATALOG[code.value].retry_class),
|
|
127
|
+
reset_class=ResetClass(ERROR_CATALOG[code.value].reset_class),
|
|
128
|
+
safe_detail_keys=ERROR_CATALOG[code.value].safe_detail_fields,
|
|
129
|
+
)
|
|
130
|
+
for code in AuthErrorCode
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
if set(AUTH_ERROR_CATALOG) != set(AuthErrorCode):
|
|
135
|
+
raise RuntimeError("global error catalog must define every AuthErrorCode exactly once")
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
_FIELD_PATH = re.compile(r"^[a-z][a-z0-9_.]{0,127}$")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _validate_safe_details(code: AuthErrorCode, details: Mapping[str, object]) -> None:
|
|
142
|
+
if code is AuthErrorCode.VALIDATION_ERROR and details:
|
|
143
|
+
field = details.get("field")
|
|
144
|
+
if not isinstance(field, str) or _FIELD_PATH.fullmatch(field) is None:
|
|
145
|
+
raise ValueError("field must be a schema-owned field path")
|
|
146
|
+
elif code is AuthErrorCode.AUTH_WEAK_PASSWORD and details:
|
|
147
|
+
raw_requirements = details.get("requirements")
|
|
148
|
+
if not isinstance(raw_requirements, (list, tuple)):
|
|
149
|
+
raise ValueError("requirements must be present")
|
|
150
|
+
try:
|
|
151
|
+
requirements = tuple(PasswordRequirement(item) for item in raw_requirements)
|
|
152
|
+
except (TypeError, ValueError) as exc:
|
|
153
|
+
raise ValueError("unknown password requirement") from exc
|
|
154
|
+
canonical = tuple(item for item in PasswordRequirement if item in requirements)
|
|
155
|
+
if requirements != canonical:
|
|
156
|
+
raise ValueError("password requirements must be unique and canonical")
|
|
157
|
+
minimum = details.get("minimum_length")
|
|
158
|
+
if minimum is not None and (
|
|
159
|
+
PasswordRequirement.LENGTH not in requirements
|
|
160
|
+
or isinstance(minimum, bool)
|
|
161
|
+
or not isinstance(minimum, int)
|
|
162
|
+
or not 1 <= minimum <= 1024
|
|
163
|
+
):
|
|
164
|
+
raise ValueError("minimum_length requires a known length requirement")
|
|
165
|
+
elif (
|
|
166
|
+
code in {AuthErrorCode.PROJECT_NOT_READY, AuthErrorCode.RUNTIME_PROJECT_NOT_READY}
|
|
167
|
+
and details
|
|
168
|
+
):
|
|
169
|
+
try:
|
|
170
|
+
ProjectStatus(details.get("status"))
|
|
171
|
+
except (TypeError, ValueError) as exc:
|
|
172
|
+
raise ValueError("status must be a ProjectStatus") from exc
|
|
173
|
+
elif code is AuthErrorCode.INVITATION_RESEND_TOO_SOON and details:
|
|
174
|
+
timestamp = details.get("resend_available_at")
|
|
175
|
+
seconds = details.get("remaining_seconds")
|
|
176
|
+
if not isinstance(timestamp, str):
|
|
177
|
+
raise ValueError("resend_available_at must be an RFC 3339 timestamp")
|
|
178
|
+
try:
|
|
179
|
+
parsed = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
|
|
180
|
+
except ValueError as exc:
|
|
181
|
+
raise ValueError("resend_available_at must be an RFC 3339 timestamp") from exc
|
|
182
|
+
if parsed.tzinfo is None or parsed.utcoffset() is None:
|
|
183
|
+
raise ValueError("resend_available_at must include a UTC offset")
|
|
184
|
+
if isinstance(seconds, bool) or not isinstance(seconds, int) or seconds < 0:
|
|
185
|
+
raise ValueError("remaining_seconds must be a non-negative integer")
|
|
186
|
+
elif code is AuthErrorCode.ORG_MEMBERSHIP_LIMIT_EXCEEDED and details:
|
|
187
|
+
try:
|
|
188
|
+
for key in ("current_organization_id", "invited_organization_id"):
|
|
189
|
+
raw = details[key]
|
|
190
|
+
if not isinstance(raw, str) or str(UUID(raw)) != raw:
|
|
191
|
+
raise ValueError
|
|
192
|
+
except (KeyError, TypeError, ValueError) as exc:
|
|
193
|
+
raise ValueError("organization details must contain canonical UUIDs") from exc
|
|
194
|
+
elif code is AuthErrorCode.AUTH_IDENTITY_CHANGED and details:
|
|
195
|
+
for key in ("previous_epoch", "current_epoch"):
|
|
196
|
+
value = details.get(key)
|
|
197
|
+
if isinstance(value, bool) or not isinstance(value, int) or value < 0:
|
|
198
|
+
raise ValueError("identity epochs must be non-negative integers")
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class AuthError(PolygresError):
|
|
202
|
+
def __init__(
|
|
203
|
+
self,
|
|
204
|
+
code: AuthErrorCode,
|
|
205
|
+
*,
|
|
206
|
+
details: Mapping[str, object] | None = None,
|
|
207
|
+
retry_after_seconds: int | None = None,
|
|
208
|
+
) -> None:
|
|
209
|
+
descriptor = AUTH_ERROR_CATALOG[code]
|
|
210
|
+
supplied = dict(details or {})
|
|
211
|
+
unknown = supplied.keys() - descriptor.safe_detail_keys
|
|
212
|
+
if unknown:
|
|
213
|
+
raise ValueError(f"unsafe error detail keys: {sorted(unknown)!r}")
|
|
214
|
+
_validate_safe_details(code, supplied)
|
|
215
|
+
if retry_after_seconds is not None and (
|
|
216
|
+
isinstance(retry_after_seconds, bool)
|
|
217
|
+
or not isinstance(retry_after_seconds, int)
|
|
218
|
+
or not 0 <= retry_after_seconds <= 86_400
|
|
219
|
+
or descriptor.retry_class is RetryClass.NEVER
|
|
220
|
+
):
|
|
221
|
+
raise ValueError("invalid retry_after_seconds for auth error")
|
|
222
|
+
super().__init__(error_record(code.value, details=supplied))
|
|
223
|
+
self.code = code
|
|
224
|
+
self.retry_class = descriptor.retry_class
|
|
225
|
+
self.reset_class = descriptor.reset_class
|
|
226
|
+
self.message_key = descriptor.message_key
|
|
227
|
+
self.retry_after_seconds = retry_after_seconds
|
|
228
|
+
|
|
229
|
+
def __repr__(self) -> str:
|
|
230
|
+
return f"AuthError(code={self.code.value!r})"
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import Enum
|
|
5
|
+
|
|
6
|
+
from ..errors import ERROR_CATALOG
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ContextErrorCode(str, Enum):
|
|
10
|
+
REQUEST_INVALID = "CONTEXT_REQUEST_INVALID"
|
|
11
|
+
IDENTIFIER_INVALID = "CONTEXT_IDENTIFIER_INVALID"
|
|
12
|
+
SOURCE_INVALID = "CONTEXT_SOURCE_INVALID"
|
|
13
|
+
DELETE_CONFIRMATION_INVALID = "CONTEXT_DELETE_CONFIRMATION_INVALID"
|
|
14
|
+
POINT_KEY_INVALID = "CONTEXT_POINT_KEY_INVALID"
|
|
15
|
+
EMBEDDING_INVALID = "CONTEXT_EMBEDDING_INVALID"
|
|
16
|
+
FILTER_INVALID = "CONTEXT_FILTER_INVALID"
|
|
17
|
+
LIMIT_EXCEEDED = "CONTEXT_LIMIT_EXCEEDED"
|
|
18
|
+
GRAPH_START_REQUIRED = "CONTEXT_GRAPH_START_REQUIRED"
|
|
19
|
+
GRAPH_DIRECTION_INVALID = "CONTEXT_GRAPH_DIRECTION_INVALID"
|
|
20
|
+
RANKING_WEIGHTS_INVALID = "CONTEXT_RANKING_WEIGHTS_INVALID"
|
|
21
|
+
RESOURCE_NAMESPACE_MISMATCH = "CONTEXT_RESOURCE_NAMESPACE_MISMATCH"
|
|
22
|
+
COLLECTION_NOT_FOUND = "CONTEXT_COLLECTION_NOT_FOUND"
|
|
23
|
+
OPERATION_NOT_FOUND = "CONTEXT_OPERATION_NOT_FOUND"
|
|
24
|
+
COLLECTION_NOT_READY = "CONTEXT_COLLECTION_NOT_READY"
|
|
25
|
+
TEXT_COLUMN_REQUIRED = "CONTEXT_TEXT_COLUMN_REQUIRED"
|
|
26
|
+
GRAPH_NOT_READY = "CONTEXT_GRAPH_NOT_READY"
|
|
27
|
+
SOURCE_KEY_ALIGNMENT_INVALID = "CONTEXT_SOURCE_KEY_ALIGNMENT_INVALID"
|
|
28
|
+
CAPABILITY_UNAVAILABLE = "CONTEXT_CAPABILITY_UNAVAILABLE"
|
|
29
|
+
SOURCE_KEY_NOT_FOUND = "CONTEXT_SOURCE_KEY_NOT_FOUND"
|
|
30
|
+
SOURCE_VECTOR_INVALID = "CONTEXT_SOURCE_VECTOR_INVALID"
|
|
31
|
+
FILTER_REGISTRATION_CONFLICT = "CONTEXT_FILTER_REGISTRATION_CONFLICT"
|
|
32
|
+
POINT_CURSOR_INVALID = "CONTEXT_POINT_CURSOR_INVALID"
|
|
33
|
+
RECALL_UNAVAILABLE = "CONTEXT_RECALL_UNAVAILABLE"
|
|
34
|
+
COLLECTION_NAME_CONFLICT = "CONTEXT_COLLECTION_NAME_CONFLICT"
|
|
35
|
+
PREFLIGHT_BLOCKED = "CONTEXT_PREFLIGHT_BLOCKED"
|
|
36
|
+
OPERATION_CONFLICT = "CONTEXT_OPERATION_CONFLICT"
|
|
37
|
+
IDEMPOTENCY_CONFLICT = "CONTEXT_IDEMPOTENCY_CONFLICT"
|
|
38
|
+
OPERATION_NOT_CANCELLABLE = "CONTEXT_OPERATION_NOT_CANCELLABLE"
|
|
39
|
+
OPERATION_NOT_RETRYABLE = "CONTEXT_OPERATION_NOT_RETRYABLE"
|
|
40
|
+
OPERATION_CANCELLED = "CONTEXT_OPERATION_CANCELLED"
|
|
41
|
+
ONBOARDING_NOT_ELIGIBLE = "CONTEXT_ONBOARDING_NOT_ELIGIBLE"
|
|
42
|
+
ONBOARDING_NOT_AVAILABLE = "CONTEXT_ONBOARDING_NOT_AVAILABLE"
|
|
43
|
+
RUNTIME_UNSUPPORTED = "CONTEXT_RUNTIME_UNSUPPORTED"
|
|
44
|
+
EXTENSION_UNAVAILABLE = "CONTEXT_EXTENSION_UNAVAILABLE"
|
|
45
|
+
SOURCE_TABLE_UNSUPPORTED = "CONTEXT_SOURCE_TABLE_UNSUPPORTED"
|
|
46
|
+
SOURCE_KEY_REQUIRED = "CONTEXT_SOURCE_KEY_REQUIRED"
|
|
47
|
+
SOURCE_KEY_TYPE_UNSUPPORTED = "CONTEXT_SOURCE_KEY_TYPE_UNSUPPORTED"
|
|
48
|
+
SOURCE_KEY_TEXT_CONSTRAINT_REQUIRED = "CONTEXT_SOURCE_KEY_TEXT_CONSTRAINT_REQUIRED"
|
|
49
|
+
SOURCE_PRIVILEGE_REQUIRED = "CONTEXT_SOURCE_PRIVILEGE_REQUIRED"
|
|
50
|
+
VECTOR_COLUMN_MISSING = "CONTEXT_VECTOR_COLUMN_MISSING"
|
|
51
|
+
VECTOR_COLUMN_CONFLICT = "CONTEXT_VECTOR_COLUMN_CONFLICT"
|
|
52
|
+
VECTOR_TYPE_UNSUPPORTED = "CONTEXT_VECTOR_TYPE_UNSUPPORTED"
|
|
53
|
+
VECTOR_NULLABLE = "CONTEXT_VECTOR_NULLABLE"
|
|
54
|
+
VECTOR_DIMENSION_INVALID = "CONTEXT_VECTOR_DIMENSION_INVALID"
|
|
55
|
+
COSINE_ZERO_VECTOR = "CONTEXT_COSINE_ZERO_VECTOR"
|
|
56
|
+
RESULT_COLUMN_INVALID = "CONTEXT_RESULT_COLUMN_INVALID"
|
|
57
|
+
FILTER_COLUMN_INVALID = "CONTEXT_FILTER_COLUMN_INVALID"
|
|
58
|
+
JSONB_FILTER_PATH_INVALID = "CONTEXT_JSONB_FILTER_PATH_INVALID"
|
|
59
|
+
RESERVED_FILTER_CONFLICT = "CONTEXT_RESERVED_FILTER_CONFLICT"
|
|
60
|
+
TEXT_COLUMN_INVALID = "CONTEXT_TEXT_COLUMN_INVALID"
|
|
61
|
+
HNSW_UNSUPPORTED = "CONTEXT_HNSW_UNSUPPORTED"
|
|
62
|
+
INDEX_CONFLICT = "CONTEXT_INDEX_CONFLICT"
|
|
63
|
+
MEMORY_PRESSURE = "CONTEXT_MEMORY_PRESSURE"
|
|
64
|
+
PGVECTOR_SOURCE = "CONTEXT_PGVECTOR_SOURCE"
|
|
65
|
+
UNSUPPORTED_VECTOR_TYPE = "CONTEXT_UNSUPPORTED_VECTOR_TYPE"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass(frozen=True, slots=True)
|
|
69
|
+
class ContextErrorDescriptor:
|
|
70
|
+
status_code: int
|
|
71
|
+
message: str
|
|
72
|
+
safe_detail_fields: tuple[str, ...] = ()
|
|
73
|
+
retryable: bool = False
|
|
74
|
+
conflict: bool = False
|
|
75
|
+
availability: bool = False
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
CONTEXT_ERROR_CATALOG: dict[ContextErrorCode, ContextErrorDescriptor] = {
|
|
79
|
+
code: ContextErrorDescriptor(
|
|
80
|
+
status_code=ERROR_CATALOG[code.value].http_status,
|
|
81
|
+
message=ERROR_CATALOG[code.value].message,
|
|
82
|
+
safe_detail_fields=tuple(sorted(ERROR_CATALOG[code.value].safe_detail_fields)),
|
|
83
|
+
retryable=ERROR_CATALOG[code.value].retry_class
|
|
84
|
+
in {"bounded_retry", "dependency_retry", "after_delay"},
|
|
85
|
+
conflict=ERROR_CATALOG[code.value].http_status == 409,
|
|
86
|
+
availability=(
|
|
87
|
+
"UNAVAILABLE" in code.value
|
|
88
|
+
or "NOT_READY" in code.value
|
|
89
|
+
or code is ContextErrorCode.MEMORY_PRESSURE
|
|
90
|
+
),
|
|
91
|
+
)
|
|
92
|
+
for code in ContextErrorCode
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if set(CONTEXT_ERROR_CATALOG) != set(ContextErrorCode):
|
|
96
|
+
raise RuntimeError("global error catalog must define every ContextErrorCode exactly once")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
__all__ = [
|
|
100
|
+
"CONTEXT_ERROR_CATALOG",
|
|
101
|
+
"ContextErrorCode",
|
|
102
|
+
"ContextErrorDescriptor",
|
|
103
|
+
]
|