Skip to content

SK-3118: FlowVault Python SDK (skyflow-flowvault-python) - #277

Open
saileshwar-skyflow wants to merge 54 commits into
mainfrom
flowvault-release/26.9.0
Open

saileshwar-skyflow wants to merge 54 commits into
mainfrom
flowvault-release/26.9.0

Conversation

@saileshwar-skyflow

Copy link
Copy Markdown
Collaborator

Summary

Adds the FlowVault Python SDK (skyflow-flowvault-python, imports as skyflow) — a high-throughput SDK for FlowVault vaults, built to mirror the Java FlowVault SDK. It shares the common client/credentials/config layer with skyvault and exposes a narrower surface: unary vault operations plus bulk (batched, concurrent) insert and detokenize.

What's included

  • Unary operations: insert, get, update, delete, detokenize — typed request/response objects, per-record http_code/error/request_id.
  • Bulk operations: bulk_insert and bulk_detokenize, each with sync and async variants, batching + bounded concurrency (env-var tuned), per-record results, and records_to_retry()/tokens_to_retry() helpers.
  • Java parity: response shapes, env resolution, retry classification (500–599 excl. 529), and error handling mirror the Java FlowVault SDK.
  • Packaging: custom build_py bundles the sibling common/ into the wheel; installs under the skyflow import name.

Notable fixes on this branch

  • Parse records-bearing non-2xx bodies as per-record rows across all unary ops (matches Java/bulk), instead of raising.
  • Populate .data on insert responses (unary + bulk) — the field the wire returns and Java maps was being dropped.
  • OpenAPI nullability fixes (skyflowID, detokenize value/tokenGroupName) so partial-failure responses parse.
  • README rewritten as a full Java-parity reference, plus review-feedback passes (multi-record insert, unary retry pattern + idempotency, per-operation vault re-declaration, import-name collision warning, batching-config rationale, accurate per-record field docs).

Testing

  • Unit tests + griffe public-API contract tests.
  • Live behave integration suite (separate sdk-integration-tests repo) exercising bulk + unary operations against a real vault.

🤖 Generated with Claude Code

saileshwar-skyflow and others added 30 commits July 7, 2026 16:31
…lowdb (v3) insert support

Restructures the repo into three build variants sharing a bundled common/
module (SK-2938 Option C): v2 (today's SDK, behavior-preserving) and a new
v3 built on the flowservice/flowdb API, insert-only this round.

common/
- Shared credential resolution, vault-URL resolution, and bearer-token
  fetch/cache/expiry logic (VaultController, BaseVaultClient), enums,
  errors, service_account, and generic validators.
- VaultController declares insert/get/update/delete/query/detokenize as
  abstract methods (Java-interface-style); v2 and v3 each provide their
  own concrete/stub implementations.

v2
- Relocated from the repo root via git mv; public API unchanged (same
  class names, signatures, import paths). Vault is now a backward-compatible
  alias for the internal PdbVaultController class.
- Fixed a latent bug where v2's own Env enum failed cross-class comparisons
  against common's Env; both now share one definition.

v3 (skyflow-flowvault, starting at 1.0.0)
- New InsertRequest/InsertRecord/Upsert/InsertResponse types, FlowVaultController,
  and VaultClient targeting the flowservice REST API.
- Insert validation ported from Java's v3 Validations.java: table/upsert
  must live in exactly one place (request-level or per-record, matching
  in both), 10k record cap, empty key/value checks.
- InsertResponse mirrors Java's v3 shape (summary/success/errors) as plain
  dicts, each result tagged with its index in the original record list
  (stable across batch boundaries).
- Structured per-record error parsing from the backend's actual error
  body, plus x-request-id propagation onto error entries.
- Batching via INSERT_BATCH_SIZE (default 50, max 1000), sequential,
  isolate-and-continue on a failing batch.
- Vault URL resolution uses v3's own skyvault.skyflowapis.* domain for
  all four envs (DEV/SANDBOX/STAGE/PROD), confirmed to differ from v2's
  vault.skyflowapis.* domain.

CI/CD
- shared-tests.yml and shared-build-and-deploy.yml now take a `variant`
  input and scope every step to v2/ or v3/ via working-directory.
- main.yml, ci.yml, beta-release.yml, internal-release.yml, and
  release.yml matrix over both variants. v3 releases are distinguished
  from v2's via a flowvault- tag/branch prefix (flowvault-1.0.0,
  flowvault-release/*) so a release trigger is never ambiguous between
  the two independently-versioned packages; v2's existing bare-semver
  tags are untouched.
- Fixed ruff.toml/.codespellrc still excluding a pre-split "skyflow/generated"
  path that no longer existed after the relocation.
- Fixed a bump_version.sh sed collision with a comment that happened to
  contain the literal text "__version__ = ...".
- Added a common/ test job to main.yml/ci.yml.

Note: v3/samples/ and the root samples/ folder are deliberately excluded
from this branch/commit -- local working copies there contain
credentials used for live testing against a real vault and must not be
pushed.

Tests: common 36, v3 65, v2 426 (2 pre-existing unrelated fixture
failures), tests/contract passing for both variants.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Distribution name was already skyflow-flowvault (setup.py) but the
importable package stayed skyflow, colliding with v2's skyflow
import name if both are ever installed in the same environment.
Rename the v3 directory to flowvault and its package to
skyflow_flowvault to match the distribution name and remove the
collision. generated/ content is left untouched (Fern-owned).
…d base insert response

Consolidates duplicated logic between v2 (PDB) and flowvault per architecture
review: shared validation (vault config, credentials, log level), LogLevel/Logger,
and insert field/table validation now live in common with per-variant message
injection; adds BaseInsertResponse alongside BaseInsertRequest so each variant's
InsertRequest/InsertResponse can extend a common base while keeping its own shape.
Also fixes flowvault's insert() response shape (drop redundant 'data'/'table',
flatten tokens, errors=None when empty) and a stale SDK_VERSION drift bug.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…insert()

Splits BaseSkyflow, BaseVaultController, and BaseVaultClient into a pure
interface (ISkyflow/IVaultController/IVaultClient, declaring the contract via
ABC + abstractmethod) plus a base class implementing the shared logic, so
future variant-specific overrides have a clear contract to satisfy. Also adds
type hints to insert() at every layer (BaseInsertRequest/BaseInsertResponse in
the abstract method, each variant's own InsertRequest/InsertResponse in their
concrete override), and renames base_vault.py to base_vault_controller.py to
match its class name.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…shape, add types

BaseInsertRequest's shared field is now named values (matching PDB's
terminology) instead of records, and table/values are required rather than
defaulted; each variant's InsertRequest forwards them explicitly. Removes
flowvault's Upsert class in favor of a plain dict (now typed via a TypedDict)
to match the rest of flowvault's dict-based request shape, and adds return
type hints to every method on v2's VaultController to match insert's.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
BaseSkyflow implements every ISkyflow abstract method, so ABC alone doesn't
block instantiating it directly -- only make_skyflow_class-produced
subclasses should be constructed. Raises SkyflowError with a new
SkyflowMessages entry instead of a raw NotImplementedError, matching how
every other SDK error is raised.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CI workflows (ci.yml, main.yml, release.yml, beta-release.yml,
internal-release.yml) still referenced the pre-rename v3/ directory, so every
flowvault CI job failed outright. Threads a package-name (skyflow vs
skyflow_flowvault) through shared-tests.yml/shared-build-and-deploy.yml/
bump_version.sh, since those hardcoded the skyflow package name too -- a real
release would've bumped the wrong version file. Also fixes common/setup.py's
missing python-dotenv dependency (test-common CI job installs only this file's
declared deps), and removes the empty-value insert tests now that empty/null
field values are explicitly allowed rather than rejected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… noise

flowvault/requirements.txt was missing coverage, so the v3 test job's
`python -m coverage run` step failed outright with "No module named
coverage" once the workflow correctly pointed at flowvault. Also excludes
**/generated/** (Fern-owned) from semgrep, since the generated REST clients
trip its secret-detection heuristics on parameter names like `token`, and
fixes a real semgrep finding: shared-build-and-deploy.yml interpolated
${{ }} context values directly into a run: shell block instead of routing
them through env: first.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…e positives

test-common never ran coverage or uploaded to Codecov, so common/ (which grew
substantially this session) was invisible to Codecov's patch/project checks.
Adds a coverage run + Codecov upload step matching v2/flowvault's pattern.
Also fixes .semgreprules/customRule.yml's check-sensitive-info regex: an
optional quote-capture group let its own backreference match empty string,
so any `keyword: value` matched regardless of quoting -- tightened to require
an actual quoted literal and exclude self-referential values (e.g. TOKEN =
'token'), which eliminates 28 false positives without any inline suppressions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tion/detect structurally absent when unsupported

Renames ISkyflow -> BaseSkyflow (pure interface) and the old BaseSkyflow ->
BaseSkyflowImpl (concrete). Moves connection/detect support into
ConnectionCapable/DetectCapable interfaces + ConnectionMixin/DetectMixin in a
new common/client/utils/_utils.py, conditionally composed into a variant's
Skyflow class by make_skyflow_class() so unsupported variants (e.g. flowvault)
genuinely lack .connection()/.detect() (AttributeError) instead of raising
NotImplementedError from a present-but-guarded method.

Also fixes two review-flagged bugs: adding a vault/connection config with a
duplicate id to an already-built client now raises SkyflowError instead of
silently overwriting the existing entry, and update_connection_config no
longer risks a bare KeyError on a missing connection_id. Extracts the
Builder's raw NotImplementedError string literals into named constants.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… common

Main advanced with the 2.1.3 release and SK-3039 (read the token roles/context
from credentials, not the vault config, and validate them). Those changes
landed on the old root-level `skyflow/` tree, which this branch has split into
`common/` + `skyvault/`, so they are re-applied where that logic now lives:

- common/utils/validations: add validate_token_options (roles/context checks,
  broadened context types, role-element validation) and call it from
  validate_credentials.
- common/vault/base_vault_client.get_bearer_token: validate token options and
  build role_ids/ctx from credentials instead of config.
- common/service_account._validate_and_resolve_ctx: take a messages param so
  delegated skyvault errors keep skyvault's SDK version in their text.
- skyvault validations delegate validate_token_options to common; skyvault
  bumped to 2.1.3 (setup.py + _version.py).
- SK-3039 client tests ported to common/tests/vault/test_base_vault_client.py
  (patch targets -> common.vault.base_vault_client) and the skyvault
  end-to-end tests repointed accordingly.
- shared-build-and-deploy.yml: keep module `ref` input alongside main's
  SK-2986 admin-token comment.
- flowvault bulk response: extract retryable-HTTP-code literals into constants
  (clears ruff PLR2004 that was failing CI).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The shared per-module test loop aborted on the first module (common) and
`bash -e` then skipped skyvault and flowvault, so their tests never ran on a
PR. Two fixes:

- Add the repo root to PYTHONPATH for the test run. common/ is imported as a
  namespace package (common.vault has no __init__), so its own wheel can't be
  imported as `common`; resolving from the source tree fixes discovery for all
  modules.
- Run every module even if one fails and fail the job only at the end, so one
  module never hides the others' results.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Fern-generated REST clients are not hand-written and were dragging module
coverage down (failing Codecov) and producing 82 of 83 Semgrep code-scanning
alerts.

- codecov.yml: ignore **/generated/**.
- Add .coveragerc omit for */generated/* to common, skyvault and flowvault so
  generated code is not measured (flowvault 96.6%, common 86.6% after).
- semgrep.yml: pass --exclude generated so the SARIF upload no longer flags
  generated code.
- shared-build-and-deploy.yml: use the built-in $GITHUB_ACTOR env var instead
  of interpolating ${{ github.actor }} in a run step (the remaining Semgrep
  shell-injection finding).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…v targets

- shared-build-and-deploy.yml: route inputs/steps-outputs/github.ref_name
  through an env: block so no untrusted ${{ }} is interpolated in the run:
  script (clears the last Semgrep run-shell-injection alert).
- codecov.yml: the base's auto-target is 99.75% (mature v2 code), which a large
  PR adding new flowvault/common code can't hit; allow a 5% project threshold
  and an 85% patch target so codecov reflects real, healthy coverage
  (project 95.4%, patch 90.6%) instead of blocking on the inherited target.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Port the Java SDK's japicmp contract gate to Python using griffe (static API
analysis), for both published packages:

- ci-scripts/contract/griffe_contract.py: builds each package's public-API
  surface from an explicit module allowlist (mirrors Java's <includes>;
  excludes generated/ and internal utils helpers) and dumps/checks it against a
  committed baseline. Removed/changed entries are breaking, added entries are
  new surface; any drift fails.
- Committed baselines skyvault/api-report/skyflow.api.json (358 members) and
  flowvault/api-report/skyflow_flowvault.api.json (153).
- ci-scripts/contract-snapshot-update.sh: regenerate baselines after an
  intentional public API change.
- .github/workflows/contract-tests.yml: per-module matrix gate (fail-fast
  false), a skyvault-only guard `griffe check skyflow -a skyflow==2.1.3` (no
  breaking changes vs the released skyflow), and a PR comment showing the
  baseline diff when it changes.
- Add griffe[pypi] to each module's dev extras.

Verified skyvault's public surface has no breaking changes vs released
skyflow 2.1.3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
griffe 2.2.0 requires Python >= 3.10, so `pip install griffe==2.2.0` failed on
the 3.9 runner. griffe analyses the SDK source statically, so the analyzer's
Python version is independent of the SDK's own >= 3.9 support and can be 3.10.
Also mark the `griffe` dev extra `python_version >= "3.10"` so a 3.9 dev install
does not fail.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Java's contract test compares only against the committed baseline, never a
published release, so remove the skyvault-only `griffe check -a skyflow==2.1.3`
step and the SKYVAULT_RELEASE bump it needed. The committed baseline is the
contract for both modules. Current skyvault was verified to have no breaking
changes vs released skyflow 2.1.3. Drop the now-unneeded griffe pypi extra.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address the code-review P0/P1 findings for flowvault:

- Cover the remaining error-handling/edge branches to reach 100% on flowvault
  product code: batching .env fallback + zero/negative concurrency, response
  parsing None/[None] cases, get_vault_url validation + get_metrics fallbacks
  (new test__utils.py), full validate_bulk_insert/detokenize_request coverage,
  update ApiError body variants, async bulk error paths, and the bulk response
  __str__/empty-retry helpers.
- Exclude setup.py and the `if __name__` boilerplate from coverage via
  .coveragerc.
- requirements.txt: bump pydantic floor 1.9.2 -> 2.0.0 (setup.py and the Fern
  client require pydantic v2).
- Remove dead GetRecordRequest import and MAX_BULK_DATA_SIZE constant; extract
  the repeated 'additional_headers'/'Unknown error' literals into named
  constants; drop explanatory comments from _validations.py.
- get_vault_url: reject an invalid env with `not isinstance(env, Env)` instead
  of `env not in Env`, which raised TypeError (and left the guard unreachable)
  for a non-member on Python < 3.12.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Change the published distribution name from skyflow-flowvault to
skyflow-flowvault-python in flowvault/setup.py, and update the pip-install and
prose references in the root README, flowvault README, and samples README. The
importable package stays skyflow_flowvault. No workflow changes are needed --
the release workflows resolve the module from the branch/tag directory name and
twine publishes whatever setup.py builds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…table_name

Match Java's flowdb contract: rename BulkInsertRecord -> BulkInsertRequestRecord
and add a `tokens` field (BYOT) on it; use `table_name` (not `table`) on
BulkInsertRequest, GetRequest, GetRecordRequest, and DeleteRequest. Update the
affected vault_api samples to the new field names.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Custom request headers for bulk_insert/bulk_detokenize (+ async): a
BulkInsertOptions/BulkDetokenizeOptions interceptor runs once per batch via a
RequestContext, mirroring Java's RequestInterceptor/CustomHeaderKey.

Full parity with Java's VaultConfig HTTP settings (timeout, connect/read/write
timeouts, max_retries, initial/max retry delay, vault_url), at both per-vault
(config dict keys) and client-wide (builder methods) levels, resolved
per-field per-vault -> client-wide -> default. Like Java (which injects a
configured OkHttpClient), flowvault injects a custom httpx transport
(RetryTransport) plus an httpx.Timeout into the generated SkyflowAuth client --
no generated-code edits. The client-wide builder methods are flowvault-only via
a builder mixin and a private base hook, so skyvault's public surface stays
identical to 2.1.3.

Also wires in the renamed BulkInsertRequestRecord/table_name across the
controller, validations, and exports, and regenerates the flowvault public-API
contract snapshot (154 -> 175 members). Full unit coverage; skyvault contract
unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Port the Java flowvault samples to Python: multi-table bulk insert (sync/async),
custom-header and timeout/retry config examples, and the service-account token
samples (bearer, context-aware, threaded, scoped, signed). Bulk tokenize and
bulk delete-tokens samples are intentionally omitted -- those operations are not
part of the Python flowvault surface.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…port-python-sdk

SK-3118: FlowDB support for Python SDK (skyflow-flowvault) + module segregation
…copy

The version-bump commit step ran find "$MODULE" -name "_version.py" after the
build step created "$MODULE/build/", so it could return the copy under the
gitignored build/ dir and "git add" would abort with "paths are ignored"
(order-dependent, so it surfaced on flowvault). Exclude build/ and dist/ from
the find so only the tracked source _version.py is staged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… doc)

Remove the internal request/response shapes reference from the branch; it stays
as a local-only file.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… refinements

Rename the importable package skyflow_flowvault -> skyflow so Flow DB code reads
identically to the skyvault (Privacy DB) SDK (`from skyflow import Skyflow`); the
PyPI distribution name stays skyflow-flowvault-python. skyvault's package and its
frozen 2.1.3 contract are untouched. Contract tooling (griffe config, snapshot
script, workflow) is updated to the skyflow package name.

Error handling now matches Java: unary ops raise SkyflowError with the parsed
server details (message, http_code, grpc_code, http_status, details, request_id)
on any API error, instead of returning a fake record with the raw exception dump;
bulk ops keep resilient per-record inline reporting but now surface the clean
server message. Drop the redundant `data` field from bulk insert response records.

Add a typed TokenGroupRedactions(token_group_name, redaction) for detokenize
requests and a typed Callable[[RequestContext], None] interceptor on
BulkInsert/BulkDetokenizeOptions -- both matching Java. Regenerate the public-API
contract snapshot (-> skyflow.api.json, 179 members) and update the vault_api /
service-account samples. Full unit coverage; skyvault contract unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
saileshwar-skyflow and others added 19 commits September 3, 2026 18:57
- update(): require non-empty dict 'data' per record and build wire records
  inside the try/except, so a missing/invalid 'data' raises SkyflowError
  instead of a raw pydantic.ValidationError escaping the SDK error contract.
- update(): plumb BYOT 'tokens' through to the update wire record (previously
  accepted by validation then silently dropped); matches the API/Java contract.
- VaultClient: close the previous sync/async httpx clients on reinitialization
  and add close()/aclose(), fixing the connection-pool leak on update_config().
- Add tests covering missing/invalid update data, BYOT tokens on update, and
  httpx client close-on-reinit / explicit close.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Upgrades the generated REST layer to the newer Fern Python generator, which
memoizes resolved type hints and short-circuits convert_and_respect_annotation_metadata
in core/serialization.py. This removes the per-request typing.get_type_hints
recomputation that dominated serialize/parse CPU (~3x lower per-request CPU cost,
122 -> 381 req/s single-thread in a mock benchmark). Output is unchanged and the
public skyflow API is unaffected; hand-written SDK code is untouched. Adds the
generated http_sse core module.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… defaults

Parity with the Java flowvault SDK:
- update(): send updateType to the API (was silently dropped). Wired the
  regenerated update endpoint's updateType through the controller, converting
  the public UpsertType enum to its wire value and omitting it when unset.
- Add typed DetokenizeResponseRecordMetadata for the metadata field on both
  unary and bulk detokenize responses (was an untyped dict).
- Rename public ColumnRedaction -> ColumnRedactions (matches Java; pre-release,
  no alias). Generated wire type untouched.
- Type update_type as UpsertType on UpdateRequest and UpsertOptions.

Internal HTTP tuning (not exposed via VaultConfig):
- httpx connection pool defaults: max_connections=100, max_keepalive_connections=100,
  keepalive_expiry=60s (was 20 / 5s) to reduce connection churn.
- Raise bulk insert/detokenize MAX_CONCURRENCY cap from 10 to 100.

Tests updated accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Typed response records matching Java: Insert/Get/Update/Delete/Detokenize/
  Query response records, Query metadata, Bulk insert/detokenize records, Token.
  Controllers now return these typed objects instead of dicts.
- update() returns a single unified records list (UpdateResponseRecord), errors
  folded inline; dropped UpdateResponse.errors (matches Java).
- request_id carried on error records across unary + bulk.
- Per-operation unary options (Insert/Get/Update/Delete/Query/Detokenize) with
  interceptor support, mirroring the bulk options.
- UpdateRequestRecord type; UpdateRequest.update_type typed as UpsertType.
- GetRequest/GetRequestRecord: ids -> skyflow_ids, fields -> columns.
- Updated validations, tests, samples, README, and regenerated the public API
  contract baseline.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ty mirror

Remove the `query` operation from the Python flowvault SDK so its operation set
mirrors Java flowvault (which has no query):
- Drop VaultController.query and the query wire helper; remove QueryRequest/
  QueryResponse/QueryResponseRecord/QueryResponseMetadata/QueryOptions data
  classes, validation, messages, the client query-api accessor, tests, and the
  query sample.
- Relax the shared common IVaultController interface: query is no longer a
  required abstract op (skyvault keeps its own concrete query, unaffected), so
  flowvault's controller is concrete without it. Updated the common contract test.
- Regenerated the flowvault public-API contract baseline (query classes removed).

Rewrite flowvault/README.md as a full mirror of the Java flowvault README
structure, adapted to Python: expanded Authenticate (bearer/context/scoped/signed
token generation via skyflow.service_account), VaultConfig + builder reference
tables, Schema-vs-schemaless, Unary-vs-bulk parity, the "SDK Guidelines: Unary vs
Bulk Operations" section, per-operation sections with sample responses, Custom
Request Headers, and a full Error Handling breakdown. Dropped the Java-only
tokenize/delete-tokens ops and the removed query op; removed the "Privacy DB"
install-vs-import note; corrected the bulk concurrency max to 100.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Java enforces MAX_BULK_DATA_SIZE=100000 only on bulk operations; unary insert has
no SDK ceiling. Python diverged: it capped at 10000 and also capped unary insert.

- Rename MAX_INSERT_RECORDS(10000) -> MAX_BULK_DATA_SIZE(100000) in _validations.
- Remove the size check from validate_insert_request (unary insert), matching Java.
- Bulk insert / bulk detokenize now cap at 100000; updated their messages.
- Drop the now-unused TOO_MANY_RECORDS_IN_INSERT message.
- Update tests (bulk boundary 100001; remove obsolete unary-insert ceiling tests).
- README: bulk ceiling 10,000 -> 100,000; unary parity row now "not enforced by
  the SDK", matching Java.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ary ops

- Unary insert/get/update/delete/detokenize now route a non-2xx response
  whose body carries a records array through the per-record formatter
  (matching Java and the existing bulk behavior) instead of raising, so
  per-record not-found/invalid rows surface with skyflowId/httpCode/error.
- Make the shared record formatters dict/object-aware via __wire_record_value
  so they handle both success models and camelCase error-body dicts.
- Treat ParsingError like ApiError in __to_skyflow_error for clean whole-call
  error shapes.
- Regenerated types: skyflowID, detokenize value and tokenGroupName are now
  optional (spec nullability fix); fern SDK version bump 0.0.21 -> 0.0.23.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Insert: add a multi-record example (and a per-record-table/upsert variant),
  since InsertRequest.records is a list but only a single-record sample existed.
- Retrying the failed records: add a worked unary retry pattern with the exact
  500-599-excluding-529 predicate; flag insert-retry idempotency (use upsert on
  a unique column so a lost-response resubmit updates instead of duplicating).
- Re-declare `vault = skyflow_client.vault('<VAULT_ID>')` at the top of every
  operation snippet so TOC-jump readers don't hit an undefined name.
- Configuration: warn that this package and the main `skyflow` SDK share the
  top-level `skyflow` import and cannot coexist in one environment.
- Batching and concurrency: explain the env-var-only model as an intentional,
  cross-SDK (Java-parity) deployment-time tuning choice.
- Per-record table: mark `.error`/`.request_id` as always present, populated
  only on failure (they show as null on success), not "failures only".
- Rename "Flow DB" -> "FlowVault" in README and samples README.

Docs only; no SDK behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The wire record response carries `data` (the record's stored column values),
and the Java SDK maps it on both unary and bulk insert. Python was dropping it:
unary insert built records with include_data=False, and the bulk insert batch
formatter never set data, so callers saw data=None even though the API returned
values. Map data on both paths, matching get/update and Java.

Also update the README: drop the "insert omits .data" notes, add `.data` to the
insert accessor lists, and show data in the insert sample responses.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Public API contract change (flowvault)

This PR changes flowvault/api-report/skyflow.api.json (the approved public API contract for skyflow). Review the surface change below:

diff --git a/flowvault/api-report/skyflow.api.json b/flowvault/api-report/skyflow.api.json
new file mode 100644
index 0000000..058075e
--- /dev/null
+++ b/flowvault/api-report/skyflow.api.json
@@ -0,0 +1,268 @@
+{
+  "skyflow.Env": "class (Enum)",
+  "skyflow.Env.DEV": "attr = 'DEV'",
+  "skyflow.Env.PROD": "attr = 'PROD'",
+  "skyflow.Env.SANDBOX": "attr = 'SANDBOX'",
+  "skyflow.Env.STAGE": "attr = 'STAGE'",
+  "skyflow.LogLevel": "class (Enum)",
+  "skyflow.LogLevel.DEBUG": "attr = 1",
+  "skyflow.LogLevel.ERROR": "attr = 4",
+  "skyflow.LogLevel.INFO": "attr = 2",
+  "skyflow.LogLevel.OFF": "attr = 5",
+  "skyflow.LogLevel.WARN": "attr = 3",
+  "skyflow.Skyflow": "attr",
+  "skyflow.client.Skyflow": "attr",
+  "skyflow.error.SkyflowError": "class (Exception)",
+  "skyflow.error.SkyflowError.__init__": "def (self, message, http_code, request_id = None, grpc_code = None, http_status = None, details = None)",
+  "skyflow.error.SkyflowError.details": "attr",
+  "skyflow.error.SkyflowError.grpc_code": "attr",
+  "skyflow.error.SkyflowError.http_code": "attr",
+  "skyflow.error.SkyflowError.http_status": "attr",
+  "skyflow.error.SkyflowError.message": "attr",
+  "skyflow.error.SkyflowError.request_id": "attr",
+  "skyflow.service_account.generate_bearer_token": "def (credentials_file_path, options = None, logger = None)",
+  "skyflow.service_account.generate_bearer_token_from_creds": "def (credentials, options = None, logger = None)",
+  "skyflow.service_account.generate_signed_data_tokens": "def (credentials_file_path, options)",
+  "skyflow.service_account.generate_signed_data_tokens_from_creds": "def (credentials, options)",
+  "skyflow.service_account.is_expired": "def (token, logger = None)",
+  "skyflow.utils.enums.CustomHeaderKey": "class (Enum)",
+  "skyflow.utils.enums.CustomHeaderKey.REQUEST_ID_HEADER": "attr = 'x-request-id'",
+  "skyflow.utils.enums.CustomHeaderKey.SKYFLOW_ACCOUNT_ID": "attr = 'x-skyflow-account-id'",
+  "skyflow.utils.enums.CustomHeaderKey.SKYFLOW_ACCOUNT_NAME": "attr = 'x-skyflow-account-name'",
+  "skyflow.utils.enums.EnvUrls": "class (Enum)",
+  "skyflow.utils.enums.EnvUrls.DEV": "attr = 'skyvault.skyflowapis.dev'",
+  "skyflow.utils.enums.EnvUrls.PROD": "attr = 'skyvault.skyflowapis.com'",
+  "skyflow.utils.enums.EnvUrls.SANDBOX": "attr = 'skyvault.skyflowapis-preview.com'",
+  "skyflow.utils.enums.EnvUrls.STAGE": "attr = 'skyvault.skyflowapis.tech'",
+  "skyflow.utils.enums.UpsertType": "class (Enum)",
+  "skyflow.utils.enums.UpsertType.REPLACE": "attr = 'REPLACE'",
+  "skyflow.utils.enums.UpsertType.UPDATE": "attr = 'UPDATE'",
+  "skyflow.vault.controller.VaultController": "class (BaseVaultController)",
+  "skyflow.vault.controller.VaultController.__init__": "def (self, vault_client)",
+  "skyflow.vault.controller.VaultController.bulk_detokenize": "def (self, request: BulkDetokenizeRequest, options: BulkDetokenizeOptions = None) -> BulkDetokenizeResponse",
+  "skyflow.vault.controller.VaultController.bulk_detokenize_async": "def (self, request: BulkDetokenizeRequest, options: BulkDetokenizeOptions = None) -> BulkDetokenizeResponse",
+  "skyflow.vault.controller.VaultController.bulk_insert": "def (self, request: BulkInsertRequest, options: BulkInsertOptions = None) -> BulkInsertResponse",
+  "skyflow.vault.controller.VaultController.bulk_insert_async": "def (self, request: BulkInsertRequest, options: BulkInsertOptions = None) -> BulkInsertResponse",
+  "skyflow.vault.controller.VaultController.delete": "def (self, request: DeleteRequest, options: DeleteOptions = None) -> DeleteResponse",
+  "skyflow.vault.controller.VaultController.detokenize": "def (self, request: DetokenizeRequest, options: DetokenizeOptions = None) -> DetokenizeResponse",
+  "skyflow.vault.controller.VaultController.get": "def (self, request: GetRequest, options: GetOptions = None) -> GetResponse",
+  "skyflow.vault.controller.VaultController.insert": "def (self, request: InsertRequest, options: InsertOptions = None) -> InsertResponse",
+  "skyflow.vault.controller.VaultController.update": "def (self, request: UpdateRequest, options: UpdateOptions = None) -> UpdateResponse",
+  "skyflow.vault.data.BulkDetokenizeOptions": "class ()",
+  "skyflow.vault.data.BulkDetokenizeOptions.__init__": "def (self, interceptor: Optional[Callable[[RequestContext], None]] = None)",
+  "skyflow.vault.data.BulkDetokenizeOptions.interceptor": "attr",
+  "skyflow.vault.data.BulkDetokenizeRequest": "class ()",
+  "skyflow.vault.data.BulkDetokenizeRequest.__init__": "def (self, tokens: list, token_group_redactions: List[TokenGroupRedactions] = None)",
+  "skyflow.vault.data.BulkDetokenizeRequest.token_group_redactions": "attr",
+  "skyflow.vault.data.BulkDetokenizeRequest.tokens": "attr",
+  "skyflow.vault.data.BulkDetokenizeResponse": "class ()",
+  "skyflow.vault.data.BulkDetokenizeResponse.__init__": "def (self, summary = None, records = None, _original_tokens = None)",
+  "skyflow.vault.data.BulkDetokenizeResponse.records": "attr",
+  "skyflow.vault.data.BulkDetokenizeResponse.summary": "attr",
+  "skyflow.vault.data.BulkDetokenizeResponse.tokens_to_retry": "def (self)",
+  "skyflow.vault.data.BulkDetokenizeResponseRecord": "class ()",
+  "skyflow.vault.data.BulkDetokenizeResponseRecord.__init__": "def (self, token = None, value = None, token_group_name = None, metadata = None, http_code = None, error = None, request_id = None, index = None)",
+  "skyflow.vault.data.BulkDetokenizeResponseRecord.error": "attr",
+  "skyflow.vault.data.BulkDetokenizeResponseRecord.http_code": "attr",
+  "skyflow.vault.data.BulkDetokenizeResponseRecord.index": "attr",
+  "skyflow.vault.data.BulkDetokenizeResponseRecord.metadata": "attr",
+  "skyflow.vault.data.BulkDetokenizeResponseRecord.request_id": "attr",
+  "skyflow.vault.data.BulkDetokenizeResponseRecord.token": "attr",
+  "skyflow.vault.data.BulkDetokenizeResponseRecord.token_group_name": "attr",
+  "skyflow.vault.data.BulkDetokenizeResponseRecord.value": "attr",
+  "skyflow.vault.data.BulkInsertOptions": "class ()",
+  "skyflow.vault.data.BulkInsertOptions.__init__": "def (self, interceptor: Optional[Callable[[RequestContext], None]] = None)",
+  "skyflow.vault.data.BulkInsertOptions.interceptor": "attr",
+  "skyflow.vault.data.BulkInsertRequest": "class ()",
+  "skyflow.vault.data.BulkInsertRequest.__init__": "def (self, records: List[BulkInsertRequestRecord], table_name: str = None, upsert: UpsertOptions = None)",
+  "skyflow.vault.data.BulkInsertRequest.records": "attr",
+  "skyflow.vault.data.BulkInsertRequest.table_name": "attr",
+  "skyflow.vault.data.BulkInsertRequest.upsert": "attr",
+  "skyflow.vault.data.BulkInsertRequestRecord": "class ()",
+  "skyflow.vault.data.BulkInsertRequestRecord.__init__": "def (self, data: dict, table_name: str = None, tokens: dict = None, upsert: UpsertOptions = None)",
+  "skyflow.vault.data.BulkInsertRequestRecord.data": "attr",
+  "skyflow.vault.data.BulkInsertRequestRecord.table_name": "attr",
+  "skyflow.vault.data.BulkInsertRequestRecord.tokens": "attr",
+  "skyflow.vault.data.BulkInsertRequestRecord.upsert": "attr",
+  "skyflow.vault.data.BulkInsertResponse": "class ()",
+  "skyflow.vault.data.BulkInsertResponse.__init__": "def (self, summary = None, records = None, _original_records = None)",
+  "skyflow.vault.data.BulkInsertResponse.records": "attr",
+  "skyflow.vault.data.BulkInsertResponse.records_to_retry": "def (self)",
+  "skyflow.vault.data.BulkInsertResponse.summary": "attr",
+  "skyflow.vault.data.BulkInsertResponseRecord": "class ()",
+  "skyflow.vault.data.BulkInsertResponseRecord.__init__": "def (self, skyflow_id = None, table_name = None, tokens = None, data = None, hashed_data = None, http_code = None, error = None, request_id = None, index = None)",
+  "skyflow.vault.data.BulkInsertResponseRecord.data": "attr",
+  "skyflow.vault.data.BulkInsertResponseRecord.error": "attr",
+  "skyflow.vault.data.BulkInsertResponseRecord.hashed_data": "attr",
+  "skyflow.vault.data.BulkInsertResponseRecord.http_code": "attr",
+  "skyflow.vault.data.BulkInsertResponseRecord.index": "attr",
+  "skyflow.vault.data.BulkInsertResponseRecord.request_id": "attr",
+  "skyflow.vault.data.BulkInsertResponseRecord.skyflow_id": "attr",
+  "skyflow.vault.data.BulkInsertResponseRecord.table_name": "attr",
+  "skyflow.vault.data.BulkInsertResponseRecord.tokens": "attr",
+  "skyflow.vault.data.BulkSummary": "class ()",
+  "skyflow.vault.data.BulkSummary.__init__": "def (self, total_records = 0, total_inserted = 0, total_failed = 0)",
+  "skyflow.vault.data.BulkSummary.total_failed": "attr",
+  "skyflow.vault.data.BulkSummary.total_inserted": "attr",
+  "skyflow.vault.data.BulkSummary.total_records": "attr",
+  "skyflow.vault.data.ColumnRedactions": "class ()",
+  "skyflow.vault.data.ColumnRedactions.__init__": "def (self, column_name: str, redaction: str = None)",
+  "skyflow.vault.data.ColumnRedactions.column_name": "attr",
+  "skyflow.vault.data.ColumnRedactions.redaction": "attr",
+  "skyflow.vault.data.CustomHeaderKey": "class (Enum)",
+  "skyflow.vault.data.CustomHeaderKey.REQUEST_ID_HEADER": "attr = 'x-request-id'",
+  "skyflow.vault.data.CustomHeaderKey.SKYFLOW_ACCOUNT_ID": "attr = 'x-skyflow-account-id'",
+  "skyflow.vault.data.CustomHeaderKey.SKYFLOW_ACCOUNT_NAME": "attr = 'x-skyflow-account-name'",
+  "skyflow.vault.data.DeleteOptions": "class ()",
+  "skyflow.vault.data.DeleteOptions.__init__": "def (self, interceptor: Optional[Callable[[RequestContext], None]] = None)",
+  "skyflow.vault.data.DeleteOptions.interceptor": "attr",
+  "skyflow.vault.data.DeleteRequest": "class ()",
+  "skyflow.vault.data.DeleteRequest.__init__": "def (self, table_name: str, ids: list = None, unique_values: list = None)",
+  "skyflow.vault.data.DeleteRequest.ids": "attr",
+  "skyflow.vault.data.DeleteRequest.table_name": "attr",
+  "skyflow.vault.data.DeleteRequest.unique_values": "attr",
+  "skyflow.vault.data.DeleteResponse": "class ()",
+  "skyflow.vault.data.DeleteResponse.__init__": "def (self, records = None)",
+  "skyflow.vault.data.DeleteResponse.records": "attr",
+  "skyflow.vault.data.DeleteResponseRecord": "class ()",
+  "skyflow.vault.data.DeleteResponseRecord.__init__": "def (self, skyflow_id = None, http_code = None, error = None, request_id = None)",
+  "skyflow.vault.data.DeleteResponseRecord.error": "attr",
+  "skyflow.vault.data.DeleteResponseRecord.http_code": "attr",
+  "skyflow.vault.data.DeleteResponseRecord.request_id": "attr",
+  "skyflow.vault.data.DeleteResponseRecord.skyflow_id": "attr",
+  "skyflow.vault.data.DetokenizeOptions": "class ()",
+  "skyflow.vault.data.DetokenizeOptions.__init__": "def (self, interceptor: Optional[Callable[[RequestContext], None]] = None)",
+  "skyflow.vault.data.DetokenizeOptions.interceptor": "attr",
+  "skyflow.vault.data.DetokenizeRequest": "class ()",
+  "skyflow.vault.data.DetokenizeRequest.__init__": "def (self, tokens: list, token_group_redactions: List[TokenGroupRedactions] = None)",
+  "skyflow.vault.data.DetokenizeRequest.token_group_redactions": "attr",
+  "skyflow.vault.data.DetokenizeRequest.tokens": "attr",
+  "skyflow.vault.data.DetokenizeResponse": "class ()",
+  "skyflow.vault.data.DetokenizeResponse.__init__": "def (self, records = None)",
+  "skyflow.vault.data.DetokenizeResponse.records": "attr",
+  "skyflow.vault.data.DetokenizeResponseRecord": "class ()",
+  "skyflow.vault.data.DetokenizeResponseRecord.__init__": "def (self, token = None, value = None, token_group_name = None, metadata = None, http_code = None, error = None, request_id = None)",
+  "skyflow.vault.data.DetokenizeResponseRecord.error": "attr",
+  "skyflow.vault.data.DetokenizeResponseRecord.http_code": "attr",
+  "skyflow.vault.data.DetokenizeResponseRecord.metadata": "attr",
+  "skyflow.vault.data.DetokenizeResponseRecord.request_id": "attr",
+  "skyflow.vault.data.DetokenizeResponseRecord.token": "attr",
+  "skyflow.vault.data.DetokenizeResponseRecord.token_group_name": "attr",
+  "skyflow.vault.data.DetokenizeResponseRecord.value": "attr",
+  "skyflow.vault.data.DetokenizeResponseRecordMetadata": "class ()",
+  "skyflow.vault.data.DetokenizeResponseRecordMetadata.__init__": "def (self, skyflow_id: str = None, table_name: str = None)",
+  "skyflow.vault.data.DetokenizeResponseRecordMetadata.skyflow_id": "attr",
+  "skyflow.vault.data.DetokenizeResponseRecordMetadata.table_name": "attr",
+  "skyflow.vault.data.DetokenizeSummary": "class ()",
+  "skyflow.vault.data.DetokenizeSummary.__init__": "def (self, total_tokens = 0, total_detokenized = 0, total_failed = 0)",
+  "skyflow.vault.data.DetokenizeSummary.total_detokenized": "attr",
+  "skyflow.vault.data.DetokenizeSummary.total_failed": "attr",
+  "skyflow.vault.data.DetokenizeSummary.total_tokens": "attr",
+  "skyflow.vault.data.GetOptions": "class ()",
+  "skyflow.vault.data.GetOptions.__init__": "def (self, interceptor: Optional[Callable[[RequestContext], None]] = None)",
+  "skyflow.vault.data.GetOptions.interceptor": "attr",
+  "skyflow.vault.data.GetRequest": "class ()",
+  "skyflow.vault.data.GetRequest.__init__": "def (self, table_name: str = None, skyflow_ids: list = None, unique_values: list = None, columns: list = None, column_redactions: List[ColumnRedactions] = None, limit: int = None, offset: int = None, records: list = None)",
+  "skyflow.vault.data.GetRequest.column_redactions": "attr",
+  "skyflow.vault.data.GetRequest.columns": "attr",
+  "skyflow.vault.data.GetRequest.limit": "attr",
+  "skyflow.vault.data.GetRequest.offset": "attr",
+  "skyflow.vault.data.GetRequest.records": "attr",
+  "skyflow.vault.data.GetRequest.skyflow_ids": "attr",
+  "skyflow.vault.data.GetRequest.table_name": "attr",
+  "skyflow.vault.data.GetRequest.unique_values": "attr",
+  "skyflow.vault.data.GetRequestRecord": "class ()",
+  "skyflow.vault.data.GetRequestRecord.__init__": "def (self, table_name: str, skyflow_ids: list = None, columns: list = None, column_redactions: List[ColumnRedactions] = None, unique_values: list = None)",
+  "skyflow.vault.data.GetRequestRecord.column_redactions": "attr",
+  "skyflow.vault.data.GetRequestRecord.columns": "attr",
+  "skyflow.vault.data.GetRequestRecord.skyflow_ids": "attr",
+  "skyflow.vault.data.GetRequestRecord.table_name": "attr",
+  "skyflow.vault.data.GetRequestRecord.unique_values": "attr",
+  "skyflow.vault.data.GetResponse": "class ()",
+  "skyflow.vault.data.GetResponse.__init__": "def (self, records = None)",
+  "skyflow.vault.data.GetResponse.records": "attr",
+  "skyflow.vault.data.GetResponseRecord": "class ()",
+  "skyflow.vault.data.GetResponseRecord.__init__": "def (self, skyflow_id = None, table_name = None, tokens = None, data = None, hashed_data = None, http_code = None, error = None, request_id = None)",
+  "skyflow.vault.data.GetResponseRecord.data": "attr",
+  "skyflow.vault.data.GetResponseRecord.error": "attr",
+  "skyflow.vault.data.GetResponseRecord.hashed_data": "attr",
+  "skyflow.vault.data.GetResponseRecord.http_code": "attr",
+  "skyflow.vault.data.GetResponseRecord.request_id": "attr",
+  "skyflow.vault.data.GetResponseRecord.skyflow_id": "attr",
+  "skyflow.vault.data.GetResponseRecord.table_name": "attr",
+  "skyflow.vault.data.GetResponseRecord.tokens": "attr",
+  "skyflow.vault.data.InsertOptions": "class ()",
+  "skyflow.vault.data.InsertOptions.__init__": "def (self, interceptor: Optional[Callable[[RequestContext], None]] = None)",
+  "skyflow.vault.data.InsertOptions.interceptor": "attr",
+  "skyflow.vault.data.InsertRequest": "class ()",
+  "skyflow.vault.data.InsertRequest.__init__": "def (self, records: List[InsertRequestRecord], table_name: str = None, upsert: UpsertOptions = None)",
+  "skyflow.vault.data.InsertRequest.records": "attr",
+  "skyflow.vault.data.InsertRequest.table_name": "attr",
+  "skyflow.vault.data.InsertRequest.upsert": "attr",
+  "skyflow.vault.data.InsertRequestRecord": "class ()",
+  "skyflow.vault.data.InsertRequestRecord.__init__": "def (self, data: dict, table_name: str = None, tokens: dict = None, upsert: UpsertOptions = None)",
+  "skyflow.vault.data.InsertRequestRecord.data": "attr",
+  "skyflow.vault.data.InsertRequestRecord.table_name": "attr",
+  "skyflow.vault.data.InsertRequestRecord.tokens": "attr",
+  "skyflow.vault.data.InsertRequestRecord.upsert": "attr",
+  "skyflow.vault.data.InsertResponse": "class ()",
+  "skyflow.vault.data.InsertResponse.__init__": "def (self, records = None)",
+  "skyflow.vault.data.InsertResponse.records": "attr",
+  "skyflow.vault.data.InsertResponseRecord": "class ()",
+  "skyflow.vault.data.InsertResponseRecord.__init__": "def (self, skyflow_id = None, table_name = None, tokens = None, data = None, hashed_data = None, http_code = None, error = None, request_id = None)",
+  "skyflow.vault.data.InsertResponseRecord.data": "attr",
+  "skyflow.vault.data.InsertResponseRecord.error": "attr",
+  "skyflow.vault.data.InsertResponseRecord.hashed_data": "attr",
+  "skyflow.vault.data.InsertResponseRecord.http_code": "attr",
+  "skyflow.vault.data.InsertResponseRecord.request_id": "attr",
+  "skyflow.vault.data.InsertResponseRecord.skyflow_id": "attr",
+  "skyflow.vault.data.InsertResponseRecord.table_name": "attr",
+  "skyflow.vault.data.InsertResponseRecord.tokens": "attr",
+  "skyflow.vault.data.RequestContext": "class ()",
+  "skyflow.vault.data.RequestContext.__init__": "def (self, operation, batch_index = NOT_BATCHED, total_batches = NOT_BATCHED)",
+  "skyflow.vault.data.RequestContext.add_header": "def (self, key, value)",
+  "skyflow.vault.data.RequestContext.batch_index": "attr",
+  "skyflow.vault.data.RequestContext.headers": "attr",
+  "skyflow.vault.data.RequestContext.operation": "attr",
+  "skyflow.vault.data.RequestContext.total_batches": "attr",
+  "skyflow.vault.data.Token": "class ()",
+  "skyflow.vault.data.Token.__init__": "def (self, token: str = None, token_group_name: str = None, path: str = None)",
+  "skyflow.vault.data.Token.path": "attr",
+  "skyflow.vault.data.Token.token": "attr",
+  "skyflow.vault.data.Token.token_group_name": "attr",
+  "skyflow.vault.data.TokenGroupRedactions": "class ()",
+  "skyflow.vault.data.TokenGroupRedactions.__init__": "def (self, token_group_name: str = None, redaction: str = None)",
+  "skyflow.vault.data.TokenGroupRedactions.redaction": "attr",
+  "skyflow.vault.data.TokenGroupRedactions.token_group_name": "attr",
+  "skyflow.vault.data.UpdateOptions": "class ()",
+  "skyflow.vault.data.UpdateOptions.__init__": "def (self, interceptor: Optional[Callable[[RequestContext], None]] = None)",
+  "skyflow.vault.data.UpdateOptions.interceptor": "attr",
+  "skyflow.vault.data.UpdateRequest": "class ()",
+  "skyflow.vault.data.UpdateRequest.__init__": "def (self, records: List[UpdateRequestRecord], table_name: str = None, update_type: UpsertType = None)",
+  "skyflow.vault.data.UpdateRequest.records": "attr",
+  "skyflow.vault.data.UpdateRequest.table_name": "attr",
+  "skyflow.vault.data.UpdateRequest.update_type": "attr",
+  "skyflow.vault.data.UpdateRequestRecord": "class ()",
+  "skyflow.vault.data.UpdateRequestRecord.__init__": "def (self, skyflow_id: str = None, data: dict = None, tokens: dict = None, table_name: str = None)",
+  "skyflow.vault.data.UpdateRequestRecord.data": "attr",
+  "skyflow.vault.data.UpdateRequestRecord.skyflow_id": "attr",
+  "skyflow.vault.data.UpdateRequestRecord.table_name": "attr",
+  "skyflow.vault.data.UpdateRequestRecord.tokens": "attr",
+  "skyflow.vault.data.UpdateResponse": "class ()",
+  "skyflow.vault.data.UpdateResponse.__init__": "def (self, records = None)",
+  "skyflow.vault.data.UpdateResponse.records": "attr",
+  "skyflow.vault.data.UpdateResponseRecord": "class ()",
+  "skyflow.vault.data.UpdateResponseRecord.__init__": "def (self, skyflow_id = None, table_name = None, tokens = None, data = None, hashed_data = None, http_code = None, error = None, request_id = None)",
+  "skyflow.vault.data.UpdateResponseRecord.data": "attr",
+  "skyflow.vault.data.UpdateResponseRecord.error": "attr",
+  "skyflow.vault.data.UpdateResponseRecord.hashed_data": "attr",
+  "skyflow.vault.data.UpdateResponseRecord.http_code": "attr",
+  "skyflow.vault.data.UpdateResponseRecord.request_id": "attr",
+  "skyflow.vault.data.UpdateResponseRecord.skyflow_id": "attr",
+  "skyflow.vault.data.UpdateResponseRecord.table_name": "attr",
+  "skyflow.vault.data.UpdateResponseRecord.tokens": "attr",
+  "skyflow.vault.data.UpsertOptions": "class ()",
+  "skyflow.vault.data.UpsertOptions.__init__": "def (self, unique_columns: list = None, update_type: UpsertType = None)",
+  "skyflow.vault.data.UpsertOptions.unique_columns": "attr",
+  "skyflow.vault.data.UpsertOptions.update_type": "attr"
+}

@github-actions

Copy link
Copy Markdown

Public API contract change (skyvault)

This PR changes skyvault/api-report/skyflow.api.json (the approved public API contract for skyflow). Review the surface change below:

diff --git a/skyvault/api-report/skyflow.api.json b/skyvault/api-report/skyflow.api.json
new file mode 100644
index 0000000..0f28168
--- /dev/null
+++ b/skyvault/api-report/skyflow.api.json
@@ -0,0 +1,360 @@
+{
+  "skyflow.Env": "class (Enum)",
+  "skyflow.Env.DEV": "attr = 'DEV'",
+  "skyflow.Env.PROD": "attr = 'PROD'",
+  "skyflow.Env.SANDBOX": "attr = 'SANDBOX'",
+  "skyflow.Env.STAGE": "attr = 'STAGE'",
+  "skyflow.LogLevel": "class (Enum)",
+  "skyflow.LogLevel.DEBUG": "attr = 1",
+  "skyflow.LogLevel.ERROR": "attr = 4",
+  "skyflow.LogLevel.INFO": "attr = 2",
+  "skyflow.LogLevel.OFF": "attr = 5",
+  "skyflow.LogLevel.WARN": "attr = 3",
+  "skyflow.Skyflow": "attr",
+  "skyflow.client.Skyflow": "attr",
+  "skyflow.error.SkyflowError": "class (Exception)",
+  "skyflow.error.SkyflowError.__init__": "def (self, message, http_code, request_id = None, grpc_code = None, http_status = None, details = None)",
+  "skyflow.error.SkyflowError.details": "attr",
+  "skyflow.error.SkyflowError.grpc_code": "attr",
+  "skyflow.error.SkyflowError.http_code": "attr",
+  "skyflow.error.SkyflowError.http_status": "attr",
+  "skyflow.error.SkyflowError.message": "attr",
+  "skyflow.error.SkyflowError.request_id": "attr",
+  "skyflow.service_account.generate_bearer_token": "def (credentials_file_path, options = None, logger = None)",
+  "skyflow.service_account.generate_bearer_token_from_creds": "def (credentials, options = None, logger = None)",
+  "skyflow.service_account.generate_signed_data_tokens": "def (credentials_file_path, options)",
+  "skyflow.service_account.generate_signed_data_tokens_from_creds": "def (credentials, options)",
+  "skyflow.service_account.is_expired": "def (token, logger = None)",
+  "skyflow.utils.enums.ContentType": "class (Enum)",
+  "skyflow.utils.enums.ContentType.FORMDATA": "attr = 'multipart/form-data'",
+  "skyflow.utils.enums.ContentType.HTML": "attr = 'text/html'",
+  "skyflow.utils.enums.ContentType.JSON": "attr = 'application/json'",
+  "skyflow.utils.enums.ContentType.PLAINTEXT": "attr = 'text/plain'",
+  "skyflow.utils.enums.ContentType.URLENCODED": "attr = 'application/x-www-form-urlencoded'",
+  "skyflow.utils.enums.ContentType.XML": "attr = 'text/xml'",
+  "skyflow.utils.enums.DetectEntities": "class (Enum)",
+  "skyflow.utils.enums.DetectEntities.ACCOUNT_NUMBER": "attr = 'account_number'",
+  "skyflow.utils.enums.DetectEntities.AGE": "attr = 'age'",
+  "skyflow.utils.enums.DetectEntities.ALL": "attr = 'all'",
+  "skyflow.utils.enums.DetectEntities.BANK_ACCOUNT": "attr = 'bank_account'",
+  "skyflow.utils.enums.DetectEntities.BLOOD_TYPE": "attr = 'blood_type'",
+  "skyflow.utils.enums.DetectEntities.CONDITION": "attr = 'condition'",
+  "skyflow.utils.enums.DetectEntities.CORPORATE_ACTION": "attr = 'corporate_action'",
+  "skyflow.utils.enums.DetectEntities.CREDIT_CARD": "attr = 'credit_card'",
+  "skyflow.utils.enums.DetectEntities.CREDIT_CARD_EXPIRATION": "attr = 'credit_card_expiration'",
+  "skyflow.utils.enums.DetectEntities.CVV": "attr = 'cvv'",
+  "skyflow.utils.enums.DetectEntities.DATE": "attr = 'date'",
+  "skyflow.utils.enums.DetectEntities.DATE_INTERVAL": "attr = 'date_interval'",
+  "skyflow.utils.enums.DetectEntities.DAY": "attr = 'day'",
+  "skyflow.utils.enums.DetectEntities.DOB": "attr = 'dob'",
+  "skyflow.utils.enums.DetectEntities.DOSE": "attr = 'dose'",
+  "skyflow.utils.enums.DetectEntities.DRIVER_LICENSE": "attr = 'driver_license'",
+  "skyflow.utils.enums.DetectEntities.DRUG": "attr = 'drug'",
+  "skyflow.utils.enums.DetectEntities.DURATION": "attr = 'duration'",
+  "skyflow.utils.enums.DetectEntities.EFFECT": "attr = 'effect'",
+  "skyflow.utils.enums.DetectEntities.EMAIL_ADDRESS": "attr = 'email_address'",
+  "skyflow.utils.enums.DetectEntities.EVENT": "attr = 'event'",
+  "skyflow.utils.enums.DetectEntities.FILENAME": "attr = 'filename'",
+  "skyflow.utils.enums.DetectEntities.FINANCIAL_METRIC": "attr = 'financial_metric'",
+  "skyflow.utils.enums.DetectEntities.GENDER": "attr = 'gender'",
+  "skyflow.utils.enums.DetectEntities.HEALTHCARE_NUMBER": "attr = 'healthcare_number'",
+  "skyflow.utils.enums.DetectEntities.INJURY": "attr = 'injury'",
+  "skyflow.utils.enums.DetectEntities.IP_ADDRESS": "attr = 'ip_address'",
+  "skyflow.utils.enums.DetectEntities.LANGUAGE": "attr = 'language'",
+  "skyflow.utils.enums.DetectEntities.LOCATION": "attr = 'location'",
+  "skyflow.utils.enums.DetectEntities.LOCATION_ADDRESS": "attr = 'location_address'",
+  "skyflow.utils.enums.DetectEntities.LOCATION_ADDRESS_STREET": "attr = 'location_address_street'",
+  "skyflow.utils.enums.DetectEntities.LOCATION_CITY": "attr = 'location_city'",
+  "skyflow.utils.enums.DetectEntities.LOCATION_COORDINATE": "attr = 'location_coordinate'",
+  "skyflow.utils.enums.DetectEntities.LOCATION_COUNTRY": "attr = 'location_country'",
+  "skyflow.utils.enums.DetectEntities.LOCATION_STATE": "attr = 'location_state'",
+  "skyflow.utils.enums.DetectEntities.LOCATION_ZIP": "attr = 'location_zip'",
+  "skyflow.utils.enums.DetectEntities.MARITAL_STATUS": "attr = 'marital_status'",
+  "skyflow.utils.enums.DetectEntities.MEDICAL_CODE": "attr = 'medical_code'",
+  "skyflow.utils.enums.DetectEntities.MEDICAL_PROCESS": "attr = 'medical_process'",
+  "skyflow.utils.enums.DetectEntities.MONEY": "attr = 'money'",
+  "skyflow.utils.enums.DetectEntities.MONTH": "attr = 'month'",
+  "skyflow.utils.enums.DetectEntities.NAME": "attr = 'name'",
+  "skyflow.utils.enums.DetectEntities.NAME_FAMILY": "attr = 'name_family'",
+  "skyflow.utils.enums.DetectEntities.NAME_GIVEN": "attr = 'name_given'",
+  "skyflow.utils.enums.DetectEntities.NAME_MEDICAL_PROFESSIONAL": "attr = 'name_medical_professional'",
+  "skyflow.utils.enums.DetectEntities.NUMERICAL_PII": "attr = 'numerical_pii'",
+  "skyflow.utils.enums.DetectEntities.OCCUPATION": "attr = 'occupation'",
+  "skyflow.utils.enums.DetectEntities.ORGANIZATION": "attr = 'organization'",
+  "skyflow.utils.enums.DetectEntities.ORGANIZATION_ID": "attr = 'organization_id'",
+  "skyflow.utils.enums.DetectEntities.ORGANIZATION_MEDICAL_FACILITY": "attr = 'organization_medical_facility'",
+  "skyflow.utils.enums.DetectEntities.ORIGIN": "attr = 'origin'",
+  "skyflow.utils.enums.DetectEntities.PASSPORT_NUMBER": "attr = 'passport_number'",
+  "skyflow.utils.enums.DetectEntities.PASSWORD": "attr = 'password'",
+  "skyflow.utils.enums.DetectEntities.PHONE_NUMBER": "attr = 'phone_number'",
+  "skyflow.utils.enums.DetectEntities.PHYSICAL_ATTRIBUTE": "attr = 'physical_attribute'",
+  "skyflow.utils.enums.DetectEntities.POLITICAL_AFFILIATION": "attr = 'political_affiliation'",
+  "skyflow.utils.enums.DetectEntities.PRODUCT": "attr = 'product'",
+  "skyflow.utils.enums.DetectEntities.PROJECT": "attr = 'project'",
+  "skyflow.utils.enums.DetectEntities.RELIGION": "attr = 'religion'",
+  "skyflow.utils.enums.DetectEntities.ROUTING_NUMBER": "attr = 'routing_number'",
+  "skyflow.utils.enums.DetectEntities.SEXUALITY": "attr = 'sexuality'",
+  "skyflow.utils.enums.DetectEntities.SSN": "attr = 'ssn'",
+  "skyflow.utils.enums.DetectEntities.STATISTICS": "attr = 'statistics'",
+  "skyflow.utils.enums.DetectEntities.TIME": "attr = 'time'",
+  "skyflow.utils.enums.DetectEntities.TREND": "attr = 'trend'",
+  "skyflow.utils.enums.DetectEntities.URL": "attr = 'url'",
+  "skyflow.utils.enums.DetectEntities.USERNAME": "attr = 'username'",
+  "skyflow.utils.enums.DetectEntities.VEHICLE_ID": "attr = 'vehicle_id'",
+  "skyflow.utils.enums.DetectEntities.YEAR": "attr = 'year'",
+  "skyflow.utils.enums.DetectEntities.ZODIAC_SIGN": "attr = 'zodiac_sign'",
+  "skyflow.utils.enums.DetectOutputTranscriptions": "class (Enum)",
+  "skyflow.utils.enums.DetectOutputTranscriptions.DIARIZED_TRANSCRIPTION": "attr = 'diarized_transcription'",
+  "skyflow.utils.enums.DetectOutputTranscriptions.MEDICAL_DIARIZED_TRANSCRIPTION": "attr = 'medical_diarized_transcription'",
+  "skyflow.utils.enums.DetectOutputTranscriptions.MEDICAL_TRANSCRIPTION": "attr = 'medical_transcription'",
+  "skyflow.utils.enums.DetectOutputTranscriptions.PLAINTEXT_TRANSCRIPTION": "attr = 'plaintext_transcription'",
+  "skyflow.utils.enums.DetectOutputTranscriptions.TRANSCRIPTION": "attr = 'transcription'",
+  "skyflow.utils.enums.Env": "class (Enum)",
+  "skyflow.utils.enums.Env.DEV": "attr = 'DEV'",
+  "skyflow.utils.enums.Env.PROD": "attr = 'PROD'",
+  "skyflow.utils.enums.Env.SANDBOX": "attr = 'SANDBOX'",
+  "skyflow.utils.enums.Env.STAGE": "attr = 'STAGE'",
+  "skyflow.utils.enums.EnvUrls": "class (Enum)",
+  "skyflow.utils.enums.EnvUrls.DEV": "attr = 'vault.skyflowapis.dev'",
+  "skyflow.utils.enums.EnvUrls.PROD": "attr = 'vault.skyflowapis.com'",
+  "skyflow.utils.enums.EnvUrls.SANDBOX": "attr = 'vault.skyflowapis-preview.com'",
+  "skyflow.utils.enums.EnvUrls.STAGE": "attr = 'vault.skyflowapis.tech'",
+  "skyflow.utils.enums.LogLevel": "class (Enum)",
+  "skyflow.utils.enums.LogLevel.DEBUG": "attr = 1",
+  "skyflow.utils.enums.LogLevel.ERROR": "attr = 4",
+  "skyflow.utils.enums.LogLevel.INFO": "attr = 2",
+  "skyflow.utils.enums.LogLevel.OFF": "attr = 5",
+  "skyflow.utils.enums.LogLevel.WARN": "attr = 3",
+  "skyflow.utils.enums.MaskingMethod": "class (Enum)",
+  "skyflow.utils.enums.MaskingMethod.BLACKBOX": "attr = 'blackbox'",
+  "skyflow.utils.enums.MaskingMethod.BLUR": "attr = 'blur'",
+  "skyflow.utils.enums.RedactionType": "class (Enum)",
+  "skyflow.utils.enums.RedactionType.DEFAULT": "attr = 'DEFAULT'",
+  "skyflow.utils.enums.RedactionType.MASKED": "attr = 'MASKED'",
+  "skyflow.utils.enums.RedactionType.PLAIN_TEXT": "attr = 'PLAIN_TEXT'",
+  "skyflow.utils.enums.RedactionType.REDACTED": "attr = 'REDACTED'",
+  "skyflow.utils.enums.RequestMethod": "class (Enum)",
+  "skyflow.utils.enums.RequestMethod.DELETE": "attr = 'DELETE'",
+  "skyflow.utils.enums.RequestMethod.GET": "attr = 'GET'",
+  "skyflow.utils.enums.RequestMethod.NONE": "attr = 'NONE'",
+  "skyflow.utils.enums.RequestMethod.POST": "attr = 'POST'",
+  "skyflow.utils.enums.RequestMethod.PUT": "attr = 'PUT'",
+  "skyflow.utils.enums.TokenMode": "class (Enum)",
+  "skyflow.utils.enums.TokenMode.DISABLE": "attr = 'DISABLE'",
+  "skyflow.utils.enums.TokenMode.ENABLE": "attr = 'ENABLE'",
+  "skyflow.utils.enums.TokenMode.ENABLE_STRICT": "attr = 'ENABLE_STRICT'",
+  "skyflow.utils.enums.TokenType": "class (Enum)",
+  "skyflow.utils.enums.TokenType.ENTITY_ONLY": "attr = 'entity_only'",
+  "skyflow.utils.enums.TokenType.ENTITY_UNIQUE_COUNTER": "attr = 'entity_unq_counter'",
+  "skyflow.utils.enums.TokenType.VAULT_TOKEN": "attr = 'vault_token'",
+  "skyflow.vault.connection.InvokeConnectionRequest": "class ()",
+  "skyflow.vault.connection.InvokeConnectionRequest.__init__": "def (self, method, body = None, path_params = None, query_params = None, headers = None)",
+  "skyflow.vault.connection.InvokeConnectionRequest.body": "attr",
+  "skyflow.vault.connection.InvokeConnectionRequest.headers": "attr",
+  "skyflow.vault.connection.InvokeConnectionRequest.method": "attr",
+  "skyflow.vault.connection.InvokeConnectionRequest.path_params": "attr",
+  "skyflow.vault.connection.InvokeConnectionRequest.query_params": "attr",
+  "skyflow.vault.connection.InvokeConnectionResponse": "class ()",
+  "skyflow.vault.connection.InvokeConnectionResponse.__init__": "def (self, data = None, metadata = None, errors = None)",
+  "skyflow.vault.connection.InvokeConnectionResponse.data": "attr",
+  "skyflow.vault.connection.InvokeConnectionResponse.errors": "attr",
+  "skyflow.vault.connection.InvokeConnectionResponse.metadata": "attr",
+  "skyflow.vault.controller.Connection": "class ()",
+  "skyflow.vault.controller.Connection.__init__": "def (self, vault_client)",
+  "skyflow.vault.controller.Connection.invoke": "def (self, request: InvokeConnectionRequest)",
+  "skyflow.vault.controller.Detect": "class ()",
+  "skyflow.vault.controller.Detect.__init__": "def (self, vault_client)",
+  "skyflow.vault.controller.Detect.deidentify_file": "def (self, request: DeidentifyFileRequest)",
+  "skyflow.vault.controller.Detect.deidentify_text": "def (self, request: DeidentifyTextRequest) -> DeidentifyTextResponse",
+  "skyflow.vault.controller.Detect.get_detect_run": "def (self, request: GetDetectRunRequest)",
+  "skyflow.vault.controller.Detect.reidentify_text": "def (self, request: ReidentifyTextRequest) -> ReidentifyTextResponse",
+  "skyflow.vault.controller.Vault": "attr",
+  "skyflow.vault.controller.VaultController": "class (BaseVaultController)",
+  "skyflow.vault.controller.VaultController.__init__": "def (self, vault_client)",
+  "skyflow.vault.controller.VaultController.delete": "def (self, request: DeleteRequest) -> DeleteResponse",
+  "skyflow.vault.controller.VaultController.detokenize": "def (self, request: DetokenizeRequest) -> DetokenizeResponse",
+  "skyflow.vault.controller.VaultController.get": "def (self, request: GetRequest) -> GetResponse",
+  "skyflow.vault.controller.VaultController.insert": "def (self, request: InsertRequest) -> InsertResponse",
+  "skyflow.vault.controller.VaultController.query": "def (self, request: QueryRequest) -> QueryResponse",
+  "skyflow.vault.controller.VaultController.tokenize": "def (self, request: TokenizeRequest) -> TokenizeResponse",
+  "skyflow.vault.controller.VaultController.update": "def (self, request: UpdateRequest) -> UpdateResponse",
+  "skyflow.vault.controller.VaultController.upload_file": "def (self, request: FileUploadRequest) -> FileUploadResponse",
+  "skyflow.vault.data.DeleteRequest": "class ()",
+  "skyflow.vault.data.DeleteRequest.__init__": "def (self, table, ids)",
+  "skyflow.vault.data.DeleteRequest.ids": "attr",
+  "skyflow.vault.data.DeleteRequest.table": "attr",
+  "skyflow.vault.data.DeleteResponse": "class ()",
+  "skyflow.vault.data.DeleteResponse.__init__": "def (self, deleted_ids = None, errors = None)",
+  "skyflow.vault.data.DeleteResponse.deleted_ids": "attr",
+  "skyflow.vault.data.DeleteResponse.errors": "attr",
+  "skyflow.vault.data.FileUploadRequest": "class ()",
+  "skyflow.vault.data.FileUploadRequest.__init__": "def (self, table: str, args = (), column_name: Optional[str] = None, skyflow_id: Optional[str] = None, file_path: Optional[str] = None, base64: Optional[str] = None, file_object: Optional[BinaryIO] = None, file_name: Optional[str] = None)",
+  "skyflow.vault.data.FileUploadRequest.base64": "attr",
+  "skyflow.vault.data.FileUploadRequest.column_name": "attr",
+  "skyflow.vault.data.FileUploadRequest.file_name": "attr",
+  "skyflow.vault.data.FileUploadRequest.file_object": "attr",
+  "skyflow.vault.data.FileUploadRequest.file_path": "attr",
+  "skyflow.vault.data.FileUploadRequest.skyflow_id": "attr",
+  "skyflow.vault.data.FileUploadRequest.table": "attr",
+  "skyflow.vault.data.FileUploadResponse": "class ()",
+  "skyflow.vault.data.FileUploadResponse.__init__": "def (self, skyflow_id, errors)",
+  "skyflow.vault.data.FileUploadResponse.errors": "attr",
+  "skyflow.vault.data.FileUploadResponse.skyflow_id": "attr",
+  "skyflow.vault.data.GetRequest": "class ()",
+  "skyflow.vault.data.GetRequest.__init__": "def (self, table, ids = None, redaction_type = None, return_tokens = False, fields = None, offset = None, limit = None, download_url = None, column_name = None, column_values = None)",
+  "skyflow.vault.data.GetRequest.column_name": "attr",
+  "skyflow.vault.data.GetRequest.column_values": "attr",
+  "skyflow.vault.data.GetRequest.download_url": "attr",
+  "skyflow.vault.data.GetRequest.fields": "attr",
+  "skyflow.vault.data.GetRequest.ids": "attr",
+  "skyflow.vault.data.GetRequest.limit": "attr",
+  "skyflow.vault.data.GetRequest.offset": "attr",
+  "skyflow.vault.data.GetRequest.redaction_type": "attr",
+  "skyflow.vault.data.GetRequest.return_tokens": "attr",
+  "skyflow.vault.data.GetRequest.table": "attr",
+  "skyflow.vault.data.GetResponse": "class ()",
+  "skyflow.vault.data.GetResponse.__init__": "def (self, data = None, errors = None)",
+  "skyflow.vault.data.GetResponse.data": "attr",
+  "skyflow.vault.data.GetResponse.errors": "attr",
+  "skyflow.vault.data.InsertRequest": "class (BaseInsertRequest)",
+  "skyflow.vault.data.InsertRequest.__init__": "def (self, table: str, values: list, tokens: list = None, upsert: str = None, homogeneous: bool = False, token_mode: TokenMode = TokenMode.DISABLE, return_tokens: bool = True, continue_on_error: bool = False)",
+  "skyflow.vault.data.InsertRequest.continue_on_error": "attr",
+  "skyflow.vault.data.InsertRequest.homogeneous": "attr",
+  "skyflow.vault.data.InsertRequest.return_tokens": "attr",
+  "skyflow.vault.data.InsertRequest.token_mode": "attr",
+  "skyflow.vault.data.InsertRequest.tokens": "attr",
+  "skyflow.vault.data.InsertResponse": "class (BaseInsertResponse)",
+  "skyflow.vault.data.QueryRequest": "class ()",
+  "skyflow.vault.data.QueryRequest.__init__": "def (self, query)",
+  "skyflow.vault.data.QueryRequest.query": "attr",
+  "skyflow.vault.data.QueryResponse": "class ()",
+  "skyflow.vault.data.QueryResponse.__init__": "def (self)",
+  "skyflow.vault.data.QueryResponse.errors": "attr",
+  "skyflow.vault.data.QueryResponse.fields": "attr",
+  "skyflow.vault.data.UpdateRequest": "class ()",
+  "skyflow.vault.data.UpdateRequest.__init__": "def (self, table, data, tokens = None, return_tokens = False, token_mode = TokenMode.DISABLE)",
+  "skyflow.vault.data.UpdateRequest.data": "attr",
+  "skyflow.vault.data.UpdateRequest.return_tokens": "attr",
+  "skyflow.vault.data.UpdateRequest.table": "attr",
+  "skyflow.vault.data.UpdateRequest.token_mode": "attr",
+  "skyflow.vault.data.UpdateRequest.tokens": "attr",
+  "skyflow.vault.data.UpdateResponse": "class ()",
+  "skyflow.vault.data.UpdateResponse.__init__": "def (self, updated_field = None, errors = None)",
+  "skyflow.vault.data.UpdateResponse.errors": "attr",
+  "skyflow.vault.data.UpdateResponse.updated_field": "attr",
+  "skyflow.vault.data.UploadFileRequest": "class ()",
+  "skyflow.vault.data.UploadFileRequest.__init__": "def (self)",
+  "skyflow.vault.detect.Bleep": "class ()",
+  "skyflow.vault.detect.Bleep.__init__": "def (self, gain: Optional[float] = None, frequency: Optional[float] = None, start_padding: Optional[float] = None, stop_padding: Optional[float] = None)",
+  "skyflow.vault.detect.Bleep.frequency": "attr",
+  "skyflow.vault.detect.Bleep.gain": "attr",
+  "skyflow.vault.detect.Bleep.start_padding": "attr",
+  "skyflow.vault.detect.Bleep.stop_padding": "attr",
+  "skyflow.vault.detect.DateTransformation": "class ()",
+  "skyflow.vault.detect.DateTransformation.__init__": "def (self, max_days: int, min_days: int, entities: List[DetectEntities])",
+  "skyflow.vault.detect.DateTransformation.entities": "attr",
+  "skyflow.vault.detect.DateTransformation.max": "attr",
+  "skyflow.vault.detect.DateTransformation.min": "attr",
+  "skyflow.vault.detect.DeidentifyFileRequest": "class ()",
+  "skyflow.vault.detect.DeidentifyFileRequest.__init__": "def (self, file = None, entities: Optional[List[DetectEntities]] = None, allow_regex_list: Optional[List[str]] = None, restrict_regex_list: Optional[List[str]] = None, token_format: Optional[TokenFormat] = None, transformations: Optional[Transformations] = None, output_processed_image: Optional[bool] = None, output_ocr_text: Optional[bool] = None, masking_method: Optional[MaskingMethod] = None, pixel_density: Optional[Union[int, float]] = None, max_resolution: Optional[Union[int, float]] = None, output_processed_audio: Optional[bool] = None, output_transcription: Optional[DetectOutputTranscriptions] = None, bleep: Optional[Bleep] = None, output_directory: Optional[str] = None, wait_time: Optional[Union[int, float]] = None)",
+  "skyflow.vault.detect.DeidentifyFileRequest.allow_regex_list": "attr: Optional[List[str]]",
+  "skyflow.vault.detect.DeidentifyFileRequest.bleep": "attr: Optional[Bleep]",
+  "skyflow.vault.detect.DeidentifyFileRequest.entities": "attr: Optional[List[DetectEntities]]",
+  "skyflow.vault.detect.DeidentifyFileRequest.file": "attr: FileInput",
+  "skyflow.vault.detect.DeidentifyFileRequest.masking_method": "attr: Optional[MaskingMethod]",
+  "skyflow.vault.detect.DeidentifyFileRequest.max_resolution": "attr: Optional[Union[int, float]]",
+  "skyflow.vault.detect.DeidentifyFileRequest.output_directory": "attr: Optional[str]",
+  "skyflow.vault.detect.DeidentifyFileRequest.output_ocr_text": "attr: Optional[bool]",
+  "skyflow.vault.detect.DeidentifyFileRequest.output_processed_audio": "attr: Optional[bool]",
+  "skyflow.vault.detect.DeidentifyFileRequest.output_processed_image": "attr: Optional[bool]",
+  "skyflow.vault.detect.DeidentifyFileRequest.output_transcription": "attr: Optional[DetectOutputTranscriptions]",
+  "skyflow.vault.detect.DeidentifyFileRequest.pixel_density": "attr: Optional[Union[int, float]]",
+  "skyflow.vault.detect.DeidentifyFileRequest.restrict_regex_list": "attr: Optional[List[str]]",
+  "skyflow.vault.detect.DeidentifyFileRequest.token_format": "attr: Optional[TokenFormat]",
+  "skyflow.vault.detect.DeidentifyFileRequest.transformations": "attr: Optional[Transformations]",
+  "skyflow.vault.detect.DeidentifyFileRequest.wait_time": "attr: Optional[Union[int, float]]",
+  "skyflow.vault.detect.DeidentifyFileResponse": "class ()",
+  "skyflow.vault.detect.DeidentifyFileResponse.__init__": "def (self, file_base64: Optional[str] = None, file: Optional[io.BytesIO] = None, type: Optional[str] = None, extension: Optional[str] = None, word_count: Optional[int] = None, char_count: Optional[int] = None, size_in_kb: Optional[float] = None, duration_in_seconds: Optional[float] = None, page_count: Optional[int] = None, slide_count: Optional[int] = None, entities: Optional[list] = None, run_id: Optional[str] = None, status: Optional[str] = None, errors: Optional[list] = None)",
+  "skyflow.vault.detect.DeidentifyFileResponse.char_count": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.duration_in_seconds": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.entities": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.errors": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.extension": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.file": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.file_base64": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.page_count": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.run_id": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.size_in_kb": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.slide_count": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.status": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.type": "attr",
+  "skyflow.vault.detect.DeidentifyFileResponse.word_count": "attr",
+  "skyflow.vault.detect.DeidentifyTextRequest": "class ()",
+  "skyflow.vault.detect.DeidentifyTextRequest.__init__": "def (self, text: str, entities: Optional[List[DetectEntities]] = None, allow_regex_list: Optional[List[str]] = None, restrict_regex_list: Optional[List[str]] = None, token_format: Optional[TokenFormat] = None, transformations: Optional[Transformations] = None)",
+  "skyflow.vault.detect.DeidentifyTextRequest.allow_regex_list": "attr",

saileshwar-skyflow and others added 2 commits September 15, 2026 18:24
- generated/rest/version.py looked up a non-existent distribution name
  ("skyflow.generated.rest"), so importing the generated package during
  unittest discovery raised PackageNotFoundError and failed CI. Use the real
  distribution name (skyflow-flowvault-python) and fall back to a default when
  the package is not installed, so the import can never crash. __version__ is
  not used at runtime (the client wrapper sends a hardcoded SDK version).
- Update the unary error tests: a non-2xx response carrying a records body now
  returns per-record error rows (matching Java and bulk) instead of raising,
  and insert responses now carry .data. Whole-call/flat-body errors still raise.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
skyflow-bharti
skyflow-bharti previously approved these changes Sep 15, 2026
The custom build_py vendors the sibling common/ tree into the wheel, but the
sdist never included it, so a source build (pip --no-binary, some mirrors)
produced a package that fails to import common. Add a custom sdist command that
vendors common/ into the tarball (MANIFEST grafts it) and clean it up after, and
resolve COMMON_SRC from that vendored copy when the sibling checkout is absent
(i.e. when building from the sdist). Exclude common from find_packages so the
vendored copy is bundled only through the build_py mechanism. Wheel builds are
unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants