+ Generates a Bearer Token to authenticate with Skyflow.
Parameters
----------
@@ -46,7 +46,7 @@ def authentication_service_get_auth_token(
Grant type of the request. Set this to `urn:ietf:params:oauth:grant-type:jwt-bearer`.
assertion : str
- User-signed JWT token that contains the following fields:
+ Generates a Bearer Token to authenticate with Skyflow.
Parameters
----------
@@ -127,7 +127,7 @@ async def authentication_service_get_auth_token(
Grant type of the request. Set this to `urn:ietf:params:oauth:grant-type:jwt-bearer`.
assertion : str
- User-signed JWT token that contains the following fields:
+ Generates a Bearer Token to authenticate with Skyflow.
Parameters
----------
@@ -41,7 +45,7 @@ def authentication_service_get_auth_token(
Grant type of the request. Set this to `urn:ietf:params:oauth:grant-type:jwt-bearer`.
assertion : str
- User-signed JWT token that contains the following fields:
+ Generates a Bearer Token to authenticate with Skyflow.
Parameters
----------
@@ -153,7 +172,7 @@ async def authentication_service_get_auth_token(
Grant type of the request. Set this to `urn:ietf:params:oauth:grant-type:jwt-bearer`.
assertion : str
- User-signed JWT token that contains the following fields:
+ User-signed JWT token that contains the following fields: iss (Issuer), key (Unique identifier), aud (Recipient), exp (Expiry), sub (Subject), ctx (Optional context for context-aware authorization).
subject_token : typing.Optional[str]
Subject token.
@@ -165,15 +184,15 @@ async def authentication_service_get_auth_token(
Token use type. Either `delegation` or `impersonation`.
scope : typing.Optional[str]
- Subset of available roles to associate with the requested token. Uses the format "role:\ role:\".
+ Subset of available roles to associate with the requested token. Uses the format "role: role:".
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- AsyncHttpResponse[V1GetAuthTokenResponse]
- A successful response.
+ AsyncHttpResponse[GetAuthTokenResponse]
+ OK
"""
_response = await self._client_wrapper.httpx_client.request(
"v1/auth/sa/oauth/token",
@@ -195,9 +214,9 @@ async def authentication_service_get_auth_token(
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- V1GetAuthTokenResponse,
+ GetAuthTokenResponse,
parse_obj_as(
- type_=V1GetAuthTokenResponse, # type: ignore
+ type_=GetAuthTokenResponse, # type: ignore
object_=_response.json(),
),
)
@@ -206,9 +225,9 @@ async def authentication_service_get_auth_token(
raise BadRequestError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Dict[str, typing.Optional[typing.Any]],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Dict[str, typing.Optional[typing.Any]], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -217,9 +236,9 @@ async def authentication_service_get_auth_token(
raise UnauthorizedError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Dict[str, typing.Optional[typing.Any]],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Dict[str, typing.Optional[typing.Any]], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -228,9 +247,20 @@ async def authentication_service_get_auth_token(
raise NotFoundError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Dict[str, typing.Optional[typing.Any]],
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
parse_obj_as(
- type_=typing.Dict[str, typing.Optional[typing.Any]], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -238,4 +268,8 @@ async def authentication_service_get_auth_token(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/common/generated/rest/client.py b/common/generated/rest/client.py
index b210e4da..7123f423 100644
--- a/common/generated/rest/client.py
+++ b/common/generated/rest/client.py
@@ -1,11 +1,22 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
+
import typing
import httpx
-from .authentication.client import AsyncAuthenticationClient, AuthenticationClient
from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from .core.logging import LogConfig, Logger
+from .core.request_options import RequestOptions
from .environment import SkyflowAuthEnvironment
+from .raw_client import AsyncRawSkyflowAuth, RawSkyflowAuth
+
+if typing.TYPE_CHECKING:
+ from .authentication.client import AsyncAuthenticationClient, AuthenticationClient
+ from .files_v2.client import AsyncFilesV2Client, FilesV2Client
+ from .guardrails_v2.client import AsyncGuardrailsV2Client, GuardrailsV2Client
+ from .strings_v2.client import AsyncStringsV2Client, StringsV2Client
+ from .token_exchange.client import AsyncTokenExchangeClient, TokenExchangeClient
class SkyflowAuth:
@@ -26,6 +37,9 @@ class SkyflowAuth:
+ vault_url : typing.Optional[str]
+ Server URL variable for 'vault_url'. Defaults to '{{vault_url}}'.
+
token : typing.Optional[typing.Union[str, typing.Callable[[], str]]]
headers : typing.Optional[typing.Dict[str, str]]
Additional headers to send with every request.
@@ -33,12 +47,24 @@ class SkyflowAuth:
timeout : typing.Optional[float]
The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
+ max_retries : typing.Optional[int]
+ The default maximum number of retries for failed requests. Defaults to 2. Per-request `max_retries` in `request_options` takes precedence over this value.
+
+ stream_reconnection_enabled : typing.Optional[bool]
+ Whether to automatically reconnect on stream disconnection for resumable streaming endpoints. Defaults to True. Per-request `stream_reconnection_enabled` in `request_options` takes precedence over this value.
+
+ max_stream_reconnection_attempts : typing.Optional[int]
+ The maximum number of reconnection attempts for resumable streaming endpoints. Defaults to no limit. Per-request `max_stream_reconnection_attempts` in `request_options` takes precedence over this value.
+
follow_redirects : typing.Optional[bool]
Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.
httpx_client : typing.Optional[httpx.Client]
The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.
+ logging : typing.Optional[typing.Union[LogConfig, Logger]]
+ Configure logging for the SDK. Accepts a LogConfig dict with 'level' (debug/info/warn/error), 'logger' (custom logger implementation), and 'silent' (boolean, defaults to True) fields. You can also pass a pre-configured Logger instance.
+
Examples
--------
from skyflow import SkyflowAuth
@@ -53,15 +79,28 @@ def __init__(
*,
base_url: typing.Optional[str] = None,
environment: SkyflowAuthEnvironment = SkyflowAuthEnvironment.PRODUCTION,
+ vault_url: typing.Optional[str] = None,
token: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None,
headers: typing.Optional[typing.Dict[str, str]] = None,
timeout: typing.Optional[float] = None,
+ max_retries: typing.Optional[int] = None,
+ stream_reconnection_enabled: typing.Optional[bool] = None,
+ max_stream_reconnection_attempts: typing.Optional[int] = None,
follow_redirects: typing.Optional[bool] = True,
httpx_client: typing.Optional[httpx.Client] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
):
- _defaulted_timeout = (
- timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
- )
+ _defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None
+ _defaulted_max_retries = max_retries if max_retries is not None else 2
+ if vault_url is not None:
+ _vault_url = vault_url if vault_url is not None else "{{vault_url}}"
+ _environment_url_templates = {
+ SkyflowAuthEnvironment.PRODUCTION: "https://{vault_url}",
+ SkyflowAuthEnvironment.SANDBOX: "https://{vault_url}",
+ }
+ _url_template = _environment_url_templates.get(environment, "https://{vault_url}")
+ if base_url is None:
+ base_url = _url_template.format(vault_url=_vault_url)
self._client_wrapper = SyncClientWrapper(
base_url=_get_base_url(base_url=base_url, environment=environment),
token=token,
@@ -72,8 +111,113 @@ def __init__(
if follow_redirects is not None
else httpx.Client(timeout=_defaulted_timeout),
timeout=_defaulted_timeout,
+ max_retries=_defaulted_max_retries,
+ stream_reconnection_enabled=stream_reconnection_enabled,
+ max_stream_reconnection_attempts=max_stream_reconnection_attempts,
+ logging=logging,
+ )
+ self._raw_client = RawSkyflowAuth(client_wrapper=self._client_wrapper)
+ self._authentication: typing.Optional[AuthenticationClient] = None
+ self._token_exchange: typing.Optional[TokenExchangeClient] = None
+ self._files_v2: typing.Optional[FilesV2Client] = None
+ self._strings_v2: typing.Optional[StringsV2Client] = None
+ self._guardrails_v2: typing.Optional[GuardrailsV2Client] = None
+
+ @property
+ def with_raw_response(self) -> RawSkyflowAuth:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawSkyflowAuth
+ """
+ return self._raw_client
+
+ def patch_v2vaults_id(
+ self, vault_id: typing.Optional[str], *, request_options: typing.Optional[RequestOptions] = None
+ ) -> None:
+ """
+ Parameters
+ ----------
+ vault_id : typing.Optional[str]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from skyflow import SkyflowAuth
+
+ client = SkyflowAuth(
+ token="YOUR_TOKEN",
)
- self.authentication = AuthenticationClient(client_wrapper=self._client_wrapper)
+ client.patch_v2vaults_id()
+ """
+ _response = self._raw_client.patch_v2vaults_id(vault_id, request_options=request_options)
+ return _response.data
+
+ @property
+ def authentication(self):
+ if self._authentication is None:
+ from .authentication.client import AuthenticationClient # noqa: E402
+
+ self._authentication = AuthenticationClient(client_wrapper=self._client_wrapper)
+ return self._authentication
+
+ @property
+ def token_exchange(self):
+ if self._token_exchange is None:
+ from .token_exchange.client import TokenExchangeClient # noqa: E402
+
+ self._token_exchange = TokenExchangeClient(client_wrapper=self._client_wrapper)
+ return self._token_exchange
+
+ @property
+ def files_v2(self):
+ if self._files_v2 is None:
+ from .files_v2.client import FilesV2Client # noqa: E402
+
+ self._files_v2 = FilesV2Client(client_wrapper=self._client_wrapper)
+ return self._files_v2
+
+ @property
+ def strings_v2(self):
+ if self._strings_v2 is None:
+ from .strings_v2.client import StringsV2Client # noqa: E402
+
+ self._strings_v2 = StringsV2Client(client_wrapper=self._client_wrapper)
+ return self._strings_v2
+
+ @property
+ def guardrails_v2(self):
+ if self._guardrails_v2 is None:
+ from .guardrails_v2.client import GuardrailsV2Client # noqa: E402
+
+ self._guardrails_v2 = GuardrailsV2Client(client_wrapper=self._client_wrapper)
+ return self._guardrails_v2
+
+
+def _make_default_async_client(
+ timeout: typing.Optional[float],
+ follow_redirects: typing.Optional[bool],
+) -> httpx.AsyncClient:
+ try:
+ import httpx_aiohttp # type: ignore[import-not-found]
+ except ImportError:
+ pass
+ else:
+ if follow_redirects is not None:
+ return httpx_aiohttp.HttpxAiohttpClient(timeout=timeout, follow_redirects=follow_redirects)
+ return httpx_aiohttp.HttpxAiohttpClient(timeout=timeout)
+
+ if follow_redirects is not None:
+ return httpx.AsyncClient(timeout=timeout, follow_redirects=follow_redirects)
+ return httpx.AsyncClient(timeout=timeout)
class AsyncSkyflowAuth:
@@ -94,19 +238,37 @@ class AsyncSkyflowAuth:
+ vault_url : typing.Optional[str]
+ Server URL variable for 'vault_url'. Defaults to '{{vault_url}}'.
+
token : typing.Optional[typing.Union[str, typing.Callable[[], str]]]
headers : typing.Optional[typing.Dict[str, str]]
Additional headers to send with every request.
+ async_token : typing.Optional[typing.Callable[[], typing.Awaitable[str]]]
+ An async callable that returns a bearer token. Use this when token acquisition involves async I/O (e.g., refreshing tokens via an async HTTP client). When provided, this is used instead of the synchronous token for async requests.
+
timeout : typing.Optional[float]
The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
+ max_retries : typing.Optional[int]
+ The default maximum number of retries for failed requests. Defaults to 2. Per-request `max_retries` in `request_options` takes precedence over this value.
+
+ stream_reconnection_enabled : typing.Optional[bool]
+ Whether to automatically reconnect on stream disconnection for resumable streaming endpoints. Defaults to True. Per-request `stream_reconnection_enabled` in `request_options` takes precedence over this value.
+
+ max_stream_reconnection_attempts : typing.Optional[int]
+ The maximum number of reconnection attempts for resumable streaming endpoints. Defaults to no limit. Per-request `max_stream_reconnection_attempts` in `request_options` takes precedence over this value.
+
follow_redirects : typing.Optional[bool]
Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.
httpx_client : typing.Optional[httpx.AsyncClient]
The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.
+ logging : typing.Optional[typing.Union[LogConfig, Logger]]
+ Configure logging for the SDK. Accepts a LogConfig dict with 'level' (debug/info/warn/error), 'logger' (custom logger implementation), and 'silent' (boolean, defaults to True) fields. You can also pass a pre-configured Logger instance.
+
Examples
--------
from skyflow import AsyncSkyflowAuth
@@ -121,27 +283,135 @@ def __init__(
*,
base_url: typing.Optional[str] = None,
environment: SkyflowAuthEnvironment = SkyflowAuthEnvironment.PRODUCTION,
+ vault_url: typing.Optional[str] = None,
token: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None,
headers: typing.Optional[typing.Dict[str, str]] = None,
+ async_token: typing.Optional[typing.Callable[[], typing.Awaitable[str]]] = None,
timeout: typing.Optional[float] = None,
+ max_retries: typing.Optional[int] = None,
+ stream_reconnection_enabled: typing.Optional[bool] = None,
+ max_stream_reconnection_attempts: typing.Optional[int] = None,
follow_redirects: typing.Optional[bool] = True,
httpx_client: typing.Optional[httpx.AsyncClient] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
):
- _defaulted_timeout = (
- timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
- )
+ _defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None
+ _defaulted_max_retries = max_retries if max_retries is not None else 2
+ if vault_url is not None:
+ _vault_url = vault_url if vault_url is not None else "{{vault_url}}"
+ _environment_url_templates = {
+ SkyflowAuthEnvironment.PRODUCTION: "https://{vault_url}",
+ SkyflowAuthEnvironment.SANDBOX: "https://{vault_url}",
+ }
+ _url_template = _environment_url_templates.get(environment, "https://{vault_url}")
+ if base_url is None:
+ base_url = _url_template.format(vault_url=_vault_url)
self._client_wrapper = AsyncClientWrapper(
base_url=_get_base_url(base_url=base_url, environment=environment),
token=token,
headers=headers,
+ async_token=async_token,
httpx_client=httpx_client
if httpx_client is not None
- else httpx.AsyncClient(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
- if follow_redirects is not None
- else httpx.AsyncClient(timeout=_defaulted_timeout),
+ else _make_default_async_client(timeout=_defaulted_timeout, follow_redirects=follow_redirects),
timeout=_defaulted_timeout,
+ max_retries=_defaulted_max_retries,
+ stream_reconnection_enabled=stream_reconnection_enabled,
+ max_stream_reconnection_attempts=max_stream_reconnection_attempts,
+ logging=logging,
+ )
+ self._raw_client = AsyncRawSkyflowAuth(client_wrapper=self._client_wrapper)
+ self._authentication: typing.Optional[AsyncAuthenticationClient] = None
+ self._token_exchange: typing.Optional[AsyncTokenExchangeClient] = None
+ self._files_v2: typing.Optional[AsyncFilesV2Client] = None
+ self._strings_v2: typing.Optional[AsyncStringsV2Client] = None
+ self._guardrails_v2: typing.Optional[AsyncGuardrailsV2Client] = None
+
+ @property
+ def with_raw_response(self) -> AsyncRawSkyflowAuth:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawSkyflowAuth
+ """
+ return self._raw_client
+
+ async def patch_v2vaults_id(
+ self, vault_id: typing.Optional[str], *, request_options: typing.Optional[RequestOptions] = None
+ ) -> None:
+ """
+ Parameters
+ ----------
+ vault_id : typing.Optional[str]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from skyflow import AsyncSkyflowAuth
+
+ client = AsyncSkyflowAuth(
+ token="YOUR_TOKEN",
)
- self.authentication = AsyncAuthenticationClient(client_wrapper=self._client_wrapper)
+
+
+ async def main() -> None:
+ await client.patch_v2vaults_id()
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.patch_v2vaults_id(vault_id, request_options=request_options)
+ return _response.data
+
+ @property
+ def authentication(self):
+ if self._authentication is None:
+ from .authentication.client import AsyncAuthenticationClient # noqa: E402
+
+ self._authentication = AsyncAuthenticationClient(client_wrapper=self._client_wrapper)
+ return self._authentication
+
+ @property
+ def token_exchange(self):
+ if self._token_exchange is None:
+ from .token_exchange.client import AsyncTokenExchangeClient # noqa: E402
+
+ self._token_exchange = AsyncTokenExchangeClient(client_wrapper=self._client_wrapper)
+ return self._token_exchange
+
+ @property
+ def files_v2(self):
+ if self._files_v2 is None:
+ from .files_v2.client import AsyncFilesV2Client # noqa: E402
+
+ self._files_v2 = AsyncFilesV2Client(client_wrapper=self._client_wrapper)
+ return self._files_v2
+
+ @property
+ def strings_v2(self):
+ if self._strings_v2 is None:
+ from .strings_v2.client import AsyncStringsV2Client # noqa: E402
+
+ self._strings_v2 = AsyncStringsV2Client(client_wrapper=self._client_wrapper)
+ return self._strings_v2
+
+ @property
+ def guardrails_v2(self):
+ if self._guardrails_v2 is None:
+ from .guardrails_v2.client import AsyncGuardrailsV2Client # noqa: E402
+
+ self._guardrails_v2 = AsyncGuardrailsV2Client(client_wrapper=self._client_wrapper)
+ return self._guardrails_v2
def _get_base_url(*, base_url: typing.Optional[str] = None, environment: SkyflowAuthEnvironment) -> str:
diff --git a/common/generated/rest/core/__init__.py b/common/generated/rest/core/__init__.py
index 31bbb818..5bc159a1 100644
--- a/common/generated/rest/core/__init__.py
+++ b/common/generated/rest/core/__init__.py
@@ -2,26 +2,91 @@
# isort: skip_file
-from .api_error import ApiError
-from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper
-from .datetime_utils import serialize_datetime
-from .file import File, convert_file_dict_to_httpx_tuples, with_content_type
-from .http_client import AsyncHttpClient, HttpClient
-from .http_response import AsyncHttpResponse, HttpResponse
-from .jsonable_encoder import jsonable_encoder
-from .pydantic_utilities import (
- IS_PYDANTIC_V2,
- UniversalBaseModel,
- UniversalRootModel,
- parse_obj_as,
- universal_field_validator,
- universal_root_validator,
- update_forward_refs,
-)
-from .query_encoder import encode_query
-from .remove_none_from_dict import remove_none_from_dict
-from .request_options import RequestOptions
-from .serialization import FieldMetadata, convert_and_respect_annotation_metadata
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .api_error import ApiError
+ from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper
+ from .datetime_utils import Rfc2822DateTime, parse_rfc2822_datetime, serialize_datetime
+ from .file import File, convert_file_dict_to_httpx_tuples, with_content_type
+ from .http_client import AsyncHttpClient, HttpClient
+ from .http_response import AsyncHttpResponse, HttpResponse
+ from .jsonable_encoder import encode_path_param, jsonable_encoder
+ from .logging import ConsoleLogger, ILogger, LogConfig, LogLevel, Logger, create_logger
+ from .parse_error import ParsingError
+ from .pydantic_utilities import (
+ IS_PYDANTIC_V2,
+ UniversalBaseModel,
+ UniversalRootModel,
+ parse_obj_as,
+ universal_field_validator,
+ universal_root_validator,
+ update_forward_refs,
+ )
+ from .query_encoder import encode_query
+ from .remove_none_from_dict import remove_none_from_dict
+ from .request_options import RequestOptions
+ from .serialization import FieldMetadata, convert_and_respect_annotation_metadata
+_dynamic_imports: typing.Dict[str, str] = {
+ "ApiError": ".api_error",
+ "AsyncClientWrapper": ".client_wrapper",
+ "AsyncHttpClient": ".http_client",
+ "AsyncHttpResponse": ".http_response",
+ "BaseClientWrapper": ".client_wrapper",
+ "ConsoleLogger": ".logging",
+ "FieldMetadata": ".serialization",
+ "File": ".file",
+ "HttpClient": ".http_client",
+ "HttpResponse": ".http_response",
+ "ILogger": ".logging",
+ "IS_PYDANTIC_V2": ".pydantic_utilities",
+ "LogConfig": ".logging",
+ "LogLevel": ".logging",
+ "Logger": ".logging",
+ "ParsingError": ".parse_error",
+ "RequestOptions": ".request_options",
+ "Rfc2822DateTime": ".datetime_utils",
+ "SyncClientWrapper": ".client_wrapper",
+ "UniversalBaseModel": ".pydantic_utilities",
+ "UniversalRootModel": ".pydantic_utilities",
+ "convert_and_respect_annotation_metadata": ".serialization",
+ "convert_file_dict_to_httpx_tuples": ".file",
+ "create_logger": ".logging",
+ "encode_path_param": ".jsonable_encoder",
+ "encode_query": ".query_encoder",
+ "jsonable_encoder": ".jsonable_encoder",
+ "parse_obj_as": ".pydantic_utilities",
+ "parse_rfc2822_datetime": ".datetime_utils",
+ "remove_none_from_dict": ".remove_none_from_dict",
+ "serialize_datetime": ".datetime_utils",
+ "universal_field_validator": ".pydantic_utilities",
+ "universal_root_validator": ".pydantic_utilities",
+ "update_forward_refs": ".pydantic_utilities",
+ "with_content_type": ".file",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
__all__ = [
"ApiError",
@@ -29,20 +94,30 @@
"AsyncHttpClient",
"AsyncHttpResponse",
"BaseClientWrapper",
+ "ConsoleLogger",
"FieldMetadata",
"File",
"HttpClient",
"HttpResponse",
+ "ILogger",
"IS_PYDANTIC_V2",
+ "LogConfig",
+ "LogLevel",
+ "Logger",
+ "ParsingError",
"RequestOptions",
+ "Rfc2822DateTime",
"SyncClientWrapper",
"UniversalBaseModel",
"UniversalRootModel",
"convert_and_respect_annotation_metadata",
"convert_file_dict_to_httpx_tuples",
+ "create_logger",
+ "encode_path_param",
"encode_query",
"jsonable_encoder",
"parse_obj_as",
+ "parse_rfc2822_datetime",
"remove_none_from_dict",
"serialize_datetime",
"universal_field_validator",
diff --git a/common/generated/rest/core/client_wrapper.py b/common/generated/rest/core/client_wrapper.py
index 9588d762..b4fbd425 100644
--- a/common/generated/rest/core/client_wrapper.py
+++ b/common/generated/rest/core/client_wrapper.py
@@ -4,6 +4,7 @@
import httpx
from .http_client import AsyncHttpClient, HttpClient
+from .logging import LogConfig, Logger
class BaseClientWrapper:
@@ -14,17 +15,29 @@ def __init__(
headers: typing.Optional[typing.Dict[str, str]] = None,
base_url: str,
timeout: typing.Optional[float] = None,
+ max_retries: int = 2,
+ stream_reconnection_enabled: typing.Optional[bool] = None,
+ max_stream_reconnection_attempts: typing.Optional[int] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
):
self._token = token
self._headers = headers
self._base_url = base_url
self._timeout = timeout
+ self._max_retries = max_retries
+ self._stream_reconnection_enabled = stream_reconnection_enabled
+ self._max_stream_reconnection_attempts = max_stream_reconnection_attempts
+ self._logging = logging
def get_headers(self) -> typing.Dict[str, str]:
+ import platform
+
headers: typing.Dict[str, str] = {
"X-Fern-Language": "Python",
+ "X-Fern-Runtime": f"python/{platform.python_version()}",
+ "X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}",
"X-Fern-SDK-Name": "skyflow.generated.rest",
- "X-Fern-SDK-Version": "0.0.9",
+ "X-Fern-SDK-Version": "0.0.45",
**(self.get_custom_headers() or {}),
}
token = self._get_token()
@@ -47,6 +60,15 @@ def get_base_url(self) -> str:
def get_timeout(self) -> typing.Optional[float]:
return self._timeout
+ def get_max_retries(self) -> int:
+ return self._max_retries
+
+ def get_stream_reconnection_enabled(self) -> bool:
+ return self._stream_reconnection_enabled if self._stream_reconnection_enabled is not None else True
+
+ def get_max_stream_reconnection_attempts(self) -> typing.Optional[int]:
+ return self._max_stream_reconnection_attempts
+
class SyncClientWrapper(BaseClientWrapper):
def __init__(
@@ -56,14 +78,29 @@ def __init__(
headers: typing.Optional[typing.Dict[str, str]] = None,
base_url: str,
timeout: typing.Optional[float] = None,
+ max_retries: int = 2,
+ stream_reconnection_enabled: typing.Optional[bool] = None,
+ max_stream_reconnection_attempts: typing.Optional[int] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
httpx_client: httpx.Client,
):
- super().__init__(token=token, headers=headers, base_url=base_url, timeout=timeout)
+ super().__init__(
+ token=token,
+ headers=headers,
+ base_url=base_url,
+ timeout=timeout,
+ max_retries=max_retries,
+ stream_reconnection_enabled=stream_reconnection_enabled,
+ max_stream_reconnection_attempts=max_stream_reconnection_attempts,
+ logging=logging,
+ )
self.httpx_client = HttpClient(
httpx_client=httpx_client,
base_headers=self.get_headers,
base_timeout=self.get_timeout,
base_url=self.get_base_url,
+ base_max_retries=self.get_max_retries(),
+ logging_config=self._logging,
)
@@ -75,12 +112,37 @@ def __init__(
headers: typing.Optional[typing.Dict[str, str]] = None,
base_url: str,
timeout: typing.Optional[float] = None,
+ max_retries: int = 2,
+ stream_reconnection_enabled: typing.Optional[bool] = None,
+ max_stream_reconnection_attempts: typing.Optional[int] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
+ async_token: typing.Optional[typing.Callable[[], typing.Awaitable[str]]] = None,
httpx_client: httpx.AsyncClient,
):
- super().__init__(token=token, headers=headers, base_url=base_url, timeout=timeout)
+ super().__init__(
+ token=token,
+ headers=headers,
+ base_url=base_url,
+ timeout=timeout,
+ max_retries=max_retries,
+ stream_reconnection_enabled=stream_reconnection_enabled,
+ max_stream_reconnection_attempts=max_stream_reconnection_attempts,
+ logging=logging,
+ )
+ self._async_token = async_token
self.httpx_client = AsyncHttpClient(
httpx_client=httpx_client,
base_headers=self.get_headers,
base_timeout=self.get_timeout,
base_url=self.get_base_url,
+ base_max_retries=self.get_max_retries(),
+ async_base_headers=self.async_get_headers,
+ logging_config=self._logging,
)
+
+ async def async_get_headers(self) -> typing.Dict[str, str]:
+ headers = self.get_headers()
+ if self._async_token is not None:
+ token = await self._async_token()
+ headers["Authorization"] = f"Bearer {token}"
+ return headers
diff --git a/common/generated/rest/core/datetime_utils.py b/common/generated/rest/core/datetime_utils.py
index 7c9864a9..a12b2ad0 100644
--- a/common/generated/rest/core/datetime_utils.py
+++ b/common/generated/rest/core/datetime_utils.py
@@ -1,6 +1,48 @@
# This file was auto-generated by Fern from our API Definition.
import datetime as dt
+from email.utils import parsedate_to_datetime
+from typing import Any
+
+import pydantic
+
+IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
+
+
+def parse_rfc2822_datetime(v: Any) -> dt.datetime:
+ """
+ Parse an RFC 2822 datetime string (e.g., "Wed, 02 Oct 2002 13:00:00 GMT")
+ into a datetime object. If the value is already a datetime, return it as-is.
+ Falls back to ISO 8601 parsing if RFC 2822 parsing fails.
+ """
+ if isinstance(v, dt.datetime):
+ return v
+ if isinstance(v, str):
+ try:
+ return parsedate_to_datetime(v)
+ except Exception:
+ pass
+ # Fallback to ISO 8601 parsing
+ return dt.datetime.fromisoformat(v.replace("Z", "+00:00"))
+ raise ValueError(f"Expected str or datetime, got {type(v)}")
+
+
+class Rfc2822DateTime(dt.datetime):
+ """A datetime subclass that parses RFC 2822 date strings.
+
+ On Pydantic V1, uses __get_validators__ for pre-validation.
+ On Pydantic V2, uses __get_pydantic_core_schema__ for BeforeValidator-style parsing.
+ """
+
+ @classmethod
+ def __get_validators__(cls): # type: ignore[no-untyped-def]
+ yield parse_rfc2822_datetime
+
+ @classmethod
+ def __get_pydantic_core_schema__(cls, _source_type: Any, _handler: Any) -> Any: # type: ignore[override]
+ from pydantic_core import core_schema
+
+ return core_schema.no_info_before_validator_function(parse_rfc2822_datetime, core_schema.datetime_schema())
def serialize_datetime(v: dt.datetime) -> str:
diff --git a/common/generated/rest/core/force_multipart.py b/common/generated/rest/core/force_multipart.py
index ae24ccff..5440913f 100644
--- a/common/generated/rest/core/force_multipart.py
+++ b/common/generated/rest/core/force_multipart.py
@@ -1,7 +1,9 @@
# This file was auto-generated by Fern from our API Definition.
+from typing import Any, Dict
-class ForceMultipartDict(dict):
+
+class ForceMultipartDict(Dict[str, Any]):
"""
A dictionary subclass that always evaluates to True in boolean contexts.
@@ -9,7 +11,7 @@ class ForceMultipartDict(dict):
the dictionary is empty, which would normally evaluate to False.
"""
- def __bool__(self):
+ def __bool__(self) -> bool:
return True
diff --git a/common/generated/rest/core/http_client.py b/common/generated/rest/core/http_client.py
index e4173f99..3e5a7865 100644
--- a/common/generated/rest/core/http_client.py
+++ b/common/generated/rest/core/http_client.py
@@ -3,9 +3,9 @@
import asyncio
import email.utils
import re
+import socket
import time
import typing
-import urllib.parse
from contextlib import asynccontextmanager, contextmanager
from random import random
@@ -13,14 +13,48 @@
from .file import File, convert_file_dict_to_httpx_tuples
from .force_multipart import FORCE_MULTIPART
from .jsonable_encoder import jsonable_encoder
+from .logging import LogConfig, Logger, create_logger
from .query_encoder import encode_query
-from .remove_none_from_dict import remove_none_from_dict
+from .remove_none_from_dict import remove_none_from_dict as remove_none_from_dict
from .request_options import RequestOptions
from httpx._types import RequestFiles
-INITIAL_RETRY_DELAY_SECONDS = 0.5
-MAX_RETRY_DELAY_SECONDS = 10
-MAX_RETRY_DELAY_SECONDS_FROM_HEADER = 30
+INITIAL_RETRY_DELAY_SECONDS = 1.0
+MAX_RETRY_DELAY_SECONDS = 60.0
+JITTER_FACTOR = 0.2 # 20% random jitter
+
+
+def get_keepalive_socket_options(
+ idle: int = 60,
+ intvl: int = 30,
+ cnt: int = 5,
+) -> typing.List[typing.Tuple[int, int, int]]:
+ """
+ Build TCP keepalive socket options for the current platform.
+
+ Keepalive probes keep otherwise-idle connections alive so that long,
+ non-streaming requests survive idle-connection reaping by a firewall,
+ load balancer, or NAT. The available socket constants are OS-dependent,
+ so each option is guarded and only emitted when the platform defines it:
+
+ - ``SO_KEEPALIVE`` is portable (Linux/macOS/Windows).
+ - The idle-before-first-probe knob is ``TCP_KEEPIDLE`` on Linux and modern
+ Windows, but ``TCP_KEEPALIVE`` on macOS.
+ - ``TCP_KEEPINTVL`` / ``TCP_KEEPCNT`` exist on Linux/macOS/modern Windows.
+
+ Passing these tuples to ``httpx.HTTPTransport(socket_options=...)`` /
+ ``httpx.AsyncHTTPTransport(socket_options=...)`` applies them to every
+ connection the transport opens.
+ """
+ opts: typing.List[typing.Tuple[int, int, int]] = [(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)]
+ idle_const = getattr(socket, "TCP_KEEPIDLE", None) or getattr(socket, "TCP_KEEPALIVE", None)
+ if idle_const:
+ opts.append((socket.IPPROTO_TCP, idle_const, idle))
+ if hasattr(socket, "TCP_KEEPINTVL"):
+ opts.append((socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, intvl))
+ if hasattr(socket, "TCP_KEEPCNT"):
+ opts.append((socket.IPPROTO_TCP, socket.TCP_KEEPCNT, cnt))
+ return opts
def _parse_retry_after(response_headers: httpx.Headers) -> typing.Optional[float]:
@@ -64,6 +98,38 @@ def _parse_retry_after(response_headers: httpx.Headers) -> typing.Optional[float
return seconds
+def _add_positive_jitter(delay: float) -> float:
+ """Add positive jitter (0-20%) to prevent thundering herd."""
+ jitter_multiplier = 1 + random() * JITTER_FACTOR
+ return delay * jitter_multiplier
+
+
+def _add_symmetric_jitter(delay: float) -> float:
+ """Add symmetric jitter (±10%) for exponential backoff."""
+ jitter_multiplier = 1 + (random() - 0.5) * JITTER_FACTOR
+ return delay * jitter_multiplier
+
+
+def _parse_x_ratelimit_reset(response_headers: httpx.Headers) -> typing.Optional[float]:
+ """
+ Parse the X-RateLimit-Reset header (Unix timestamp in seconds).
+ Returns seconds to wait, or None if header is missing/invalid.
+ """
+ reset_time_str = response_headers.get("x-ratelimit-reset")
+ if reset_time_str is None:
+ return None
+
+ try:
+ reset_time = int(reset_time_str)
+ delay = reset_time - time.time()
+ if delay > 0:
+ return delay
+ except (ValueError, TypeError):
+ pass
+
+ return None
+
+
def _retry_timeout(response: httpx.Response, retries: int) -> float:
"""
Determine the amount of time to wait before retrying a request.
@@ -71,22 +137,94 @@ def _retry_timeout(response: httpx.Response, retries: int) -> float:
with a jitter to determine the number of seconds to wait.
"""
- # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says.
+ # 1. Check Retry-After header first
retry_after = _parse_retry_after(response.headers)
- if retry_after is not None and retry_after <= MAX_RETRY_DELAY_SECONDS_FROM_HEADER:
- return retry_after
+ if retry_after is not None and retry_after > 0:
+ return min(retry_after, MAX_RETRY_DELAY_SECONDS)
+
+ # 2. Check X-RateLimit-Reset header (with positive jitter)
+ ratelimit_reset = _parse_x_ratelimit_reset(response.headers)
+ if ratelimit_reset is not None:
+ return _add_positive_jitter(min(ratelimit_reset, MAX_RETRY_DELAY_SECONDS))
- # Apply exponential backoff, capped at MAX_RETRY_DELAY_SECONDS.
- retry_delay = min(INITIAL_RETRY_DELAY_SECONDS * pow(2.0, retries), MAX_RETRY_DELAY_SECONDS)
+ # 3. Fall back to exponential backoff (with symmetric jitter)
+ backoff = min(INITIAL_RETRY_DELAY_SECONDS * pow(2.0, retries), MAX_RETRY_DELAY_SECONDS)
+ return _add_symmetric_jitter(backoff)
- # Add a randomness / jitter to the retry delay to avoid overwhelming the server with retries.
- timeout = retry_delay * (1 - 0.25 * random())
- return timeout if timeout >= 0 else 0
+
+def _retry_timeout_from_retries(retries: int) -> float:
+ """Determine retry timeout using exponential backoff when no response is available."""
+ backoff = min(INITIAL_RETRY_DELAY_SECONDS * pow(2.0, retries), MAX_RETRY_DELAY_SECONDS)
+ return _add_symmetric_jitter(backoff)
def _should_retry(response: httpx.Response) -> bool:
- retryable_400s = [429, 408, 409]
- return response.status_code >= 500 or response.status_code in retryable_400s
+ return response.status_code >= 500 or response.status_code in [429, 408, 409]
+
+
+_SENSITIVE_HEADERS = frozenset(
+ {
+ "authorization",
+ "www-authenticate",
+ "x-api-key",
+ "api-key",
+ "apikey",
+ "x-api-token",
+ "x-auth-token",
+ "auth-token",
+ "cookie",
+ "set-cookie",
+ "proxy-authorization",
+ "proxy-authenticate",
+ "x-csrf-token",
+ "x-xsrf-token",
+ "x-session-token",
+ "x-access-token",
+ }
+)
+
+
+def _redact_headers(headers: typing.Dict[str, str]) -> typing.Dict[str, str]:
+ return {k: ("[REDACTED]" if k.lower() in _SENSITIVE_HEADERS else v) for k, v in headers.items()}
+
+
+def _build_url(base_url: str, path: typing.Optional[str]) -> str:
+ """
+ Build a full URL by joining a base URL with a path.
+
+ This function correctly handles base URLs that contain path prefixes (e.g., tenant-based URLs)
+ by using string concatenation instead of urllib.parse.urljoin(), which would incorrectly
+ strip path components when the path starts with '/'.
+
+ Example:
+ >>> _build_url("https://cloud.example.com/org/tenant/api", "/users")
+ 'https://cloud.example.com/org/tenant/api/users'
+
+ Args:
+ base_url: The base URL, which may contain path prefixes.
+ path: The path to append. Can be None or empty string.
+
+ Returns:
+ The full URL with base_url and path properly joined.
+ """
+ if not path:
+ return base_url
+ return f"{base_url.rstrip('/')}/{path.lstrip('/')}"
+
+
+def _maybe_filter_none_from_multipart_data(
+ data: typing.Optional[typing.Any],
+ request_files: typing.Optional[RequestFiles],
+ force_multipart: typing.Optional[bool],
+) -> typing.Optional[typing.Any]:
+ """
+ Filter None values from data body for multipart/form requests.
+ This prevents httpx from converting None to empty strings in multipart encoding.
+ Only applies when files are present or force_multipart is True.
+ """
+ if data is not None and isinstance(data, typing.Mapping) and (request_files or force_multipart):
+ return remove_none_from_dict(data)
+ return data
def remove_omit_from_dict(
@@ -134,7 +272,16 @@ def get_request_body(
data: typing.Optional[typing.Any],
request_options: typing.Optional[RequestOptions],
omit: typing.Optional[typing.Any],
+ optional_body: bool = False,
) -> typing.Tuple[typing.Optional[typing.Any], typing.Optional[typing.Any]]:
+ # A whole body left at the sentinel was never passed by the caller, so it is absent
+ # rather than empty: the request carries no content and no `Content-Type`.
+ if omit is not None:
+ if json is omit:
+ json = None
+ if data is omit:
+ data = None
+
json_body = None
data_body = None
if data is not None:
@@ -143,8 +290,41 @@ def get_request_body(
# If both data and json are None, we send json data in the event extra properties are specified
json_body = maybe_filter_request_body(json, request_options, omit)
- # If you have an empty JSON body, you should just send None
- return (json_body if json_body != {} else None), data_body if data_body != {} else None
+ has_additional_body_parameters = bool(
+ request_options is not None and request_options.get("additional_body_parameters")
+ )
+
+ # Only collapse empty dict to None when the body was not explicitly provided
+ # and there are no additional body parameters. This preserves explicit empty
+ # bodies (e.g., when an endpoint has a request body type but all fields are optional).
+ # `optional_body` marks an endpoint whose body the API does not require, where a body
+ # that ends up empty means the caller passed none of its properties, so the request is
+ # sent with no content and no `Content-Type`.
+ if json_body == {} and (json is None or optional_body) and not has_additional_body_parameters:
+ json_body = None
+ if data_body == {} and (data is None or optional_body) and not has_additional_body_parameters:
+ data_body = None
+
+ return json_body, data_body
+
+
+def drop_content_type_without_body(
+ headers: typing.Dict[str, typing.Any],
+ *,
+ json_body: typing.Optional[typing.Any],
+ data_body: typing.Optional[typing.Any],
+ optional_body: bool,
+) -> typing.Dict[str, typing.Any]:
+ """Strip ``Content-Type`` from a request that carries no body.
+
+ ``get_request_body`` drops the body of an ``optional_body`` endpoint when the caller
+ supplied none of it, but the endpoint still passes the content type it would have used.
+ A request that sends nothing must not advertise a media type, so a server that branches
+ on the header sees a bodyless call for what it is.
+ """
+ if not optional_body or json_body is not None or data_body is not None:
+ return headers
+ return {key: value for key, value in headers.items() if key.lower() != "content-type"}
class HttpClient:
@@ -155,11 +335,15 @@ def __init__(
base_timeout: typing.Callable[[], typing.Optional[float]],
base_headers: typing.Callable[[], typing.Dict[str, str]],
base_url: typing.Optional[typing.Callable[[], str]] = None,
+ base_max_retries: int = 2,
+ logging_config: typing.Optional[typing.Union[LogConfig, Logger]] = None,
):
self.base_url = base_url
self.base_timeout = base_timeout
self.base_headers = base_headers
+ self.base_max_retries = base_max_retries
self.httpx_client = httpx_client
+ self.logger = create_logger(logging_config)
def get_base_url(self, maybe_base_url: typing.Optional[str]) -> str:
base_url = maybe_base_url
@@ -188,18 +372,24 @@ def request(
] = None,
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
request_options: typing.Optional[RequestOptions] = None,
- retries: int = 2,
+ retries: int = 0,
omit: typing.Optional[typing.Any] = None,
+ optional_body: bool = False,
force_multipart: typing.Optional[bool] = None,
) -> httpx.Response:
base_url = self.get_base_url(base_url)
- timeout = (
- request_options.get("timeout_in_seconds")
+ _timeout = (
+ request_options.get("timeout")
+ if request_options is not None and request_options.get("timeout") is not None
+ else request_options.get("timeout_in_seconds")
if request_options is not None and request_options.get("timeout_in_seconds") is not None
else self.base_timeout()
)
+ timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT
- json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+ json_body, data_body = get_request_body(
+ json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body
+ )
request_files: typing.Optional[RequestFiles] = (
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
@@ -210,45 +400,91 @@ def request(
if (request_files is None or len(request_files) == 0) and force_multipart:
request_files = FORCE_MULTIPART
- response = self.httpx_client.request(
- method=method,
- url=urllib.parse.urljoin(f"{base_url}/", path),
- headers=jsonable_encoder(
+ data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
+
+ # Compute encoded params separately to avoid passing empty list to httpx
+ # (httpx strips existing query params from URL when params=[] is passed)
+ _encoded_params = encode_query(
+ jsonable_encoder(
remove_none_from_dict(
- {
- **self.base_headers(),
- **(headers if headers is not None else {}),
- **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}),
- }
- )
- ),
- params=encode_query(
- jsonable_encoder(
- remove_none_from_dict(
- remove_omit_from_dict(
- {
- **(params if params is not None else {}),
- **(
- request_options.get("additional_query_parameters", {}) or {}
- if request_options is not None
- else {}
- ),
- },
- omit,
- )
+ remove_omit_from_dict(
+ {
+ **(params if params is not None else {}),
+ **(
+ request_options.get("additional_query_parameters", {}) or {}
+ if request_options is not None
+ else {}
+ ),
+ },
+ omit,
)
)
- ),
- json=json_body,
- data=data_body,
- content=content,
- files=request_files,
- timeout=timeout,
+ )
+ )
+
+ _request_url = _build_url(base_url, path)
+ _request_headers = jsonable_encoder(
+ remove_none_from_dict(
+ {
+ **self.base_headers(),
+ **(headers if headers is not None else {}),
+ **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}),
+ }
+ )
+ )
+ _request_headers = drop_content_type_without_body(
+ _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body
+ )
+
+ if self.logger.is_debug():
+ self.logger.debug(
+ "Making HTTP request",
+ method=method,
+ url=_request_url,
+ headers=_redact_headers(_request_headers),
+ has_body=json_body is not None or data_body is not None,
+ )
+
+ max_retries: int = (
+ request_options.get("max_retries", self.base_max_retries)
+ if request_options is not None
+ else self.base_max_retries
)
- max_retries: int = request_options.get("max_retries", 0) if request_options is not None else 0
+ try:
+ response = self.httpx_client.request(
+ method=method,
+ url=_request_url,
+ headers=_request_headers,
+ params=_encoded_params if _encoded_params else None,
+ json=json_body,
+ data=data_body,
+ content=content,
+ files=request_files,
+ timeout=timeout,
+ )
+ except (httpx.ConnectError, httpx.RemoteProtocolError):
+ if retries < max_retries:
+ time.sleep(_retry_timeout_from_retries(retries=retries))
+ return self.request(
+ path=path,
+ method=method,
+ base_url=base_url,
+ params=params,
+ json=json,
+ data=data,
+ content=content,
+ files=files,
+ headers=headers,
+ request_options=request_options,
+ retries=retries + 1,
+ omit=omit,
+ force_multipart=force_multipart,
+ )
+ raise
+
if _should_retry(response=response):
- if max_retries > retries:
+ if retries < max_retries:
time.sleep(_retry_timeout(response=response, retries=retries))
return self.request(
path=path,
@@ -256,12 +492,32 @@ def request(
base_url=base_url,
params=params,
json=json,
+ data=data,
content=content,
files=files,
headers=headers,
request_options=request_options,
retries=retries + 1,
omit=omit,
+ force_multipart=force_multipart,
+ )
+
+ if self.logger.is_debug():
+ if 200 <= response.status_code < 400:
+ self.logger.debug(
+ "HTTP request succeeded",
+ method=method,
+ url=_request_url,
+ status_code=response.status_code,
+ )
+
+ if self.logger.is_error():
+ if response.status_code >= 400:
+ self.logger.error(
+ "HTTP request failed with error status",
+ method=method,
+ url=_request_url,
+ status_code=response.status_code,
)
return response
@@ -285,16 +541,20 @@ def stream(
] = None,
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
request_options: typing.Optional[RequestOptions] = None,
- retries: int = 2,
+ retries: int = 0,
omit: typing.Optional[typing.Any] = None,
+ optional_body: bool = False,
force_multipart: typing.Optional[bool] = None,
) -> typing.Iterator[httpx.Response]:
base_url = self.get_base_url(base_url)
- timeout = (
- request_options.get("timeout_in_seconds")
+ _timeout = (
+ request_options.get("timeout")
+ if request_options is not None and request_options.get("timeout") is not None
+ else request_options.get("timeout_in_seconds")
if request_options is not None and request_options.get("timeout_in_seconds") is not None
else self.base_timeout()
)
+ timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT
request_files: typing.Optional[RequestFiles] = (
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
@@ -305,37 +565,59 @@ def stream(
if (request_files is None or len(request_files) == 0) and force_multipart:
request_files = FORCE_MULTIPART
- json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+ json_body, data_body = get_request_body(
+ json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body
+ )
+
+ data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
- with self.httpx_client.stream(
- method=method,
- url=urllib.parse.urljoin(f"{base_url}/", path),
- headers=jsonable_encoder(
+ # Compute encoded params separately to avoid passing empty list to httpx
+ # (httpx strips existing query params from URL when params=[] is passed)
+ _encoded_params = encode_query(
+ jsonable_encoder(
remove_none_from_dict(
- {
- **self.base_headers(),
- **(headers if headers is not None else {}),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- params=encode_query(
- jsonable_encoder(
- remove_none_from_dict(
- remove_omit_from_dict(
- {
- **(params if params is not None else {}),
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- },
- omit,
- )
+ remove_omit_from_dict(
+ {
+ **(params if params is not None else {}),
+ **(
+ request_options.get("additional_query_parameters", {})
+ if request_options is not None
+ else {}
+ ),
+ },
+ omit,
)
)
- ),
+ )
+ )
+
+ _request_url = _build_url(base_url, path)
+ _request_headers = jsonable_encoder(
+ remove_none_from_dict(
+ {
+ **self.base_headers(),
+ **(headers if headers is not None else {}),
+ **(request_options.get("additional_headers", {}) if request_options is not None else {}),
+ }
+ )
+ )
+ _request_headers = drop_content_type_without_body(
+ _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body
+ )
+
+ if self.logger.is_debug():
+ self.logger.debug(
+ "Making streaming HTTP request",
+ method=method,
+ url=_request_url,
+ headers=_redact_headers(_request_headers),
+ )
+
+ with self.httpx_client.stream(
+ method=method,
+ url=_request_url,
+ headers=_request_headers,
+ params=_encoded_params if _encoded_params else None,
json=json_body,
data=data_body,
content=content,
@@ -353,11 +635,22 @@ def __init__(
base_timeout: typing.Callable[[], typing.Optional[float]],
base_headers: typing.Callable[[], typing.Dict[str, str]],
base_url: typing.Optional[typing.Callable[[], str]] = None,
+ base_max_retries: int = 2,
+ async_base_headers: typing.Optional[typing.Callable[[], typing.Awaitable[typing.Dict[str, str]]]] = None,
+ logging_config: typing.Optional[typing.Union[LogConfig, Logger]] = None,
):
self.base_url = base_url
self.base_timeout = base_timeout
self.base_headers = base_headers
+ self.base_max_retries = base_max_retries
+ self.async_base_headers = async_base_headers
self.httpx_client = httpx_client
+ self.logger = create_logger(logging_config)
+
+ async def _get_headers(self) -> typing.Dict[str, str]:
+ if self.async_base_headers is not None:
+ return await self.async_base_headers()
+ return self.base_headers()
def get_base_url(self, maybe_base_url: typing.Optional[str]) -> str:
base_url = maybe_base_url
@@ -386,16 +679,20 @@ async def request(
] = None,
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
request_options: typing.Optional[RequestOptions] = None,
- retries: int = 2,
+ retries: int = 0,
omit: typing.Optional[typing.Any] = None,
+ optional_body: bool = False,
force_multipart: typing.Optional[bool] = None,
) -> httpx.Response:
base_url = self.get_base_url(base_url)
- timeout = (
- request_options.get("timeout_in_seconds")
+ _timeout = (
+ request_options.get("timeout")
+ if request_options is not None and request_options.get("timeout") is not None
+ else request_options.get("timeout_in_seconds")
if request_options is not None and request_options.get("timeout_in_seconds") is not None
else self.base_timeout()
)
+ timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT
request_files: typing.Optional[RequestFiles] = (
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
@@ -406,48 +703,98 @@ async def request(
if (request_files is None or len(request_files) == 0) and force_multipart:
request_files = FORCE_MULTIPART
- json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+ json_body, data_body = get_request_body(
+ json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body
+ )
- # Add the input to each of these and do None-safety checks
- response = await self.httpx_client.request(
- method=method,
- url=urllib.parse.urljoin(f"{base_url}/", path),
- headers=jsonable_encoder(
+ data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
+
+ # Get headers (supports async token providers)
+ _headers = await self._get_headers()
+
+ # Compute encoded params separately to avoid passing empty list to httpx
+ # (httpx strips existing query params from URL when params=[] is passed)
+ _encoded_params = encode_query(
+ jsonable_encoder(
remove_none_from_dict(
- {
- **self.base_headers(),
- **(headers if headers is not None else {}),
- **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}),
- }
- )
- ),
- params=encode_query(
- jsonable_encoder(
- remove_none_from_dict(
- remove_omit_from_dict(
- {
- **(params if params is not None else {}),
- **(
- request_options.get("additional_query_parameters", {}) or {}
- if request_options is not None
- else {}
- ),
- },
- omit,
- )
+ remove_omit_from_dict(
+ {
+ **(params if params is not None else {}),
+ **(
+ request_options.get("additional_query_parameters", {}) or {}
+ if request_options is not None
+ else {}
+ ),
+ },
+ omit,
)
)
- ),
- json=json_body,
- data=data_body,
- content=content,
- files=request_files,
- timeout=timeout,
+ )
+ )
+
+ _request_url = _build_url(base_url, path)
+ _request_headers = jsonable_encoder(
+ remove_none_from_dict(
+ {
+ **_headers,
+ **(headers if headers is not None else {}),
+ **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}),
+ }
+ )
+ )
+ _request_headers = drop_content_type_without_body(
+ _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body
+ )
+
+ if self.logger.is_debug():
+ self.logger.debug(
+ "Making HTTP request",
+ method=method,
+ url=_request_url,
+ headers=_redact_headers(_request_headers),
+ has_body=json_body is not None or data_body is not None,
+ )
+
+ max_retries: int = (
+ request_options.get("max_retries", self.base_max_retries)
+ if request_options is not None
+ else self.base_max_retries
)
- max_retries: int = request_options.get("max_retries", 0) if request_options is not None else 0
+ try:
+ response = await self.httpx_client.request(
+ method=method,
+ url=_request_url,
+ headers=_request_headers,
+ params=_encoded_params if _encoded_params else None,
+ json=json_body,
+ data=data_body,
+ content=content,
+ files=request_files,
+ timeout=timeout,
+ )
+ except (httpx.ConnectError, httpx.RemoteProtocolError):
+ if retries < max_retries:
+ await asyncio.sleep(_retry_timeout_from_retries(retries=retries))
+ return await self.request(
+ path=path,
+ method=method,
+ base_url=base_url,
+ params=params,
+ json=json,
+ data=data,
+ content=content,
+ files=files,
+ headers=headers,
+ request_options=request_options,
+ retries=retries + 1,
+ omit=omit,
+ force_multipart=force_multipart,
+ )
+ raise
+
if _should_retry(response=response):
- if max_retries > retries:
+ if retries < max_retries:
await asyncio.sleep(_retry_timeout(response=response, retries=retries))
return await self.request(
path=path,
@@ -455,13 +802,34 @@ async def request(
base_url=base_url,
params=params,
json=json,
+ data=data,
content=content,
files=files,
headers=headers,
request_options=request_options,
retries=retries + 1,
omit=omit,
+ force_multipart=force_multipart,
+ )
+
+ if self.logger.is_debug():
+ if 200 <= response.status_code < 400:
+ self.logger.debug(
+ "HTTP request succeeded",
+ method=method,
+ url=_request_url,
+ status_code=response.status_code,
+ )
+
+ if self.logger.is_error():
+ if response.status_code >= 400:
+ self.logger.error(
+ "HTTP request failed with error status",
+ method=method,
+ url=_request_url,
+ status_code=response.status_code,
)
+
return response
@asynccontextmanager
@@ -483,16 +851,20 @@ async def stream(
] = None,
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
request_options: typing.Optional[RequestOptions] = None,
- retries: int = 2,
+ retries: int = 0,
omit: typing.Optional[typing.Any] = None,
+ optional_body: bool = False,
force_multipart: typing.Optional[bool] = None,
) -> typing.AsyncIterator[httpx.Response]:
base_url = self.get_base_url(base_url)
- timeout = (
- request_options.get("timeout_in_seconds")
+ _timeout = (
+ request_options.get("timeout")
+ if request_options is not None and request_options.get("timeout") is not None
+ else request_options.get("timeout_in_seconds")
if request_options is not None and request_options.get("timeout_in_seconds") is not None
else self.base_timeout()
)
+ timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT
request_files: typing.Optional[RequestFiles] = (
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
@@ -503,37 +875,62 @@ async def stream(
if (request_files is None or len(request_files) == 0) and force_multipart:
request_files = FORCE_MULTIPART
- json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+ json_body, data_body = get_request_body(
+ json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body
+ )
- async with self.httpx_client.stream(
- method=method,
- url=urllib.parse.urljoin(f"{base_url}/", path),
- headers=jsonable_encoder(
+ data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
+
+ # Get headers (supports async token providers)
+ _headers = await self._get_headers()
+
+ # Compute encoded params separately to avoid passing empty list to httpx
+ # (httpx strips existing query params from URL when params=[] is passed)
+ _encoded_params = encode_query(
+ jsonable_encoder(
remove_none_from_dict(
- {
- **self.base_headers(),
- **(headers if headers is not None else {}),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- params=encode_query(
- jsonable_encoder(
- remove_none_from_dict(
- remove_omit_from_dict(
- {
- **(params if params is not None else {}),
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- },
- omit=omit,
- )
+ remove_omit_from_dict(
+ {
+ **(params if params is not None else {}),
+ **(
+ request_options.get("additional_query_parameters", {})
+ if request_options is not None
+ else {}
+ ),
+ },
+ omit=omit,
)
)
- ),
+ )
+ )
+
+ _request_url = _build_url(base_url, path)
+ _request_headers = jsonable_encoder(
+ remove_none_from_dict(
+ {
+ **_headers,
+ **(headers if headers is not None else {}),
+ **(request_options.get("additional_headers", {}) if request_options is not None else {}),
+ }
+ )
+ )
+ _request_headers = drop_content_type_without_body(
+ _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body
+ )
+
+ if self.logger.is_debug():
+ self.logger.debug(
+ "Making streaming HTTP request",
+ method=method,
+ url=_request_url,
+ headers=_redact_headers(_request_headers),
+ )
+
+ async with self.httpx_client.stream(
+ method=method,
+ url=_request_url,
+ headers=_request_headers,
+ params=_encoded_params if _encoded_params else None,
json=json_body,
data=data_body,
content=content,
diff --git a/common/generated/rest/core/http_response.py b/common/generated/rest/core/http_response.py
index 48a1798a..9aa1e188 100644
--- a/common/generated/rest/core/http_response.py
+++ b/common/generated/rest/core/http_response.py
@@ -4,12 +4,12 @@
import httpx
+# Generic to represent the underlying type of the data wrapped by the HTTP response.
T = TypeVar("T")
-"""Generic to represent the underlying type of the data wrapped by the HTTP response."""
class BaseHttpResponse:
- """Minimalist HTTP response wrapper that exposes response headers."""
+ """Minimalist HTTP response wrapper that exposes response headers and status code."""
_response: httpx.Response
@@ -20,6 +20,14 @@ def __init__(self, response: httpx.Response):
def headers(self) -> Dict[str, str]:
return dict(self._response.headers)
+ @property
+ def status_code(self) -> int:
+ return self._response.status_code
+
+ @property
+ def response(self) -> httpx.Response:
+ return self._response
+
class HttpResponse(Generic[T], BaseHttpResponse):
"""HTTP response wrapper that exposes response headers and data."""
diff --git a/common/generated/rest/core/http_sse/__init__.py b/common/generated/rest/core/http_sse/__init__.py
new file mode 100644
index 00000000..730e5a33
--- /dev/null
+++ b/common/generated/rest/core/http_sse/__init__.py
@@ -0,0 +1,42 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from ._api import EventSource, aconnect_sse, connect_sse
+ from ._exceptions import SSEError
+ from ._models import ServerSentEvent
+_dynamic_imports: typing.Dict[str, str] = {
+ "EventSource": "._api",
+ "SSEError": "._exceptions",
+ "ServerSentEvent": "._models",
+ "aconnect_sse": "._api",
+ "connect_sse": "._api",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["EventSource", "SSEError", "ServerSentEvent", "aconnect_sse", "connect_sse"]
diff --git a/common/generated/rest/core/http_sse/_api.py b/common/generated/rest/core/http_sse/_api.py
new file mode 100644
index 00000000..9ca5602c
--- /dev/null
+++ b/common/generated/rest/core/http_sse/_api.py
@@ -0,0 +1,455 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import codecs
+import re
+import time
+from contextlib import asynccontextmanager, contextmanager
+from typing import (
+ Any,
+ AsyncContextManager,
+ AsyncGenerator,
+ AsyncIterator,
+ Callable,
+ ContextManager,
+ Iterator,
+ Optional,
+)
+
+import anyio
+import httpx
+from ._decoders import SSEDecoder
+from ._exceptions import SSEError
+from ._models import ServerSentEvent
+
+MAX_LINE_SIZE: int = 1_048_576 # 1 MiB
+
+# Reconnection defaults, mirroring the TypeScript SDK's Stream implementation.
+DEFAULT_MAX_RECONNECTION_ATTEMPTS: int = 5
+DEFAULT_RECONNECT_DELAY_MS: int = 1_000
+MAX_RECONNECT_DELAY_MS: int = 30_000
+
+
+# A reconnect callback re-issues the original request (with a ``Last-Event-ID``
+# header set to the supplied event id) and returns a *context manager* yielding
+# a fresh streaming ``httpx.Response``. Sync clients supply a sync context
+# manager; async clients supply an async one.
+class EventSource:
+ def __init__(
+ self,
+ response: httpx.Response,
+ *,
+ resumable: bool = False,
+ stream_reconnection_enabled: bool = True,
+ max_stream_reconnection_attempts: Optional[int] = None,
+ stream_terminator: Optional[str] = None,
+ reconnect: Optional[Callable[[str], Any]] = None,
+ ) -> None:
+ self._response = response
+ self._resumable = resumable
+ self._stream_reconnection_enabled = stream_reconnection_enabled
+ self._max_stream_reconnection_attempts = max_stream_reconnection_attempts
+ self._stream_terminator = stream_terminator
+ self._reconnect = reconnect
+
+ @staticmethod
+ def _is_event_stream(response: httpx.Response) -> bool:
+ content_type = response.headers.get("content-type", "").partition(";")[0]
+ return "text/event-stream" in content_type
+
+ def _check_content_type(self) -> None:
+ if not self._is_event_stream(self._response):
+ content_type = self._response.headers.get("content-type", "").partition(";")[0]
+ raise SSEError(
+ f"Expected response header Content-Type to contain 'text/event-stream', got {content_type!r}"
+ )
+
+ def _is_reconnect_response_usable(self, response: httpx.Response) -> bool:
+ """Whether a reconnected response can be resumed as an SSE stream.
+
+ ``httpx.stream`` does not raise on non-success status, so a resume that
+ returns an error page (e.g. ``200 text/html`` or a ``500`` body) would
+ otherwise be parsed as SSE and yield garbage/zero events. Such a
+ response is treated as a failed attempt (back off and retry) instead.
+ """
+ return response.status_code < 400 and self._is_event_stream(response)
+
+ def _get_charset(self, response: Optional[httpx.Response] = None) -> str:
+ """Extract charset from Content-Type header, fallback to UTF-8."""
+ resolved = response if response is not None else self._response
+ content_type = resolved.headers.get("content-type", "")
+
+ # Parse charset parameter using regex
+ charset_match = re.search(r"charset=([^;\s]+)", content_type, re.IGNORECASE)
+ if charset_match:
+ charset = charset_match.group(1).strip("\"'")
+ # Validate that it's a known encoding
+ try:
+ # Test if the charset is valid by trying to encode/decode
+ "test".encode(charset).decode(charset)
+ return charset
+ except (LookupError, UnicodeError):
+ # If charset is invalid, fall back to UTF-8
+ pass
+
+ # Default to UTF-8 if no charset specified or invalid charset
+ return "utf-8"
+
+ @property
+ def response(self) -> httpx.Response:
+ return self._response
+
+ @staticmethod
+ def _normalize_sse_line_endings(buf: str) -> str:
+ """Normalize line endings per the SSE spec (\\r\\n → \\n, bare \\r → \\n).
+
+ A trailing \\r is preserved because it may pair with a leading \\n in
+ the next chunk to form a single \\r\\n terminator.
+ """
+ buf = buf.replace("\r\n", "\n")
+ if buf.endswith("\r"):
+ return buf[:-1].replace("\r", "\n") + "\r"
+ return buf.replace("\r", "\n")
+
+ def _new_text_decoder(self, response: Optional[httpx.Response] = None) -> "codecs.IncrementalDecoder":
+ return codecs.getincrementaldecoder(self._get_charset(response))(errors="replace")
+
+ def _reconnect_applicable(self) -> bool:
+ """Whether reconnection is configured for this stream at all.
+
+ This is the terminator-gating half of the reconnect decision, kept
+ separate from :meth:`_should_reconnect` (which additionally requires a
+ last *dispatched* id and an unexhausted attempt budget). The split lets
+ a mid-stream transport error terminate consistently:
+ - a stream that can never reconnect (non-resumable, no terminator,
+ disabled, or no callback) must re-raise the error to the caller, so a
+ truncated stream is not mistaken for a clean completion;
+ - a resumable stream that has merely run out of attempts (or has no id
+ to resume from) ends cleanly — the same way an exhausted empty/error
+ -body resume already does, matching the TypeScript ``return``.
+ """
+ return (
+ self._resumable
+ and self._stream_terminator is not None
+ and self._stream_reconnection_enabled
+ and self._reconnect is not None
+ )
+
+ def _should_reconnect(self, last_dispatched_id: Optional[str], reconnect_attempts: int) -> bool:
+ """Decide whether a prematurely-ended stream should be reconnected.
+
+ Mirrors the TypeScript ``shouldReconnect`` gating:
+ - only resumable SSE endpoints with a configured terminator, reconnect
+ enabled, and a reconnect callback are eligible (see
+ :meth:`_reconnect_applicable`);
+ - a last *dispatched* event id must exist to resume from;
+ - the consecutive-failed-attempt cap must not be exceeded.
+ """
+ if not self._reconnect_applicable():
+ return False
+ if not last_dispatched_id:
+ return False
+ max_attempts = (
+ self._max_stream_reconnection_attempts
+ if self._max_stream_reconnection_attempts is not None
+ else DEFAULT_MAX_RECONNECTION_ATTEMPTS
+ )
+ if reconnect_attempts >= max_attempts:
+ return False
+ return True
+
+ def _reconnect_delay_seconds(self, last_retry: Optional[int]) -> float:
+ """Backoff before a reconnect.
+
+ Uses the server's most recent ``retry:`` directive (milliseconds) when
+ present, otherwise a default of ``DEFAULT_RECONNECT_DELAY_MS``, clamped
+ to ``MAX_RECONNECT_DELAY_MS``.
+ """
+ base_ms = last_retry if (last_retry is not None and last_retry > 0) else DEFAULT_RECONNECT_DELAY_MS
+ return min(base_ms, MAX_RECONNECT_DELAY_MS) / 1000.0
+
+ def _sleep_before_reconnect(self, last_retry: Optional[int]) -> None:
+ # ``time.sleep`` blocks the calling thread but remains interruptible by
+ # signals (e.g. ``KeyboardInterrupt``), which propagate out and abort
+ # the reconnect without issuing another request.
+ time.sleep(self._reconnect_delay_seconds(last_retry))
+
+ async def _asleep_before_reconnect(self, last_retry: Optional[int]) -> None:
+ # ``anyio.sleep`` is cancellation-aware: if the consumer cancels the task
+ # or closes the async generator mid-delay, this raises (and no further
+ # request is issued) instead of blocking for the whole interval.
+ await anyio.sleep(self._reconnect_delay_seconds(last_retry))
+
+ def _decode_response(
+ self,
+ response: httpx.Response,
+ decoder: SSEDecoder,
+ text_decoder: "codecs.IncrementalDecoder",
+ ) -> Iterator[ServerSentEvent]:
+ buf = ""
+ for chunk in response.iter_bytes():
+ buf += text_decoder.decode(chunk)
+ buf = self._normalize_sse_line_endings(buf)
+
+ while "\n" in buf:
+ line, buf = buf.split("\n", 1)
+ sse = decoder.decode(line)
+ if sse is not None:
+ yield sse
+
+ if len(buf) > MAX_LINE_SIZE:
+ raise SSEError(
+ f"SSE line exceeded maximum size of {MAX_LINE_SIZE} characters without encountering a newline"
+ )
+
+ yield from self._flush_decoder(buf, decoder, text_decoder)
+
+ async def _adecode_response(
+ self,
+ response: httpx.Response,
+ decoder: SSEDecoder,
+ text_decoder: "codecs.IncrementalDecoder",
+ ) -> AsyncGenerator[ServerSentEvent, None]:
+ buf = ""
+ async for chunk in response.aiter_bytes():
+ buf += text_decoder.decode(chunk)
+ buf = self._normalize_sse_line_endings(buf)
+
+ while "\n" in buf:
+ line, buf = buf.split("\n", 1)
+ sse = decoder.decode(line)
+ if sse is not None:
+ yield sse
+
+ if len(buf) > MAX_LINE_SIZE:
+ raise SSEError(
+ f"SSE line exceeded maximum size of {MAX_LINE_SIZE} characters without encountering a newline"
+ )
+
+ for sse in self._flush_decoder(buf, decoder, text_decoder):
+ yield sse
+
+ def _flush_decoder(
+ self,
+ buf: str,
+ decoder: SSEDecoder,
+ text_decoder: "codecs.IncrementalDecoder",
+ ) -> Iterator[ServerSentEvent]:
+ # Flush any remaining bytes from the incremental decoder
+ buf += text_decoder.decode(b"", final=True)
+ buf = buf.replace("\r\n", "\n").replace("\r", "\n")
+
+ if len(buf) > MAX_LINE_SIZE:
+ raise SSEError(
+ f"SSE line exceeded maximum size of {MAX_LINE_SIZE} characters without encountering a newline"
+ )
+
+ while "\n" in buf:
+ line, buf = buf.split("\n", 1)
+ sse = decoder.decode(line)
+ if sse is not None:
+ yield sse
+
+ if buf.strip():
+ sse = decoder.decode(buf)
+ if sse is not None:
+ yield sse
+
+ def iter_sse(self) -> Iterator[ServerSentEvent]:
+ self._check_content_type()
+ decoder = SSEDecoder()
+ text_decoder = self._new_text_decoder()
+
+ last_dispatched_id: Optional[str] = None
+ last_retry: Optional[int] = None
+ # Consecutive failed reconnection attempts. Reset to 0 whenever an event
+ # is successfully dispatched (reset-on-progress) — matching browser
+ # `EventSource` semantics: a server that emits >=1 event then drops on
+ # every connection can reconnect indefinitely.
+ reconnect_attempts = 0
+
+ # ``None`` means there is no live stream to read this iteration (e.g. a
+ # failed reconnect); the loop then re-evaluates the reconnect decision
+ # without re-reading an exhausted response.
+ response: Optional[httpx.Response] = self._response
+ # Context manager for a response we opened ourselves and must close.
+ # The initial response is owned by the caller, so it starts as None.
+ owned_cm: Optional[ContextManager[httpx.Response]] = None
+ try:
+ while True:
+ if response is not None:
+ events = self._decode_response(response, decoder, text_decoder)
+ while True:
+ try:
+ sse = next(events)
+ except StopIteration:
+ break
+ except SSEError:
+ # A protocol violation (e.g. an oversized line) is a
+ # genuine error, not a dropped connection; propagate it.
+ # Listed first because ``SSEError`` subclasses
+ # ``httpx.TransportError``.
+ raise
+ except httpx.TransportError:
+ # A transport error mid-stream (e.g. the server dropped
+ # the connection: ``ReadError``/``RemoteProtocolError``)
+ # is a premature end. Only swallow it when reconnection
+ # is configured for this stream; otherwise re-raise so a
+ # non-resumable stream still surfaces the error to the
+ # caller instead of looking like a clean completion.
+ # When reconnection is applicable but the attempt budget
+ # is exhausted, we ``break`` and end cleanly below — the
+ # same way an exhausted empty/error-body resume does, so
+ # give-up is consistent regardless of failure shape.
+ # ``next`` is used rather than ``for`` so this cannot
+ # swallow a ``GeneratorExit`` raised at a ``yield``.
+ if not self._reconnect_applicable():
+ raise
+ break
+ yield sse
+ if sse.id:
+ last_dispatched_id = sse.id
+ if sse.retry is not None:
+ last_retry = sse.retry
+ reconnect_attempts = 0
+
+ if not self._should_reconnect(last_dispatched_id, reconnect_attempts):
+ return
+ reconnect_attempts += 1
+
+ self._sleep_before_reconnect(last_retry)
+
+ # Close the previously-opened reconnect response before opening
+ # a new one so we never hold more than one extra connection.
+ if owned_cm is not None:
+ owned_cm.__exit__(None, None, None)
+ owned_cm = None
+
+ assert self._reconnect is not None # guaranteed by _should_reconnect
+ try:
+ cm: ContextManager[httpx.Response] = self._reconnect(last_dispatched_id or "")
+ new_response = cm.__enter__()
+ except Exception:
+ # A failed reconnect consumes an attempt; back off and retry.
+ response = None
+ continue
+ owned_cm = cm
+ if new_response is None or not self._is_reconnect_response_usable(new_response):
+ # Null/empty body or a non-SSE/error response (e.g. 204/304,
+ # a 500, or an HTML error page): treat as a failed attempt.
+ response = None
+ continue
+
+ response = new_response
+ # Drop any partial event left over from the dropped stream, but
+ # keep the last event id (per the SSE spec) and start a fresh
+ # incremental text decoder for the new connection.
+ decoder.reset_in_progress_event()
+ text_decoder = self._new_text_decoder(new_response)
+ finally:
+ if owned_cm is not None:
+ owned_cm.__exit__(None, None, None)
+
+ async def aiter_sse(self) -> AsyncGenerator[ServerSentEvent, None]:
+ self._check_content_type()
+ decoder = SSEDecoder()
+ text_decoder = self._new_text_decoder()
+
+ last_dispatched_id: Optional[str] = None
+ last_retry: Optional[int] = None
+ reconnect_attempts = 0
+
+ response: Optional[httpx.Response] = self._response
+ owned_cm: Optional[AsyncContextManager[httpx.Response]] = None
+ try:
+ while True:
+ if response is not None:
+ events = self._adecode_response(response, decoder, text_decoder)
+ while True:
+ try:
+ sse = await events.__anext__()
+ except StopAsyncIteration:
+ break
+ except SSEError:
+ # A protocol violation (e.g. an oversized line) is a
+ # genuine error, not a dropped connection; propagate it.
+ # Listed first because ``SSEError`` subclasses
+ # ``httpx.TransportError``.
+ raise
+ except httpx.TransportError:
+ # A transport error mid-stream (e.g. the server dropped
+ # the connection: ``ReadError``/``RemoteProtocolError``)
+ # is a premature end. Only swallow it when reconnection
+ # is configured for this stream; otherwise re-raise so a
+ # non-resumable stream still surfaces the error to the
+ # caller instead of looking like a clean completion.
+ # When reconnection is applicable but the attempt budget
+ # is exhausted, we ``break`` and end cleanly below — the
+ # same way an exhausted empty/error-body resume does, so
+ # give-up is consistent regardless of failure shape.
+ if not self._reconnect_applicable():
+ raise
+ break
+ yield sse
+ if sse.id:
+ last_dispatched_id = sse.id
+ if sse.retry is not None:
+ last_retry = sse.retry
+ reconnect_attempts = 0
+
+ if not self._should_reconnect(last_dispatched_id, reconnect_attempts):
+ return
+ reconnect_attempts += 1
+
+ await self._asleep_before_reconnect(last_retry)
+
+ if owned_cm is not None:
+ await owned_cm.__aexit__(None, None, None)
+ owned_cm = None
+
+ assert self._reconnect is not None # guaranteed by _should_reconnect
+ try:
+ cm: AsyncContextManager[httpx.Response] = self._reconnect(last_dispatched_id or "")
+ new_response = await cm.__aenter__()
+ except Exception:
+ response = None
+ continue
+ owned_cm = cm
+ if new_response is None or not self._is_reconnect_response_usable(new_response):
+ response = None
+ continue
+
+ response = new_response
+ decoder.reset_in_progress_event()
+ text_decoder = self._new_text_decoder(new_response)
+ finally:
+ if owned_cm is not None:
+ # Shield the close so a cancellation delivered while reading a
+ # reconnected response still fully tears the connection down
+ # instead of leaking it until the client is closed.
+ with anyio.CancelScope(shield=True):
+ await owned_cm.__aexit__(None, None, None)
+
+
+@contextmanager
+def connect_sse(client: httpx.Client, method: str, url: str, **kwargs: Any) -> Iterator[EventSource]:
+ headers = kwargs.pop("headers", {})
+ headers["Accept"] = "text/event-stream"
+ headers["Cache-Control"] = "no-store"
+
+ with client.stream(method, url, headers=headers, **kwargs) as response:
+ yield EventSource(response)
+
+
+@asynccontextmanager
+async def aconnect_sse(
+ client: httpx.AsyncClient,
+ method: str,
+ url: str,
+ **kwargs: Any,
+) -> AsyncIterator[EventSource]:
+ headers = kwargs.pop("headers", {})
+ headers["Accept"] = "text/event-stream"
+ headers["Cache-Control"] = "no-store"
+
+ async with client.stream(method, url, headers=headers, **kwargs) as response:
+ yield EventSource(response)
diff --git a/common/generated/rest/core/http_sse/_decoders.py b/common/generated/rest/core/http_sse/_decoders.py
new file mode 100644
index 00000000..1f6b35ec
--- /dev/null
+++ b/common/generated/rest/core/http_sse/_decoders.py
@@ -0,0 +1,74 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from typing import List, Optional
+
+from ._models import ServerSentEvent
+
+
+class SSEDecoder:
+ def __init__(self) -> None:
+ self._event = ""
+ self._data: List[str] = []
+ self._last_event_id = ""
+ self._retry: Optional[int] = None
+
+ def reset_in_progress_event(self) -> None:
+ """Discard any partially-parsed (undispatched) event.
+
+ Used when a stream ends mid-event before reconnecting: the buffered
+ ``event``/``data``/``retry`` fields of the never-dispatched event must
+ be dropped so they do not corrupt the first event of the reconnected
+ stream. Per the SSE spec the last event id is *not* reset here — it
+ persists across connections.
+ """
+ self._event = ""
+ self._data = []
+ self._retry = None
+
+ def decode(self, line: str) -> Optional[ServerSentEvent]:
+ # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501
+
+ if not line:
+ if not self._event and not self._data and not self._last_event_id and self._retry is None:
+ return None
+
+ sse = ServerSentEvent(
+ event=self._event,
+ data="\n".join(self._data),
+ id=self._last_event_id,
+ retry=self._retry,
+ )
+
+ # NOTE: as per the SSE spec, do not reset last_event_id.
+ self._event = ""
+ self._data = []
+ self._retry = None
+
+ return sse
+
+ if line.startswith(":"):
+ return None
+
+ fieldname, _, value = line.partition(":")
+
+ if value.startswith(" "):
+ value = value[1:]
+
+ if fieldname == "event":
+ self._event = value
+ elif fieldname == "data":
+ self._data.append(value)
+ elif fieldname == "id":
+ if "\0" in value:
+ pass
+ else:
+ self._last_event_id = value
+ elif fieldname == "retry":
+ try:
+ self._retry = int(value)
+ except (TypeError, ValueError):
+ pass
+ else:
+ pass # Field is ignored.
+
+ return None
diff --git a/skyvault/skyflow/generated/rest/types/resource_id.py b/common/generated/rest/core/http_sse/_exceptions.py
similarity index 51%
rename from skyvault/skyflow/generated/rest/types/resource_id.py
rename to common/generated/rest/core/http_sse/_exceptions.py
index 211b4108..81605a8a 100644
--- a/skyvault/skyflow/generated/rest/types/resource_id.py
+++ b/common/generated/rest/core/http_sse/_exceptions.py
@@ -1,3 +1,7 @@
# This file was auto-generated by Fern from our API Definition.
-ResourceId = str
+import httpx
+
+
+class SSEError(httpx.TransportError):
+ pass
diff --git a/common/generated/rest/core/http_sse/_models.py b/common/generated/rest/core/http_sse/_models.py
new file mode 100644
index 00000000..1af57f8f
--- /dev/null
+++ b/common/generated/rest/core/http_sse/_models.py
@@ -0,0 +1,17 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import json
+from dataclasses import dataclass
+from typing import Any, Optional
+
+
+@dataclass(frozen=True)
+class ServerSentEvent:
+ event: str = "message"
+ data: str = ""
+ id: str = ""
+ retry: Optional[int] = None
+
+ def json(self) -> Any:
+ """Parse the data field as JSON."""
+ return json.loads(self.data)
diff --git a/common/generated/rest/core/jsonable_encoder.py b/common/generated/rest/core/jsonable_encoder.py
index afee3662..f638cc9a 100644
--- a/common/generated/rest/core/jsonable_encoder.py
+++ b/common/generated/rest/core/jsonable_encoder.py
@@ -15,6 +15,7 @@
from pathlib import PurePath
from types import GeneratorType
from typing import Any, Callable, Dict, List, Optional, Set, Union
+from urllib.parse import quote
import pydantic
from .datetime_utils import serialize_datetime
@@ -30,6 +31,10 @@
def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any], Any]]] = None) -> Any:
custom_encoder = custom_encoder or {}
+ # Generated SDKs use Ellipsis (`...`) as the sentinel value for "OMIT".
+ # OMIT values should be excluded from serialized payloads.
+ if obj is Ellipsis:
+ return None
if custom_encoder:
if type(obj) in custom_encoder:
return custom_encoder[type(obj)](obj)
@@ -70,6 +75,8 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any]
allowed_keys = set(obj.keys())
for key, value in obj.items():
if key in allowed_keys:
+ if value is Ellipsis:
+ continue
encoded_key = jsonable_encoder(key, custom_encoder=custom_encoder)
encoded_value = jsonable_encoder(value, custom_encoder=custom_encoder)
encoded_dict[encoded_key] = encoded_value
@@ -77,6 +84,8 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any]
if isinstance(obj, (list, set, frozenset, GeneratorType, tuple)):
encoded_list = []
for item in obj:
+ if item is Ellipsis:
+ continue
encoded_list.append(jsonable_encoder(item, custom_encoder=custom_encoder))
return encoded_list
@@ -98,3 +107,27 @@ def fallback_serializer(o: Any) -> Any:
return jsonable_encoder(data, custom_encoder=custom_encoder)
return to_jsonable_with_fallback(obj, fallback_serializer)
+
+
+def encode_path_param(obj: Any) -> str:
+ """Encode a value for use in a URL path segment.
+
+ Ensures proper string conversion for all types, including
+ booleans which need lowercase 'true'/'false' rather than
+ Python's 'True'/'False'.
+ """
+ if isinstance(obj, bool):
+ return "true" if obj else "false"
+ return str(jsonable_encoder(obj))
+
+
+def quote_path_param(obj: Any) -> str:
+ """Encode a value for use in a URL path segment, percent-encoding it.
+
+ Same as encode_path_param, except the result is percent-encoded so
+ that a value containing "/" or ".." cannot change which endpoint
+ the request resolves to.
+ """
+ if isinstance(obj, bool):
+ return "true" if obj else "false"
+ return quote(str(jsonable_encoder(obj)), safe="")
diff --git a/common/generated/rest/core/logging.py b/common/generated/rest/core/logging.py
new file mode 100644
index 00000000..e5e57245
--- /dev/null
+++ b/common/generated/rest/core/logging.py
@@ -0,0 +1,107 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import logging
+import typing
+
+LogLevel = typing.Literal["debug", "info", "warn", "error"]
+
+_LOG_LEVEL_MAP: typing.Dict[LogLevel, int] = {
+ "debug": 1,
+ "info": 2,
+ "warn": 3,
+ "error": 4,
+}
+
+
+class ILogger(typing.Protocol):
+ def debug(self, message: str, **kwargs: typing.Any) -> None: ...
+ def info(self, message: str, **kwargs: typing.Any) -> None: ...
+ def warn(self, message: str, **kwargs: typing.Any) -> None: ...
+ def error(self, message: str, **kwargs: typing.Any) -> None: ...
+
+
+class ConsoleLogger:
+ _logger: logging.Logger
+
+ def __init__(self) -> None:
+ self._logger = logging.getLogger("fern")
+ if not self._logger.handlers:
+ handler = logging.StreamHandler()
+ handler.setFormatter(logging.Formatter("%(levelname)s - %(message)s"))
+ self._logger.addHandler(handler)
+ self._logger.setLevel(logging.DEBUG)
+
+ def debug(self, message: str, **kwargs: typing.Any) -> None:
+ self._logger.debug(message, extra=kwargs)
+
+ def info(self, message: str, **kwargs: typing.Any) -> None:
+ self._logger.info(message, extra=kwargs)
+
+ def warn(self, message: str, **kwargs: typing.Any) -> None:
+ self._logger.warning(message, extra=kwargs)
+
+ def error(self, message: str, **kwargs: typing.Any) -> None:
+ self._logger.error(message, extra=kwargs)
+
+
+class LogConfig(typing.TypedDict, total=False):
+ level: LogLevel
+ logger: ILogger
+ silent: bool
+
+
+class Logger:
+ _level: int
+ _logger: ILogger
+ _silent: bool
+
+ def __init__(self, *, level: LogLevel, logger: ILogger, silent: bool) -> None:
+ self._level = _LOG_LEVEL_MAP[level]
+ self._logger = logger
+ self._silent = silent
+
+ def _should_log(self, level: LogLevel) -> bool:
+ return not self._silent and self._level <= _LOG_LEVEL_MAP[level]
+
+ def is_debug(self) -> bool:
+ return self._should_log("debug")
+
+ def is_info(self) -> bool:
+ return self._should_log("info")
+
+ def is_warn(self) -> bool:
+ return self._should_log("warn")
+
+ def is_error(self) -> bool:
+ return self._should_log("error")
+
+ def debug(self, message: str, **kwargs: typing.Any) -> None:
+ if self.is_debug():
+ self._logger.debug(message, **kwargs)
+
+ def info(self, message: str, **kwargs: typing.Any) -> None:
+ if self.is_info():
+ self._logger.info(message, **kwargs)
+
+ def warn(self, message: str, **kwargs: typing.Any) -> None:
+ if self.is_warn():
+ self._logger.warn(message, **kwargs)
+
+ def error(self, message: str, **kwargs: typing.Any) -> None:
+ if self.is_error():
+ self._logger.error(message, **kwargs)
+
+
+_default_logger: Logger = Logger(level="info", logger=ConsoleLogger(), silent=True)
+
+
+def create_logger(config: typing.Optional[typing.Union[LogConfig, Logger]] = None) -> Logger:
+ if config is None:
+ return _default_logger
+ if isinstance(config, Logger):
+ return config
+ return Logger(
+ level=config.get("level", "info"),
+ logger=config.get("logger", ConsoleLogger()),
+ silent=config.get("silent", True),
+ )
diff --git a/common/generated/rest/core/parse_error.py b/common/generated/rest/core/parse_error.py
new file mode 100644
index 00000000..4527c6a8
--- /dev/null
+++ b/common/generated/rest/core/parse_error.py
@@ -0,0 +1,36 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from typing import Any, Dict, Optional
+
+
+class ParsingError(Exception):
+ """
+ Raised when the SDK fails to parse/validate a response from the server.
+ This typically indicates that the server returned a response whose shape
+ does not match the expected schema.
+ """
+
+ headers: Optional[Dict[str, str]]
+ status_code: Optional[int]
+ body: Any
+ cause: Optional[Exception]
+
+ def __init__(
+ self,
+ *,
+ headers: Optional[Dict[str, str]] = None,
+ status_code: Optional[int] = None,
+ body: Any = None,
+ cause: Optional[Exception] = None,
+ ) -> None:
+ self.headers = headers
+ self.status_code = status_code
+ self.body = body
+ self.cause = cause
+ super().__init__()
+ if cause is not None:
+ self.__cause__ = cause
+
+ def __str__(self) -> str:
+ cause_str = f", cause: {self.cause}" if self.cause is not None else ""
+ return f"headers: {self.headers}, status_code: {self.status_code}, body: {self.body}{cause_str}"
diff --git a/common/generated/rest/core/pydantic_utilities.py b/common/generated/rest/core/pydantic_utilities.py
index 7db29500..70816b99 100644
--- a/common/generated/rest/core/pydantic_utilities.py
+++ b/common/generated/rest/core/pydantic_utilities.py
@@ -2,30 +2,130 @@
# nopycln: file
import datetime as dt
+import inspect
+import json
+import logging
+import weakref
from collections import defaultdict
-from typing import Any, Callable, ClassVar, Dict, List, Mapping, Optional, Set, Tuple, Type, TypeVar, Union, cast
+from dataclasses import asdict
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Callable,
+ ClassVar,
+ Dict,
+ List,
+ Mapping,
+ Optional,
+ Set,
+ Tuple,
+ Type,
+ TypeVar,
+ Union,
+ cast,
+)
import pydantic
+import typing_extensions
+from pydantic.fields import FieldInfo as _FieldInfo
+
+_logger = logging.getLogger(__name__)
+
+if TYPE_CHECKING:
+ from .http_sse._models import ServerSentEvent
IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
if IS_PYDANTIC_V2:
- from pydantic.v1.datetime_parse import parse_date as parse_date
- from pydantic.v1.datetime_parse import parse_datetime as parse_datetime
- from pydantic.v1.fields import ModelField as ModelField
- from pydantic.v1.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[attr-defined]
- from pydantic.v1.typing import get_args as get_args
- from pydantic.v1.typing import get_origin as get_origin
- from pydantic.v1.typing import is_literal_type as is_literal_type
- from pydantic.v1.typing import is_union as is_union
+ _datetime_adapter = pydantic.TypeAdapter(dt.datetime) # type: ignore[attr-defined]
+ _date_adapter = pydantic.TypeAdapter(dt.date) # type: ignore[attr-defined]
+
+ def parse_datetime(value: Any) -> dt.datetime: # type: ignore[misc]
+ if isinstance(value, dt.datetime):
+ return value
+ return _datetime_adapter.validate_python(value)
+
+ def parse_date(value: Any) -> dt.date: # type: ignore[misc]
+ if isinstance(value, dt.datetime):
+ return value.date()
+ if isinstance(value, dt.date):
+ return value
+ return _date_adapter.validate_python(value)
+
+ # Avoid importing from pydantic.v1 to maintain Python 3.14 compatibility.
+ from typing import get_args as get_args # type: ignore[assignment]
+ from typing import get_origin as get_origin # type: ignore[assignment]
+
+ def is_literal_type(tp: Optional[Type[Any]]) -> bool: # type: ignore[misc]
+ return typing_extensions.get_origin(tp) is typing_extensions.Literal
+
+ def is_union(tp: Optional[Type[Any]]) -> bool: # type: ignore[misc]
+ return tp is Union or typing_extensions.get_origin(tp) is Union # type: ignore[comparison-overlap]
+
+ # Inline encoders_by_type to avoid importing from pydantic.v1.json
+ import re as _re
+ from collections import deque as _deque
+ from decimal import Decimal as _Decimal
+ from enum import Enum as _Enum
+ from ipaddress import (
+ IPv4Address as _IPv4Address,
+ )
+ from ipaddress import (
+ IPv4Interface as _IPv4Interface,
+ )
+ from ipaddress import (
+ IPv4Network as _IPv4Network,
+ )
+ from ipaddress import (
+ IPv6Address as _IPv6Address,
+ )
+ from ipaddress import (
+ IPv6Interface as _IPv6Interface,
+ )
+ from ipaddress import (
+ IPv6Network as _IPv6Network,
+ )
+ from pathlib import Path as _Path
+ from types import GeneratorType as _GeneratorType
+ from uuid import UUID as _UUID
+
+ from pydantic.fields import FieldInfo as ModelField # type: ignore[no-redef, assignment]
+
+ def _decimal_encoder(dec_value: Any) -> Any:
+ if dec_value.as_tuple().exponent >= 0:
+ return int(dec_value)
+ return float(dec_value)
+
+ encoders_by_type: Dict[Type[Any], Callable[[Any], Any]] = { # type: ignore[no-redef]
+ bytes: lambda o: o.decode(),
+ dt.date: lambda o: o.isoformat(),
+ dt.datetime: lambda o: o.isoformat(),
+ dt.time: lambda o: o.isoformat(),
+ dt.timedelta: lambda td: td.total_seconds(),
+ _Decimal: _decimal_encoder,
+ _Enum: lambda o: o.value,
+ frozenset: list,
+ _deque: list,
+ _GeneratorType: list,
+ _IPv4Address: str,
+ _IPv4Interface: str,
+ _IPv4Network: str,
+ _IPv6Address: str,
+ _IPv6Interface: str,
+ _IPv6Network: str,
+ _Path: str,
+ _re.Pattern: lambda o: o.pattern,
+ set: list,
+ _UUID: str,
+ }
else:
from pydantic.datetime_parse import parse_date as parse_date # type: ignore[no-redef]
from pydantic.datetime_parse import parse_datetime as parse_datetime # type: ignore[no-redef]
- from pydantic.fields import ModelField as ModelField # type: ignore[attr-defined, no-redef]
+ from pydantic.fields import ModelField as ModelField # type: ignore[attr-defined, no-redef, assignment]
from pydantic.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[no-redef]
from pydantic.typing import get_args as get_args # type: ignore[no-redef]
from pydantic.typing import get_origin as get_origin # type: ignore[no-redef]
- from pydantic.typing import is_literal_type as is_literal_type # type: ignore[no-redef]
+ from pydantic.typing import is_literal_type as is_literal_type # type: ignore[no-redef, assignment]
from pydantic.typing import is_union as is_union # type: ignore[no-redef]
from .datetime_utils import serialize_datetime
@@ -36,11 +136,128 @@
Model = TypeVar("Model", bound=pydantic.BaseModel)
+def parse_sse_obj(sse: "ServerSentEvent", type_: Type[T]) -> T:
+ """
+ Parse a ServerSentEvent into the appropriate type.
+
+ This function handles data-level discrimination where the discriminator
+ (e.g., 'type') is inside the 'data' payload. It parses the SSE data field
+ as JSON and deserializes it into the target type.
+
+ Note: Protocol-level discrimination (where the discriminator comes from
+ the SSE event: field) is handled at code-generation time and does not
+ use this function.
+
+ Args:
+ sse: The ServerSentEvent object to parse
+ type_: The target type to deserialize into
+
+ Returns:
+ The parsed object of type T
+
+ Note:
+ This function is only available in SDK contexts where http_sse module exists.
+ """
+ sse_event = asdict(sse)
+ data_value = sse_event.get("data")
+ if isinstance(data_value, str) and data_value:
+ try:
+ parsed_data = json.loads(data_value)
+ return parse_obj_as(type_, parsed_data)
+ except json.JSONDecodeError as e:
+ _logger.warning(
+ "Failed to parse SSE data field as JSON: %s, data: %s",
+ e,
+ data_value[:100] if len(data_value) > 100 else data_value,
+ )
+ return parse_obj_as(type_, sse_event)
+
+
+_type_adapter_cache: Dict[int, Any] = {}
+
+
+def _get_type_adapter(type_: Type[Any]) -> Any:
+ key = id(type_)
+ adapter = _type_adapter_cache.get(key)
+ if adapter is None:
+ adapter = pydantic.TypeAdapter(type_) # type: ignore[attr-defined]
+ _type_adapter_cache[key] = adapter
+ return adapter
+
+
+_field_alias_cache: "weakref.WeakKeyDictionary[type, Tuple[Dict[str, str], Tuple[str, ...]]]" = (
+ weakref.WeakKeyDictionary()
+)
+
+
+def _get_field_aliases(model: type) -> Tuple[Dict[str, str], Tuple[str, ...]]:
+ """
+ Map of field name to Pydantic alias for the fields whose alias differs from their name, together with the
+ keys that are ambiguous (an alias of one field and the name of another). Computed once per model class.
+ """
+ cached = _field_alias_cache.get(model)
+ if cached is None:
+ fields: Mapping[str, Any] = (
+ getattr(model, "model_fields", {}) if IS_PYDANTIC_V2 else getattr(model, "__fields__", {})
+ )
+ name_to_alias: Dict[str, str] = {}
+ for name, field in fields.items():
+ alias = getattr(field, "alias", None)
+ if alias is not None and alias != name:
+ name_to_alias[name] = alias
+ cached = (name_to_alias, tuple(alias for alias in name_to_alias.values() if alias in fields))
+ _field_alias_cache[model] = cached
+ return cached
+
+
+def _coerce_keys_to_aliases(model: type, data: Any) -> Any:
+ """
+ Accept Python field names in input by rewriting them to their Pydantic aliases,
+ while avoiding silent collisions when a key could refer to multiple fields.
+ """
+ if not isinstance(data, Mapping):
+ return data
+
+ name_to_alias, ambiguous_keys = _get_field_aliases(model)
+ for key in ambiguous_keys:
+ if key in data and name_to_alias.get(key, key) not in data:
+ raise ValueError(
+ f"Ambiguous input key '{key}': it is both a field name and an alias. "
+ "Provide the explicit alias key to disambiguate."
+ )
+
+ if not name_to_alias or not any(name in data for name in name_to_alias):
+ return data if isinstance(data, dict) else dict(data)
+
+ rewritten: Dict[str, Any] = dict(data)
+ for name, alias in name_to_alias.items():
+ if name in data and alias not in rewritten:
+ rewritten[alias] = rewritten.pop(name)
+
+ return rewritten
+
+
def parse_obj_as(type_: Type[T], object_: Any) -> T:
- dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read")
+ # convert_and_respect_annotation_metadata is required for TypedDict aliasing.
+ #
+ # For Pydantic models, whether we should pre-dealias depends on how the model encodes aliasing:
+ # - If the model uses real Pydantic aliases (pydantic.Field(alias=...)), then we must pass wire keys through
+ # unchanged so Pydantic can validate them.
+ # - If the model encodes aliasing only via FieldMetadata annotations, then we MUST pre-dealias because Pydantic
+ # will not recognize those aliases during validation.
+ if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel):
+ has_pydantic_aliases = bool(_get_field_aliases(type_)[0])
+
+ dealiased_object = (
+ object_
+ if has_pydantic_aliases
+ else convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read")
+ )
+ else:
+ dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read")
if IS_PYDANTIC_V2:
- adapter = pydantic.TypeAdapter(type_) # type: ignore[attr-defined]
- return adapter.validate_python(dealiased_object)
+ adapter = _get_type_adapter(type_)
+ return adapter.validate_python(dealiased_object) # type: ignore[no-any-return]
return pydantic.parse_obj_as(type_, dealiased_object)
@@ -59,9 +276,14 @@ class UniversalBaseModel(pydantic.BaseModel):
protected_namespaces=(),
)
+ @pydantic.model_validator(mode="before") # type: ignore[attr-defined]
+ @classmethod
+ def _coerce_field_names_to_aliases(cls, data: Any) -> Any:
+ return _coerce_keys_to_aliases(cls, data)
+
@pydantic.model_serializer(mode="plain", when_used="json") # type: ignore[attr-defined]
def serialize_model(self) -> Any: # type: ignore[name-defined]
- serialized = self.model_dump()
+ serialized = self.dict() # type: ignore[attr-defined]
data = {k: serialize_datetime(v) if isinstance(v, dt.datetime) else v for k, v in serialized.items()}
return data
@@ -71,6 +293,10 @@ class Config:
smart_union = True
json_encoders = {dt.datetime: serialize_datetime}
+ @pydantic.root_validator(pre=True)
+ def _coerce_field_names_to_aliases(cls, values: Any) -> Any:
+ return _coerce_keys_to_aliases(cls, values) # type: ignore[arg-type]
+
@classmethod
def model_construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model":
dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read")
@@ -147,7 +373,10 @@ def dict(self, **kwargs: Any) -> Dict[str, Any]:
dict_dump = super().dict(**kwargs_with_defaults_exclude_unset_include_fields)
- return convert_and_respect_annotation_metadata(object_=dict_dump, annotation=self.__class__, direction="write")
+ return cast(
+ Dict[str, Any],
+ convert_and_respect_annotation_metadata(object_=dict_dump, annotation=self.__class__, direction="write"),
+ )
def _union_list_of_pydantic_dicts(source: List[Any], destination: List[Any]) -> List[Any]:
@@ -217,7 +446,9 @@ def universal_root_validator(
) -> Callable[[AnyCallable], AnyCallable]:
def decorator(func: AnyCallable) -> AnyCallable:
if IS_PYDANTIC_V2:
- return cast(AnyCallable, pydantic.model_validator(mode="before" if pre else "after")(func)) # type: ignore[attr-defined]
+ # In Pydantic v2, for RootModel we always use "before" mode
+ # The custom validators transform the input value before the model is created
+ return cast(AnyCallable, pydantic.model_validator(mode="before")(func)) # type: ignore[attr-defined]
return cast(AnyCallable, pydantic.root_validator(pre=pre)(func)) # type: ignore[call-overload]
return decorator
@@ -232,7 +463,7 @@ def decorator(func: AnyCallable) -> AnyCallable:
return decorator
-PydanticField = Union[ModelField, pydantic.fields.FieldInfo]
+PydanticField = Union[ModelField, _FieldInfo]
def _get_model_fields(model: Type["Model"]) -> Mapping[str, PydanticField]:
diff --git a/common/generated/rest/core/request_options.py b/common/generated/rest/core/request_options.py
index 1b388044..caa6f669 100644
--- a/common/generated/rest/core/request_options.py
+++ b/common/generated/rest/core/request_options.py
@@ -14,7 +14,9 @@ class RequestOptions(typing.TypedDict, total=False):
This is used primarily as an optional final parameter for service functions.
Attributes:
- - timeout_in_seconds: int. The number of seconds to await an API call before timing out.
+ - timeout: float. The number of seconds to await an API call before timing out.
+
+ - timeout_in_seconds: int. Deprecated alias for `timeout`; both are in seconds. Prefer `timeout`.
- max_retries: int. The max number of retries to attempt if the API call fails.
@@ -27,9 +29,12 @@ class RequestOptions(typing.TypedDict, total=False):
- chunk_size: int. The size, in bytes, to process each chunk of data being streamed back within the response. This equates to leveraging `chunk_size` within `requests` or `httpx`, and is only leveraged for file downloads.
"""
+ timeout: NotRequired[float]
timeout_in_seconds: NotRequired[int]
max_retries: NotRequired[int]
additional_headers: NotRequired[typing.Dict[str, typing.Any]]
additional_query_parameters: NotRequired[typing.Dict[str, typing.Any]]
additional_body_parameters: NotRequired[typing.Dict[str, typing.Any]]
chunk_size: NotRequired[int]
+ stream_reconnection_enabled: NotRequired[bool]
+ max_stream_reconnection_attempts: NotRequired[int]
diff --git a/common/generated/rest/core/serialization.py b/common/generated/rest/core/serialization.py
index c36e865c..1d753e26 100644
--- a/common/generated/rest/core/serialization.py
+++ b/common/generated/rest/core/serialization.py
@@ -26,6 +26,75 @@ def __init__(self, *, alias: str) -> None:
self.alias = alias
+# Resolving type hints (typing.get_type_hints) is expensive because it eval/compiles
+# forward-reference annotations. The result is constant for a given type, so we cache it.
+# This is critical for hot paths like SSE event parsing, where the same (often large
+# discriminated-union) type is converted on every single event.
+_type_hints_cache: typing.Dict[typing.Any, typing.Dict[str, typing.Any]] = {}
+
+
+def _get_cached_type_hints(expected_type: typing.Any) -> typing.Dict[str, typing.Any]:
+ try:
+ cached = _type_hints_cache.get(expected_type)
+ except TypeError:
+ # Unhashable type; resolve without caching.
+ return _resolve_type_hints(expected_type)
+ if cached is None:
+ cached = _resolve_type_hints(expected_type)
+ _type_hints_cache[expected_type] = cached
+ return cached
+
+
+def _resolve_type_hints(expected_type: typing.Any) -> typing.Dict[str, typing.Any]:
+ try:
+ return typing_extensions.get_type_hints(expected_type, include_extras=True)
+ except NameError:
+ # The type contains a circular reference, so we use the __annotations__ attribute directly.
+ return getattr(expected_type, "__annotations__", {})
+
+
+# Whether convert_and_respect_annotation_metadata can possibly rewrite anything for a given
+# annotation, i.e. whether any reachable model/TypedDict field carries a FieldMetadata alias.
+# This is constant per type, so we cache it and use it to short-circuit the recursive walk.
+_requires_conversion_cache: typing.Dict[typing.Any, bool] = {}
+
+
+def _requires_conversion(type_: typing.Any) -> bool:
+ try:
+ cached = _requires_conversion_cache.get(type_)
+ except TypeError:
+ # Unhashable annotation; compute without caching.
+ return _compute_requires_conversion(type_, set())
+ if cached is None:
+ cached = _compute_requires_conversion(type_, set())
+ _requires_conversion_cache[type_] = cached
+ return cached
+
+
+def _compute_requires_conversion(type_: typing.Any, seen: typing.Set[typing.Any]) -> bool:
+ clean_type = _remove_annotations(type_)
+
+ try:
+ if clean_type in seen:
+ return False
+ seen = seen | {clean_type}
+ except TypeError:
+ # Unhashable type; skip cycle tracking (the type graph is finite in practice).
+ pass
+
+ # Models / TypedDicts: a field alias here means we must dealias; otherwise recurse into fields.
+ if (inspect.isclass(clean_type) and issubclass(clean_type, pydantic.BaseModel)) or typing_extensions.is_typeddict(
+ clean_type
+ ):
+ annotations = _get_cached_type_hints(clean_type)
+ if _get_alias_to_field_name(annotations):
+ return True
+ return any(_compute_requires_conversion(hint, seen) for hint in annotations.values())
+
+ # Containers / unions: recurse into the type arguments (List/Set/Sequence/Dict/Union/etc.).
+ return any(_compute_requires_conversion(arg, seen) for arg in typing_extensions.get_args(clean_type))
+
+
def convert_and_respect_annotation_metadata(
*,
object_: typing.Any,
@@ -57,6 +126,13 @@ def convert_and_respect_annotation_metadata(
return None
if inner_type is None:
inner_type = annotation
+ # The only thing this function ever rewrites is keys that carry a FieldMetadata
+ # alias. If nothing in the (cached) type graph has such an alias, the conversion is
+ # a content-identity transform, so we can skip the entire recursive walk. This is
+ # the hot path for SSE streaming, where a large discriminated union would otherwise
+ # be traversed on every single event.
+ if not _requires_conversion(annotation):
+ return object_
clean_type = _remove_annotations(inner_type)
# Pydantic models
@@ -160,12 +236,7 @@ def _convert_mapping(
direction: typing.Literal["read", "write"],
) -> typing.Mapping[str, object]:
converted_object: typing.Dict[str, object] = {}
- try:
- annotations = typing_extensions.get_type_hints(expected_type, include_extras=True)
- except NameError:
- # The TypedDict contains a circular reference, so
- # we use the __annotations__ attribute directly.
- annotations = getattr(expected_type, "__annotations__", {})
+ annotations = _get_cached_type_hints(expected_type)
aliases_to_field_names = _get_alias_to_field_name(annotations)
for key, value in object_.items():
if direction == "read" and key in aliases_to_field_names:
@@ -221,12 +292,12 @@ def _remove_annotations(type_: typing.Any) -> typing.Any:
def get_alias_to_field_mapping(type_: typing.Any) -> typing.Dict[str, str]:
- annotations = typing_extensions.get_type_hints(type_, include_extras=True)
+ annotations = _get_cached_type_hints(type_)
return _get_alias_to_field_name(annotations)
def get_field_to_alias_mapping(type_: typing.Any) -> typing.Dict[str, str]:
- annotations = typing_extensions.get_type_hints(type_, include_extras=True)
+ annotations = _get_cached_type_hints(type_)
return _get_field_to_alias_name(annotations)
diff --git a/common/generated/rest/environment.py b/common/generated/rest/environment.py
index b1c13812..d03788a0 100644
--- a/common/generated/rest/environment.py
+++ b/common/generated/rest/environment.py
@@ -4,5 +4,5 @@
class SkyflowAuthEnvironment(enum.Enum):
- PRODUCTION = "https://manage.skyflowapis.com"
- SANDBOX = "https://manage.skyflowapis-preview.com"
+ PRODUCTION = "https://%7B%7Bvault_url%7D%7D"
+ SANDBOX = "https://%7B%7Bvault_url%7D%7D"
diff --git a/common/generated/rest/errors/__init__.py b/common/generated/rest/errors/__init__.py
index fdf6196c..8810eed8 100644
--- a/common/generated/rest/errors/__init__.py
+++ b/common/generated/rest/errors/__init__.py
@@ -2,8 +2,41 @@
# isort: skip_file
-from .bad_request_error import BadRequestError
-from .not_found_error import NotFoundError
-from .unauthorized_error import UnauthorizedError
+import typing
+from importlib import import_module
-__all__ = ["BadRequestError", "NotFoundError", "UnauthorizedError"]
+if typing.TYPE_CHECKING:
+ from .bad_request_error import BadRequestError
+ from .internal_server_error import InternalServerError
+ from .not_found_error import NotFoundError
+ from .unauthorized_error import UnauthorizedError
+_dynamic_imports: typing.Dict[str, str] = {
+ "BadRequestError": ".bad_request_error",
+ "InternalServerError": ".internal_server_error",
+ "NotFoundError": ".not_found_error",
+ "UnauthorizedError": ".unauthorized_error",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["BadRequestError", "InternalServerError", "NotFoundError", "UnauthorizedError"]
diff --git a/common/generated/rest/errors/bad_request_error.py b/common/generated/rest/errors/bad_request_error.py
index c5d0db48..92449913 100644
--- a/common/generated/rest/errors/bad_request_error.py
+++ b/common/generated/rest/errors/bad_request_error.py
@@ -3,12 +3,9 @@
import typing
from ..core.api_error import ApiError
+from ..types.error_response import ErrorResponse
class BadRequestError(ApiError):
- def __init__(
- self,
- body: typing.Dict[str, typing.Optional[typing.Any]],
- headers: typing.Optional[typing.Dict[str, str]] = None,
- ):
+ def __init__(self, body: ErrorResponse, headers: typing.Optional[typing.Dict[str, str]] = None):
super().__init__(status_code=400, headers=headers, body=body)
diff --git a/common/generated/rest/errors/internal_server_error.py b/common/generated/rest/errors/internal_server_error.py
new file mode 100644
index 00000000..d7a796c6
--- /dev/null
+++ b/common/generated/rest/errors/internal_server_error.py
@@ -0,0 +1,11 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from ..core.api_error import ApiError
+from ..types.error_response import ErrorResponse
+
+
+class InternalServerError(ApiError):
+ def __init__(self, body: ErrorResponse, headers: typing.Optional[typing.Dict[str, str]] = None):
+ super().__init__(status_code=500, headers=headers, body=body)
diff --git a/common/generated/rest/errors/not_found_error.py b/common/generated/rest/errors/not_found_error.py
index 66307415..3b2a2d1f 100644
--- a/common/generated/rest/errors/not_found_error.py
+++ b/common/generated/rest/errors/not_found_error.py
@@ -3,12 +3,9 @@
import typing
from ..core.api_error import ApiError
+from ..types.error_response import ErrorResponse
class NotFoundError(ApiError):
- def __init__(
- self,
- body: typing.Dict[str, typing.Optional[typing.Any]],
- headers: typing.Optional[typing.Dict[str, str]] = None,
- ):
+ def __init__(self, body: ErrorResponse, headers: typing.Optional[typing.Dict[str, str]] = None):
super().__init__(status_code=404, headers=headers, body=body)
diff --git a/common/generated/rest/errors/unauthorized_error.py b/common/generated/rest/errors/unauthorized_error.py
index 3d58c2e6..00a614a3 100644
--- a/common/generated/rest/errors/unauthorized_error.py
+++ b/common/generated/rest/errors/unauthorized_error.py
@@ -3,12 +3,9 @@
import typing
from ..core.api_error import ApiError
+from ..types.error_response import ErrorResponse
class UnauthorizedError(ApiError):
- def __init__(
- self,
- body: typing.Dict[str, typing.Optional[typing.Any]],
- headers: typing.Optional[typing.Dict[str, str]] = None,
- ):
+ def __init__(self, body: ErrorResponse, headers: typing.Optional[typing.Dict[str, str]] = None):
super().__init__(status_code=401, headers=headers, body=body)
diff --git a/common/generated/rest/files_v2/__init__.py b/common/generated/rest/files_v2/__init__.py
new file mode 100644
index 00000000..eb9ad9e9
--- /dev/null
+++ b/common/generated/rest/files_v2/__init__.py
@@ -0,0 +1,49 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .types import (
+ DeidentifyFileRequestV2DataFormat,
+ DeidentifyFileRequestV2DataSource,
+ ReidentifyFileRequestV2DataFormat,
+ ReidentifyFileRequestV2DataSource,
+ )
+_dynamic_imports: typing.Dict[str, str] = {
+ "DeidentifyFileRequestV2DataFormat": ".types",
+ "DeidentifyFileRequestV2DataSource": ".types",
+ "ReidentifyFileRequestV2DataFormat": ".types",
+ "ReidentifyFileRequestV2DataSource": ".types",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "DeidentifyFileRequestV2DataFormat",
+ "DeidentifyFileRequestV2DataSource",
+ "ReidentifyFileRequestV2DataFormat",
+ "ReidentifyFileRequestV2DataSource",
+]
diff --git a/common/generated/rest/files_v2/client.py b/common/generated/rest/files_v2/client.py
new file mode 100644
index 00000000..250fb259
--- /dev/null
+++ b/common/generated/rest/files_v2/client.py
@@ -0,0 +1,515 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ..core.request_options import RequestOptions
+from ..types.deidentify_file_response_v2 import DeidentifyFileResponseV2
+from ..types.detect_config_v2 import DetectConfigV2
+from ..types.detect_runs_response_v2 import DetectRunsResponseV2
+from ..types.redaction_level import RedactionLevel
+from ..types.reidentify_file_response_v2 import ReidentifyFileResponseV2
+from .raw_client import AsyncRawFilesV2Client, RawFilesV2Client
+from .types.deidentify_file_request_v2data_format import DeidentifyFileRequestV2DataFormat
+from .types.deidentify_file_request_v2data_source import DeidentifyFileRequestV2DataSource
+from .types.reidentify_file_request_v2data_format import ReidentifyFileRequestV2DataFormat
+from .types.reidentify_file_request_v2data_source import ReidentifyFileRequestV2DataSource
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class FilesV2Client:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawFilesV2Client(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawFilesV2Client:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawFilesV2Client
+ """
+ return self._raw_client
+
+ def deidentify_file_v2(
+ self,
+ *,
+ data_source: DeidentifyFileRequestV2DataSource,
+ value: str,
+ data_format: typing.Optional[DeidentifyFileRequestV2DataFormat] = OMIT,
+ configuration_id: typing.Optional[str] = OMIT,
+ configuration: typing.Optional[DetectConfigV2] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> DeidentifyFileResponseV2:
+ """
+ De-identifies sensitive data from a file.
Note:
+ - Layout may vary with token-based redaction for MS Office files (PPT, DOCX, and XLS) and PDFs when token-based PDF processing is selected.
+ - V2 API is in beta.
+
+ Parameters
+ ----------
+ data_source : DeidentifyFileRequestV2DataSource
+ Data source of the input file. `BASE64`: Base64-encoded file string. `SKYFLOW_ID`: Reference file by vault ID. `PRESIGNED_URL`: S3 presigned URL of input file.
+
+ value : str
+ File data corresponding to the specified `dataSource` type.
+
+ data_format : typing.Optional[DeidentifyFileRequestV2DataFormat]
+ Format of the input file. The `VAULT_TOKEN` de-identification type is supported only for `txt`, `json`, `csv`, `xml`, `jsonl`, `docx`, `xlsx`, and `pptx` files.
+
+ configuration_id : typing.Optional[str]
+ ID of the Detect configuration to use for de-identification.
+
+ configuration : typing.Optional[DetectConfigV2]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ DeidentifyFileResponseV2
+ OK
+
+ Examples
+ --------
+ from skyflow import (
+ Detect,
+ DetectConfigV2,
+ DetectCustomTypes,
+ DetectEntity,
+ DocumentV2,
+ DocumentV2Pdf,
+ EntityTransformation,
+ Media,
+ SkyflowAuth,
+ TransformationShiftDates,
+ )
+
+ client = SkyflowAuth(
+ token="YOUR_TOKEN",
+ )
+ client.files_v2.deidentify_file_v2(
+ data_source="BASE64",
+ value="$BASE64_DATA",
+ data_format="pdf",
+ configuration=DetectConfigV2(
+ vault_id="$VAULT_ID",
+ detect=Detect(
+ entities=[
+ DetectEntity(
+ entity_type="NAME",
+ deidentification_type="VAULT_TOKEN",
+ destination="persons.name",
+ ),
+ DetectEntity(
+ entity_type="DOB",
+ deidentification_type="ENTITY_UNIQUE_COUNTER",
+ transformation=EntityTransformation(
+ shift_dates=TransformationShiftDates(
+ min_days=10,
+ max_days=30,
+ ),
+ ),
+ ),
+ DetectEntity(
+ entity_type="ALL",
+ deidentification_type="ENTITY_UNIQUE_COUNTER",
+ ),
+ ],
+ restrict=["restrict"],
+ skip=["skip"],
+ custom_types=[
+ DetectCustomTypes(
+ label="EMPLOYEE_ID",
+ match=["EMP-[0-9]{6}"],
+ )
+ ],
+ return_entities="EXCLUDE_SENSITIVE_DATA",
+ ),
+ media=Media(
+ document=DocumentV2(
+ pdf=DocumentV2Pdf(
+ processing_mode="TEXT_LAYER",
+ density=200,
+ max_resolution=3000,
+ ),
+ ),
+ ),
+ ),
+ )
+ """
+ _response = self._raw_client.deidentify_file_v2(
+ data_source=data_source,
+ value=value,
+ data_format=data_format,
+ configuration_id=configuration_id,
+ configuration=configuration,
+ request_options=request_options,
+ )
+ return _response.data
+
+ def reidentify_file_v2(
+ self,
+ *,
+ data_source: ReidentifyFileRequestV2DataSource,
+ value: str,
+ vault_id: str,
+ data_format: typing.Optional[ReidentifyFileRequestV2DataFormat] = OMIT,
+ redaction_level: typing.Optional[typing.Sequence[RedactionLevel]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ReidentifyFileResponseV2:
+ """
+ Re-identifies tokens in a file.
Requires the Detect Invoker, Detect Manager, or Vault Owner role. Re-identifying `vault_token` values also requires a policy that separately grants the Detokenization action, unless the caller has the Vault Owner role.
Note: V2 API is in beta.
+
+ Parameters
+ ----------
+ data_source : ReidentifyFileRequestV2DataSource
+ Data source of the input file. `BASE64`: Base64-encoded file string. `SKYFLOW_ID`: Reference file by vault ID. `PRESIGNED_URL`: S3 presigned URL of input file.
+
+ value : str
+ File data corresponding to the specified `dataSource` type.
+
+ vault_id : str
+ ID of the vault used for de-identification.
+
+ data_format : typing.Optional[ReidentifyFileRequestV2DataFormat]
+ Format of the input file. Limited to the formats that support the `VAULT_TOKEN` de-identification type.
+
+ redaction_level : typing.Optional[typing.Sequence[RedactionLevel]]
+ Replacement patterns or types applied to entity types or token groups during re-identification. Specifies a replacement pattern/type and the token group or entity type it applies to during re-identification. Set `tokenGroupName` for FlowVault and `entityName` for SkyVault. Similarly, set `redactionType` for FlowVault and `redactionPattern` for SkyVaultto specify the replacement.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ReidentifyFileResponseV2
+ OK
+
+ Examples
+ --------
+ from skyflow import RedactionLevel, SkyflowAuth
+
+ client = SkyflowAuth(
+ token="YOUR_TOKEN",
+ )
+ client.files_v2.reidentify_file_v2(
+ data_source="BASE64",
+ value="$BASE64_DATA",
+ data_format="txt",
+ vault_id="$VAULT_ID",
+ redaction_level=[
+ RedactionLevel(
+ entity_name="EMAIL_ADDRESS",
+ redaction_type="MASKED",
+ )
+ ],
+ )
+ """
+ _response = self._raw_client.reidentify_file_v2(
+ data_source=data_source,
+ value=value,
+ vault_id=vault_id,
+ data_format=data_format,
+ redaction_level=redaction_level,
+ request_options=request_options,
+ )
+ return _response.data
+
+ def get_run_v2(
+ self, run_id: str, *, vault_id: str, request_options: typing.Optional[RequestOptions] = None
+ ) -> DetectRunsResponseV2:
+ """
+ Returns the status of a detect run.
Note:
+ - Layout may vary with token-based redaction for MS Office files (PPT, DOCX, and XLS) and PDFs when token-based PDF processing is selected.
+ - V2 API is in beta.
+
+ Parameters
+ ----------
+ data_source : DeidentifyFileRequestV2DataSource
+ Data source of the input file. `BASE64`: Base64-encoded file string. `SKYFLOW_ID`: Reference file by vault ID. `PRESIGNED_URL`: S3 presigned URL of input file.
+
+ value : str
+ File data corresponding to the specified `dataSource` type.
+
+ data_format : typing.Optional[DeidentifyFileRequestV2DataFormat]
+ Format of the input file. The `VAULT_TOKEN` de-identification type is supported only for `txt`, `json`, `csv`, `xml`, `jsonl`, `docx`, `xlsx`, and `pptx` files.
+
+ configuration_id : typing.Optional[str]
+ ID of the Detect configuration to use for de-identification.
+
+ configuration : typing.Optional[DetectConfigV2]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ DeidentifyFileResponseV2
+ OK
+
+ Examples
+ --------
+ import asyncio
+
+ from skyflow import (
+ AsyncSkyflowAuth,
+ Detect,
+ DetectConfigV2,
+ DetectCustomTypes,
+ DetectEntity,
+ DocumentV2,
+ DocumentV2Pdf,
+ EntityTransformation,
+ Media,
+ TransformationShiftDates,
+ )
+
+ client = AsyncSkyflowAuth(
+ token="YOUR_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.files_v2.deidentify_file_v2(
+ data_source="BASE64",
+ value="$BASE64_DATA",
+ data_format="pdf",
+ configuration=DetectConfigV2(
+ vault_id="$VAULT_ID",
+ detect=Detect(
+ entities=[
+ DetectEntity(
+ entity_type="NAME",
+ deidentification_type="VAULT_TOKEN",
+ destination="persons.name",
+ ),
+ DetectEntity(
+ entity_type="DOB",
+ deidentification_type="ENTITY_UNIQUE_COUNTER",
+ transformation=EntityTransformation(
+ shift_dates=TransformationShiftDates(
+ min_days=10,
+ max_days=30,
+ ),
+ ),
+ ),
+ DetectEntity(
+ entity_type="ALL",
+ deidentification_type="ENTITY_UNIQUE_COUNTER",
+ ),
+ ],
+ restrict=["restrict"],
+ skip=["skip"],
+ custom_types=[
+ DetectCustomTypes(
+ label="EMPLOYEE_ID",
+ match=["EMP-[0-9]{6}"],
+ )
+ ],
+ return_entities="EXCLUDE_SENSITIVE_DATA",
+ ),
+ media=Media(
+ document=DocumentV2(
+ pdf=DocumentV2Pdf(
+ processing_mode="TEXT_LAYER",
+ density=200,
+ max_resolution=3000,
+ ),
+ ),
+ ),
+ ),
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.deidentify_file_v2(
+ data_source=data_source,
+ value=value,
+ data_format=data_format,
+ configuration_id=configuration_id,
+ configuration=configuration,
+ request_options=request_options,
+ )
+ return _response.data
+
+ async def reidentify_file_v2(
+ self,
+ *,
+ data_source: ReidentifyFileRequestV2DataSource,
+ value: str,
+ vault_id: str,
+ data_format: typing.Optional[ReidentifyFileRequestV2DataFormat] = OMIT,
+ redaction_level: typing.Optional[typing.Sequence[RedactionLevel]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> ReidentifyFileResponseV2:
+ """
+ Re-identifies tokens in a file.
Requires the Detect Invoker, Detect Manager, or Vault Owner role. Re-identifying `vault_token` values also requires a policy that separately grants the Detokenization action, unless the caller has the Vault Owner role.
Note: V2 API is in beta.
+
+ Parameters
+ ----------
+ data_source : ReidentifyFileRequestV2DataSource
+ Data source of the input file. `BASE64`: Base64-encoded file string. `SKYFLOW_ID`: Reference file by vault ID. `PRESIGNED_URL`: S3 presigned URL of input file.
+
+ value : str
+ File data corresponding to the specified `dataSource` type.
+
+ vault_id : str
+ ID of the vault used for de-identification.
+
+ data_format : typing.Optional[ReidentifyFileRequestV2DataFormat]
+ Format of the input file. Limited to the formats that support the `VAULT_TOKEN` de-identification type.
+
+ redaction_level : typing.Optional[typing.Sequence[RedactionLevel]]
+ Replacement patterns or types applied to entity types or token groups during re-identification. Specifies a replacement pattern/type and the token group or entity type it applies to during re-identification. Set `tokenGroupName` for FlowVault and `entityName` for SkyVault. Similarly, set `redactionType` for FlowVault and `redactionPattern` for SkyVaultto specify the replacement.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ReidentifyFileResponseV2
+ OK
+
+ Examples
+ --------
+ import asyncio
+
+ from skyflow import AsyncSkyflowAuth, RedactionLevel
+
+ client = AsyncSkyflowAuth(
+ token="YOUR_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.files_v2.reidentify_file_v2(
+ data_source="BASE64",
+ value="$BASE64_DATA",
+ data_format="txt",
+ vault_id="$VAULT_ID",
+ redaction_level=[
+ RedactionLevel(
+ entity_name="EMAIL_ADDRESS",
+ redaction_type="MASKED",
+ )
+ ],
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.reidentify_file_v2(
+ data_source=data_source,
+ value=value,
+ vault_id=vault_id,
+ data_format=data_format,
+ redaction_level=redaction_level,
+ request_options=request_options,
+ )
+ return _response.data
+
+ async def get_run_v2(
+ self, run_id: str, *, vault_id: str, request_options: typing.Optional[RequestOptions] = None
+ ) -> DetectRunsResponseV2:
+ """
+ Returns the status of a detect run.
Note:
+ - Layout may vary with token-based redaction for MS Office files (PPT, DOCX, and XLS) and PDFs when token-based PDF processing is selected.
+ - V2 API is in beta.
+
+ Parameters
+ ----------
+ data_source : DeidentifyFileRequestV2DataSource
+ Data source of the input file. `BASE64`: Base64-encoded file string. `SKYFLOW_ID`: Reference file by vault ID. `PRESIGNED_URL`: S3 presigned URL of input file.
+
+ value : str
+ File data corresponding to the specified `dataSource` type.
+
+ data_format : typing.Optional[DeidentifyFileRequestV2DataFormat]
+ Format of the input file. The `VAULT_TOKEN` de-identification type is supported only for `txt`, `json`, `csv`, `xml`, `jsonl`, `docx`, `xlsx`, and `pptx` files.
+
+ configuration_id : typing.Optional[str]
+ ID of the Detect configuration to use for de-identification.
+
+ configuration : typing.Optional[DetectConfigV2]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[DeidentifyFileResponseV2]
+ OK
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "v2/detect/deidentify/file",
+ method="POST",
+ json={
+ "dataSource": data_source,
+ "value": value,
+ "dataFormat": data_format,
+ "configurationId": configuration_id,
+ "configuration": convert_and_respect_annotation_metadata(
+ object_=configuration, annotation=DetectConfigV2, direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ DeidentifyFileResponseV2,
+ parse_obj_as(
+ type_=DeidentifyFileResponseV2, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def reidentify_file_v2(
+ self,
+ *,
+ data_source: ReidentifyFileRequestV2DataSource,
+ value: str,
+ vault_id: str,
+ data_format: typing.Optional[ReidentifyFileRequestV2DataFormat] = OMIT,
+ redaction_level: typing.Optional[typing.Sequence[RedactionLevel]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> HttpResponse[ReidentifyFileResponseV2]:
+ """
+ Re-identifies tokens in a file.
Requires the Detect Invoker, Detect Manager, or Vault Owner role. Re-identifying `vault_token` values also requires a policy that separately grants the Detokenization action, unless the caller has the Vault Owner role.
Note: V2 API is in beta.
+
+ Parameters
+ ----------
+ data_source : ReidentifyFileRequestV2DataSource
+ Data source of the input file. `BASE64`: Base64-encoded file string. `SKYFLOW_ID`: Reference file by vault ID. `PRESIGNED_URL`: S3 presigned URL of input file.
+
+ value : str
+ File data corresponding to the specified `dataSource` type.
+
+ vault_id : str
+ ID of the vault used for de-identification.
+
+ data_format : typing.Optional[ReidentifyFileRequestV2DataFormat]
+ Format of the input file. Limited to the formats that support the `VAULT_TOKEN` de-identification type.
+
+ redaction_level : typing.Optional[typing.Sequence[RedactionLevel]]
+ Replacement patterns or types applied to entity types or token groups during re-identification. Specifies a replacement pattern/type and the token group or entity type it applies to during re-identification. Set `tokenGroupName` for FlowVault and `entityName` for SkyVault. Similarly, set `redactionType` for FlowVault and `redactionPattern` for SkyVaultto specify the replacement.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ HttpResponse[ReidentifyFileResponseV2]
+ OK
+ """
+ _response = self._client_wrapper.httpx_client.request(
+ "v2/detect/reidentify/file",
+ method="POST",
+ json={
+ "dataSource": data_source,
+ "value": value,
+ "dataFormat": data_format,
+ "vaultId": vault_id,
+ "redactionLevel": convert_and_respect_annotation_metadata(
+ object_=redaction_level, annotation=typing.Sequence[RedactionLevel], direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ReidentifyFileResponseV2,
+ parse_obj_as(
+ type_=ReidentifyFileResponseV2, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ def get_run_v2(
+ self, run_id: str, *, vault_id: str, request_options: typing.Optional[RequestOptions] = None
+ ) -> HttpResponse[DetectRunsResponseV2]:
+ """
+ Returns the status of a detect run.
Note:
+ - Layout may vary with token-based redaction for MS Office files (PPT, DOCX, and XLS) and PDFs when token-based PDF processing is selected.
+ - V2 API is in beta.
+
+ Parameters
+ ----------
+ data_source : DeidentifyFileRequestV2DataSource
+ Data source of the input file. `BASE64`: Base64-encoded file string. `SKYFLOW_ID`: Reference file by vault ID. `PRESIGNED_URL`: S3 presigned URL of input file.
+
+ value : str
+ File data corresponding to the specified `dataSource` type.
+
+ data_format : typing.Optional[DeidentifyFileRequestV2DataFormat]
+ Format of the input file. The `VAULT_TOKEN` de-identification type is supported only for `txt`, `json`, `csv`, `xml`, `jsonl`, `docx`, `xlsx`, and `pptx` files.
+
+ configuration_id : typing.Optional[str]
+ ID of the Detect configuration to use for de-identification.
+
+ configuration : typing.Optional[DetectConfigV2]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[DeidentifyFileResponseV2]
+ OK
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "v2/detect/deidentify/file",
+ method="POST",
+ json={
+ "dataSource": data_source,
+ "value": value,
+ "dataFormat": data_format,
+ "configurationId": configuration_id,
+ "configuration": convert_and_respect_annotation_metadata(
+ object_=configuration, annotation=DetectConfigV2, direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ DeidentifyFileResponseV2,
+ parse_obj_as(
+ type_=DeidentifyFileResponseV2, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def reidentify_file_v2(
+ self,
+ *,
+ data_source: ReidentifyFileRequestV2DataSource,
+ value: str,
+ vault_id: str,
+ data_format: typing.Optional[ReidentifyFileRequestV2DataFormat] = OMIT,
+ redaction_level: typing.Optional[typing.Sequence[RedactionLevel]] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> AsyncHttpResponse[ReidentifyFileResponseV2]:
+ """
+ Re-identifies tokens in a file.
Requires the Detect Invoker, Detect Manager, or Vault Owner role. Re-identifying `vault_token` values also requires a policy that separately grants the Detokenization action, unless the caller has the Vault Owner role.
Note: V2 API is in beta.
+
+ Parameters
+ ----------
+ data_source : ReidentifyFileRequestV2DataSource
+ Data source of the input file. `BASE64`: Base64-encoded file string. `SKYFLOW_ID`: Reference file by vault ID. `PRESIGNED_URL`: S3 presigned URL of input file.
+
+ value : str
+ File data corresponding to the specified `dataSource` type.
+
+ vault_id : str
+ ID of the vault used for de-identification.
+
+ data_format : typing.Optional[ReidentifyFileRequestV2DataFormat]
+ Format of the input file. Limited to the formats that support the `VAULT_TOKEN` de-identification type.
+
+ redaction_level : typing.Optional[typing.Sequence[RedactionLevel]]
+ Replacement patterns or types applied to entity types or token groups during re-identification. Specifies a replacement pattern/type and the token group or entity type it applies to during re-identification. Set `tokenGroupName` for FlowVault and `entityName` for SkyVault. Similarly, set `redactionType` for FlowVault and `redactionPattern` for SkyVaultto specify the replacement.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[ReidentifyFileResponseV2]
+ OK
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ "v2/detect/reidentify/file",
+ method="POST",
+ json={
+ "dataSource": data_source,
+ "value": value,
+ "dataFormat": data_format,
+ "vaultId": vault_id,
+ "redactionLevel": convert_and_respect_annotation_metadata(
+ object_=redaction_level, annotation=typing.Sequence[RedactionLevel], direction="write"
+ ),
+ },
+ headers={
+ "content-type": "application/json",
+ },
+ request_options=request_options,
+ omit=OMIT,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ ReidentifyFileResponseV2,
+ parse_obj_as(
+ type_=ReidentifyFileResponseV2, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+
+ async def get_run_v2(
+ self, run_id: str, *, vault_id: str, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[DetectRunsResponseV2]:
+ """
+ Returns the status of a detect run.
Note: V2 API is in beta.
+
+ Parameters
+ ----------
+ run_id : str
+
+ vault_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ AsyncHttpResponse[DetectRunsResponseV2]
+ OK
+ """
+ _response = await self._client_wrapper.httpx_client.request(
+ f"v2/detect/runs/{encode_path_param(run_id)}",
+ method="GET",
+ params={
+ "vaultId": vault_id,
+ },
+ request_options=request_options,
+ )
+ try:
+ if 200 <= _response.status_code < 300:
+ _data = typing.cast(
+ DetectRunsResponseV2,
+ parse_obj_as(
+ type_=DetectRunsResponseV2, # type: ignore
+ object_=_response.json(),
+ ),
+ )
+ return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ _response_json = _response.json()
+ except JSONDecodeError:
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
+ raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/common/generated/rest/files_v2/types/__init__.py b/common/generated/rest/files_v2/types/__init__.py
new file mode 100644
index 00000000..645b6ea7
--- /dev/null
+++ b/common/generated/rest/files_v2/types/__init__.py
@@ -0,0 +1,47 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .deidentify_file_request_v2data_format import DeidentifyFileRequestV2DataFormat
+ from .deidentify_file_request_v2data_source import DeidentifyFileRequestV2DataSource
+ from .reidentify_file_request_v2data_format import ReidentifyFileRequestV2DataFormat
+ from .reidentify_file_request_v2data_source import ReidentifyFileRequestV2DataSource
+_dynamic_imports: typing.Dict[str, str] = {
+ "DeidentifyFileRequestV2DataFormat": ".deidentify_file_request_v2data_format",
+ "DeidentifyFileRequestV2DataSource": ".deidentify_file_request_v2data_source",
+ "ReidentifyFileRequestV2DataFormat": ".reidentify_file_request_v2data_format",
+ "ReidentifyFileRequestV2DataSource": ".reidentify_file_request_v2data_source",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = [
+ "DeidentifyFileRequestV2DataFormat",
+ "DeidentifyFileRequestV2DataSource",
+ "ReidentifyFileRequestV2DataFormat",
+ "ReidentifyFileRequestV2DataSource",
+]
diff --git a/skyvault/skyflow/generated/rest/types/reidentified_file_output_processed_file_extension.py b/common/generated/rest/files_v2/types/deidentify_file_request_v2data_format.py
similarity index 81%
rename from skyvault/skyflow/generated/rest/types/reidentified_file_output_processed_file_extension.py
rename to common/generated/rest/files_v2/types/deidentify_file_request_v2data_format.py
index c6cbfd02..14b3dfe6 100644
--- a/skyvault/skyflow/generated/rest/types/reidentified_file_output_processed_file_extension.py
+++ b/common/generated/rest/files_v2/types/deidentify_file_request_v2data_format.py
@@ -2,7 +2,7 @@
import typing
-ReidentifiedFileOutputProcessedFileExtension = typing.Union[
+DeidentifyFileRequestV2DataFormat = typing.Union[
typing.Literal[
"mp3",
"wav",
@@ -24,6 +24,9 @@
"pptx",
"xml",
"dcm",
+ "jsonl",
+ "zip",
+ "gif",
],
typing.Any,
]
diff --git a/common/generated/rest/files_v2/types/deidentify_file_request_v2data_source.py b/common/generated/rest/files_v2/types/deidentify_file_request_v2data_source.py
new file mode 100644
index 00000000..143d390a
--- /dev/null
+++ b/common/generated/rest/files_v2/types/deidentify_file_request_v2data_source.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+DeidentifyFileRequestV2DataSource = typing.Union[typing.Literal["BASE64", "SKYFLOW_ID", "PRESIGNED_URL"], typing.Any]
diff --git a/common/generated/rest/files_v2/types/reidentify_file_request_v2data_format.py b/common/generated/rest/files_v2/types/reidentify_file_request_v2data_format.py
new file mode 100644
index 00000000..787c86e3
--- /dev/null
+++ b/common/generated/rest/files_v2/types/reidentify_file_request_v2data_format.py
@@ -0,0 +1,7 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+ReidentifyFileRequestV2DataFormat = typing.Union[
+ typing.Literal["txt", "csv", "json", "xlsx", "docx", "pptx", "xml", "jsonl"], typing.Any
+]
diff --git a/common/generated/rest/files_v2/types/reidentify_file_request_v2data_source.py b/common/generated/rest/files_v2/types/reidentify_file_request_v2data_source.py
new file mode 100644
index 00000000..c80efffc
--- /dev/null
+++ b/common/generated/rest/files_v2/types/reidentify_file_request_v2data_source.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+ReidentifyFileRequestV2DataSource = typing.Union[typing.Literal["BASE64", "SKYFLOW_ID", "PRESIGNED_URL"], typing.Any]
diff --git a/skyvault/skyflow/generated/rest/authentication/__init__.py b/common/generated/rest/guardrails_v2/__init__.py
similarity index 100%
rename from skyvault/skyflow/generated/rest/authentication/__init__.py
rename to common/generated/rest/guardrails_v2/__init__.py
diff --git a/skyvault/skyflow/generated/rest/guardrails/client.py b/common/generated/rest/guardrails_v2/client.py
similarity index 71%
rename from skyvault/skyflow/generated/rest/guardrails/client.py
rename to common/generated/rest/guardrails_v2/client.py
index 88cab59d..f6cd62e1 100644
--- a/skyvault/skyflow/generated/rest/guardrails/client.py
+++ b/common/generated/rest/guardrails_v2/client.py
@@ -4,29 +4,29 @@
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.request_options import RequestOptions
-from ..types.detect_guardrails_response import DetectGuardrailsResponse
-from .raw_client import AsyncRawGuardrailsClient, RawGuardrailsClient
+from ..types.detect_guardrails_response_v2 import DetectGuardrailsResponseV2
+from .raw_client import AsyncRawGuardrailsV2Client, RawGuardrailsV2Client
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
-class GuardrailsClient:
+class GuardrailsV2Client:
def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._raw_client = RawGuardrailsClient(client_wrapper=client_wrapper)
+ self._raw_client = RawGuardrailsV2Client(client_wrapper=client_wrapper)
@property
- def with_raw_response(self) -> RawGuardrailsClient:
+ def with_raw_response(self) -> RawGuardrailsV2Client:
"""
Retrieves a raw implementation of this client that returns raw responses.
Returns
-------
- RawGuardrailsClient
+ RawGuardrailsV2Client
"""
return self._raw_client
- def check_guardrails(
+ def check_guardrails_v2(
self,
*,
text: str,
@@ -34,9 +34,9 @@ def check_guardrails(
check_toxicity: typing.Optional[bool] = OMIT,
deny_topics: typing.Optional[typing.Sequence[str]] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> DetectGuardrailsResponse:
+ ) -> DetectGuardrailsResponseV2:
"""
- Preserve safety and compliance with usage policies.
+ Preserve safety and compliance with usage policies.
Note: V2 API is in beta.
Parameters
----------
@@ -57,24 +57,24 @@ def check_guardrails(
Returns
-------
- DetectGuardrailsResponse
+ DetectGuardrailsResponseV2
OK
Examples
--------
- from skyflow import Skyflow
+ from skyflow import SkyflowAuth
- client = Skyflow(
+ client = SkyflowAuth(
token="YOUR_TOKEN",
)
- client.guardrails.check_guardrails(
+ client.guardrails_v2.check_guardrails_v2(
text="I love to play cricket.",
check_toxicity=True,
deny_topics=["sports"],
vault_id="$VAULT_ID",
)
"""
- _response = self._raw_client.check_guardrails(
+ _response = self._raw_client.check_guardrails_v2(
text=text,
vault_id=vault_id,
check_toxicity=check_toxicity,
@@ -84,22 +84,22 @@ def check_guardrails(
return _response.data
-class AsyncGuardrailsClient:
+class AsyncGuardrailsV2Client:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._raw_client = AsyncRawGuardrailsClient(client_wrapper=client_wrapper)
+ self._raw_client = AsyncRawGuardrailsV2Client(client_wrapper=client_wrapper)
@property
- def with_raw_response(self) -> AsyncRawGuardrailsClient:
+ def with_raw_response(self) -> AsyncRawGuardrailsV2Client:
"""
Retrieves a raw implementation of this client that returns raw responses.
Returns
-------
- AsyncRawGuardrailsClient
+ AsyncRawGuardrailsV2Client
"""
return self._raw_client
- async def check_guardrails(
+ async def check_guardrails_v2(
self,
*,
text: str,
@@ -107,9 +107,9 @@ async def check_guardrails(
check_toxicity: typing.Optional[bool] = OMIT,
deny_topics: typing.Optional[typing.Sequence[str]] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> DetectGuardrailsResponse:
+ ) -> DetectGuardrailsResponseV2:
"""
- Preserve safety and compliance with usage policies.
+ Preserve safety and compliance with usage policies.
Note: V2 API is in beta.
Parameters
----------
@@ -130,22 +130,22 @@ async def check_guardrails(
Returns
-------
- DetectGuardrailsResponse
+ DetectGuardrailsResponseV2
OK
Examples
--------
import asyncio
- from skyflow import AsyncSkyflow
+ from skyflow import AsyncSkyflowAuth
- client = AsyncSkyflow(
+ client = AsyncSkyflowAuth(
token="YOUR_TOKEN",
)
async def main() -> None:
- await client.guardrails.check_guardrails(
+ await client.guardrails_v2.check_guardrails_v2(
text="I love to play cricket.",
check_toxicity=True,
deny_topics=["sports"],
@@ -155,7 +155,7 @@ async def main() -> None:
asyncio.run(main())
"""
- _response = await self._raw_client.check_guardrails(
+ _response = await self._raw_client.check_guardrails_v2(
text=text,
vault_id=vault_id,
check_toxicity=check_toxicity,
diff --git a/skyvault/skyflow/generated/rest/guardrails/raw_client.py b/common/generated/rest/guardrails_v2/raw_client.py
similarity index 76%
rename from skyvault/skyflow/generated/rest/guardrails/raw_client.py
rename to common/generated/rest/guardrails_v2/raw_client.py
index 1328b1b8..6f0dd663 100644
--- a/skyvault/skyflow/generated/rest/guardrails/raw_client.py
+++ b/common/generated/rest/guardrails_v2/raw_client.py
@@ -6,23 +6,25 @@
from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.http_response import AsyncHttpResponse, HttpResponse
+from ..core.parse_error import ParsingError
from ..core.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
from ..errors.bad_request_error import BadRequestError
from ..errors.internal_server_error import InternalServerError
from ..errors.unauthorized_error import UnauthorizedError
-from ..types.detect_guardrails_response import DetectGuardrailsResponse
+from ..types.detect_guardrails_response_v2 import DetectGuardrailsResponseV2
from ..types.error_response import ErrorResponse
+from pydantic import ValidationError
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
-class RawGuardrailsClient:
+class RawGuardrailsV2Client:
def __init__(self, *, client_wrapper: SyncClientWrapper):
self._client_wrapper = client_wrapper
- def check_guardrails(
+ def check_guardrails_v2(
self,
*,
text: str,
@@ -30,9 +32,9 @@ def check_guardrails(
check_toxicity: typing.Optional[bool] = OMIT,
deny_topics: typing.Optional[typing.Sequence[str]] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[DetectGuardrailsResponse]:
+ ) -> HttpResponse[DetectGuardrailsResponseV2]:
"""
- Preserve safety and compliance with usage policies.
+ Preserve safety and compliance with usage policies.
Requires the Detect Invoker, Detect Manager, or Vault Owner role. Re-identifying `vault_token` values also requires a policy that separately grants the Detokenization action, unless the caller has the Vault Owner role.
Note: V2 API is in beta.
+
+ Parameters
+ ----------
+ vault_id : str
+ ID of the vault used for re-identification. Requires the Detect Invoker, Detect Manager, or Vault Owner role for this vault. Re-identifying `vault_token` values also requires a role or policy that separately grants the Detokenization action, unless the caller has the Vault Owner role.
+
+ text : str
+ Text to reidentify.
+
+ redaction_level : typing.Optional[typing.Sequence[RedactionLevel]]
+ Replacement patterns or types applied to entity types or token groups during re-identification. Specifies a replacement pattern/type and the token group or entity type it applies to during re-identification. Set exactly one of `tokenGroupName` or `entityName`. Use `tokenGroupName` for FlowVault and `entityName` for SkyVault. Similarly, set exactly one of `redactionType` or `redactionPattern` to specify the replacement.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ReidentifyStringResponseV2
+ OK
+
+ Examples
+ --------
+ from skyflow import RedactionLevel, SkyflowAuth
+
+ client = SkyflowAuth(
+ token="YOUR_TOKEN",
+ )
+ client.strings_v2.reidentify_string_v2(
+ vault_id="$VAULT_ID",
+ text="My name is [NAME_1], and my email is [EMAIL_ADDRESS_1].",
+ redaction_level=[
+ RedactionLevel(
+ entity_name="EMAIL_ADDRESS",
+ redaction_type="MASKED",
+ )
+ ],
+ )
+ """
+ _response = self._raw_client.reidentify_string_v2(
+ vault_id=vault_id, text=text, redaction_level=redaction_level, request_options=request_options
+ )
+ return _response.data
+
+
+class AsyncStringsV2Client:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawStringsV2Client(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawStringsV2Client:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawStringsV2Client
+ """
+ return self._raw_client
+
+ async def deidentify_string_v2(
+ self,
+ *,
+ text: str,
+ configuration_id: typing.Optional[str] = OMIT,
+ configuration: typing.Optional[DetectConfigV2] = OMIT,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> DeidentifyStringResponseV2:
+ """
+ De-identifies sensitive data from a string.
Requires the Detect Invoker, Detect Manager, or Vault Owner role. Re-identifying `vault_token` values also requires a policy that separately grants the Detokenization action, unless the caller has the Vault Owner role.
Note: V2 API is in beta.
+
+ Parameters
+ ----------
+ vault_id : str
+ ID of the vault used for re-identification. Requires the Detect Invoker, Detect Manager, or Vault Owner role for this vault. Re-identifying `vault_token` values also requires a role or policy that separately grants the Detokenization action, unless the caller has the Vault Owner role.
+
+ text : str
+ Text to reidentify.
+
+ redaction_level : typing.Optional[typing.Sequence[RedactionLevel]]
+ Replacement patterns or types applied to entity types or token groups during re-identification. Specifies a replacement pattern/type and the token group or entity type it applies to during re-identification. Set exactly one of `tokenGroupName` or `entityName`. Use `tokenGroupName` for FlowVault and `entityName` for SkyVault. Similarly, set exactly one of `redactionType` or `redactionPattern` to specify the replacement.
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ ReidentifyStringResponseV2
+ OK
+
+ Examples
+ --------
+ import asyncio
+
+ from skyflow import AsyncSkyflowAuth, RedactionLevel
+
+ client = AsyncSkyflowAuth(
+ token="YOUR_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.strings_v2.reidentify_string_v2(
+ vault_id="$VAULT_ID",
+ text="My name is [NAME_1], and my email is [EMAIL_ADDRESS_1].",
+ redaction_level=[
+ RedactionLevel(
+ entity_name="EMAIL_ADDRESS",
+ redaction_type="MASKED",
+ )
+ ],
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.reidentify_string_v2(
+ vault_id=vault_id, text=text, redaction_level=redaction_level, request_options=request_options
+ )
+ return _response.data
diff --git a/skyvault/skyflow/generated/rest/strings/raw_client.py b/common/generated/rest/strings_v2/raw_client.py
similarity index 55%
rename from skyvault/skyflow/generated/rest/strings/raw_client.py
rename to common/generated/rest/strings_v2/raw_client.py
index 313c10ce..9418317f 100644
--- a/skyvault/skyflow/generated/rest/strings/raw_client.py
+++ b/common/generated/rest/strings_v2/raw_client.py
@@ -6,92 +6,66 @@
from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.http_response import AsyncHttpResponse, HttpResponse
+from ..core.parse_error import ParsingError
from ..core.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
from ..core.serialization import convert_and_respect_annotation_metadata
from ..errors.bad_request_error import BadRequestError
from ..errors.internal_server_error import InternalServerError
from ..errors.unauthorized_error import UnauthorizedError
-from ..types.deidentify_string_response import DeidentifyStringResponse
+from ..types.deidentify_string_response_v2 import DeidentifyStringResponseV2
+from ..types.detect_config_v2 import DetectConfigV2
from ..types.error_response import ErrorResponse
-from ..types.format import Format
-from ..types.identify_response import IdentifyResponse
-from ..types.token_type_mapping import TokenTypeMapping
-from ..types.transformations import Transformations
-from .types.deidentify_string_request_entity_types_item import DeidentifyStringRequestEntityTypesItem
+from ..types.redaction_level import RedactionLevel
+from ..types.reidentify_string_response_v2 import ReidentifyStringResponseV2
+from pydantic import ValidationError
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
-class RawStringsClient:
+class RawStringsV2Client:
def __init__(self, *, client_wrapper: SyncClientWrapper):
self._client_wrapper = client_wrapper
- def deidentify_string(
+ def deidentify_string_v2(
self,
*,
text: str,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyStringRequestEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
configuration_id: typing.Optional[str] = OMIT,
+ configuration: typing.Optional[DetectConfigV2] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[DeidentifyStringResponse]:
+ ) -> HttpResponse[DeidentifyStringResponseV2]:
"""
- De-identifies sensitive data from a string.
+ De-identifies sensitive data from a string.
Note: V2 API is in beta.
Parameters
----------
text : str
- Text to de-identify.
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyStringRequestEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
+ Text to deidentify.
configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
+ ID of the Detect configuration to use for de-identification.
+
+ configuration : typing.Optional[DetectConfigV2]
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- HttpResponse[DeidentifyStringResponse]
+ HttpResponse[DeidentifyStringResponseV2]
OK
"""
_response = self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/string",
+ "v2/detect/deidentify/string",
method="POST",
json={
"text": text,
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
+ "configurationId": configuration_id,
+ "configuration": convert_and_respect_annotation_metadata(
+ object_=configuration, annotation=DetectConfigV2, direction="write"
),
- "configuration_id": configuration_id,
},
headers={
"content-type": "application/json",
@@ -102,9 +76,9 @@ def deidentify_string(
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- DeidentifyStringResponse,
+ DeidentifyStringResponseV2,
parse_obj_as(
- type_=DeidentifyStringResponse, # type: ignore
+ type_=DeidentifyStringResponseV2, # type: ignore
object_=_response.json(),
),
)
@@ -113,9 +87,9 @@ def deidentify_string(
raise BadRequestError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -124,9 +98,9 @@ def deidentify_string(
raise UnauthorizedError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -145,44 +119,51 @@ def deidentify_string(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
- def reidentify_string(
+ def reidentify_string_v2(
self,
*,
- text: typing.Optional[str] = OMIT,
- vault_id: typing.Optional[str] = OMIT,
- format: typing.Optional[Format] = OMIT,
+ vault_id: str,
+ text: str,
+ redaction_level: typing.Optional[typing.Sequence[RedactionLevel]] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[IdentifyResponse]:
+ ) -> HttpResponse[ReidentifyStringResponseV2]:
"""
- Re-identifies tokens in a string.
+ Re-identifies tokens in a string.
Requires the Detect Invoker, Detect Manager, or Vault Owner role. Re-identifying `vault_token` values also requires a policy that separately grants the Detokenization action, unless the caller has the Vault Owner role.
Note: V2 API is in beta.
Parameters
----------
- text : typing.Optional[str]
- Text to reidentify.
+ vault_id : str
+ ID of the vault used for re-identification. Requires the Detect Invoker, Detect Manager, or Vault Owner role for this vault. Re-identifying `vault_token` values also requires a role or policy that separately grants the Detokenization action, unless the caller has the Vault Owner role.
- vault_id : typing.Optional[str]
- ID of the vault where the entities are stored.
+ text : str
+ Text to reidentify.
- format : typing.Optional[Format]
+ redaction_level : typing.Optional[typing.Sequence[RedactionLevel]]
+ Replacement patterns or types applied to entity types or token groups during re-identification. Specifies a replacement pattern/type and the token group or entity type it applies to during re-identification. Set exactly one of `tokenGroupName` or `entityName`. Use `tokenGroupName` for FlowVault and `entityName` for SkyVault. Similarly, set exactly one of `redactionType` or `redactionPattern` to specify the replacement.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- HttpResponse[IdentifyResponse]
+ HttpResponse[ReidentifyStringResponseV2]
OK
"""
_response = self._client_wrapper.httpx_client.request(
- "v1/detect/reidentify/string",
+ "v2/detect/reidentify/string",
method="POST",
json={
+ "vaultId": vault_id,
"text": text,
- "vault_id": vault_id,
- "format": convert_and_respect_annotation_metadata(object_=format, annotation=Format, direction="write"),
+ "redactionLevel": convert_and_respect_annotation_metadata(
+ object_=redaction_level, annotation=typing.Sequence[RedactionLevel], direction="write"
+ ),
},
headers={
"content-type": "application/json",
@@ -193,9 +174,9 @@ def reidentify_string(
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- IdentifyResponse,
+ ReidentifyStringResponseV2,
parse_obj_as(
- type_=IdentifyResponse, # type: ignore
+ type_=ReidentifyStringResponseV2, # type: ignore
object_=_response.json(),
),
)
@@ -204,9 +185,9 @@ def reidentify_string(
raise BadRequestError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -215,9 +196,9 @@ def reidentify_string(
raise UnauthorizedError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -236,77 +217,55 @@ def reidentify_string(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-class AsyncRawStringsClient:
+class AsyncRawStringsV2Client:
def __init__(self, *, client_wrapper: AsyncClientWrapper):
self._client_wrapper = client_wrapper
- async def deidentify_string(
+ async def deidentify_string_v2(
self,
*,
text: str,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyStringRequestEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
configuration_id: typing.Optional[str] = OMIT,
+ configuration: typing.Optional[DetectConfigV2] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[DeidentifyStringResponse]:
+ ) -> AsyncHttpResponse[DeidentifyStringResponseV2]:
"""
- De-identifies sensitive data from a string.
+ De-identifies sensitive data from a string.
Note: V2 API is in beta.
Parameters
----------
text : str
- Text to de-identify.
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyStringRequestEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
+ Text to deidentify.
configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
+ ID of the Detect configuration to use for de-identification.
+
+ configuration : typing.Optional[DetectConfigV2]
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- AsyncHttpResponse[DeidentifyStringResponse]
+ AsyncHttpResponse[DeidentifyStringResponseV2]
OK
"""
_response = await self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/string",
+ "v2/detect/deidentify/string",
method="POST",
json={
"text": text,
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
+ "configurationId": configuration_id,
+ "configuration": convert_and_respect_annotation_metadata(
+ object_=configuration, annotation=DetectConfigV2, direction="write"
),
- "configuration_id": configuration_id,
},
headers={
"content-type": "application/json",
@@ -317,9 +276,9 @@ async def deidentify_string(
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- DeidentifyStringResponse,
+ DeidentifyStringResponseV2,
parse_obj_as(
- type_=DeidentifyStringResponse, # type: ignore
+ type_=DeidentifyStringResponseV2, # type: ignore
object_=_response.json(),
),
)
@@ -328,9 +287,9 @@ async def deidentify_string(
raise BadRequestError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -339,9 +298,9 @@ async def deidentify_string(
raise UnauthorizedError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -360,44 +319,51 @@ async def deidentify_string(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
- async def reidentify_string(
+ async def reidentify_string_v2(
self,
*,
- text: typing.Optional[str] = OMIT,
- vault_id: typing.Optional[str] = OMIT,
- format: typing.Optional[Format] = OMIT,
+ vault_id: str,
+ text: str,
+ redaction_level: typing.Optional[typing.Sequence[RedactionLevel]] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[IdentifyResponse]:
+ ) -> AsyncHttpResponse[ReidentifyStringResponseV2]:
"""
- Re-identifies tokens in a string.
+ Re-identifies tokens in a string.
Requires the Detect Invoker, Detect Manager, or Vault Owner role. Re-identifying `vault_token` values also requires a policy that separately grants the Detokenization action, unless the caller has the Vault Owner role.
Note: V2 API is in beta.
Parameters
----------
- text : typing.Optional[str]
- Text to reidentify.
+ vault_id : str
+ ID of the vault used for re-identification. Requires the Detect Invoker, Detect Manager, or Vault Owner role for this vault. Re-identifying `vault_token` values also requires a role or policy that separately grants the Detokenization action, unless the caller has the Vault Owner role.
- vault_id : typing.Optional[str]
- ID of the vault where the entities are stored.
+ text : str
+ Text to reidentify.
- format : typing.Optional[Format]
+ redaction_level : typing.Optional[typing.Sequence[RedactionLevel]]
+ Replacement patterns or types applied to entity types or token groups during re-identification. Specifies a replacement pattern/type and the token group or entity type it applies to during re-identification. Set exactly one of `tokenGroupName` or `entityName`. Use `tokenGroupName` for FlowVault and `entityName` for SkyVault. Similarly, set exactly one of `redactionType` or `redactionPattern` to specify the replacement.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- AsyncHttpResponse[IdentifyResponse]
+ AsyncHttpResponse[ReidentifyStringResponseV2]
OK
"""
_response = await self._client_wrapper.httpx_client.request(
- "v1/detect/reidentify/string",
+ "v2/detect/reidentify/string",
method="POST",
json={
+ "vaultId": vault_id,
"text": text,
- "vault_id": vault_id,
- "format": convert_and_respect_annotation_metadata(object_=format, annotation=Format, direction="write"),
+ "redactionLevel": convert_and_respect_annotation_metadata(
+ object_=redaction_level, annotation=typing.Sequence[RedactionLevel], direction="write"
+ ),
},
headers={
"content-type": "application/json",
@@ -408,9 +374,9 @@ async def reidentify_string(
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- IdentifyResponse,
+ ReidentifyStringResponseV2,
parse_obj_as(
- type_=IdentifyResponse, # type: ignore
+ type_=ReidentifyStringResponseV2, # type: ignore
object_=_response.json(),
),
)
@@ -419,9 +385,9 @@ async def reidentify_string(
raise BadRequestError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -430,9 +396,9 @@ async def reidentify_string(
raise UnauthorizedError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -451,4 +417,8 @@ async def reidentify_string(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/skyvault/skyflow/generated/rest/guardrails/__init__.py b/common/generated/rest/token_exchange/__init__.py
similarity index 100%
rename from skyvault/skyflow/generated/rest/guardrails/__init__.py
rename to common/generated/rest/token_exchange/__init__.py
diff --git a/common/generated/rest/token_exchange/client.py b/common/generated/rest/token_exchange/client.py
new file mode 100644
index 00000000..b3727f1e
--- /dev/null
+++ b/common/generated/rest/token_exchange/client.py
@@ -0,0 +1,161 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
+from ..core.request_options import RequestOptions
+from ..types.get_sts_token_response import GetStsTokenResponse
+from .raw_client import AsyncRawTokenExchangeClient, RawTokenExchangeClient
+
+# this is used as the default value for optional parameters
+OMIT = typing.cast(typing.Any, ...)
+
+
+class TokenExchangeClient:
+ def __init__(self, *, client_wrapper: SyncClientWrapper):
+ self._raw_client = RawTokenExchangeClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> RawTokenExchangeClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawTokenExchangeClient
+ """
+ return self._raw_client
+
+ def get_sts_token(
+ self,
+ *,
+ grant_type: str,
+ subject_token: str,
+ subject_token_type: str,
+ service_account_id: str,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> GetStsTokenResponse:
+ """
+ Generates a Bearer Token to authenticate with Skyflow.
+
+ Parameters
+ ----------
+ grant_type : str
+
+ subject_token : str
+ Subject token.
+
+ subject_token_type : str
+ Subject token type.
+
+ service_account_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ GetStsTokenResponse
+ OK
+
+ Examples
+ --------
+ from skyflow import SkyflowAuth
+
+ client = SkyflowAuth(
+ token="YOUR_TOKEN",
+ )
+ client.token_exchange.get_sts_token(
+ grant_type="grant_type",
+ subject_token="subject_token",
+ subject_token_type="subject_token_type",
+ service_account_id="service_account_id",
+ )
+ """
+ _response = self._raw_client.get_sts_token(
+ grant_type=grant_type,
+ subject_token=subject_token,
+ subject_token_type=subject_token_type,
+ service_account_id=service_account_id,
+ request_options=request_options,
+ )
+ return _response.data
+
+
+class AsyncTokenExchangeClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawTokenExchangeClient(client_wrapper=client_wrapper)
+
+ @property
+ def with_raw_response(self) -> AsyncRawTokenExchangeClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawTokenExchangeClient
+ """
+ return self._raw_client
+
+ async def get_sts_token(
+ self,
+ *,
+ grant_type: str,
+ subject_token: str,
+ subject_token_type: str,
+ service_account_id: str,
+ request_options: typing.Optional[RequestOptions] = None,
+ ) -> GetStsTokenResponse:
+ """
+ Generates a Bearer Token to authenticate with Skyflow.
+
+ Parameters
+ ----------
+ grant_type : str
+
+ subject_token : str
+ Subject token.
+
+ subject_token_type : str
+ Subject token type.
+
+ service_account_id : str
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ GetStsTokenResponse
+ OK
+
+ Examples
+ --------
+ import asyncio
+
+ from skyflow import AsyncSkyflowAuth
+
+ client = AsyncSkyflowAuth(
+ token="YOUR_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.token_exchange.get_sts_token(
+ grant_type="grant_type",
+ subject_token="subject_token",
+ subject_token_type="subject_token_type",
+ service_account_id="service_account_id",
+ )
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.get_sts_token(
+ grant_type=grant_type,
+ subject_token=subject_token,
+ subject_token_type=subject_token_type,
+ service_account_id=service_account_id,
+ request_options=request_options,
+ )
+ return _response.data
diff --git a/skyvault/skyflow/generated/rest/authentication/raw_client.py b/common/generated/rest/token_exchange/raw_client.py
similarity index 54%
rename from skyvault/skyflow/generated/rest/authentication/raw_client.py
rename to common/generated/rest/token_exchange/raw_client.py
index ad2caef6..c6eae1f2 100644
--- a/skyvault/skyflow/generated/rest/authentication/raw_client.py
+++ b/common/generated/rest/token_exchange/raw_client.py
@@ -6,73 +6,65 @@
from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.http_response import AsyncHttpResponse, HttpResponse
+from ..core.parse_error import ParsingError
from ..core.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
from ..errors.bad_request_error import BadRequestError
+from ..errors.internal_server_error import InternalServerError
from ..errors.not_found_error import NotFoundError
from ..errors.unauthorized_error import UnauthorizedError
-from ..types.v_1_get_auth_token_response import V1GetAuthTokenResponse
+from ..types.error_response import ErrorResponse
+from ..types.get_sts_token_response import GetStsTokenResponse
+from pydantic import ValidationError
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
-class RawAuthenticationClient:
+class RawTokenExchangeClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
self._client_wrapper = client_wrapper
- def authentication_service_get_auth_token(
+ def get_sts_token(
self,
*,
grant_type: str,
- assertion: str,
- subject_token: typing.Optional[str] = OMIT,
- subject_token_type: typing.Optional[str] = OMIT,
- requested_token_use: typing.Optional[str] = OMIT,
- scope: typing.Optional[str] = OMIT,
+ subject_token: str,
+ subject_token_type: str,
+ service_account_id: str,
request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[V1GetAuthTokenResponse]:
+ ) -> HttpResponse[GetStsTokenResponse]:
"""
-
Generates a Bearer Token to authenticate with Skyflow. This method doesn't require the Authorization header.
+ Generates a Bearer Token to authenticate with Skyflow.
Parameters
----------
grant_type : str
- Grant type of the request. Set this to `urn:ietf:params:oauth:grant-type:jwt-bearer`.
- assertion : str
- User-signed JWT token that contains the following fields:
+ Generates a Bearer Token to authenticate with Skyflow.
Parameters
----------
grant_type : str
- Grant type of the request. Set this to `urn:ietf:params:oauth:grant-type:jwt-bearer`.
- assertion : str
- User-signed JWT token that contains the following fields:
-
- Parameters
- ----------
- grant_type : str
- Grant type of the request. Set this to `urn:ietf:params:oauth:grant-type:jwt-bearer`.
-
- assertion : str
- User-signed JWT token that contains the following fields:
-
- Parameters
- ----------
- grant_type : str
- Grant type of the request. Set this to `urn:ietf:params:oauth:grant-type:jwt-bearer`.
-
- assertion : str
- User-signed JWT token that contains the following fields:
Returns the specified card metadata.
-
- Parameters
- ----------
- fields : typing.Optional[typing.Sequence[str]]
- Fields to return. If not specified, all fields are returned.
-
- bin : typing.Optional[str]
- BIN of the card.
-
- vault_schema_config : typing.Optional[V1VaultSchemaConfig]
-
- skyflow_id : typing.Optional[str]
- skyflow_id of the record.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[V1BinListResponse]
- A successful response.
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/card_lookup",
- method="POST",
- json={
- "fields": fields,
- "BIN": bin,
- "vault_schema_config": convert_and_respect_annotation_metadata(
- object_=vault_schema_config, annotation=V1VaultSchemaConfig, direction="write"
- ),
- "skyflow_id": skyflow_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- V1BinListResponse,
- parse_obj_as(
- type_=V1BinListResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 404:
- raise NotFoundError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/skyvault/skyflow/generated/rest/client.py b/skyvault/skyflow/generated/rest/client.py
index e8abdf54..1d896ec7 100644
--- a/skyvault/skyflow/generated/rest/client.py
+++ b/skyvault/skyflow/generated/rest/client.py
@@ -1,22 +1,24 @@
# This file was auto-generated by Fern from our API Definition.
+from __future__ import annotations
+
import typing
import httpx
-from .audit.client import AsyncAuditClient, AuditClient
-from .authentication.client import AsyncAuthenticationClient, AuthenticationClient
-from .bin_lookup.client import AsyncBinLookupClient, BinLookupClient
from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from .environment import SkyflowEnvironment
-from .files.client import AsyncFilesClient, FilesClient
-from .guardrails.client import AsyncGuardrailsClient, GuardrailsClient
-from .query.client import AsyncQueryClient, QueryClient
-from .records.client import AsyncRecordsClient, RecordsClient
-from .strings.client import AsyncStringsClient, StringsClient
-from .tokens.client import AsyncTokensClient, TokensClient
+from .core.logging import LogConfig, Logger
+from .core.request_options import RequestOptions
+from .environment import SkyflowAuthEnvironment
+from .raw_client import AsyncRawSkyflowAuth, RawSkyflowAuth
+
+if typing.TYPE_CHECKING:
+ from .files.client import AsyncFilesClient, FilesClient
+ from .query.client import AsyncQueryClient, QueryClient
+ from .records.client import AsyncRecordsClient, RecordsClient
+ from .tokens.client import AsyncTokensClient, TokensClient
-class Skyflow:
+class SkyflowAuth:
"""
Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propagate to these functions.
@@ -25,14 +27,17 @@ class Skyflow:
base_url : typing.Optional[str]
The base url to use for requests from the client.
- environment : SkyflowEnvironment
- The environment to use for requests from the client. from .environment import SkyflowEnvironment
+ environment : SkyflowAuthEnvironment
+ The environment to use for requests from the client. from .environment import SkyflowAuthEnvironment
+
+ Defaults to SkyflowAuthEnvironment.PRODUCTION
- Defaults to SkyflowEnvironment.PRODUCTION
+ identifier : typing.Optional[str]
+ Server URL variable for 'identifier'. Defaults to '{{vault_uri}}'.
token : typing.Optional[typing.Union[str, typing.Callable[[], str]]]
headers : typing.Optional[typing.Dict[str, str]]
@@ -41,17 +46,29 @@ class Skyflow:
timeout : typing.Optional[float]
The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
+ max_retries : typing.Optional[int]
+ The default maximum number of retries for failed requests. Defaults to 2. Per-request `max_retries` in `request_options` takes precedence over this value.
+
+ stream_reconnection_enabled : typing.Optional[bool]
+ Whether to automatically reconnect on stream disconnection for resumable streaming endpoints. Defaults to True. Per-request `stream_reconnection_enabled` in `request_options` takes precedence over this value.
+
+ max_stream_reconnection_attempts : typing.Optional[int]
+ The maximum number of reconnection attempts for resumable streaming endpoints. Defaults to no limit. Per-request `max_stream_reconnection_attempts` in `request_options` takes precedence over this value.
+
follow_redirects : typing.Optional[bool]
Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.
httpx_client : typing.Optional[httpx.Client]
The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.
+ logging : typing.Optional[typing.Union[LogConfig, Logger]]
+ Configure logging for the SDK. Accepts a LogConfig dict with 'level' (debug/info/warn/error), 'logger' (custom logger implementation), and 'silent' (boolean, defaults to True) fields. You can also pass a pre-configured Logger instance.
+
Examples
--------
- from skyflow import Skyflow
+ from skyflow import SkyflowAuth
- client = Skyflow(
+ client = SkyflowAuth(
token="YOUR_TOKEN",
)
"""
@@ -60,16 +77,29 @@ def __init__(
self,
*,
base_url: typing.Optional[str] = None,
- environment: SkyflowEnvironment = SkyflowEnvironment.PRODUCTION,
+ environment: SkyflowAuthEnvironment = SkyflowAuthEnvironment.PRODUCTION,
+ identifier: typing.Optional[str] = None,
token: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None,
headers: typing.Optional[typing.Dict[str, str]] = None,
timeout: typing.Optional[float] = None,
+ max_retries: typing.Optional[int] = None,
+ stream_reconnection_enabled: typing.Optional[bool] = None,
+ max_stream_reconnection_attempts: typing.Optional[int] = None,
follow_redirects: typing.Optional[bool] = True,
httpx_client: typing.Optional[httpx.Client] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
):
- _defaulted_timeout = (
- timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
- )
+ _defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None
+ _defaulted_max_retries = max_retries if max_retries is not None else 2
+ if identifier is not None:
+ _identifier = identifier if identifier is not None else "{{vault_uri}}"
+ _environment_url_templates = {
+ SkyflowAuthEnvironment.PRODUCTION: "https://{identifier}.vault.skyflowapis.com",
+ SkyflowAuthEnvironment.SANDBOX: "https://{identifier}.vault.skyflowapis-preview.com",
+ }
+ _url_template = _environment_url_templates.get(environment, "https://{identifier}.vault.skyflowapis.com")
+ if base_url is None:
+ base_url = _url_template.format(identifier=_identifier)
self._client_wrapper = SyncClientWrapper(
base_url=_get_base_url(base_url=base_url, environment=environment),
token=token,
@@ -80,19 +110,107 @@ def __init__(
if follow_redirects is not None
else httpx.Client(timeout=_defaulted_timeout),
timeout=_defaulted_timeout,
+ max_retries=_defaulted_max_retries,
+ stream_reconnection_enabled=stream_reconnection_enabled,
+ max_stream_reconnection_attempts=max_stream_reconnection_attempts,
+ logging=logging,
+ )
+ self._raw_client = RawSkyflowAuth(client_wrapper=self._client_wrapper)
+ self._records: typing.Optional[RecordsClient] = None
+ self._tokens: typing.Optional[TokensClient] = None
+ self._query: typing.Optional[QueryClient] = None
+ self._files: typing.Optional[FilesClient] = None
+
+ @property
+ def with_raw_response(self) -> RawSkyflowAuth:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ RawSkyflowAuth
+ """
+ return self._raw_client
+
+ def patch_v2vaults_id(
+ self, vault_id: typing.Optional[str], *, request_options: typing.Optional[RequestOptions] = None
+ ) -> None:
+ """
+ Parameters
+ ----------
+ vault_id : typing.Optional[str]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ from skyflow import SkyflowAuth
+
+ client = SkyflowAuth(
+ token="YOUR_TOKEN",
)
- self.audit = AuditClient(client_wrapper=self._client_wrapper)
- self.bin_lookup = BinLookupClient(client_wrapper=self._client_wrapper)
- self.records = RecordsClient(client_wrapper=self._client_wrapper)
- self.tokens = TokensClient(client_wrapper=self._client_wrapper)
- self.query = QueryClient(client_wrapper=self._client_wrapper)
- self.authentication = AuthenticationClient(client_wrapper=self._client_wrapper)
- self.files = FilesClient(client_wrapper=self._client_wrapper)
- self.strings = StringsClient(client_wrapper=self._client_wrapper)
- self.guardrails = GuardrailsClient(client_wrapper=self._client_wrapper)
-
-
-class AsyncSkyflow:
+ client.patch_v2vaults_id()
+ """
+ _response = self._raw_client.patch_v2vaults_id(vault_id, request_options=request_options)
+ return _response.data
+
+ @property
+ def records(self):
+ if self._records is None:
+ from .records.client import RecordsClient # noqa: E402
+
+ self._records = RecordsClient(client_wrapper=self._client_wrapper)
+ return self._records
+
+ @property
+ def tokens(self):
+ if self._tokens is None:
+ from .tokens.client import TokensClient # noqa: E402
+
+ self._tokens = TokensClient(client_wrapper=self._client_wrapper)
+ return self._tokens
+
+ @property
+ def query(self):
+ if self._query is None:
+ from .query.client import QueryClient # noqa: E402
+
+ self._query = QueryClient(client_wrapper=self._client_wrapper)
+ return self._query
+
+ @property
+ def files(self):
+ if self._files is None:
+ from .files.client import FilesClient # noqa: E402
+
+ self._files = FilesClient(client_wrapper=self._client_wrapper)
+ return self._files
+
+
+def _make_default_async_client(
+ timeout: typing.Optional[float],
+ follow_redirects: typing.Optional[bool],
+) -> httpx.AsyncClient:
+ try:
+ import httpx_aiohttp # type: ignore[import-not-found]
+ except ImportError:
+ pass
+ else:
+ if follow_redirects is not None:
+ return httpx_aiohttp.HttpxAiohttpClient(timeout=timeout, follow_redirects=follow_redirects)
+ return httpx_aiohttp.HttpxAiohttpClient(timeout=timeout)
+
+ if follow_redirects is not None:
+ return httpx.AsyncClient(timeout=timeout, follow_redirects=follow_redirects)
+ return httpx.AsyncClient(timeout=timeout)
+
+
+class AsyncSkyflowAuth:
"""
Use this class to access the different functions within the SDK. You can instantiate any number of clients with different configuration that will propagate to these functions.
@@ -101,33 +219,51 @@ class AsyncSkyflow:
base_url : typing.Optional[str]
The base url to use for requests from the client.
- environment : SkyflowEnvironment
- The environment to use for requests from the client. from .environment import SkyflowEnvironment
+ environment : SkyflowAuthEnvironment
+ The environment to use for requests from the client. from .environment import SkyflowAuthEnvironment
+
+ Defaults to SkyflowAuthEnvironment.PRODUCTION
- Defaults to SkyflowEnvironment.PRODUCTION
+ identifier : typing.Optional[str]
+ Server URL variable for 'identifier'. Defaults to '{{vault_uri}}'.
token : typing.Optional[typing.Union[str, typing.Callable[[], str]]]
headers : typing.Optional[typing.Dict[str, str]]
Additional headers to send with every request.
+ async_token : typing.Optional[typing.Callable[[], typing.Awaitable[str]]]
+ An async callable that returns a bearer token. Use this when token acquisition involves async I/O (e.g., refreshing tokens via an async HTTP client). When provided, this is used instead of the synchronous token for async requests.
+
timeout : typing.Optional[float]
The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
+ max_retries : typing.Optional[int]
+ The default maximum number of retries for failed requests. Defaults to 2. Per-request `max_retries` in `request_options` takes precedence over this value.
+
+ stream_reconnection_enabled : typing.Optional[bool]
+ Whether to automatically reconnect on stream disconnection for resumable streaming endpoints. Defaults to True. Per-request `stream_reconnection_enabled` in `request_options` takes precedence over this value.
+
+ max_stream_reconnection_attempts : typing.Optional[int]
+ The maximum number of reconnection attempts for resumable streaming endpoints. Defaults to no limit. Per-request `max_stream_reconnection_attempts` in `request_options` takes precedence over this value.
+
follow_redirects : typing.Optional[bool]
Whether the default httpx client follows redirects or not, this is irrelevant if a custom httpx client is passed in.
httpx_client : typing.Optional[httpx.AsyncClient]
The httpx client to use for making requests, a preconfigured client is used by default, however this is useful should you want to pass in any custom httpx configuration.
+ logging : typing.Optional[typing.Union[LogConfig, Logger]]
+ Configure logging for the SDK. Accepts a LogConfig dict with 'level' (debug/info/warn/error), 'logger' (custom logger implementation), and 'silent' (boolean, defaults to True) fields. You can also pass a pre-configured Logger instance.
+
Examples
--------
- from skyflow import AsyncSkyflow
+ from skyflow import AsyncSkyflowAuth
- client = AsyncSkyflow(
+ client = AsyncSkyflowAuth(
token="YOUR_TOKEN",
)
"""
@@ -136,39 +272,130 @@ def __init__(
self,
*,
base_url: typing.Optional[str] = None,
- environment: SkyflowEnvironment = SkyflowEnvironment.PRODUCTION,
+ environment: SkyflowAuthEnvironment = SkyflowAuthEnvironment.PRODUCTION,
+ identifier: typing.Optional[str] = None,
token: typing.Optional[typing.Union[str, typing.Callable[[], str]]] = None,
headers: typing.Optional[typing.Dict[str, str]] = None,
+ async_token: typing.Optional[typing.Callable[[], typing.Awaitable[str]]] = None,
timeout: typing.Optional[float] = None,
+ max_retries: typing.Optional[int] = None,
+ stream_reconnection_enabled: typing.Optional[bool] = None,
+ max_stream_reconnection_attempts: typing.Optional[int] = None,
follow_redirects: typing.Optional[bool] = True,
httpx_client: typing.Optional[httpx.AsyncClient] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
):
- _defaulted_timeout = (
- timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
- )
+ _defaulted_timeout = timeout if timeout is not None else 60 if httpx_client is None else None
+ _defaulted_max_retries = max_retries if max_retries is not None else 2
+ if identifier is not None:
+ _identifier = identifier if identifier is not None else "{{vault_uri}}"
+ _environment_url_templates = {
+ SkyflowAuthEnvironment.PRODUCTION: "https://{identifier}.vault.skyflowapis.com",
+ SkyflowAuthEnvironment.SANDBOX: "https://{identifier}.vault.skyflowapis-preview.com",
+ }
+ _url_template = _environment_url_templates.get(environment, "https://{identifier}.vault.skyflowapis.com")
+ if base_url is None:
+ base_url = _url_template.format(identifier=_identifier)
self._client_wrapper = AsyncClientWrapper(
base_url=_get_base_url(base_url=base_url, environment=environment),
token=token,
headers=headers,
+ async_token=async_token,
httpx_client=httpx_client
if httpx_client is not None
- else httpx.AsyncClient(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
- if follow_redirects is not None
- else httpx.AsyncClient(timeout=_defaulted_timeout),
+ else _make_default_async_client(timeout=_defaulted_timeout, follow_redirects=follow_redirects),
timeout=_defaulted_timeout,
+ max_retries=_defaulted_max_retries,
+ stream_reconnection_enabled=stream_reconnection_enabled,
+ max_stream_reconnection_attempts=max_stream_reconnection_attempts,
+ logging=logging,
)
- self.audit = AsyncAuditClient(client_wrapper=self._client_wrapper)
- self.bin_lookup = AsyncBinLookupClient(client_wrapper=self._client_wrapper)
- self.records = AsyncRecordsClient(client_wrapper=self._client_wrapper)
- self.tokens = AsyncTokensClient(client_wrapper=self._client_wrapper)
- self.query = AsyncQueryClient(client_wrapper=self._client_wrapper)
- self.authentication = AsyncAuthenticationClient(client_wrapper=self._client_wrapper)
- self.files = AsyncFilesClient(client_wrapper=self._client_wrapper)
- self.strings = AsyncStringsClient(client_wrapper=self._client_wrapper)
- self.guardrails = AsyncGuardrailsClient(client_wrapper=self._client_wrapper)
-
-
-def _get_base_url(*, base_url: typing.Optional[str] = None, environment: SkyflowEnvironment) -> str:
+ self._raw_client = AsyncRawSkyflowAuth(client_wrapper=self._client_wrapper)
+ self._records: typing.Optional[AsyncRecordsClient] = None
+ self._tokens: typing.Optional[AsyncTokensClient] = None
+ self._query: typing.Optional[AsyncQueryClient] = None
+ self._files: typing.Optional[AsyncFilesClient] = None
+
+ @property
+ def with_raw_response(self) -> AsyncRawSkyflowAuth:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
+
+ Returns
+ -------
+ AsyncRawSkyflowAuth
+ """
+ return self._raw_client
+
+ async def patch_v2vaults_id(
+ self, vault_id: typing.Optional[str], *, request_options: typing.Optional[RequestOptions] = None
+ ) -> None:
+ """
+ Parameters
+ ----------
+ vault_id : typing.Optional[str]
+
+ request_options : typing.Optional[RequestOptions]
+ Request-specific configuration.
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ import asyncio
+
+ from skyflow import AsyncSkyflowAuth
+
+ client = AsyncSkyflowAuth(
+ token="YOUR_TOKEN",
+ )
+
+
+ async def main() -> None:
+ await client.patch_v2vaults_id()
+
+
+ asyncio.run(main())
+ """
+ _response = await self._raw_client.patch_v2vaults_id(vault_id, request_options=request_options)
+ return _response.data
+
+ @property
+ def records(self):
+ if self._records is None:
+ from .records.client import AsyncRecordsClient # noqa: E402
+
+ self._records = AsyncRecordsClient(client_wrapper=self._client_wrapper)
+ return self._records
+
+ @property
+ def tokens(self):
+ if self._tokens is None:
+ from .tokens.client import AsyncTokensClient # noqa: E402
+
+ self._tokens = AsyncTokensClient(client_wrapper=self._client_wrapper)
+ return self._tokens
+
+ @property
+ def query(self):
+ if self._query is None:
+ from .query.client import AsyncQueryClient # noqa: E402
+
+ self._query = AsyncQueryClient(client_wrapper=self._client_wrapper)
+ return self._query
+
+ @property
+ def files(self):
+ if self._files is None:
+ from .files.client import AsyncFilesClient # noqa: E402
+
+ self._files = AsyncFilesClient(client_wrapper=self._client_wrapper)
+ return self._files
+
+
+def _get_base_url(*, base_url: typing.Optional[str] = None, environment: SkyflowAuthEnvironment) -> str:
if base_url is not None:
return base_url
elif environment is not None:
diff --git a/skyvault/skyflow/generated/rest/core/__init__.py b/skyvault/skyflow/generated/rest/core/__init__.py
index 31bbb818..5bc159a1 100644
--- a/skyvault/skyflow/generated/rest/core/__init__.py
+++ b/skyvault/skyflow/generated/rest/core/__init__.py
@@ -2,26 +2,91 @@
# isort: skip_file
-from .api_error import ApiError
-from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper
-from .datetime_utils import serialize_datetime
-from .file import File, convert_file_dict_to_httpx_tuples, with_content_type
-from .http_client import AsyncHttpClient, HttpClient
-from .http_response import AsyncHttpResponse, HttpResponse
-from .jsonable_encoder import jsonable_encoder
-from .pydantic_utilities import (
- IS_PYDANTIC_V2,
- UniversalBaseModel,
- UniversalRootModel,
- parse_obj_as,
- universal_field_validator,
- universal_root_validator,
- update_forward_refs,
-)
-from .query_encoder import encode_query
-from .remove_none_from_dict import remove_none_from_dict
-from .request_options import RequestOptions
-from .serialization import FieldMetadata, convert_and_respect_annotation_metadata
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .api_error import ApiError
+ from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper
+ from .datetime_utils import Rfc2822DateTime, parse_rfc2822_datetime, serialize_datetime
+ from .file import File, convert_file_dict_to_httpx_tuples, with_content_type
+ from .http_client import AsyncHttpClient, HttpClient
+ from .http_response import AsyncHttpResponse, HttpResponse
+ from .jsonable_encoder import encode_path_param, jsonable_encoder
+ from .logging import ConsoleLogger, ILogger, LogConfig, LogLevel, Logger, create_logger
+ from .parse_error import ParsingError
+ from .pydantic_utilities import (
+ IS_PYDANTIC_V2,
+ UniversalBaseModel,
+ UniversalRootModel,
+ parse_obj_as,
+ universal_field_validator,
+ universal_root_validator,
+ update_forward_refs,
+ )
+ from .query_encoder import encode_query
+ from .remove_none_from_dict import remove_none_from_dict
+ from .request_options import RequestOptions
+ from .serialization import FieldMetadata, convert_and_respect_annotation_metadata
+_dynamic_imports: typing.Dict[str, str] = {
+ "ApiError": ".api_error",
+ "AsyncClientWrapper": ".client_wrapper",
+ "AsyncHttpClient": ".http_client",
+ "AsyncHttpResponse": ".http_response",
+ "BaseClientWrapper": ".client_wrapper",
+ "ConsoleLogger": ".logging",
+ "FieldMetadata": ".serialization",
+ "File": ".file",
+ "HttpClient": ".http_client",
+ "HttpResponse": ".http_response",
+ "ILogger": ".logging",
+ "IS_PYDANTIC_V2": ".pydantic_utilities",
+ "LogConfig": ".logging",
+ "LogLevel": ".logging",
+ "Logger": ".logging",
+ "ParsingError": ".parse_error",
+ "RequestOptions": ".request_options",
+ "Rfc2822DateTime": ".datetime_utils",
+ "SyncClientWrapper": ".client_wrapper",
+ "UniversalBaseModel": ".pydantic_utilities",
+ "UniversalRootModel": ".pydantic_utilities",
+ "convert_and_respect_annotation_metadata": ".serialization",
+ "convert_file_dict_to_httpx_tuples": ".file",
+ "create_logger": ".logging",
+ "encode_path_param": ".jsonable_encoder",
+ "encode_query": ".query_encoder",
+ "jsonable_encoder": ".jsonable_encoder",
+ "parse_obj_as": ".pydantic_utilities",
+ "parse_rfc2822_datetime": ".datetime_utils",
+ "remove_none_from_dict": ".remove_none_from_dict",
+ "serialize_datetime": ".datetime_utils",
+ "universal_field_validator": ".pydantic_utilities",
+ "universal_root_validator": ".pydantic_utilities",
+ "update_forward_refs": ".pydantic_utilities",
+ "with_content_type": ".file",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
__all__ = [
"ApiError",
@@ -29,20 +94,30 @@
"AsyncHttpClient",
"AsyncHttpResponse",
"BaseClientWrapper",
+ "ConsoleLogger",
"FieldMetadata",
"File",
"HttpClient",
"HttpResponse",
+ "ILogger",
"IS_PYDANTIC_V2",
+ "LogConfig",
+ "LogLevel",
+ "Logger",
+ "ParsingError",
"RequestOptions",
+ "Rfc2822DateTime",
"SyncClientWrapper",
"UniversalBaseModel",
"UniversalRootModel",
"convert_and_respect_annotation_metadata",
"convert_file_dict_to_httpx_tuples",
+ "create_logger",
+ "encode_path_param",
"encode_query",
"jsonable_encoder",
"parse_obj_as",
+ "parse_rfc2822_datetime",
"remove_none_from_dict",
"serialize_datetime",
"universal_field_validator",
diff --git a/skyvault/skyflow/generated/rest/core/client_wrapper.py b/skyvault/skyflow/generated/rest/core/client_wrapper.py
index 355d775e..561d8aa6 100644
--- a/skyvault/skyflow/generated/rest/core/client_wrapper.py
+++ b/skyvault/skyflow/generated/rest/core/client_wrapper.py
@@ -4,6 +4,7 @@
import httpx
from .http_client import AsyncHttpClient, HttpClient
+from .logging import LogConfig, Logger
class BaseClientWrapper:
@@ -14,18 +15,29 @@ def __init__(
headers: typing.Optional[typing.Dict[str, str]] = None,
base_url: str,
timeout: typing.Optional[float] = None,
+ max_retries: int = 2,
+ stream_reconnection_enabled: typing.Optional[bool] = None,
+ max_stream_reconnection_attempts: typing.Optional[int] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
):
self._token = token
self._headers = headers
self._base_url = base_url
self._timeout = timeout
+ self._max_retries = max_retries
+ self._stream_reconnection_enabled = stream_reconnection_enabled
+ self._max_stream_reconnection_attempts = max_stream_reconnection_attempts
+ self._logging = logging
def get_headers(self) -> typing.Dict[str, str]:
+ import platform
+
headers: typing.Dict[str, str] = {
- "User-Agent": "skyflow/1.16.1",
"X-Fern-Language": "Python",
- "X-Fern-SDK-Name": "skyflow",
- "X-Fern-SDK-Version": "1.16.1",
+ "X-Fern-Runtime": f"python/{platform.python_version()}",
+ "X-Fern-Platform": f"{platform.system().lower()}/{platform.release()}",
+ "X-Fern-SDK-Name": "skyflow.generated.rest",
+ "X-Fern-SDK-Version": "0.0.49",
**(self.get_custom_headers() or {}),
}
token = self._get_token()
@@ -48,6 +60,15 @@ def get_base_url(self) -> str:
def get_timeout(self) -> typing.Optional[float]:
return self._timeout
+ def get_max_retries(self) -> int:
+ return self._max_retries
+
+ def get_stream_reconnection_enabled(self) -> bool:
+ return self._stream_reconnection_enabled if self._stream_reconnection_enabled is not None else True
+
+ def get_max_stream_reconnection_attempts(self) -> typing.Optional[int]:
+ return self._max_stream_reconnection_attempts
+
class SyncClientWrapper(BaseClientWrapper):
def __init__(
@@ -57,14 +78,29 @@ def __init__(
headers: typing.Optional[typing.Dict[str, str]] = None,
base_url: str,
timeout: typing.Optional[float] = None,
+ max_retries: int = 2,
+ stream_reconnection_enabled: typing.Optional[bool] = None,
+ max_stream_reconnection_attempts: typing.Optional[int] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
httpx_client: httpx.Client,
):
- super().__init__(token=token, headers=headers, base_url=base_url, timeout=timeout)
+ super().__init__(
+ token=token,
+ headers=headers,
+ base_url=base_url,
+ timeout=timeout,
+ max_retries=max_retries,
+ stream_reconnection_enabled=stream_reconnection_enabled,
+ max_stream_reconnection_attempts=max_stream_reconnection_attempts,
+ logging=logging,
+ )
self.httpx_client = HttpClient(
httpx_client=httpx_client,
base_headers=self.get_headers,
base_timeout=self.get_timeout,
base_url=self.get_base_url,
+ base_max_retries=self.get_max_retries(),
+ logging_config=self._logging,
)
@@ -76,12 +112,37 @@ def __init__(
headers: typing.Optional[typing.Dict[str, str]] = None,
base_url: str,
timeout: typing.Optional[float] = None,
+ max_retries: int = 2,
+ stream_reconnection_enabled: typing.Optional[bool] = None,
+ max_stream_reconnection_attempts: typing.Optional[int] = None,
+ logging: typing.Optional[typing.Union[LogConfig, Logger]] = None,
+ async_token: typing.Optional[typing.Callable[[], typing.Awaitable[str]]] = None,
httpx_client: httpx.AsyncClient,
):
- super().__init__(token=token, headers=headers, base_url=base_url, timeout=timeout)
+ super().__init__(
+ token=token,
+ headers=headers,
+ base_url=base_url,
+ timeout=timeout,
+ max_retries=max_retries,
+ stream_reconnection_enabled=stream_reconnection_enabled,
+ max_stream_reconnection_attempts=max_stream_reconnection_attempts,
+ logging=logging,
+ )
+ self._async_token = async_token
self.httpx_client = AsyncHttpClient(
httpx_client=httpx_client,
base_headers=self.get_headers,
base_timeout=self.get_timeout,
base_url=self.get_base_url,
+ base_max_retries=self.get_max_retries(),
+ async_base_headers=self.async_get_headers,
+ logging_config=self._logging,
)
+
+ async def async_get_headers(self) -> typing.Dict[str, str]:
+ headers = self.get_headers()
+ if self._async_token is not None:
+ token = await self._async_token()
+ headers["Authorization"] = f"Bearer {token}"
+ return headers
diff --git a/skyvault/skyflow/generated/rest/core/datetime_utils.py b/skyvault/skyflow/generated/rest/core/datetime_utils.py
index 7c9864a9..a12b2ad0 100644
--- a/skyvault/skyflow/generated/rest/core/datetime_utils.py
+++ b/skyvault/skyflow/generated/rest/core/datetime_utils.py
@@ -1,6 +1,48 @@
# This file was auto-generated by Fern from our API Definition.
import datetime as dt
+from email.utils import parsedate_to_datetime
+from typing import Any
+
+import pydantic
+
+IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
+
+
+def parse_rfc2822_datetime(v: Any) -> dt.datetime:
+ """
+ Parse an RFC 2822 datetime string (e.g., "Wed, 02 Oct 2002 13:00:00 GMT")
+ into a datetime object. If the value is already a datetime, return it as-is.
+ Falls back to ISO 8601 parsing if RFC 2822 parsing fails.
+ """
+ if isinstance(v, dt.datetime):
+ return v
+ if isinstance(v, str):
+ try:
+ return parsedate_to_datetime(v)
+ except Exception:
+ pass
+ # Fallback to ISO 8601 parsing
+ return dt.datetime.fromisoformat(v.replace("Z", "+00:00"))
+ raise ValueError(f"Expected str or datetime, got {type(v)}")
+
+
+class Rfc2822DateTime(dt.datetime):
+ """A datetime subclass that parses RFC 2822 date strings.
+
+ On Pydantic V1, uses __get_validators__ for pre-validation.
+ On Pydantic V2, uses __get_pydantic_core_schema__ for BeforeValidator-style parsing.
+ """
+
+ @classmethod
+ def __get_validators__(cls): # type: ignore[no-untyped-def]
+ yield parse_rfc2822_datetime
+
+ @classmethod
+ def __get_pydantic_core_schema__(cls, _source_type: Any, _handler: Any) -> Any: # type: ignore[override]
+ from pydantic_core import core_schema
+
+ return core_schema.no_info_before_validator_function(parse_rfc2822_datetime, core_schema.datetime_schema())
def serialize_datetime(v: dt.datetime) -> str:
diff --git a/skyvault/skyflow/generated/rest/core/force_multipart.py b/skyvault/skyflow/generated/rest/core/force_multipart.py
index ae24ccff..5440913f 100644
--- a/skyvault/skyflow/generated/rest/core/force_multipart.py
+++ b/skyvault/skyflow/generated/rest/core/force_multipart.py
@@ -1,7 +1,9 @@
# This file was auto-generated by Fern from our API Definition.
+from typing import Any, Dict
-class ForceMultipartDict(dict):
+
+class ForceMultipartDict(Dict[str, Any]):
"""
A dictionary subclass that always evaluates to True in boolean contexts.
@@ -9,7 +11,7 @@ class ForceMultipartDict(dict):
the dictionary is empty, which would normally evaluate to False.
"""
- def __bool__(self):
+ def __bool__(self) -> bool:
return True
diff --git a/skyvault/skyflow/generated/rest/core/http_client.py b/skyvault/skyflow/generated/rest/core/http_client.py
index e4173f99..3e5a7865 100644
--- a/skyvault/skyflow/generated/rest/core/http_client.py
+++ b/skyvault/skyflow/generated/rest/core/http_client.py
@@ -3,9 +3,9 @@
import asyncio
import email.utils
import re
+import socket
import time
import typing
-import urllib.parse
from contextlib import asynccontextmanager, contextmanager
from random import random
@@ -13,14 +13,48 @@
from .file import File, convert_file_dict_to_httpx_tuples
from .force_multipart import FORCE_MULTIPART
from .jsonable_encoder import jsonable_encoder
+from .logging import LogConfig, Logger, create_logger
from .query_encoder import encode_query
-from .remove_none_from_dict import remove_none_from_dict
+from .remove_none_from_dict import remove_none_from_dict as remove_none_from_dict
from .request_options import RequestOptions
from httpx._types import RequestFiles
-INITIAL_RETRY_DELAY_SECONDS = 0.5
-MAX_RETRY_DELAY_SECONDS = 10
-MAX_RETRY_DELAY_SECONDS_FROM_HEADER = 30
+INITIAL_RETRY_DELAY_SECONDS = 1.0
+MAX_RETRY_DELAY_SECONDS = 60.0
+JITTER_FACTOR = 0.2 # 20% random jitter
+
+
+def get_keepalive_socket_options(
+ idle: int = 60,
+ intvl: int = 30,
+ cnt: int = 5,
+) -> typing.List[typing.Tuple[int, int, int]]:
+ """
+ Build TCP keepalive socket options for the current platform.
+
+ Keepalive probes keep otherwise-idle connections alive so that long,
+ non-streaming requests survive idle-connection reaping by a firewall,
+ load balancer, or NAT. The available socket constants are OS-dependent,
+ so each option is guarded and only emitted when the platform defines it:
+
+ - ``SO_KEEPALIVE`` is portable (Linux/macOS/Windows).
+ - The idle-before-first-probe knob is ``TCP_KEEPIDLE`` on Linux and modern
+ Windows, but ``TCP_KEEPALIVE`` on macOS.
+ - ``TCP_KEEPINTVL`` / ``TCP_KEEPCNT`` exist on Linux/macOS/modern Windows.
+
+ Passing these tuples to ``httpx.HTTPTransport(socket_options=...)`` /
+ ``httpx.AsyncHTTPTransport(socket_options=...)`` applies them to every
+ connection the transport opens.
+ """
+ opts: typing.List[typing.Tuple[int, int, int]] = [(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)]
+ idle_const = getattr(socket, "TCP_KEEPIDLE", None) or getattr(socket, "TCP_KEEPALIVE", None)
+ if idle_const:
+ opts.append((socket.IPPROTO_TCP, idle_const, idle))
+ if hasattr(socket, "TCP_KEEPINTVL"):
+ opts.append((socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, intvl))
+ if hasattr(socket, "TCP_KEEPCNT"):
+ opts.append((socket.IPPROTO_TCP, socket.TCP_KEEPCNT, cnt))
+ return opts
def _parse_retry_after(response_headers: httpx.Headers) -> typing.Optional[float]:
@@ -64,6 +98,38 @@ def _parse_retry_after(response_headers: httpx.Headers) -> typing.Optional[float
return seconds
+def _add_positive_jitter(delay: float) -> float:
+ """Add positive jitter (0-20%) to prevent thundering herd."""
+ jitter_multiplier = 1 + random() * JITTER_FACTOR
+ return delay * jitter_multiplier
+
+
+def _add_symmetric_jitter(delay: float) -> float:
+ """Add symmetric jitter (±10%) for exponential backoff."""
+ jitter_multiplier = 1 + (random() - 0.5) * JITTER_FACTOR
+ return delay * jitter_multiplier
+
+
+def _parse_x_ratelimit_reset(response_headers: httpx.Headers) -> typing.Optional[float]:
+ """
+ Parse the X-RateLimit-Reset header (Unix timestamp in seconds).
+ Returns seconds to wait, or None if header is missing/invalid.
+ """
+ reset_time_str = response_headers.get("x-ratelimit-reset")
+ if reset_time_str is None:
+ return None
+
+ try:
+ reset_time = int(reset_time_str)
+ delay = reset_time - time.time()
+ if delay > 0:
+ return delay
+ except (ValueError, TypeError):
+ pass
+
+ return None
+
+
def _retry_timeout(response: httpx.Response, retries: int) -> float:
"""
Determine the amount of time to wait before retrying a request.
@@ -71,22 +137,94 @@ def _retry_timeout(response: httpx.Response, retries: int) -> float:
with a jitter to determine the number of seconds to wait.
"""
- # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says.
+ # 1. Check Retry-After header first
retry_after = _parse_retry_after(response.headers)
- if retry_after is not None and retry_after <= MAX_RETRY_DELAY_SECONDS_FROM_HEADER:
- return retry_after
+ if retry_after is not None and retry_after > 0:
+ return min(retry_after, MAX_RETRY_DELAY_SECONDS)
+
+ # 2. Check X-RateLimit-Reset header (with positive jitter)
+ ratelimit_reset = _parse_x_ratelimit_reset(response.headers)
+ if ratelimit_reset is not None:
+ return _add_positive_jitter(min(ratelimit_reset, MAX_RETRY_DELAY_SECONDS))
- # Apply exponential backoff, capped at MAX_RETRY_DELAY_SECONDS.
- retry_delay = min(INITIAL_RETRY_DELAY_SECONDS * pow(2.0, retries), MAX_RETRY_DELAY_SECONDS)
+ # 3. Fall back to exponential backoff (with symmetric jitter)
+ backoff = min(INITIAL_RETRY_DELAY_SECONDS * pow(2.0, retries), MAX_RETRY_DELAY_SECONDS)
+ return _add_symmetric_jitter(backoff)
- # Add a randomness / jitter to the retry delay to avoid overwhelming the server with retries.
- timeout = retry_delay * (1 - 0.25 * random())
- return timeout if timeout >= 0 else 0
+
+def _retry_timeout_from_retries(retries: int) -> float:
+ """Determine retry timeout using exponential backoff when no response is available."""
+ backoff = min(INITIAL_RETRY_DELAY_SECONDS * pow(2.0, retries), MAX_RETRY_DELAY_SECONDS)
+ return _add_symmetric_jitter(backoff)
def _should_retry(response: httpx.Response) -> bool:
- retryable_400s = [429, 408, 409]
- return response.status_code >= 500 or response.status_code in retryable_400s
+ return response.status_code >= 500 or response.status_code in [429, 408, 409]
+
+
+_SENSITIVE_HEADERS = frozenset(
+ {
+ "authorization",
+ "www-authenticate",
+ "x-api-key",
+ "api-key",
+ "apikey",
+ "x-api-token",
+ "x-auth-token",
+ "auth-token",
+ "cookie",
+ "set-cookie",
+ "proxy-authorization",
+ "proxy-authenticate",
+ "x-csrf-token",
+ "x-xsrf-token",
+ "x-session-token",
+ "x-access-token",
+ }
+)
+
+
+def _redact_headers(headers: typing.Dict[str, str]) -> typing.Dict[str, str]:
+ return {k: ("[REDACTED]" if k.lower() in _SENSITIVE_HEADERS else v) for k, v in headers.items()}
+
+
+def _build_url(base_url: str, path: typing.Optional[str]) -> str:
+ """
+ Build a full URL by joining a base URL with a path.
+
+ This function correctly handles base URLs that contain path prefixes (e.g., tenant-based URLs)
+ by using string concatenation instead of urllib.parse.urljoin(), which would incorrectly
+ strip path components when the path starts with '/'.
+
+ Example:
+ >>> _build_url("https://cloud.example.com/org/tenant/api", "/users")
+ 'https://cloud.example.com/org/tenant/api/users'
+
+ Args:
+ base_url: The base URL, which may contain path prefixes.
+ path: The path to append. Can be None or empty string.
+
+ Returns:
+ The full URL with base_url and path properly joined.
+ """
+ if not path:
+ return base_url
+ return f"{base_url.rstrip('/')}/{path.lstrip('/')}"
+
+
+def _maybe_filter_none_from_multipart_data(
+ data: typing.Optional[typing.Any],
+ request_files: typing.Optional[RequestFiles],
+ force_multipart: typing.Optional[bool],
+) -> typing.Optional[typing.Any]:
+ """
+ Filter None values from data body for multipart/form requests.
+ This prevents httpx from converting None to empty strings in multipart encoding.
+ Only applies when files are present or force_multipart is True.
+ """
+ if data is not None and isinstance(data, typing.Mapping) and (request_files or force_multipart):
+ return remove_none_from_dict(data)
+ return data
def remove_omit_from_dict(
@@ -134,7 +272,16 @@ def get_request_body(
data: typing.Optional[typing.Any],
request_options: typing.Optional[RequestOptions],
omit: typing.Optional[typing.Any],
+ optional_body: bool = False,
) -> typing.Tuple[typing.Optional[typing.Any], typing.Optional[typing.Any]]:
+ # A whole body left at the sentinel was never passed by the caller, so it is absent
+ # rather than empty: the request carries no content and no `Content-Type`.
+ if omit is not None:
+ if json is omit:
+ json = None
+ if data is omit:
+ data = None
+
json_body = None
data_body = None
if data is not None:
@@ -143,8 +290,41 @@ def get_request_body(
# If both data and json are None, we send json data in the event extra properties are specified
json_body = maybe_filter_request_body(json, request_options, omit)
- # If you have an empty JSON body, you should just send None
- return (json_body if json_body != {} else None), data_body if data_body != {} else None
+ has_additional_body_parameters = bool(
+ request_options is not None and request_options.get("additional_body_parameters")
+ )
+
+ # Only collapse empty dict to None when the body was not explicitly provided
+ # and there are no additional body parameters. This preserves explicit empty
+ # bodies (e.g., when an endpoint has a request body type but all fields are optional).
+ # `optional_body` marks an endpoint whose body the API does not require, where a body
+ # that ends up empty means the caller passed none of its properties, so the request is
+ # sent with no content and no `Content-Type`.
+ if json_body == {} and (json is None or optional_body) and not has_additional_body_parameters:
+ json_body = None
+ if data_body == {} and (data is None or optional_body) and not has_additional_body_parameters:
+ data_body = None
+
+ return json_body, data_body
+
+
+def drop_content_type_without_body(
+ headers: typing.Dict[str, typing.Any],
+ *,
+ json_body: typing.Optional[typing.Any],
+ data_body: typing.Optional[typing.Any],
+ optional_body: bool,
+) -> typing.Dict[str, typing.Any]:
+ """Strip ``Content-Type`` from a request that carries no body.
+
+ ``get_request_body`` drops the body of an ``optional_body`` endpoint when the caller
+ supplied none of it, but the endpoint still passes the content type it would have used.
+ A request that sends nothing must not advertise a media type, so a server that branches
+ on the header sees a bodyless call for what it is.
+ """
+ if not optional_body or json_body is not None or data_body is not None:
+ return headers
+ return {key: value for key, value in headers.items() if key.lower() != "content-type"}
class HttpClient:
@@ -155,11 +335,15 @@ def __init__(
base_timeout: typing.Callable[[], typing.Optional[float]],
base_headers: typing.Callable[[], typing.Dict[str, str]],
base_url: typing.Optional[typing.Callable[[], str]] = None,
+ base_max_retries: int = 2,
+ logging_config: typing.Optional[typing.Union[LogConfig, Logger]] = None,
):
self.base_url = base_url
self.base_timeout = base_timeout
self.base_headers = base_headers
+ self.base_max_retries = base_max_retries
self.httpx_client = httpx_client
+ self.logger = create_logger(logging_config)
def get_base_url(self, maybe_base_url: typing.Optional[str]) -> str:
base_url = maybe_base_url
@@ -188,18 +372,24 @@ def request(
] = None,
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
request_options: typing.Optional[RequestOptions] = None,
- retries: int = 2,
+ retries: int = 0,
omit: typing.Optional[typing.Any] = None,
+ optional_body: bool = False,
force_multipart: typing.Optional[bool] = None,
) -> httpx.Response:
base_url = self.get_base_url(base_url)
- timeout = (
- request_options.get("timeout_in_seconds")
+ _timeout = (
+ request_options.get("timeout")
+ if request_options is not None and request_options.get("timeout") is not None
+ else request_options.get("timeout_in_seconds")
if request_options is not None and request_options.get("timeout_in_seconds") is not None
else self.base_timeout()
)
+ timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT
- json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+ json_body, data_body = get_request_body(
+ json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body
+ )
request_files: typing.Optional[RequestFiles] = (
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
@@ -210,45 +400,91 @@ def request(
if (request_files is None or len(request_files) == 0) and force_multipart:
request_files = FORCE_MULTIPART
- response = self.httpx_client.request(
- method=method,
- url=urllib.parse.urljoin(f"{base_url}/", path),
- headers=jsonable_encoder(
+ data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
+
+ # Compute encoded params separately to avoid passing empty list to httpx
+ # (httpx strips existing query params from URL when params=[] is passed)
+ _encoded_params = encode_query(
+ jsonable_encoder(
remove_none_from_dict(
- {
- **self.base_headers(),
- **(headers if headers is not None else {}),
- **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}),
- }
- )
- ),
- params=encode_query(
- jsonable_encoder(
- remove_none_from_dict(
- remove_omit_from_dict(
- {
- **(params if params is not None else {}),
- **(
- request_options.get("additional_query_parameters", {}) or {}
- if request_options is not None
- else {}
- ),
- },
- omit,
- )
+ remove_omit_from_dict(
+ {
+ **(params if params is not None else {}),
+ **(
+ request_options.get("additional_query_parameters", {}) or {}
+ if request_options is not None
+ else {}
+ ),
+ },
+ omit,
)
)
- ),
- json=json_body,
- data=data_body,
- content=content,
- files=request_files,
- timeout=timeout,
+ )
+ )
+
+ _request_url = _build_url(base_url, path)
+ _request_headers = jsonable_encoder(
+ remove_none_from_dict(
+ {
+ **self.base_headers(),
+ **(headers if headers is not None else {}),
+ **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}),
+ }
+ )
+ )
+ _request_headers = drop_content_type_without_body(
+ _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body
+ )
+
+ if self.logger.is_debug():
+ self.logger.debug(
+ "Making HTTP request",
+ method=method,
+ url=_request_url,
+ headers=_redact_headers(_request_headers),
+ has_body=json_body is not None or data_body is not None,
+ )
+
+ max_retries: int = (
+ request_options.get("max_retries", self.base_max_retries)
+ if request_options is not None
+ else self.base_max_retries
)
- max_retries: int = request_options.get("max_retries", 0) if request_options is not None else 0
+ try:
+ response = self.httpx_client.request(
+ method=method,
+ url=_request_url,
+ headers=_request_headers,
+ params=_encoded_params if _encoded_params else None,
+ json=json_body,
+ data=data_body,
+ content=content,
+ files=request_files,
+ timeout=timeout,
+ )
+ except (httpx.ConnectError, httpx.RemoteProtocolError):
+ if retries < max_retries:
+ time.sleep(_retry_timeout_from_retries(retries=retries))
+ return self.request(
+ path=path,
+ method=method,
+ base_url=base_url,
+ params=params,
+ json=json,
+ data=data,
+ content=content,
+ files=files,
+ headers=headers,
+ request_options=request_options,
+ retries=retries + 1,
+ omit=omit,
+ force_multipart=force_multipart,
+ )
+ raise
+
if _should_retry(response=response):
- if max_retries > retries:
+ if retries < max_retries:
time.sleep(_retry_timeout(response=response, retries=retries))
return self.request(
path=path,
@@ -256,12 +492,32 @@ def request(
base_url=base_url,
params=params,
json=json,
+ data=data,
content=content,
files=files,
headers=headers,
request_options=request_options,
retries=retries + 1,
omit=omit,
+ force_multipart=force_multipart,
+ )
+
+ if self.logger.is_debug():
+ if 200 <= response.status_code < 400:
+ self.logger.debug(
+ "HTTP request succeeded",
+ method=method,
+ url=_request_url,
+ status_code=response.status_code,
+ )
+
+ if self.logger.is_error():
+ if response.status_code >= 400:
+ self.logger.error(
+ "HTTP request failed with error status",
+ method=method,
+ url=_request_url,
+ status_code=response.status_code,
)
return response
@@ -285,16 +541,20 @@ def stream(
] = None,
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
request_options: typing.Optional[RequestOptions] = None,
- retries: int = 2,
+ retries: int = 0,
omit: typing.Optional[typing.Any] = None,
+ optional_body: bool = False,
force_multipart: typing.Optional[bool] = None,
) -> typing.Iterator[httpx.Response]:
base_url = self.get_base_url(base_url)
- timeout = (
- request_options.get("timeout_in_seconds")
+ _timeout = (
+ request_options.get("timeout")
+ if request_options is not None and request_options.get("timeout") is not None
+ else request_options.get("timeout_in_seconds")
if request_options is not None and request_options.get("timeout_in_seconds") is not None
else self.base_timeout()
)
+ timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT
request_files: typing.Optional[RequestFiles] = (
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
@@ -305,37 +565,59 @@ def stream(
if (request_files is None or len(request_files) == 0) and force_multipart:
request_files = FORCE_MULTIPART
- json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+ json_body, data_body = get_request_body(
+ json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body
+ )
+
+ data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
- with self.httpx_client.stream(
- method=method,
- url=urllib.parse.urljoin(f"{base_url}/", path),
- headers=jsonable_encoder(
+ # Compute encoded params separately to avoid passing empty list to httpx
+ # (httpx strips existing query params from URL when params=[] is passed)
+ _encoded_params = encode_query(
+ jsonable_encoder(
remove_none_from_dict(
- {
- **self.base_headers(),
- **(headers if headers is not None else {}),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- params=encode_query(
- jsonable_encoder(
- remove_none_from_dict(
- remove_omit_from_dict(
- {
- **(params if params is not None else {}),
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- },
- omit,
- )
+ remove_omit_from_dict(
+ {
+ **(params if params is not None else {}),
+ **(
+ request_options.get("additional_query_parameters", {})
+ if request_options is not None
+ else {}
+ ),
+ },
+ omit,
)
)
- ),
+ )
+ )
+
+ _request_url = _build_url(base_url, path)
+ _request_headers = jsonable_encoder(
+ remove_none_from_dict(
+ {
+ **self.base_headers(),
+ **(headers if headers is not None else {}),
+ **(request_options.get("additional_headers", {}) if request_options is not None else {}),
+ }
+ )
+ )
+ _request_headers = drop_content_type_without_body(
+ _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body
+ )
+
+ if self.logger.is_debug():
+ self.logger.debug(
+ "Making streaming HTTP request",
+ method=method,
+ url=_request_url,
+ headers=_redact_headers(_request_headers),
+ )
+
+ with self.httpx_client.stream(
+ method=method,
+ url=_request_url,
+ headers=_request_headers,
+ params=_encoded_params if _encoded_params else None,
json=json_body,
data=data_body,
content=content,
@@ -353,11 +635,22 @@ def __init__(
base_timeout: typing.Callable[[], typing.Optional[float]],
base_headers: typing.Callable[[], typing.Dict[str, str]],
base_url: typing.Optional[typing.Callable[[], str]] = None,
+ base_max_retries: int = 2,
+ async_base_headers: typing.Optional[typing.Callable[[], typing.Awaitable[typing.Dict[str, str]]]] = None,
+ logging_config: typing.Optional[typing.Union[LogConfig, Logger]] = None,
):
self.base_url = base_url
self.base_timeout = base_timeout
self.base_headers = base_headers
+ self.base_max_retries = base_max_retries
+ self.async_base_headers = async_base_headers
self.httpx_client = httpx_client
+ self.logger = create_logger(logging_config)
+
+ async def _get_headers(self) -> typing.Dict[str, str]:
+ if self.async_base_headers is not None:
+ return await self.async_base_headers()
+ return self.base_headers()
def get_base_url(self, maybe_base_url: typing.Optional[str]) -> str:
base_url = maybe_base_url
@@ -386,16 +679,20 @@ async def request(
] = None,
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
request_options: typing.Optional[RequestOptions] = None,
- retries: int = 2,
+ retries: int = 0,
omit: typing.Optional[typing.Any] = None,
+ optional_body: bool = False,
force_multipart: typing.Optional[bool] = None,
) -> httpx.Response:
base_url = self.get_base_url(base_url)
- timeout = (
- request_options.get("timeout_in_seconds")
+ _timeout = (
+ request_options.get("timeout")
+ if request_options is not None and request_options.get("timeout") is not None
+ else request_options.get("timeout_in_seconds")
if request_options is not None and request_options.get("timeout_in_seconds") is not None
else self.base_timeout()
)
+ timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT
request_files: typing.Optional[RequestFiles] = (
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
@@ -406,48 +703,98 @@ async def request(
if (request_files is None or len(request_files) == 0) and force_multipart:
request_files = FORCE_MULTIPART
- json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+ json_body, data_body = get_request_body(
+ json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body
+ )
- # Add the input to each of these and do None-safety checks
- response = await self.httpx_client.request(
- method=method,
- url=urllib.parse.urljoin(f"{base_url}/", path),
- headers=jsonable_encoder(
+ data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
+
+ # Get headers (supports async token providers)
+ _headers = await self._get_headers()
+
+ # Compute encoded params separately to avoid passing empty list to httpx
+ # (httpx strips existing query params from URL when params=[] is passed)
+ _encoded_params = encode_query(
+ jsonable_encoder(
remove_none_from_dict(
- {
- **self.base_headers(),
- **(headers if headers is not None else {}),
- **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}),
- }
- )
- ),
- params=encode_query(
- jsonable_encoder(
- remove_none_from_dict(
- remove_omit_from_dict(
- {
- **(params if params is not None else {}),
- **(
- request_options.get("additional_query_parameters", {}) or {}
- if request_options is not None
- else {}
- ),
- },
- omit,
- )
+ remove_omit_from_dict(
+ {
+ **(params if params is not None else {}),
+ **(
+ request_options.get("additional_query_parameters", {}) or {}
+ if request_options is not None
+ else {}
+ ),
+ },
+ omit,
)
)
- ),
- json=json_body,
- data=data_body,
- content=content,
- files=request_files,
- timeout=timeout,
+ )
+ )
+
+ _request_url = _build_url(base_url, path)
+ _request_headers = jsonable_encoder(
+ remove_none_from_dict(
+ {
+ **_headers,
+ **(headers if headers is not None else {}),
+ **(request_options.get("additional_headers", {}) or {} if request_options is not None else {}),
+ }
+ )
+ )
+ _request_headers = drop_content_type_without_body(
+ _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body
+ )
+
+ if self.logger.is_debug():
+ self.logger.debug(
+ "Making HTTP request",
+ method=method,
+ url=_request_url,
+ headers=_redact_headers(_request_headers),
+ has_body=json_body is not None or data_body is not None,
+ )
+
+ max_retries: int = (
+ request_options.get("max_retries", self.base_max_retries)
+ if request_options is not None
+ else self.base_max_retries
)
- max_retries: int = request_options.get("max_retries", 0) if request_options is not None else 0
+ try:
+ response = await self.httpx_client.request(
+ method=method,
+ url=_request_url,
+ headers=_request_headers,
+ params=_encoded_params if _encoded_params else None,
+ json=json_body,
+ data=data_body,
+ content=content,
+ files=request_files,
+ timeout=timeout,
+ )
+ except (httpx.ConnectError, httpx.RemoteProtocolError):
+ if retries < max_retries:
+ await asyncio.sleep(_retry_timeout_from_retries(retries=retries))
+ return await self.request(
+ path=path,
+ method=method,
+ base_url=base_url,
+ params=params,
+ json=json,
+ data=data,
+ content=content,
+ files=files,
+ headers=headers,
+ request_options=request_options,
+ retries=retries + 1,
+ omit=omit,
+ force_multipart=force_multipart,
+ )
+ raise
+
if _should_retry(response=response):
- if max_retries > retries:
+ if retries < max_retries:
await asyncio.sleep(_retry_timeout(response=response, retries=retries))
return await self.request(
path=path,
@@ -455,13 +802,34 @@ async def request(
base_url=base_url,
params=params,
json=json,
+ data=data,
content=content,
files=files,
headers=headers,
request_options=request_options,
retries=retries + 1,
omit=omit,
+ force_multipart=force_multipart,
+ )
+
+ if self.logger.is_debug():
+ if 200 <= response.status_code < 400:
+ self.logger.debug(
+ "HTTP request succeeded",
+ method=method,
+ url=_request_url,
+ status_code=response.status_code,
+ )
+
+ if self.logger.is_error():
+ if response.status_code >= 400:
+ self.logger.error(
+ "HTTP request failed with error status",
+ method=method,
+ url=_request_url,
+ status_code=response.status_code,
)
+
return response
@asynccontextmanager
@@ -483,16 +851,20 @@ async def stream(
] = None,
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
request_options: typing.Optional[RequestOptions] = None,
- retries: int = 2,
+ retries: int = 0,
omit: typing.Optional[typing.Any] = None,
+ optional_body: bool = False,
force_multipart: typing.Optional[bool] = None,
) -> typing.AsyncIterator[httpx.Response]:
base_url = self.get_base_url(base_url)
- timeout = (
- request_options.get("timeout_in_seconds")
+ _timeout = (
+ request_options.get("timeout")
+ if request_options is not None and request_options.get("timeout") is not None
+ else request_options.get("timeout_in_seconds")
if request_options is not None and request_options.get("timeout_in_seconds") is not None
else self.base_timeout()
)
+ timeout = _timeout if _timeout is not None else httpx.USE_CLIENT_DEFAULT
request_files: typing.Optional[RequestFiles] = (
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
@@ -503,37 +875,62 @@ async def stream(
if (request_files is None or len(request_files) == 0) and force_multipart:
request_files = FORCE_MULTIPART
- json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
+ json_body, data_body = get_request_body(
+ json=json, data=data, request_options=request_options, omit=omit, optional_body=optional_body
+ )
- async with self.httpx_client.stream(
- method=method,
- url=urllib.parse.urljoin(f"{base_url}/", path),
- headers=jsonable_encoder(
+ data_body = _maybe_filter_none_from_multipart_data(data_body, request_files, force_multipart)
+
+ # Get headers (supports async token providers)
+ _headers = await self._get_headers()
+
+ # Compute encoded params separately to avoid passing empty list to httpx
+ # (httpx strips existing query params from URL when params=[] is passed)
+ _encoded_params = encode_query(
+ jsonable_encoder(
remove_none_from_dict(
- {
- **self.base_headers(),
- **(headers if headers is not None else {}),
- **(request_options.get("additional_headers", {}) if request_options is not None else {}),
- }
- )
- ),
- params=encode_query(
- jsonable_encoder(
- remove_none_from_dict(
- remove_omit_from_dict(
- {
- **(params if params is not None else {}),
- **(
- request_options.get("additional_query_parameters", {})
- if request_options is not None
- else {}
- ),
- },
- omit=omit,
- )
+ remove_omit_from_dict(
+ {
+ **(params if params is not None else {}),
+ **(
+ request_options.get("additional_query_parameters", {})
+ if request_options is not None
+ else {}
+ ),
+ },
+ omit=omit,
)
)
- ),
+ )
+ )
+
+ _request_url = _build_url(base_url, path)
+ _request_headers = jsonable_encoder(
+ remove_none_from_dict(
+ {
+ **_headers,
+ **(headers if headers is not None else {}),
+ **(request_options.get("additional_headers", {}) if request_options is not None else {}),
+ }
+ )
+ )
+ _request_headers = drop_content_type_without_body(
+ _request_headers, json_body=json_body, data_body=data_body, optional_body=optional_body
+ )
+
+ if self.logger.is_debug():
+ self.logger.debug(
+ "Making streaming HTTP request",
+ method=method,
+ url=_request_url,
+ headers=_redact_headers(_request_headers),
+ )
+
+ async with self.httpx_client.stream(
+ method=method,
+ url=_request_url,
+ headers=_request_headers,
+ params=_encoded_params if _encoded_params else None,
json=json_body,
data=data_body,
content=content,
diff --git a/skyvault/skyflow/generated/rest/core/http_response.py b/skyvault/skyflow/generated/rest/core/http_response.py
index 48a1798a..9aa1e188 100644
--- a/skyvault/skyflow/generated/rest/core/http_response.py
+++ b/skyvault/skyflow/generated/rest/core/http_response.py
@@ -4,12 +4,12 @@
import httpx
+# Generic to represent the underlying type of the data wrapped by the HTTP response.
T = TypeVar("T")
-"""Generic to represent the underlying type of the data wrapped by the HTTP response."""
class BaseHttpResponse:
- """Minimalist HTTP response wrapper that exposes response headers."""
+ """Minimalist HTTP response wrapper that exposes response headers and status code."""
_response: httpx.Response
@@ -20,6 +20,14 @@ def __init__(self, response: httpx.Response):
def headers(self) -> Dict[str, str]:
return dict(self._response.headers)
+ @property
+ def status_code(self) -> int:
+ return self._response.status_code
+
+ @property
+ def response(self) -> httpx.Response:
+ return self._response
+
class HttpResponse(Generic[T], BaseHttpResponse):
"""HTTP response wrapper that exposes response headers and data."""
diff --git a/skyvault/skyflow/generated/rest/core/http_sse/__init__.py b/skyvault/skyflow/generated/rest/core/http_sse/__init__.py
new file mode 100644
index 00000000..730e5a33
--- /dev/null
+++ b/skyvault/skyflow/generated/rest/core/http_sse/__init__.py
@@ -0,0 +1,42 @@
+# This file was auto-generated by Fern from our API Definition.
+
+# isort: skip_file
+
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from ._api import EventSource, aconnect_sse, connect_sse
+ from ._exceptions import SSEError
+ from ._models import ServerSentEvent
+_dynamic_imports: typing.Dict[str, str] = {
+ "EventSource": "._api",
+ "SSEError": "._exceptions",
+ "ServerSentEvent": "._models",
+ "aconnect_sse": "._api",
+ "connect_sse": "._api",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
+
+__all__ = ["EventSource", "SSEError", "ServerSentEvent", "aconnect_sse", "connect_sse"]
diff --git a/skyvault/skyflow/generated/rest/core/http_sse/_api.py b/skyvault/skyflow/generated/rest/core/http_sse/_api.py
new file mode 100644
index 00000000..9ca5602c
--- /dev/null
+++ b/skyvault/skyflow/generated/rest/core/http_sse/_api.py
@@ -0,0 +1,455 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import codecs
+import re
+import time
+from contextlib import asynccontextmanager, contextmanager
+from typing import (
+ Any,
+ AsyncContextManager,
+ AsyncGenerator,
+ AsyncIterator,
+ Callable,
+ ContextManager,
+ Iterator,
+ Optional,
+)
+
+import anyio
+import httpx
+from ._decoders import SSEDecoder
+from ._exceptions import SSEError
+from ._models import ServerSentEvent
+
+MAX_LINE_SIZE: int = 1_048_576 # 1 MiB
+
+# Reconnection defaults, mirroring the TypeScript SDK's Stream implementation.
+DEFAULT_MAX_RECONNECTION_ATTEMPTS: int = 5
+DEFAULT_RECONNECT_DELAY_MS: int = 1_000
+MAX_RECONNECT_DELAY_MS: int = 30_000
+
+
+# A reconnect callback re-issues the original request (with a ``Last-Event-ID``
+# header set to the supplied event id) and returns a *context manager* yielding
+# a fresh streaming ``httpx.Response``. Sync clients supply a sync context
+# manager; async clients supply an async one.
+class EventSource:
+ def __init__(
+ self,
+ response: httpx.Response,
+ *,
+ resumable: bool = False,
+ stream_reconnection_enabled: bool = True,
+ max_stream_reconnection_attempts: Optional[int] = None,
+ stream_terminator: Optional[str] = None,
+ reconnect: Optional[Callable[[str], Any]] = None,
+ ) -> None:
+ self._response = response
+ self._resumable = resumable
+ self._stream_reconnection_enabled = stream_reconnection_enabled
+ self._max_stream_reconnection_attempts = max_stream_reconnection_attempts
+ self._stream_terminator = stream_terminator
+ self._reconnect = reconnect
+
+ @staticmethod
+ def _is_event_stream(response: httpx.Response) -> bool:
+ content_type = response.headers.get("content-type", "").partition(";")[0]
+ return "text/event-stream" in content_type
+
+ def _check_content_type(self) -> None:
+ if not self._is_event_stream(self._response):
+ content_type = self._response.headers.get("content-type", "").partition(";")[0]
+ raise SSEError(
+ f"Expected response header Content-Type to contain 'text/event-stream', got {content_type!r}"
+ )
+
+ def _is_reconnect_response_usable(self, response: httpx.Response) -> bool:
+ """Whether a reconnected response can be resumed as an SSE stream.
+
+ ``httpx.stream`` does not raise on non-success status, so a resume that
+ returns an error page (e.g. ``200 text/html`` or a ``500`` body) would
+ otherwise be parsed as SSE and yield garbage/zero events. Such a
+ response is treated as a failed attempt (back off and retry) instead.
+ """
+ return response.status_code < 400 and self._is_event_stream(response)
+
+ def _get_charset(self, response: Optional[httpx.Response] = None) -> str:
+ """Extract charset from Content-Type header, fallback to UTF-8."""
+ resolved = response if response is not None else self._response
+ content_type = resolved.headers.get("content-type", "")
+
+ # Parse charset parameter using regex
+ charset_match = re.search(r"charset=([^;\s]+)", content_type, re.IGNORECASE)
+ if charset_match:
+ charset = charset_match.group(1).strip("\"'")
+ # Validate that it's a known encoding
+ try:
+ # Test if the charset is valid by trying to encode/decode
+ "test".encode(charset).decode(charset)
+ return charset
+ except (LookupError, UnicodeError):
+ # If charset is invalid, fall back to UTF-8
+ pass
+
+ # Default to UTF-8 if no charset specified or invalid charset
+ return "utf-8"
+
+ @property
+ def response(self) -> httpx.Response:
+ return self._response
+
+ @staticmethod
+ def _normalize_sse_line_endings(buf: str) -> str:
+ """Normalize line endings per the SSE spec (\\r\\n → \\n, bare \\r → \\n).
+
+ A trailing \\r is preserved because it may pair with a leading \\n in
+ the next chunk to form a single \\r\\n terminator.
+ """
+ buf = buf.replace("\r\n", "\n")
+ if buf.endswith("\r"):
+ return buf[:-1].replace("\r", "\n") + "\r"
+ return buf.replace("\r", "\n")
+
+ def _new_text_decoder(self, response: Optional[httpx.Response] = None) -> "codecs.IncrementalDecoder":
+ return codecs.getincrementaldecoder(self._get_charset(response))(errors="replace")
+
+ def _reconnect_applicable(self) -> bool:
+ """Whether reconnection is configured for this stream at all.
+
+ This is the terminator-gating half of the reconnect decision, kept
+ separate from :meth:`_should_reconnect` (which additionally requires a
+ last *dispatched* id and an unexhausted attempt budget). The split lets
+ a mid-stream transport error terminate consistently:
+ - a stream that can never reconnect (non-resumable, no terminator,
+ disabled, or no callback) must re-raise the error to the caller, so a
+ truncated stream is not mistaken for a clean completion;
+ - a resumable stream that has merely run out of attempts (or has no id
+ to resume from) ends cleanly — the same way an exhausted empty/error
+ -body resume already does, matching the TypeScript ``return``.
+ """
+ return (
+ self._resumable
+ and self._stream_terminator is not None
+ and self._stream_reconnection_enabled
+ and self._reconnect is not None
+ )
+
+ def _should_reconnect(self, last_dispatched_id: Optional[str], reconnect_attempts: int) -> bool:
+ """Decide whether a prematurely-ended stream should be reconnected.
+
+ Mirrors the TypeScript ``shouldReconnect`` gating:
+ - only resumable SSE endpoints with a configured terminator, reconnect
+ enabled, and a reconnect callback are eligible (see
+ :meth:`_reconnect_applicable`);
+ - a last *dispatched* event id must exist to resume from;
+ - the consecutive-failed-attempt cap must not be exceeded.
+ """
+ if not self._reconnect_applicable():
+ return False
+ if not last_dispatched_id:
+ return False
+ max_attempts = (
+ self._max_stream_reconnection_attempts
+ if self._max_stream_reconnection_attempts is not None
+ else DEFAULT_MAX_RECONNECTION_ATTEMPTS
+ )
+ if reconnect_attempts >= max_attempts:
+ return False
+ return True
+
+ def _reconnect_delay_seconds(self, last_retry: Optional[int]) -> float:
+ """Backoff before a reconnect.
+
+ Uses the server's most recent ``retry:`` directive (milliseconds) when
+ present, otherwise a default of ``DEFAULT_RECONNECT_DELAY_MS``, clamped
+ to ``MAX_RECONNECT_DELAY_MS``.
+ """
+ base_ms = last_retry if (last_retry is not None and last_retry > 0) else DEFAULT_RECONNECT_DELAY_MS
+ return min(base_ms, MAX_RECONNECT_DELAY_MS) / 1000.0
+
+ def _sleep_before_reconnect(self, last_retry: Optional[int]) -> None:
+ # ``time.sleep`` blocks the calling thread but remains interruptible by
+ # signals (e.g. ``KeyboardInterrupt``), which propagate out and abort
+ # the reconnect without issuing another request.
+ time.sleep(self._reconnect_delay_seconds(last_retry))
+
+ async def _asleep_before_reconnect(self, last_retry: Optional[int]) -> None:
+ # ``anyio.sleep`` is cancellation-aware: if the consumer cancels the task
+ # or closes the async generator mid-delay, this raises (and no further
+ # request is issued) instead of blocking for the whole interval.
+ await anyio.sleep(self._reconnect_delay_seconds(last_retry))
+
+ def _decode_response(
+ self,
+ response: httpx.Response,
+ decoder: SSEDecoder,
+ text_decoder: "codecs.IncrementalDecoder",
+ ) -> Iterator[ServerSentEvent]:
+ buf = ""
+ for chunk in response.iter_bytes():
+ buf += text_decoder.decode(chunk)
+ buf = self._normalize_sse_line_endings(buf)
+
+ while "\n" in buf:
+ line, buf = buf.split("\n", 1)
+ sse = decoder.decode(line)
+ if sse is not None:
+ yield sse
+
+ if len(buf) > MAX_LINE_SIZE:
+ raise SSEError(
+ f"SSE line exceeded maximum size of {MAX_LINE_SIZE} characters without encountering a newline"
+ )
+
+ yield from self._flush_decoder(buf, decoder, text_decoder)
+
+ async def _adecode_response(
+ self,
+ response: httpx.Response,
+ decoder: SSEDecoder,
+ text_decoder: "codecs.IncrementalDecoder",
+ ) -> AsyncGenerator[ServerSentEvent, None]:
+ buf = ""
+ async for chunk in response.aiter_bytes():
+ buf += text_decoder.decode(chunk)
+ buf = self._normalize_sse_line_endings(buf)
+
+ while "\n" in buf:
+ line, buf = buf.split("\n", 1)
+ sse = decoder.decode(line)
+ if sse is not None:
+ yield sse
+
+ if len(buf) > MAX_LINE_SIZE:
+ raise SSEError(
+ f"SSE line exceeded maximum size of {MAX_LINE_SIZE} characters without encountering a newline"
+ )
+
+ for sse in self._flush_decoder(buf, decoder, text_decoder):
+ yield sse
+
+ def _flush_decoder(
+ self,
+ buf: str,
+ decoder: SSEDecoder,
+ text_decoder: "codecs.IncrementalDecoder",
+ ) -> Iterator[ServerSentEvent]:
+ # Flush any remaining bytes from the incremental decoder
+ buf += text_decoder.decode(b"", final=True)
+ buf = buf.replace("\r\n", "\n").replace("\r", "\n")
+
+ if len(buf) > MAX_LINE_SIZE:
+ raise SSEError(
+ f"SSE line exceeded maximum size of {MAX_LINE_SIZE} characters without encountering a newline"
+ )
+
+ while "\n" in buf:
+ line, buf = buf.split("\n", 1)
+ sse = decoder.decode(line)
+ if sse is not None:
+ yield sse
+
+ if buf.strip():
+ sse = decoder.decode(buf)
+ if sse is not None:
+ yield sse
+
+ def iter_sse(self) -> Iterator[ServerSentEvent]:
+ self._check_content_type()
+ decoder = SSEDecoder()
+ text_decoder = self._new_text_decoder()
+
+ last_dispatched_id: Optional[str] = None
+ last_retry: Optional[int] = None
+ # Consecutive failed reconnection attempts. Reset to 0 whenever an event
+ # is successfully dispatched (reset-on-progress) — matching browser
+ # `EventSource` semantics: a server that emits >=1 event then drops on
+ # every connection can reconnect indefinitely.
+ reconnect_attempts = 0
+
+ # ``None`` means there is no live stream to read this iteration (e.g. a
+ # failed reconnect); the loop then re-evaluates the reconnect decision
+ # without re-reading an exhausted response.
+ response: Optional[httpx.Response] = self._response
+ # Context manager for a response we opened ourselves and must close.
+ # The initial response is owned by the caller, so it starts as None.
+ owned_cm: Optional[ContextManager[httpx.Response]] = None
+ try:
+ while True:
+ if response is not None:
+ events = self._decode_response(response, decoder, text_decoder)
+ while True:
+ try:
+ sse = next(events)
+ except StopIteration:
+ break
+ except SSEError:
+ # A protocol violation (e.g. an oversized line) is a
+ # genuine error, not a dropped connection; propagate it.
+ # Listed first because ``SSEError`` subclasses
+ # ``httpx.TransportError``.
+ raise
+ except httpx.TransportError:
+ # A transport error mid-stream (e.g. the server dropped
+ # the connection: ``ReadError``/``RemoteProtocolError``)
+ # is a premature end. Only swallow it when reconnection
+ # is configured for this stream; otherwise re-raise so a
+ # non-resumable stream still surfaces the error to the
+ # caller instead of looking like a clean completion.
+ # When reconnection is applicable but the attempt budget
+ # is exhausted, we ``break`` and end cleanly below — the
+ # same way an exhausted empty/error-body resume does, so
+ # give-up is consistent regardless of failure shape.
+ # ``next`` is used rather than ``for`` so this cannot
+ # swallow a ``GeneratorExit`` raised at a ``yield``.
+ if not self._reconnect_applicable():
+ raise
+ break
+ yield sse
+ if sse.id:
+ last_dispatched_id = sse.id
+ if sse.retry is not None:
+ last_retry = sse.retry
+ reconnect_attempts = 0
+
+ if not self._should_reconnect(last_dispatched_id, reconnect_attempts):
+ return
+ reconnect_attempts += 1
+
+ self._sleep_before_reconnect(last_retry)
+
+ # Close the previously-opened reconnect response before opening
+ # a new one so we never hold more than one extra connection.
+ if owned_cm is not None:
+ owned_cm.__exit__(None, None, None)
+ owned_cm = None
+
+ assert self._reconnect is not None # guaranteed by _should_reconnect
+ try:
+ cm: ContextManager[httpx.Response] = self._reconnect(last_dispatched_id or "")
+ new_response = cm.__enter__()
+ except Exception:
+ # A failed reconnect consumes an attempt; back off and retry.
+ response = None
+ continue
+ owned_cm = cm
+ if new_response is None or not self._is_reconnect_response_usable(new_response):
+ # Null/empty body or a non-SSE/error response (e.g. 204/304,
+ # a 500, or an HTML error page): treat as a failed attempt.
+ response = None
+ continue
+
+ response = new_response
+ # Drop any partial event left over from the dropped stream, but
+ # keep the last event id (per the SSE spec) and start a fresh
+ # incremental text decoder for the new connection.
+ decoder.reset_in_progress_event()
+ text_decoder = self._new_text_decoder(new_response)
+ finally:
+ if owned_cm is not None:
+ owned_cm.__exit__(None, None, None)
+
+ async def aiter_sse(self) -> AsyncGenerator[ServerSentEvent, None]:
+ self._check_content_type()
+ decoder = SSEDecoder()
+ text_decoder = self._new_text_decoder()
+
+ last_dispatched_id: Optional[str] = None
+ last_retry: Optional[int] = None
+ reconnect_attempts = 0
+
+ response: Optional[httpx.Response] = self._response
+ owned_cm: Optional[AsyncContextManager[httpx.Response]] = None
+ try:
+ while True:
+ if response is not None:
+ events = self._adecode_response(response, decoder, text_decoder)
+ while True:
+ try:
+ sse = await events.__anext__()
+ except StopAsyncIteration:
+ break
+ except SSEError:
+ # A protocol violation (e.g. an oversized line) is a
+ # genuine error, not a dropped connection; propagate it.
+ # Listed first because ``SSEError`` subclasses
+ # ``httpx.TransportError``.
+ raise
+ except httpx.TransportError:
+ # A transport error mid-stream (e.g. the server dropped
+ # the connection: ``ReadError``/``RemoteProtocolError``)
+ # is a premature end. Only swallow it when reconnection
+ # is configured for this stream; otherwise re-raise so a
+ # non-resumable stream still surfaces the error to the
+ # caller instead of looking like a clean completion.
+ # When reconnection is applicable but the attempt budget
+ # is exhausted, we ``break`` and end cleanly below — the
+ # same way an exhausted empty/error-body resume does, so
+ # give-up is consistent regardless of failure shape.
+ if not self._reconnect_applicable():
+ raise
+ break
+ yield sse
+ if sse.id:
+ last_dispatched_id = sse.id
+ if sse.retry is not None:
+ last_retry = sse.retry
+ reconnect_attempts = 0
+
+ if not self._should_reconnect(last_dispatched_id, reconnect_attempts):
+ return
+ reconnect_attempts += 1
+
+ await self._asleep_before_reconnect(last_retry)
+
+ if owned_cm is not None:
+ await owned_cm.__aexit__(None, None, None)
+ owned_cm = None
+
+ assert self._reconnect is not None # guaranteed by _should_reconnect
+ try:
+ cm: AsyncContextManager[httpx.Response] = self._reconnect(last_dispatched_id or "")
+ new_response = await cm.__aenter__()
+ except Exception:
+ response = None
+ continue
+ owned_cm = cm
+ if new_response is None or not self._is_reconnect_response_usable(new_response):
+ response = None
+ continue
+
+ response = new_response
+ decoder.reset_in_progress_event()
+ text_decoder = self._new_text_decoder(new_response)
+ finally:
+ if owned_cm is not None:
+ # Shield the close so a cancellation delivered while reading a
+ # reconnected response still fully tears the connection down
+ # instead of leaking it until the client is closed.
+ with anyio.CancelScope(shield=True):
+ await owned_cm.__aexit__(None, None, None)
+
+
+@contextmanager
+def connect_sse(client: httpx.Client, method: str, url: str, **kwargs: Any) -> Iterator[EventSource]:
+ headers = kwargs.pop("headers", {})
+ headers["Accept"] = "text/event-stream"
+ headers["Cache-Control"] = "no-store"
+
+ with client.stream(method, url, headers=headers, **kwargs) as response:
+ yield EventSource(response)
+
+
+@asynccontextmanager
+async def aconnect_sse(
+ client: httpx.AsyncClient,
+ method: str,
+ url: str,
+ **kwargs: Any,
+) -> AsyncIterator[EventSource]:
+ headers = kwargs.pop("headers", {})
+ headers["Accept"] = "text/event-stream"
+ headers["Cache-Control"] = "no-store"
+
+ async with client.stream(method, url, headers=headers, **kwargs) as response:
+ yield EventSource(response)
diff --git a/skyvault/skyflow/generated/rest/core/http_sse/_decoders.py b/skyvault/skyflow/generated/rest/core/http_sse/_decoders.py
new file mode 100644
index 00000000..1f6b35ec
--- /dev/null
+++ b/skyvault/skyflow/generated/rest/core/http_sse/_decoders.py
@@ -0,0 +1,74 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from typing import List, Optional
+
+from ._models import ServerSentEvent
+
+
+class SSEDecoder:
+ def __init__(self) -> None:
+ self._event = ""
+ self._data: List[str] = []
+ self._last_event_id = ""
+ self._retry: Optional[int] = None
+
+ def reset_in_progress_event(self) -> None:
+ """Discard any partially-parsed (undispatched) event.
+
+ Used when a stream ends mid-event before reconnecting: the buffered
+ ``event``/``data``/``retry`` fields of the never-dispatched event must
+ be dropped so they do not corrupt the first event of the reconnected
+ stream. Per the SSE spec the last event id is *not* reset here — it
+ persists across connections.
+ """
+ self._event = ""
+ self._data = []
+ self._retry = None
+
+ def decode(self, line: str) -> Optional[ServerSentEvent]:
+ # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501
+
+ if not line:
+ if not self._event and not self._data and not self._last_event_id and self._retry is None:
+ return None
+
+ sse = ServerSentEvent(
+ event=self._event,
+ data="\n".join(self._data),
+ id=self._last_event_id,
+ retry=self._retry,
+ )
+
+ # NOTE: as per the SSE spec, do not reset last_event_id.
+ self._event = ""
+ self._data = []
+ self._retry = None
+
+ return sse
+
+ if line.startswith(":"):
+ return None
+
+ fieldname, _, value = line.partition(":")
+
+ if value.startswith(" "):
+ value = value[1:]
+
+ if fieldname == "event":
+ self._event = value
+ elif fieldname == "data":
+ self._data.append(value)
+ elif fieldname == "id":
+ if "\0" in value:
+ pass
+ else:
+ self._last_event_id = value
+ elif fieldname == "retry":
+ try:
+ self._retry = int(value)
+ except (TypeError, ValueError):
+ pass
+ else:
+ pass # Field is ignored.
+
+ return None
diff --git a/skyvault/skyflow/generated/rest/types/uuid_.py b/skyvault/skyflow/generated/rest/core/http_sse/_exceptions.py
similarity index 51%
rename from skyvault/skyflow/generated/rest/types/uuid_.py
rename to skyvault/skyflow/generated/rest/core/http_sse/_exceptions.py
index cf319b43..81605a8a 100644
--- a/skyvault/skyflow/generated/rest/types/uuid_.py
+++ b/skyvault/skyflow/generated/rest/core/http_sse/_exceptions.py
@@ -1,3 +1,7 @@
# This file was auto-generated by Fern from our API Definition.
-Uuid = str
+import httpx
+
+
+class SSEError(httpx.TransportError):
+ pass
diff --git a/skyvault/skyflow/generated/rest/core/http_sse/_models.py b/skyvault/skyflow/generated/rest/core/http_sse/_models.py
new file mode 100644
index 00000000..1af57f8f
--- /dev/null
+++ b/skyvault/skyflow/generated/rest/core/http_sse/_models.py
@@ -0,0 +1,17 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import json
+from dataclasses import dataclass
+from typing import Any, Optional
+
+
+@dataclass(frozen=True)
+class ServerSentEvent:
+ event: str = "message"
+ data: str = ""
+ id: str = ""
+ retry: Optional[int] = None
+
+ def json(self) -> Any:
+ """Parse the data field as JSON."""
+ return json.loads(self.data)
diff --git a/skyvault/skyflow/generated/rest/core/jsonable_encoder.py b/skyvault/skyflow/generated/rest/core/jsonable_encoder.py
index afee3662..f638cc9a 100644
--- a/skyvault/skyflow/generated/rest/core/jsonable_encoder.py
+++ b/skyvault/skyflow/generated/rest/core/jsonable_encoder.py
@@ -15,6 +15,7 @@
from pathlib import PurePath
from types import GeneratorType
from typing import Any, Callable, Dict, List, Optional, Set, Union
+from urllib.parse import quote
import pydantic
from .datetime_utils import serialize_datetime
@@ -30,6 +31,10 @@
def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any], Any]]] = None) -> Any:
custom_encoder = custom_encoder or {}
+ # Generated SDKs use Ellipsis (`...`) as the sentinel value for "OMIT".
+ # OMIT values should be excluded from serialized payloads.
+ if obj is Ellipsis:
+ return None
if custom_encoder:
if type(obj) in custom_encoder:
return custom_encoder[type(obj)](obj)
@@ -70,6 +75,8 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any]
allowed_keys = set(obj.keys())
for key, value in obj.items():
if key in allowed_keys:
+ if value is Ellipsis:
+ continue
encoded_key = jsonable_encoder(key, custom_encoder=custom_encoder)
encoded_value = jsonable_encoder(value, custom_encoder=custom_encoder)
encoded_dict[encoded_key] = encoded_value
@@ -77,6 +84,8 @@ def jsonable_encoder(obj: Any, custom_encoder: Optional[Dict[Any, Callable[[Any]
if isinstance(obj, (list, set, frozenset, GeneratorType, tuple)):
encoded_list = []
for item in obj:
+ if item is Ellipsis:
+ continue
encoded_list.append(jsonable_encoder(item, custom_encoder=custom_encoder))
return encoded_list
@@ -98,3 +107,27 @@ def fallback_serializer(o: Any) -> Any:
return jsonable_encoder(data, custom_encoder=custom_encoder)
return to_jsonable_with_fallback(obj, fallback_serializer)
+
+
+def encode_path_param(obj: Any) -> str:
+ """Encode a value for use in a URL path segment.
+
+ Ensures proper string conversion for all types, including
+ booleans which need lowercase 'true'/'false' rather than
+ Python's 'True'/'False'.
+ """
+ if isinstance(obj, bool):
+ return "true" if obj else "false"
+ return str(jsonable_encoder(obj))
+
+
+def quote_path_param(obj: Any) -> str:
+ """Encode a value for use in a URL path segment, percent-encoding it.
+
+ Same as encode_path_param, except the result is percent-encoded so
+ that a value containing "/" or ".." cannot change which endpoint
+ the request resolves to.
+ """
+ if isinstance(obj, bool):
+ return "true" if obj else "false"
+ return quote(str(jsonable_encoder(obj)), safe="")
diff --git a/skyvault/skyflow/generated/rest/core/logging.py b/skyvault/skyflow/generated/rest/core/logging.py
new file mode 100644
index 00000000..e5e57245
--- /dev/null
+++ b/skyvault/skyflow/generated/rest/core/logging.py
@@ -0,0 +1,107 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import logging
+import typing
+
+LogLevel = typing.Literal["debug", "info", "warn", "error"]
+
+_LOG_LEVEL_MAP: typing.Dict[LogLevel, int] = {
+ "debug": 1,
+ "info": 2,
+ "warn": 3,
+ "error": 4,
+}
+
+
+class ILogger(typing.Protocol):
+ def debug(self, message: str, **kwargs: typing.Any) -> None: ...
+ def info(self, message: str, **kwargs: typing.Any) -> None: ...
+ def warn(self, message: str, **kwargs: typing.Any) -> None: ...
+ def error(self, message: str, **kwargs: typing.Any) -> None: ...
+
+
+class ConsoleLogger:
+ _logger: logging.Logger
+
+ def __init__(self) -> None:
+ self._logger = logging.getLogger("fern")
+ if not self._logger.handlers:
+ handler = logging.StreamHandler()
+ handler.setFormatter(logging.Formatter("%(levelname)s - %(message)s"))
+ self._logger.addHandler(handler)
+ self._logger.setLevel(logging.DEBUG)
+
+ def debug(self, message: str, **kwargs: typing.Any) -> None:
+ self._logger.debug(message, extra=kwargs)
+
+ def info(self, message: str, **kwargs: typing.Any) -> None:
+ self._logger.info(message, extra=kwargs)
+
+ def warn(self, message: str, **kwargs: typing.Any) -> None:
+ self._logger.warning(message, extra=kwargs)
+
+ def error(self, message: str, **kwargs: typing.Any) -> None:
+ self._logger.error(message, extra=kwargs)
+
+
+class LogConfig(typing.TypedDict, total=False):
+ level: LogLevel
+ logger: ILogger
+ silent: bool
+
+
+class Logger:
+ _level: int
+ _logger: ILogger
+ _silent: bool
+
+ def __init__(self, *, level: LogLevel, logger: ILogger, silent: bool) -> None:
+ self._level = _LOG_LEVEL_MAP[level]
+ self._logger = logger
+ self._silent = silent
+
+ def _should_log(self, level: LogLevel) -> bool:
+ return not self._silent and self._level <= _LOG_LEVEL_MAP[level]
+
+ def is_debug(self) -> bool:
+ return self._should_log("debug")
+
+ def is_info(self) -> bool:
+ return self._should_log("info")
+
+ def is_warn(self) -> bool:
+ return self._should_log("warn")
+
+ def is_error(self) -> bool:
+ return self._should_log("error")
+
+ def debug(self, message: str, **kwargs: typing.Any) -> None:
+ if self.is_debug():
+ self._logger.debug(message, **kwargs)
+
+ def info(self, message: str, **kwargs: typing.Any) -> None:
+ if self.is_info():
+ self._logger.info(message, **kwargs)
+
+ def warn(self, message: str, **kwargs: typing.Any) -> None:
+ if self.is_warn():
+ self._logger.warn(message, **kwargs)
+
+ def error(self, message: str, **kwargs: typing.Any) -> None:
+ if self.is_error():
+ self._logger.error(message, **kwargs)
+
+
+_default_logger: Logger = Logger(level="info", logger=ConsoleLogger(), silent=True)
+
+
+def create_logger(config: typing.Optional[typing.Union[LogConfig, Logger]] = None) -> Logger:
+ if config is None:
+ return _default_logger
+ if isinstance(config, Logger):
+ return config
+ return Logger(
+ level=config.get("level", "info"),
+ logger=config.get("logger", ConsoleLogger()),
+ silent=config.get("silent", True),
+ )
diff --git a/skyvault/skyflow/generated/rest/core/parse_error.py b/skyvault/skyflow/generated/rest/core/parse_error.py
new file mode 100644
index 00000000..4527c6a8
--- /dev/null
+++ b/skyvault/skyflow/generated/rest/core/parse_error.py
@@ -0,0 +1,36 @@
+# This file was auto-generated by Fern from our API Definition.
+
+from typing import Any, Dict, Optional
+
+
+class ParsingError(Exception):
+ """
+ Raised when the SDK fails to parse/validate a response from the server.
+ This typically indicates that the server returned a response whose shape
+ does not match the expected schema.
+ """
+
+ headers: Optional[Dict[str, str]]
+ status_code: Optional[int]
+ body: Any
+ cause: Optional[Exception]
+
+ def __init__(
+ self,
+ *,
+ headers: Optional[Dict[str, str]] = None,
+ status_code: Optional[int] = None,
+ body: Any = None,
+ cause: Optional[Exception] = None,
+ ) -> None:
+ self.headers = headers
+ self.status_code = status_code
+ self.body = body
+ self.cause = cause
+ super().__init__()
+ if cause is not None:
+ self.__cause__ = cause
+
+ def __str__(self) -> str:
+ cause_str = f", cause: {self.cause}" if self.cause is not None else ""
+ return f"headers: {self.headers}, status_code: {self.status_code}, body: {self.body}{cause_str}"
diff --git a/skyvault/skyflow/generated/rest/core/pydantic_utilities.py b/skyvault/skyflow/generated/rest/core/pydantic_utilities.py
index 7db29500..70816b99 100644
--- a/skyvault/skyflow/generated/rest/core/pydantic_utilities.py
+++ b/skyvault/skyflow/generated/rest/core/pydantic_utilities.py
@@ -2,30 +2,130 @@
# nopycln: file
import datetime as dt
+import inspect
+import json
+import logging
+import weakref
from collections import defaultdict
-from typing import Any, Callable, ClassVar, Dict, List, Mapping, Optional, Set, Tuple, Type, TypeVar, Union, cast
+from dataclasses import asdict
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Callable,
+ ClassVar,
+ Dict,
+ List,
+ Mapping,
+ Optional,
+ Set,
+ Tuple,
+ Type,
+ TypeVar,
+ Union,
+ cast,
+)
import pydantic
+import typing_extensions
+from pydantic.fields import FieldInfo as _FieldInfo
+
+_logger = logging.getLogger(__name__)
+
+if TYPE_CHECKING:
+ from .http_sse._models import ServerSentEvent
IS_PYDANTIC_V2 = pydantic.VERSION.startswith("2.")
if IS_PYDANTIC_V2:
- from pydantic.v1.datetime_parse import parse_date as parse_date
- from pydantic.v1.datetime_parse import parse_datetime as parse_datetime
- from pydantic.v1.fields import ModelField as ModelField
- from pydantic.v1.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[attr-defined]
- from pydantic.v1.typing import get_args as get_args
- from pydantic.v1.typing import get_origin as get_origin
- from pydantic.v1.typing import is_literal_type as is_literal_type
- from pydantic.v1.typing import is_union as is_union
+ _datetime_adapter = pydantic.TypeAdapter(dt.datetime) # type: ignore[attr-defined]
+ _date_adapter = pydantic.TypeAdapter(dt.date) # type: ignore[attr-defined]
+
+ def parse_datetime(value: Any) -> dt.datetime: # type: ignore[misc]
+ if isinstance(value, dt.datetime):
+ return value
+ return _datetime_adapter.validate_python(value)
+
+ def parse_date(value: Any) -> dt.date: # type: ignore[misc]
+ if isinstance(value, dt.datetime):
+ return value.date()
+ if isinstance(value, dt.date):
+ return value
+ return _date_adapter.validate_python(value)
+
+ # Avoid importing from pydantic.v1 to maintain Python 3.14 compatibility.
+ from typing import get_args as get_args # type: ignore[assignment]
+ from typing import get_origin as get_origin # type: ignore[assignment]
+
+ def is_literal_type(tp: Optional[Type[Any]]) -> bool: # type: ignore[misc]
+ return typing_extensions.get_origin(tp) is typing_extensions.Literal
+
+ def is_union(tp: Optional[Type[Any]]) -> bool: # type: ignore[misc]
+ return tp is Union or typing_extensions.get_origin(tp) is Union # type: ignore[comparison-overlap]
+
+ # Inline encoders_by_type to avoid importing from pydantic.v1.json
+ import re as _re
+ from collections import deque as _deque
+ from decimal import Decimal as _Decimal
+ from enum import Enum as _Enum
+ from ipaddress import (
+ IPv4Address as _IPv4Address,
+ )
+ from ipaddress import (
+ IPv4Interface as _IPv4Interface,
+ )
+ from ipaddress import (
+ IPv4Network as _IPv4Network,
+ )
+ from ipaddress import (
+ IPv6Address as _IPv6Address,
+ )
+ from ipaddress import (
+ IPv6Interface as _IPv6Interface,
+ )
+ from ipaddress import (
+ IPv6Network as _IPv6Network,
+ )
+ from pathlib import Path as _Path
+ from types import GeneratorType as _GeneratorType
+ from uuid import UUID as _UUID
+
+ from pydantic.fields import FieldInfo as ModelField # type: ignore[no-redef, assignment]
+
+ def _decimal_encoder(dec_value: Any) -> Any:
+ if dec_value.as_tuple().exponent >= 0:
+ return int(dec_value)
+ return float(dec_value)
+
+ encoders_by_type: Dict[Type[Any], Callable[[Any], Any]] = { # type: ignore[no-redef]
+ bytes: lambda o: o.decode(),
+ dt.date: lambda o: o.isoformat(),
+ dt.datetime: lambda o: o.isoformat(),
+ dt.time: lambda o: o.isoformat(),
+ dt.timedelta: lambda td: td.total_seconds(),
+ _Decimal: _decimal_encoder,
+ _Enum: lambda o: o.value,
+ frozenset: list,
+ _deque: list,
+ _GeneratorType: list,
+ _IPv4Address: str,
+ _IPv4Interface: str,
+ _IPv4Network: str,
+ _IPv6Address: str,
+ _IPv6Interface: str,
+ _IPv6Network: str,
+ _Path: str,
+ _re.Pattern: lambda o: o.pattern,
+ set: list,
+ _UUID: str,
+ }
else:
from pydantic.datetime_parse import parse_date as parse_date # type: ignore[no-redef]
from pydantic.datetime_parse import parse_datetime as parse_datetime # type: ignore[no-redef]
- from pydantic.fields import ModelField as ModelField # type: ignore[attr-defined, no-redef]
+ from pydantic.fields import ModelField as ModelField # type: ignore[attr-defined, no-redef, assignment]
from pydantic.json import ENCODERS_BY_TYPE as encoders_by_type # type: ignore[no-redef]
from pydantic.typing import get_args as get_args # type: ignore[no-redef]
from pydantic.typing import get_origin as get_origin # type: ignore[no-redef]
- from pydantic.typing import is_literal_type as is_literal_type # type: ignore[no-redef]
+ from pydantic.typing import is_literal_type as is_literal_type # type: ignore[no-redef, assignment]
from pydantic.typing import is_union as is_union # type: ignore[no-redef]
from .datetime_utils import serialize_datetime
@@ -36,11 +136,128 @@
Model = TypeVar("Model", bound=pydantic.BaseModel)
+def parse_sse_obj(sse: "ServerSentEvent", type_: Type[T]) -> T:
+ """
+ Parse a ServerSentEvent into the appropriate type.
+
+ This function handles data-level discrimination where the discriminator
+ (e.g., 'type') is inside the 'data' payload. It parses the SSE data field
+ as JSON and deserializes it into the target type.
+
+ Note: Protocol-level discrimination (where the discriminator comes from
+ the SSE event: field) is handled at code-generation time and does not
+ use this function.
+
+ Args:
+ sse: The ServerSentEvent object to parse
+ type_: The target type to deserialize into
+
+ Returns:
+ The parsed object of type T
+
+ Note:
+ This function is only available in SDK contexts where http_sse module exists.
+ """
+ sse_event = asdict(sse)
+ data_value = sse_event.get("data")
+ if isinstance(data_value, str) and data_value:
+ try:
+ parsed_data = json.loads(data_value)
+ return parse_obj_as(type_, parsed_data)
+ except json.JSONDecodeError as e:
+ _logger.warning(
+ "Failed to parse SSE data field as JSON: %s, data: %s",
+ e,
+ data_value[:100] if len(data_value) > 100 else data_value,
+ )
+ return parse_obj_as(type_, sse_event)
+
+
+_type_adapter_cache: Dict[int, Any] = {}
+
+
+def _get_type_adapter(type_: Type[Any]) -> Any:
+ key = id(type_)
+ adapter = _type_adapter_cache.get(key)
+ if adapter is None:
+ adapter = pydantic.TypeAdapter(type_) # type: ignore[attr-defined]
+ _type_adapter_cache[key] = adapter
+ return adapter
+
+
+_field_alias_cache: "weakref.WeakKeyDictionary[type, Tuple[Dict[str, str], Tuple[str, ...]]]" = (
+ weakref.WeakKeyDictionary()
+)
+
+
+def _get_field_aliases(model: type) -> Tuple[Dict[str, str], Tuple[str, ...]]:
+ """
+ Map of field name to Pydantic alias for the fields whose alias differs from their name, together with the
+ keys that are ambiguous (an alias of one field and the name of another). Computed once per model class.
+ """
+ cached = _field_alias_cache.get(model)
+ if cached is None:
+ fields: Mapping[str, Any] = (
+ getattr(model, "model_fields", {}) if IS_PYDANTIC_V2 else getattr(model, "__fields__", {})
+ )
+ name_to_alias: Dict[str, str] = {}
+ for name, field in fields.items():
+ alias = getattr(field, "alias", None)
+ if alias is not None and alias != name:
+ name_to_alias[name] = alias
+ cached = (name_to_alias, tuple(alias for alias in name_to_alias.values() if alias in fields))
+ _field_alias_cache[model] = cached
+ return cached
+
+
+def _coerce_keys_to_aliases(model: type, data: Any) -> Any:
+ """
+ Accept Python field names in input by rewriting them to their Pydantic aliases,
+ while avoiding silent collisions when a key could refer to multiple fields.
+ """
+ if not isinstance(data, Mapping):
+ return data
+
+ name_to_alias, ambiguous_keys = _get_field_aliases(model)
+ for key in ambiguous_keys:
+ if key in data and name_to_alias.get(key, key) not in data:
+ raise ValueError(
+ f"Ambiguous input key '{key}': it is both a field name and an alias. "
+ "Provide the explicit alias key to disambiguate."
+ )
+
+ if not name_to_alias or not any(name in data for name in name_to_alias):
+ return data if isinstance(data, dict) else dict(data)
+
+ rewritten: Dict[str, Any] = dict(data)
+ for name, alias in name_to_alias.items():
+ if name in data and alias not in rewritten:
+ rewritten[alias] = rewritten.pop(name)
+
+ return rewritten
+
+
def parse_obj_as(type_: Type[T], object_: Any) -> T:
- dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read")
+ # convert_and_respect_annotation_metadata is required for TypedDict aliasing.
+ #
+ # For Pydantic models, whether we should pre-dealias depends on how the model encodes aliasing:
+ # - If the model uses real Pydantic aliases (pydantic.Field(alias=...)), then we must pass wire keys through
+ # unchanged so Pydantic can validate them.
+ # - If the model encodes aliasing only via FieldMetadata annotations, then we MUST pre-dealias because Pydantic
+ # will not recognize those aliases during validation.
+ if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel):
+ has_pydantic_aliases = bool(_get_field_aliases(type_)[0])
+
+ dealiased_object = (
+ object_
+ if has_pydantic_aliases
+ else convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read")
+ )
+ else:
+ dealiased_object = convert_and_respect_annotation_metadata(object_=object_, annotation=type_, direction="read")
if IS_PYDANTIC_V2:
- adapter = pydantic.TypeAdapter(type_) # type: ignore[attr-defined]
- return adapter.validate_python(dealiased_object)
+ adapter = _get_type_adapter(type_)
+ return adapter.validate_python(dealiased_object) # type: ignore[no-any-return]
return pydantic.parse_obj_as(type_, dealiased_object)
@@ -59,9 +276,14 @@ class UniversalBaseModel(pydantic.BaseModel):
protected_namespaces=(),
)
+ @pydantic.model_validator(mode="before") # type: ignore[attr-defined]
+ @classmethod
+ def _coerce_field_names_to_aliases(cls, data: Any) -> Any:
+ return _coerce_keys_to_aliases(cls, data)
+
@pydantic.model_serializer(mode="plain", when_used="json") # type: ignore[attr-defined]
def serialize_model(self) -> Any: # type: ignore[name-defined]
- serialized = self.model_dump()
+ serialized = self.dict() # type: ignore[attr-defined]
data = {k: serialize_datetime(v) if isinstance(v, dt.datetime) else v for k, v in serialized.items()}
return data
@@ -71,6 +293,10 @@ class Config:
smart_union = True
json_encoders = {dt.datetime: serialize_datetime}
+ @pydantic.root_validator(pre=True)
+ def _coerce_field_names_to_aliases(cls, values: Any) -> Any:
+ return _coerce_keys_to_aliases(cls, values) # type: ignore[arg-type]
+
@classmethod
def model_construct(cls: Type["Model"], _fields_set: Optional[Set[str]] = None, **values: Any) -> "Model":
dealiased_object = convert_and_respect_annotation_metadata(object_=values, annotation=cls, direction="read")
@@ -147,7 +373,10 @@ def dict(self, **kwargs: Any) -> Dict[str, Any]:
dict_dump = super().dict(**kwargs_with_defaults_exclude_unset_include_fields)
- return convert_and_respect_annotation_metadata(object_=dict_dump, annotation=self.__class__, direction="write")
+ return cast(
+ Dict[str, Any],
+ convert_and_respect_annotation_metadata(object_=dict_dump, annotation=self.__class__, direction="write"),
+ )
def _union_list_of_pydantic_dicts(source: List[Any], destination: List[Any]) -> List[Any]:
@@ -217,7 +446,9 @@ def universal_root_validator(
) -> Callable[[AnyCallable], AnyCallable]:
def decorator(func: AnyCallable) -> AnyCallable:
if IS_PYDANTIC_V2:
- return cast(AnyCallable, pydantic.model_validator(mode="before" if pre else "after")(func)) # type: ignore[attr-defined]
+ # In Pydantic v2, for RootModel we always use "before" mode
+ # The custom validators transform the input value before the model is created
+ return cast(AnyCallable, pydantic.model_validator(mode="before")(func)) # type: ignore[attr-defined]
return cast(AnyCallable, pydantic.root_validator(pre=pre)(func)) # type: ignore[call-overload]
return decorator
@@ -232,7 +463,7 @@ def decorator(func: AnyCallable) -> AnyCallable:
return decorator
-PydanticField = Union[ModelField, pydantic.fields.FieldInfo]
+PydanticField = Union[ModelField, _FieldInfo]
def _get_model_fields(model: Type["Model"]) -> Mapping[str, PydanticField]:
diff --git a/skyvault/skyflow/generated/rest/core/request_options.py b/skyvault/skyflow/generated/rest/core/request_options.py
index 1b388044..caa6f669 100644
--- a/skyvault/skyflow/generated/rest/core/request_options.py
+++ b/skyvault/skyflow/generated/rest/core/request_options.py
@@ -14,7 +14,9 @@ class RequestOptions(typing.TypedDict, total=False):
This is used primarily as an optional final parameter for service functions.
Attributes:
- - timeout_in_seconds: int. The number of seconds to await an API call before timing out.
+ - timeout: float. The number of seconds to await an API call before timing out.
+
+ - timeout_in_seconds: int. Deprecated alias for `timeout`; both are in seconds. Prefer `timeout`.
- max_retries: int. The max number of retries to attempt if the API call fails.
@@ -27,9 +29,12 @@ class RequestOptions(typing.TypedDict, total=False):
- chunk_size: int. The size, in bytes, to process each chunk of data being streamed back within the response. This equates to leveraging `chunk_size` within `requests` or `httpx`, and is only leveraged for file downloads.
"""
+ timeout: NotRequired[float]
timeout_in_seconds: NotRequired[int]
max_retries: NotRequired[int]
additional_headers: NotRequired[typing.Dict[str, typing.Any]]
additional_query_parameters: NotRequired[typing.Dict[str, typing.Any]]
additional_body_parameters: NotRequired[typing.Dict[str, typing.Any]]
chunk_size: NotRequired[int]
+ stream_reconnection_enabled: NotRequired[bool]
+ max_stream_reconnection_attempts: NotRequired[int]
diff --git a/skyvault/skyflow/generated/rest/core/serialization.py b/skyvault/skyflow/generated/rest/core/serialization.py
index c36e865c..1d753e26 100644
--- a/skyvault/skyflow/generated/rest/core/serialization.py
+++ b/skyvault/skyflow/generated/rest/core/serialization.py
@@ -26,6 +26,75 @@ def __init__(self, *, alias: str) -> None:
self.alias = alias
+# Resolving type hints (typing.get_type_hints) is expensive because it eval/compiles
+# forward-reference annotations. The result is constant for a given type, so we cache it.
+# This is critical for hot paths like SSE event parsing, where the same (often large
+# discriminated-union) type is converted on every single event.
+_type_hints_cache: typing.Dict[typing.Any, typing.Dict[str, typing.Any]] = {}
+
+
+def _get_cached_type_hints(expected_type: typing.Any) -> typing.Dict[str, typing.Any]:
+ try:
+ cached = _type_hints_cache.get(expected_type)
+ except TypeError:
+ # Unhashable type; resolve without caching.
+ return _resolve_type_hints(expected_type)
+ if cached is None:
+ cached = _resolve_type_hints(expected_type)
+ _type_hints_cache[expected_type] = cached
+ return cached
+
+
+def _resolve_type_hints(expected_type: typing.Any) -> typing.Dict[str, typing.Any]:
+ try:
+ return typing_extensions.get_type_hints(expected_type, include_extras=True)
+ except NameError:
+ # The type contains a circular reference, so we use the __annotations__ attribute directly.
+ return getattr(expected_type, "__annotations__", {})
+
+
+# Whether convert_and_respect_annotation_metadata can possibly rewrite anything for a given
+# annotation, i.e. whether any reachable model/TypedDict field carries a FieldMetadata alias.
+# This is constant per type, so we cache it and use it to short-circuit the recursive walk.
+_requires_conversion_cache: typing.Dict[typing.Any, bool] = {}
+
+
+def _requires_conversion(type_: typing.Any) -> bool:
+ try:
+ cached = _requires_conversion_cache.get(type_)
+ except TypeError:
+ # Unhashable annotation; compute without caching.
+ return _compute_requires_conversion(type_, set())
+ if cached is None:
+ cached = _compute_requires_conversion(type_, set())
+ _requires_conversion_cache[type_] = cached
+ return cached
+
+
+def _compute_requires_conversion(type_: typing.Any, seen: typing.Set[typing.Any]) -> bool:
+ clean_type = _remove_annotations(type_)
+
+ try:
+ if clean_type in seen:
+ return False
+ seen = seen | {clean_type}
+ except TypeError:
+ # Unhashable type; skip cycle tracking (the type graph is finite in practice).
+ pass
+
+ # Models / TypedDicts: a field alias here means we must dealias; otherwise recurse into fields.
+ if (inspect.isclass(clean_type) and issubclass(clean_type, pydantic.BaseModel)) or typing_extensions.is_typeddict(
+ clean_type
+ ):
+ annotations = _get_cached_type_hints(clean_type)
+ if _get_alias_to_field_name(annotations):
+ return True
+ return any(_compute_requires_conversion(hint, seen) for hint in annotations.values())
+
+ # Containers / unions: recurse into the type arguments (List/Set/Sequence/Dict/Union/etc.).
+ return any(_compute_requires_conversion(arg, seen) for arg in typing_extensions.get_args(clean_type))
+
+
def convert_and_respect_annotation_metadata(
*,
object_: typing.Any,
@@ -57,6 +126,13 @@ def convert_and_respect_annotation_metadata(
return None
if inner_type is None:
inner_type = annotation
+ # The only thing this function ever rewrites is keys that carry a FieldMetadata
+ # alias. If nothing in the (cached) type graph has such an alias, the conversion is
+ # a content-identity transform, so we can skip the entire recursive walk. This is
+ # the hot path for SSE streaming, where a large discriminated union would otherwise
+ # be traversed on every single event.
+ if not _requires_conversion(annotation):
+ return object_
clean_type = _remove_annotations(inner_type)
# Pydantic models
@@ -160,12 +236,7 @@ def _convert_mapping(
direction: typing.Literal["read", "write"],
) -> typing.Mapping[str, object]:
converted_object: typing.Dict[str, object] = {}
- try:
- annotations = typing_extensions.get_type_hints(expected_type, include_extras=True)
- except NameError:
- # The TypedDict contains a circular reference, so
- # we use the __annotations__ attribute directly.
- annotations = getattr(expected_type, "__annotations__", {})
+ annotations = _get_cached_type_hints(expected_type)
aliases_to_field_names = _get_alias_to_field_name(annotations)
for key, value in object_.items():
if direction == "read" and key in aliases_to_field_names:
@@ -221,12 +292,12 @@ def _remove_annotations(type_: typing.Any) -> typing.Any:
def get_alias_to_field_mapping(type_: typing.Any) -> typing.Dict[str, str]:
- annotations = typing_extensions.get_type_hints(type_, include_extras=True)
+ annotations = _get_cached_type_hints(type_)
return _get_alias_to_field_name(annotations)
def get_field_to_alias_mapping(type_: typing.Any) -> typing.Dict[str, str]:
- annotations = typing_extensions.get_type_hints(type_, include_extras=True)
+ annotations = _get_cached_type_hints(type_)
return _get_field_to_alias_name(annotations)
diff --git a/skyvault/skyflow/generated/rest/environment.py b/skyvault/skyflow/generated/rest/environment.py
index 8c4747ca..3aa335bb 100644
--- a/skyvault/skyflow/generated/rest/environment.py
+++ b/skyvault/skyflow/generated/rest/environment.py
@@ -3,6 +3,6 @@
import enum
-class SkyflowEnvironment(enum.Enum):
- PRODUCTION = "https://identifier.vault.skyflowapis.com"
- SANDBOX = "https://identifier.vault.skyflowapis-preview.com"
+class SkyflowAuthEnvironment(enum.Enum):
+ PRODUCTION = "https://%7B%7Bvault_uri%7D%7D.vault.skyflowapis.com"
+ SANDBOX = "https://%7B%7Bvault_uri%7D%7D.vault.skyflowapis-preview.com"
diff --git a/skyvault/skyflow/generated/rest/errors/__init__.py b/skyvault/skyflow/generated/rest/errors/__init__.py
index 27c36553..8810eed8 100644
--- a/skyvault/skyflow/generated/rest/errors/__init__.py
+++ b/skyvault/skyflow/generated/rest/errors/__init__.py
@@ -2,9 +2,41 @@
# isort: skip_file
-from .bad_request_error import BadRequestError
-from .internal_server_error import InternalServerError
-from .not_found_error import NotFoundError
-from .unauthorized_error import UnauthorizedError
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .bad_request_error import BadRequestError
+ from .internal_server_error import InternalServerError
+ from .not_found_error import NotFoundError
+ from .unauthorized_error import UnauthorizedError
+_dynamic_imports: typing.Dict[str, str] = {
+ "BadRequestError": ".bad_request_error",
+ "InternalServerError": ".internal_server_error",
+ "NotFoundError": ".not_found_error",
+ "UnauthorizedError": ".unauthorized_error",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
__all__ = ["BadRequestError", "InternalServerError", "NotFoundError", "UnauthorizedError"]
diff --git a/skyvault/skyflow/generated/rest/errors/bad_request_error.py b/skyvault/skyflow/generated/rest/errors/bad_request_error.py
index baf5be4f..92449913 100644
--- a/skyvault/skyflow/generated/rest/errors/bad_request_error.py
+++ b/skyvault/skyflow/generated/rest/errors/bad_request_error.py
@@ -3,8 +3,9 @@
import typing
from ..core.api_error import ApiError
+from ..types.error_response import ErrorResponse
class BadRequestError(ApiError):
- def __init__(self, body: typing.Optional[typing.Any], headers: typing.Optional[typing.Dict[str, str]] = None):
+ def __init__(self, body: ErrorResponse, headers: typing.Optional[typing.Dict[str, str]] = None):
super().__init__(status_code=400, headers=headers, body=body)
diff --git a/skyvault/skyflow/generated/rest/errors/not_found_error.py b/skyvault/skyflow/generated/rest/errors/not_found_error.py
index dcd60e38..3b2a2d1f 100644
--- a/skyvault/skyflow/generated/rest/errors/not_found_error.py
+++ b/skyvault/skyflow/generated/rest/errors/not_found_error.py
@@ -3,8 +3,9 @@
import typing
from ..core.api_error import ApiError
+from ..types.error_response import ErrorResponse
class NotFoundError(ApiError):
- def __init__(self, body: typing.Optional[typing.Any], headers: typing.Optional[typing.Dict[str, str]] = None):
+ def __init__(self, body: ErrorResponse, headers: typing.Optional[typing.Dict[str, str]] = None):
super().__init__(status_code=404, headers=headers, body=body)
diff --git a/skyvault/skyflow/generated/rest/errors/unauthorized_error.py b/skyvault/skyflow/generated/rest/errors/unauthorized_error.py
index c83b25c2..00a614a3 100644
--- a/skyvault/skyflow/generated/rest/errors/unauthorized_error.py
+++ b/skyvault/skyflow/generated/rest/errors/unauthorized_error.py
@@ -3,8 +3,9 @@
import typing
from ..core.api_error import ApiError
+from ..types.error_response import ErrorResponse
class UnauthorizedError(ApiError):
- def __init__(self, body: typing.Optional[typing.Any], headers: typing.Optional[typing.Dict[str, str]] = None):
+ def __init__(self, body: ErrorResponse, headers: typing.Optional[typing.Dict[str, str]] = None):
super().__init__(status_code=401, headers=headers, body=body)
diff --git a/skyvault/skyflow/generated/rest/files/__init__.py b/skyvault/skyflow/generated/rest/files/__init__.py
index f313ad67..5cde0202 100644
--- a/skyvault/skyflow/generated/rest/files/__init__.py
+++ b/skyvault/skyflow/generated/rest/files/__init__.py
@@ -2,30 +2,3 @@
# isort: skip_file
-from .types import (
- DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem,
- DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription,
- DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem,
- DeidentifyFileImageRequestDeidentifyImageEntityTypesItem,
- DeidentifyFileImageRequestDeidentifyImageMaskingMethod,
- DeidentifyFileRequestDeidentifyDocumentEntityTypesItem,
- DeidentifyFileRequestDeidentifyPresentationEntityTypesItem,
- DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem,
- DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem,
- DeidentifyFileRequestDeidentifyTextEntityTypesItem,
- DeidentifyFileRequestEntityTypesItem,
-)
-
-__all__ = [
- "DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem",
- "DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription",
- "DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem",
- "DeidentifyFileImageRequestDeidentifyImageEntityTypesItem",
- "DeidentifyFileImageRequestDeidentifyImageMaskingMethod",
- "DeidentifyFileRequestDeidentifyDocumentEntityTypesItem",
- "DeidentifyFileRequestDeidentifyPresentationEntityTypesItem",
- "DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem",
- "DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem",
- "DeidentifyFileRequestDeidentifyTextEntityTypesItem",
- "DeidentifyFileRequestEntityTypesItem",
-]
diff --git a/skyvault/skyflow/generated/rest/files/client.py b/skyvault/skyflow/generated/rest/files/client.py
index 539d2161..dc8bf433 100644
--- a/skyvault/skyflow/generated/rest/files/client.py
+++ b/skyvault/skyflow/generated/rest/files/client.py
@@ -2,56 +2,11 @@
import typing
+from .. import core
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.request_options import RequestOptions
-from ..types.deidentify_file_response import DeidentifyFileResponse
-from ..types.detect_runs_response import DetectRunsResponse
-from ..types.file_data import FileData
-from ..types.file_data_deidentify_audio import FileDataDeidentifyAudio
-from ..types.file_data_deidentify_document import FileDataDeidentifyDocument
-from ..types.file_data_deidentify_image import FileDataDeidentifyImage
-from ..types.file_data_deidentify_pdf import FileDataDeidentifyPdf
-from ..types.file_data_deidentify_presentation import FileDataDeidentifyPresentation
-from ..types.file_data_deidentify_spreadsheet import FileDataDeidentifySpreadsheet
-from ..types.file_data_deidentify_structured_text import FileDataDeidentifyStructuredText
-from ..types.file_data_deidentify_text import FileDataDeidentifyText
-from ..types.file_data_reidentify_file import FileDataReidentifyFile
-from ..types.format import Format
-from ..types.reidentify_file_response import ReidentifyFileResponse
-from ..types.token_type_mapping import TokenTypeMapping
-from ..types.transformations import Transformations
+from ..types.upload_file_response_v2 import UploadFileResponseV2
from .raw_client import AsyncRawFilesClient, RawFilesClient
-from .types.deidentify_file_audio_request_deidentify_audio_entity_types_item import (
- DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem,
-)
-from .types.deidentify_file_audio_request_deidentify_audio_output_transcription import (
- DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription,
-)
-from .types.deidentify_file_document_pdf_request_deidentify_pdf_entity_types_item import (
- DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem,
-)
-from .types.deidentify_file_image_request_deidentify_image_entity_types_item import (
- DeidentifyFileImageRequestDeidentifyImageEntityTypesItem,
-)
-from .types.deidentify_file_image_request_deidentify_image_masking_method import (
- DeidentifyFileImageRequestDeidentifyImageMaskingMethod,
-)
-from .types.deidentify_file_request_deidentify_document_entity_types_item import (
- DeidentifyFileRequestDeidentifyDocumentEntityTypesItem,
-)
-from .types.deidentify_file_request_deidentify_presentation_entity_types_item import (
- DeidentifyFileRequestDeidentifyPresentationEntityTypesItem,
-)
-from .types.deidentify_file_request_deidentify_spreadsheet_entity_types_item import (
- DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem,
-)
-from .types.deidentify_file_request_deidentify_structured_text_entity_types_item import (
- DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem,
-)
-from .types.deidentify_file_request_deidentify_text_entity_types_item import (
- DeidentifyFileRequestDeidentifyTextEntityTypesItem,
-)
-from .types.deidentify_file_request_entity_types_item import DeidentifyFileRequestEntityTypesItem
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -72,1752 +27,156 @@ def with_raw_response(self) -> RawFilesClient:
"""
return self._raw_client
- def deidentify_file(
+ def upload_file_v2(
self,
- *,
- file: FileData,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileRequestEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from a file. This operation includes options applicable to all supported file types.
For more specific options, see the category-specific operations (like De-identify Document) and the file type-specific opertions (like De-identify PDF).
-
- Parameters
- ----------
- file : FileData
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- from skyflow import FileData, Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.files.deidentify_file(
- file=FileData(
- base_64="base64",
- data_format="mp3",
- ),
- vault_id="vault_id",
- )
- """
- _response = self._raw_client.deidentify_file(
- file=file,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- def deidentify_audio(
- self,
- *,
- file: FileDataDeidentifyAudio,
- vault_id: str,
- output_transcription: typing.Optional[DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription] = OMIT,
- output_processed_audio: typing.Optional[bool] = OMIT,
- bleep_start_padding: typing.Optional[float] = OMIT,
- bleep_stop_padding: typing.Optional[float] = OMIT,
- bleep_frequency: typing.Optional[int] = OMIT,
- bleep_gain: typing.Optional[int] = OMIT,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from an audio file. This operation includes options applicable to all supported audio file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyAudio
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- output_transcription : typing.Optional[DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription]
- Type of transcription to output.
-
- output_processed_audio : typing.Optional[bool]
- Whether to include the processed audio file in the response.
-
- bleep_start_padding : typing.Optional[float]
- Padding added to the beginning of a bleep, in seconds.
-
- bleep_stop_padding : typing.Optional[float]
- Padding added to the end of a bleep, in seconds.
-
- bleep_frequency : typing.Optional[int]
- The pitch of the bleep sound, in Hz. The higher the number, the higher the pitch.
-
- bleep_gain : typing.Optional[int]
- Relative loudness of the bleep in dB. Positive values increase its loudness, and negative values decrease it.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- from skyflow import FileDataDeidentifyAudio, Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.files.deidentify_audio(
- file=FileDataDeidentifyAudio(
- base_64="base64",
- data_format="mp3",
- ),
- vault_id="vault_id",
- )
- """
- _response = self._raw_client.deidentify_audio(
- file=file,
- vault_id=vault_id,
- output_transcription=output_transcription,
- output_processed_audio=output_processed_audio,
- bleep_start_padding=bleep_start_padding,
- bleep_stop_padding=bleep_stop_padding,
- bleep_frequency=bleep_frequency,
- bleep_gain=bleep_gain,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- def deidentify_document(
- self,
- *,
- file: FileDataDeidentifyDocument,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyDocumentEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from a document file. This operation includes options applicable to all supported document file types.
For more specific options, see the file type-specific opertions (like De-identify PDF) where they're available. For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyDocument
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyDocumentEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- from skyflow import FileDataDeidentifyDocument, Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.files.deidentify_document(
- file=FileDataDeidentifyDocument(
- base_64="base64",
- data_format="pdf",
- ),
- vault_id="vault_id",
- )
- """
- _response = self._raw_client.deidentify_document(
- file=file,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- def deidentify_pdf(
- self,
- *,
- file: FileDataDeidentifyPdf,
- vault_id: str,
- density: typing.Optional[int] = OMIT,
- max_resolution: typing.Optional[int] = OMIT,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from a PDF file. This operation includes options specific to PDF files.
For broader file type support, see De-identify Document and De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyPdf
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- density : typing.Optional[int]
- Pixel density at which to process the PDF file.
-
- max_resolution : typing.Optional[int]
- Max resolution at which to process the PDF file.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- from skyflow import FileDataDeidentifyPdf, Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.files.deidentify_pdf(
- file=FileDataDeidentifyPdf(
- base_64="base64",
- ),
- vault_id="vault_id",
- )
- """
- _response = self._raw_client.deidentify_pdf(
- file=file,
- vault_id=vault_id,
- density=density,
- max_resolution=max_resolution,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- def deidentify_image(
- self,
- *,
- file: FileDataDeidentifyImage,
- vault_id: str,
- output_processed_image: typing.Optional[bool] = OMIT,
- output_ocr_text: typing.Optional[bool] = OMIT,
- masking_method: typing.Optional[DeidentifyFileImageRequestDeidentifyImageMaskingMethod] = OMIT,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileImageRequestDeidentifyImageEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from an image file. This operation includes options applicable to all supported image file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyImage
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- output_processed_image : typing.Optional[bool]
- If `true`, includes processed image in the output.
-
- output_ocr_text : typing.Optional[bool]
- If `true`, includes text detected by OCR in the response.
-
- masking_method : typing.Optional[DeidentifyFileImageRequestDeidentifyImageMaskingMethod]
- Method to mask the entities in the image.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileImageRequestDeidentifyImageEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- from skyflow import FileDataDeidentifyImage, Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.files.deidentify_image(
- file=FileDataDeidentifyImage(
- base_64="base64",
- data_format="jpg",
- ),
- vault_id="vault_id",
- )
- """
- _response = self._raw_client.deidentify_image(
- file=file,
- vault_id=vault_id,
- output_processed_image=output_processed_image,
- output_ocr_text=output_ocr_text,
- masking_method=masking_method,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- def deidentify_presentation(
- self,
- *,
- file: FileDataDeidentifyPresentation,
- vault_id: str,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileRequestDeidentifyPresentationEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from a presentation file. This operation includes options applicable to all supported presentation file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyPresentation
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyPresentationEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- from skyflow import FileDataDeidentifyPresentation, Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.files.deidentify_presentation(
- file=FileDataDeidentifyPresentation(
- base_64="base64",
- data_format="ppt",
- ),
- vault_id="vault_id",
- )
- """
- _response = self._raw_client.deidentify_presentation(
- file=file,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- def deidentify_spreadsheet(
- self,
- *,
- file: FileDataDeidentifySpreadsheet,
- vault_id: str,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from a spreadsheet file. This operation includes options applicable to all supported spreadsheet file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifySpreadsheet
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- from skyflow import FileDataDeidentifySpreadsheet, Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.files.deidentify_spreadsheet(
- file=FileDataDeidentifySpreadsheet(
- base_64="base64",
- data_format="csv",
- ),
- vault_id="vault_id",
- )
- """
- _response = self._raw_client.deidentify_spreadsheet(
- file=file,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- def deidentify_structured_text(
- self,
- *,
- file: FileDataDeidentifyStructuredText,
- vault_id: str,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from a structured text file. This operation includes options applicable to all supported structured text file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyStructuredText
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- from skyflow import FileDataDeidentifyStructuredText, Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.files.deidentify_structured_text(
- file=FileDataDeidentifyStructuredText(
- base_64="base64",
- data_format="json",
- ),
- vault_id="vault_id",
- )
- """
- _response = self._raw_client.deidentify_structured_text(
- file=file,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- def deidentify_text(
- self,
- *,
- file: FileDataDeidentifyText,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyTextEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from a text file. This operation includes options applicable to all supported image text types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyText
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyTextEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- from skyflow import FileDataDeidentifyText, Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.files.deidentify_text(
- file=FileDataDeidentifyText(
- base_64="base64",
- ),
- vault_id="vault_id",
- )
- """
- _response = self._raw_client.deidentify_text(
- file=file,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- def reidentify_file(
- self,
- *,
- file: FileDataReidentifyFile,
- vault_id: str,
- format: typing.Optional[Format] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> ReidentifyFileResponse:
- """
- Re-identifies tokens in a file.
-
- Parameters
- ----------
- file : FileDataReidentifyFile
-
- vault_id : str
- ID of the vault where the entities are stored.
-
- format : typing.Optional[Format]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ReidentifyFileResponse
- OK
-
- Examples
- --------
- from skyflow import FileDataReidentifyFile, Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.files.reidentify_file(
- file=FileDataReidentifyFile(
- base_64="base64",
- data_format="txt",
- ),
- vault_id="vault_id",
- )
- """
- _response = self._raw_client.reidentify_file(
- file=file, vault_id=vault_id, format=format, request_options=request_options
- )
- return _response.data
-
- def get_run(
- self,
- run_id: str,
- *,
- vault_id: typing.Optional[str] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DetectRunsResponse:
- """
- Returns the status of a detect run.
-
- Parameters
- ----------
- run_id : str
-
- vault_id : typing.Optional[str]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DetectRunsResponse
- OK
-
- Examples
- --------
- from skyflow import Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.files.get_run(
- run_id="run_id",
- vault_id="vault_id",
- )
- """
- _response = self._raw_client.get_run(run_id, vault_id=vault_id, request_options=request_options)
- return _response.data
-
-
-class AsyncFilesClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._raw_client = AsyncRawFilesClient(client_wrapper=client_wrapper)
-
- @property
- def with_raw_response(self) -> AsyncRawFilesClient:
- """
- Retrieves a raw implementation of this client that returns raw responses.
-
- Returns
- -------
- AsyncRawFilesClient
- """
- return self._raw_client
-
- async def deidentify_file(
- self,
- *,
- file: FileData,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileRequestEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from a file. This operation includes options applicable to all supported file types.
For more specific options, see the category-specific operations (like De-identify Document) and the file type-specific opertions (like De-identify PDF).
-
- Parameters
- ----------
- file : FileData
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow, FileData
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.files.deidentify_file(
- file=FileData(
- base_64="base64",
- data_format="mp3",
- ),
- vault_id="vault_id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.deidentify_file(
- file=file,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- async def deidentify_audio(
- self,
- *,
- file: FileDataDeidentifyAudio,
- vault_id: str,
- output_transcription: typing.Optional[DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription] = OMIT,
- output_processed_audio: typing.Optional[bool] = OMIT,
- bleep_start_padding: typing.Optional[float] = OMIT,
- bleep_stop_padding: typing.Optional[float] = OMIT,
- bleep_frequency: typing.Optional[int] = OMIT,
- bleep_gain: typing.Optional[int] = OMIT,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from an audio file. This operation includes options applicable to all supported audio file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyAudio
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- output_transcription : typing.Optional[DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription]
- Type of transcription to output.
-
- output_processed_audio : typing.Optional[bool]
- Whether to include the processed audio file in the response.
-
- bleep_start_padding : typing.Optional[float]
- Padding added to the beginning of a bleep, in seconds.
-
- bleep_stop_padding : typing.Optional[float]
- Padding added to the end of a bleep, in seconds.
-
- bleep_frequency : typing.Optional[int]
- The pitch of the bleep sound, in Hz. The higher the number, the higher the pitch.
-
- bleep_gain : typing.Optional[int]
- Relative loudness of the bleep in dB. Positive values increase its loudness, and negative values decrease it.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow, FileDataDeidentifyAudio
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.files.deidentify_audio(
- file=FileDataDeidentifyAudio(
- base_64="base64",
- data_format="mp3",
- ),
- vault_id="vault_id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.deidentify_audio(
- file=file,
- vault_id=vault_id,
- output_transcription=output_transcription,
- output_processed_audio=output_processed_audio,
- bleep_start_padding=bleep_start_padding,
- bleep_stop_padding=bleep_stop_padding,
- bleep_frequency=bleep_frequency,
- bleep_gain=bleep_gain,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- async def deidentify_document(
- self,
- *,
- file: FileDataDeidentifyDocument,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyDocumentEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from a document file. This operation includes options applicable to all supported document file types.
For more specific options, see the file type-specific opertions (like De-identify PDF) where they're available. For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyDocument
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyDocumentEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow, FileDataDeidentifyDocument
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.files.deidentify_document(
- file=FileDataDeidentifyDocument(
- base_64="base64",
- data_format="pdf",
- ),
- vault_id="vault_id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.deidentify_document(
- file=file,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- async def deidentify_pdf(
- self,
- *,
- file: FileDataDeidentifyPdf,
- vault_id: str,
- density: typing.Optional[int] = OMIT,
- max_resolution: typing.Optional[int] = OMIT,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from a PDF file. This operation includes options specific to PDF files.
For broader file type support, see De-identify Document and De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyPdf
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- density : typing.Optional[int]
- Pixel density at which to process the PDF file.
-
- max_resolution : typing.Optional[int]
- Max resolution at which to process the PDF file.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow, FileDataDeidentifyPdf
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.files.deidentify_pdf(
- file=FileDataDeidentifyPdf(
- base_64="base64",
- ),
- vault_id="vault_id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.deidentify_pdf(
- file=file,
- vault_id=vault_id,
- density=density,
- max_resolution=max_resolution,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- async def deidentify_image(
- self,
- *,
- file: FileDataDeidentifyImage,
vault_id: str,
- output_processed_image: typing.Optional[bool] = OMIT,
- output_ocr_text: typing.Optional[bool] = OMIT,
- masking_method: typing.Optional[DeidentifyFileImageRequestDeidentifyImageMaskingMethod] = OMIT,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileImageRequestDeidentifyImageEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from an image file. This operation includes options applicable to all supported image file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyImage
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- output_processed_image : typing.Optional[bool]
- If `true`, includes processed image in the output.
-
- output_ocr_text : typing.Optional[bool]
- If `true`, includes text detected by OCR in the response.
-
- masking_method : typing.Optional[DeidentifyFileImageRequestDeidentifyImageMaskingMethod]
- Method to mask the entities in the image.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileImageRequestDeidentifyImageEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow, FileDataDeidentifyImage
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.files.deidentify_image(
- file=FileDataDeidentifyImage(
- base_64="base64",
- data_format="jpg",
- ),
- vault_id="vault_id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.deidentify_image(
- file=file,
- vault_id=vault_id,
- output_processed_image=output_processed_image,
- output_ocr_text=output_ocr_text,
- masking_method=masking_method,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- async def deidentify_presentation(
- self,
*,
- file: FileDataDeidentifyPresentation,
- vault_id: str,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileRequestDeidentifyPresentationEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
+ table_name: str,
+ column_name: str,
+ file: core.File,
+ skyflow_id: typing.Optional[str] = OMIT,
+ return_file_metadata: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
+ ) -> UploadFileResponseV2:
"""
- De-identifies sensitive data from a presentation file. This operation includes options applicable to all supported presentation file types.
For broader file type support, see De-identify File.
+ Uploads a file to a new or specified record.
Parameters
----------
- file : FileDataDeidentifyPresentation
-
vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyPresentationEntityTypesItem]]
- Entities to detect and de-identify.
- token_type : typing.Optional[TokenTypeMapping]
+ table_name : str
+ Name of the table.
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
+ column_name : str
+ Name of the column that contains the file.
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
+ file : core.File
+ See core.File for more documentation
- transformations : typing.Optional[Transformations]
+ skyflow_id : typing.Optional[str]
+ ID of the record to update.
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
+ return_file_metadata : typing.Optional[bool]
+ If `true`, returns metadata about the uploaded file.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- DeidentifyFileResponse
+ UploadFileResponseV2
OK
Examples
--------
- import asyncio
-
- from skyflow import AsyncSkyflow, FileDataDeidentifyPresentation
+ from skyflow import SkyflowAuth
- client = AsyncSkyflow(
+ client = SkyflowAuth(
token="YOUR_TOKEN",
)
-
-
- async def main() -> None:
- await client.files.deidentify_presentation(
- file=FileDataDeidentifyPresentation(
- base_64="base64",
- data_format="ppt",
- ),
- vault_id="vault_id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.deidentify_presentation(
- file=file,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- async def deidentify_spreadsheet(
- self,
- *,
- file: FileDataDeidentifySpreadsheet,
- vault_id: str,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from a spreadsheet file. This operation includes options applicable to all supported spreadsheet file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifySpreadsheet
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow, FileDataDeidentifySpreadsheet
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
+ client.files.upload_file_v2(
+ vault_id="vaultID",
+ table_name="tableName",
+ column_name="columnName",
)
-
-
- async def main() -> None:
- await client.files.deidentify_spreadsheet(
- file=FileDataDeidentifySpreadsheet(
- base_64="base64",
- data_format="csv",
- ),
- vault_id="vault_id",
- )
-
-
- asyncio.run(main())
"""
- _response = await self._raw_client.deidentify_spreadsheet(
+ _response = self._raw_client.upload_file_v2(
+ vault_id,
+ table_name=table_name,
+ column_name=column_name,
file=file,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
+ skyflow_id=skyflow_id,
+ return_file_metadata=return_file_metadata,
request_options=request_options,
)
return _response.data
- async def deidentify_structured_text(
- self,
- *,
- file: FileDataDeidentifyStructuredText,
- vault_id: str,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
- """
- De-identifies sensitive data from a structured text file. This operation includes options applicable to all supported structured text file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyStructuredText
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
+class AsyncFilesClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._raw_client = AsyncRawFilesClient(client_wrapper=client_wrapper)
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
+ @property
+ def with_raw_response(self) -> AsyncRawFilesClient:
+ """
+ Retrieves a raw implementation of this client that returns raw responses.
Returns
-------
- DeidentifyFileResponse
- OK
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow, FileDataDeidentifyStructuredText
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.files.deidentify_structured_text(
- file=FileDataDeidentifyStructuredText(
- base_64="base64",
- data_format="json",
- ),
- vault_id="vault_id",
- )
-
-
- asyncio.run(main())
+ AsyncRawFilesClient
"""
- _response = await self._raw_client.deidentify_structured_text(
- file=file,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
+ return self._raw_client
- async def deidentify_text(
+ async def upload_file_v2(
self,
- *,
- file: FileDataDeidentifyText,
vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyTextEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
+ *,
+ table_name: str,
+ column_name: str,
+ file: core.File,
+ skyflow_id: typing.Optional[str] = OMIT,
+ return_file_metadata: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyFileResponse:
+ ) -> UploadFileResponseV2:
"""
- De-identifies sensitive data from a text file. This operation includes options applicable to all supported image text types.
For broader file type support, see De-identify File.
+ Uploads a file to a new or specified record.
Parameters
----------
- file : FileDataDeidentifyText
-
vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyTextEntityTypesItem]]
- Entities to detect and de-identify.
- token_type : typing.Optional[TokenTypeMapping]
+ table_name : str
+ Name of the table.
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
+ column_name : str
+ Name of the column that contains the file.
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
+ file : core.File
+ See core.File for more documentation
- transformations : typing.Optional[Transformations]
+ skyflow_id : typing.Optional[str]
+ ID of the record to update.
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
+ return_file_metadata : typing.Optional[bool]
+ If `true`, returns metadata about the uploaded file.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- DeidentifyFileResponse
+ UploadFileResponseV2
OK
Examples
--------
import asyncio
- from skyflow import AsyncSkyflow, FileDataDeidentifyText
+ from skyflow import AsyncSkyflowAuth
- client = AsyncSkyflow(
+ client = AsyncSkyflowAuth(
token="YOUR_TOKEN",
)
async def main() -> None:
- await client.files.deidentify_text(
- file=FileDataDeidentifyText(
- base_64="base64",
- ),
- vault_id="vault_id",
+ await client.files.upload_file_v2(
+ vault_id="vaultID",
+ table_name="tableName",
+ column_name="columnName",
)
asyncio.run(main())
"""
- _response = await self._raw_client.deidentify_text(
+ _response = await self._raw_client.upload_file_v2(
+ vault_id,
+ table_name=table_name,
+ column_name=column_name,
file=file,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
+ skyflow_id=skyflow_id,
+ return_file_metadata=return_file_metadata,
request_options=request_options,
)
return _response.data
-
- async def reidentify_file(
- self,
- *,
- file: FileDataReidentifyFile,
- vault_id: str,
- format: typing.Optional[Format] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> ReidentifyFileResponse:
- """
- Re-identifies tokens in a file.
-
- Parameters
- ----------
- file : FileDataReidentifyFile
-
- vault_id : str
- ID of the vault where the entities are stored.
-
- format : typing.Optional[Format]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- ReidentifyFileResponse
- OK
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow, FileDataReidentifyFile
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.files.reidentify_file(
- file=FileDataReidentifyFile(
- base_64="base64",
- data_format="txt",
- ),
- vault_id="vault_id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.reidentify_file(
- file=file, vault_id=vault_id, format=format, request_options=request_options
- )
- return _response.data
-
- async def get_run(
- self,
- run_id: str,
- *,
- vault_id: typing.Optional[str] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DetectRunsResponse:
- """
- Returns the status of a detect run.
-
- Parameters
- ----------
- run_id : str
-
- vault_id : typing.Optional[str]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DetectRunsResponse
- OK
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.files.get_run(
- run_id="run_id",
- vault_id="vault_id",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.get_run(run_id, vault_id=vault_id, request_options=request_options)
- return _response.data
diff --git a/skyvault/skyflow/generated/rest/files/raw_client.py b/skyvault/skyflow/generated/rest/files/raw_client.py
index 863ae5e3..c32bc035 100644
--- a/skyvault/skyflow/generated/rest/files/raw_client.py
+++ b/skyvault/skyflow/generated/rest/files/raw_client.py
@@ -3,64 +3,21 @@
import typing
from json.decoder import JSONDecodeError
+from .. import core
from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.http_response import AsyncHttpResponse, HttpResponse
-from ..core.jsonable_encoder import jsonable_encoder
+from ..core.jsonable_encoder import encode_path_param
+from ..core.parse_error import ParsingError
from ..core.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
-from ..core.serialization import convert_and_respect_annotation_metadata
from ..errors.bad_request_error import BadRequestError
from ..errors.internal_server_error import InternalServerError
+from ..errors.not_found_error import NotFoundError
from ..errors.unauthorized_error import UnauthorizedError
-from ..types.deidentify_file_response import DeidentifyFileResponse
-from ..types.detect_runs_response import DetectRunsResponse
from ..types.error_response import ErrorResponse
-from ..types.file_data import FileData
-from ..types.file_data_deidentify_audio import FileDataDeidentifyAudio
-from ..types.file_data_deidentify_document import FileDataDeidentifyDocument
-from ..types.file_data_deidentify_image import FileDataDeidentifyImage
-from ..types.file_data_deidentify_pdf import FileDataDeidentifyPdf
-from ..types.file_data_deidentify_presentation import FileDataDeidentifyPresentation
-from ..types.file_data_deidentify_spreadsheet import FileDataDeidentifySpreadsheet
-from ..types.file_data_deidentify_structured_text import FileDataDeidentifyStructuredText
-from ..types.file_data_deidentify_text import FileDataDeidentifyText
-from ..types.file_data_reidentify_file import FileDataReidentifyFile
-from ..types.format import Format
-from ..types.reidentify_file_response import ReidentifyFileResponse
-from ..types.token_type_mapping import TokenTypeMapping
-from ..types.transformations import Transformations
-from .types.deidentify_file_audio_request_deidentify_audio_entity_types_item import (
- DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem,
-)
-from .types.deidentify_file_audio_request_deidentify_audio_output_transcription import (
- DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription,
-)
-from .types.deidentify_file_document_pdf_request_deidentify_pdf_entity_types_item import (
- DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem,
-)
-from .types.deidentify_file_image_request_deidentify_image_entity_types_item import (
- DeidentifyFileImageRequestDeidentifyImageEntityTypesItem,
-)
-from .types.deidentify_file_image_request_deidentify_image_masking_method import (
- DeidentifyFileImageRequestDeidentifyImageMaskingMethod,
-)
-from .types.deidentify_file_request_deidentify_document_entity_types_item import (
- DeidentifyFileRequestDeidentifyDocumentEntityTypesItem,
-)
-from .types.deidentify_file_request_deidentify_presentation_entity_types_item import (
- DeidentifyFileRequestDeidentifyPresentationEntityTypesItem,
-)
-from .types.deidentify_file_request_deidentify_spreadsheet_entity_types_item import (
- DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem,
-)
-from .types.deidentify_file_request_deidentify_structured_text_entity_types_item import (
- DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem,
-)
-from .types.deidentify_file_request_deidentify_text_entity_types_item import (
- DeidentifyFileRequestDeidentifyTextEntityTypesItem,
-)
-from .types.deidentify_file_request_entity_types_item import DeidentifyFileRequestEntityTypesItem
+from ..types.upload_file_response_v2 import UploadFileResponseV2
+from pydantic import ValidationError
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -70,110 +27,75 @@ class RawFilesClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
self._client_wrapper = client_wrapper
- def deidentify_file(
+ def upload_file_v2(
self,
- *,
- file: FileData,
vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileRequestEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
+ *,
+ table_name: str,
+ column_name: str,
+ file: core.File,
+ skyflow_id: typing.Optional[str] = OMIT,
+ return_file_metadata: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[DeidentifyFileResponse]:
+ ) -> HttpResponse[UploadFileResponseV2]:
"""
- De-identifies sensitive data from a file. This operation includes options applicable to all supported file types.
For more specific options, see the category-specific operations (like De-identify Document) and the file type-specific opertions (like De-identify PDF).
+ Uploads a file to a new or specified record.
Parameters
----------
- file : FileData
-
vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestEntityTypesItem]]
- Entities to detect and de-identify.
- token_type : typing.Optional[TokenTypeMapping]
+ table_name : str
+ Name of the table.
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
+ column_name : str
+ Name of the column that contains the file.
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
+ file : core.File
+ See core.File for more documentation
- transformations : typing.Optional[Transformations]
+ skyflow_id : typing.Optional[str]
+ ID of the record to update.
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
+ return_file_metadata : typing.Optional[bool]
+ If `true`, returns metadata about the uploaded file.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- HttpResponse[DeidentifyFileResponse]
+ HttpResponse[UploadFileResponseV2]
OK
"""
_response = self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file",
+ f"v2/vaults/{encode_path_param(vault_id)}/files/upload",
method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(object_=file, annotation=FileData, direction="write"),
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
+ data={
+ "tableName": table_name,
+ "columnName": column_name,
+ "skyflowID": skyflow_id,
+ "returnFileMetadata": return_file_metadata,
},
- headers={
- "content-type": "application/json",
+ files={
+ "file": file,
},
request_options=request_options,
omit=OMIT,
+ force_multipart=True,
)
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- DeidentifyFileResponse,
+ UploadFileResponseV2,
parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
+ type_=UploadFileResponseV2, # type: ignore
object_=_response.json(),
),
)
return HttpResponse(response=_response, data=_data)
if _response.status_code == 400:
raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
headers=dict(_response.headers),
body=typing.cast(
ErrorResponse,
@@ -183,147 +105,8 @@ def deidentify_file(
),
),
)
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- def deidentify_audio(
- self,
- *,
- file: FileDataDeidentifyAudio,
- vault_id: str,
- output_transcription: typing.Optional[DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription] = OMIT,
- output_processed_audio: typing.Optional[bool] = OMIT,
- bleep_start_padding: typing.Optional[float] = OMIT,
- bleep_stop_padding: typing.Optional[float] = OMIT,
- bleep_frequency: typing.Optional[int] = OMIT,
- bleep_gain: typing.Optional[int] = OMIT,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from an audio file. This operation includes options applicable to all supported audio file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyAudio
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- output_transcription : typing.Optional[DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription]
- Type of transcription to output.
-
- output_processed_audio : typing.Optional[bool]
- Whether to include the processed audio file in the response.
-
- bleep_start_padding : typing.Optional[float]
- Padding added to the beginning of a bleep, in seconds.
-
- bleep_stop_padding : typing.Optional[float]
- Padding added to the end of a bleep, in seconds.
-
- bleep_frequency : typing.Optional[int]
- The pitch of the bleep sound, in Hz. The higher the number, the higher the pitch.
-
- bleep_gain : typing.Optional[int]
- Relative loudness of the bleep in dB. Positive values increase its loudness, and negative values decrease it.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/audio",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyAudio, direction="write"
- ),
- "vault_id": vault_id,
- "output_transcription": output_transcription,
- "output_processed_audio": output_processed_audio,
- "bleep_start_padding": bleep_start_padding,
- "bleep_stop_padding": bleep_stop_padding,
- "bleep_frequency": bleep_frequency,
- "bleep_gain": bleep_gain,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
if _response.status_code == 401:
raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
headers=dict(_response.headers),
body=typing.cast(
ErrorResponse,
@@ -333,117 +116,8 @@ def deidentify_audio(
),
),
)
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- def deidentify_document(
- self,
- *,
- file: FileDataDeidentifyDocument,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyDocumentEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a document file. This operation includes options applicable to all supported document file types.
For more specific options, see the file type-specific opertions (like De-identify PDF) where they're available. For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyDocument
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyDocumentEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/document",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyDocument, direction="write"
- ),
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
+ if _response.status_code == 404:
+ raise NotFoundError(
headers=dict(_response.headers),
body=typing.cast(
ErrorResponse,
@@ -453,127 +127,6 @@ def deidentify_document(
),
),
)
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- def deidentify_pdf(
- self,
- *,
- file: FileDataDeidentifyPdf,
- vault_id: str,
- density: typing.Optional[int] = OMIT,
- max_resolution: typing.Optional[int] = OMIT,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a PDF file. This operation includes options specific to PDF files.
For broader file type support, see De-identify Document and De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyPdf
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- density : typing.Optional[int]
- Pixel density at which to process the PDF file.
-
- max_resolution : typing.Optional[int]
- Max resolution at which to process the PDF file.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/document/pdf",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyPdf, direction="write"
- ),
- "vault_id": vault_id,
- "density": density,
- "max_resolution": max_resolution,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
if _response.status_code == 500:
raise InternalServerError(
headers=dict(_response.headers),
@@ -588,112 +141,91 @@ def deidentify_pdf(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
- def deidentify_image(
+
+class AsyncRawFilesClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
+
+ async def upload_file_v2(
self,
- *,
- file: FileDataDeidentifyImage,
vault_id: str,
- output_processed_image: typing.Optional[bool] = OMIT,
- output_ocr_text: typing.Optional[bool] = OMIT,
- masking_method: typing.Optional[DeidentifyFileImageRequestDeidentifyImageMaskingMethod] = OMIT,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileImageRequestDeidentifyImageEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
+ *,
+ table_name: str,
+ column_name: str,
+ file: core.File,
+ skyflow_id: typing.Optional[str] = OMIT,
+ return_file_metadata: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[DeidentifyFileResponse]:
+ ) -> AsyncHttpResponse[UploadFileResponseV2]:
"""
- De-identifies sensitive data from an image file. This operation includes options applicable to all supported image file types.
For broader file type support, see De-identify File.
+ Uploads a file to a new or specified record.
Parameters
----------
- file : FileDataDeidentifyImage
-
vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- output_processed_image : typing.Optional[bool]
- If `true`, includes processed image in the output.
-
- output_ocr_text : typing.Optional[bool]
- If `true`, includes text detected by OCR in the response.
- masking_method : typing.Optional[DeidentifyFileImageRequestDeidentifyImageMaskingMethod]
- Method to mask the entities in the image.
+ table_name : str
+ Name of the table.
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileImageRequestDeidentifyImageEntityTypesItem]]
- Entities to detect and de-identify.
+ column_name : str
+ Name of the column that contains the file.
- token_type : typing.Optional[TokenTypeMapping]
+ file : core.File
+ See core.File for more documentation
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
+ skyflow_id : typing.Optional[str]
+ ID of the record to update.
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
+ return_file_metadata : typing.Optional[bool]
+ If `true`, returns metadata about the uploaded file.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- HttpResponse[DeidentifyFileResponse]
+ AsyncHttpResponse[UploadFileResponseV2]
OK
"""
- _response = self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/image",
+ _response = await self._client_wrapper.httpx_client.request(
+ f"v2/vaults/{encode_path_param(vault_id)}/files/upload",
method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyImage, direction="write"
- ),
- "vault_id": vault_id,
- "output_processed_image": output_processed_image,
- "output_ocr_text": output_ocr_text,
- "masking_method": masking_method,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
+ data={
+ "tableName": table_name,
+ "columnName": column_name,
+ "skyflowID": skyflow_id,
+ "returnFileMetadata": return_file_metadata,
},
- headers={
- "content-type": "application/json",
+ files={
+ "file": file,
},
request_options=request_options,
omit=OMIT,
+ force_multipart=True,
)
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- DeidentifyFileResponse,
+ UploadFileResponseV2,
parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
+ type_=UploadFileResponseV2, # type: ignore
object_=_response.json(),
),
)
- return HttpResponse(response=_response, data=_data)
+ return AsyncHttpResponse(response=_response, data=_data)
if _response.status_code == 400:
raise BadRequestError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -702,15 +234,15 @@ def deidentify_image(
raise UnauthorizedError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
)
- if _response.status_code == 500:
- raise InternalServerError(
+ if _response.status_code == 404:
+ raise NotFoundError(
headers=dict(_response.headers),
body=typing.cast(
ErrorResponse,
@@ -720,1971 +252,6 @@ def deidentify_image(
),
),
)
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- def deidentify_presentation(
- self,
- *,
- file: FileDataDeidentifyPresentation,
- vault_id: str,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileRequestDeidentifyPresentationEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a presentation file. This operation includes options applicable to all supported presentation file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyPresentation
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyPresentationEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/presentation",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyPresentation, direction="write"
- ),
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- def deidentify_spreadsheet(
- self,
- *,
- file: FileDataDeidentifySpreadsheet,
- vault_id: str,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a spreadsheet file. This operation includes options applicable to all supported spreadsheet file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifySpreadsheet
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/spreadsheet",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifySpreadsheet, direction="write"
- ),
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- def deidentify_structured_text(
- self,
- *,
- file: FileDataDeidentifyStructuredText,
- vault_id: str,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a structured text file. This operation includes options applicable to all supported structured text file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyStructuredText
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/structured_text",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyStructuredText, direction="write"
- ),
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- def deidentify_text(
- self,
- *,
- file: FileDataDeidentifyText,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyTextEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a text file. This operation includes options applicable to all supported image text types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyText
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyTextEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/text",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyText, direction="write"
- ),
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- def reidentify_file(
- self,
- *,
- file: FileDataReidentifyFile,
- vault_id: str,
- format: typing.Optional[Format] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[ReidentifyFileResponse]:
- """
- Re-identifies tokens in a file.
-
- Parameters
- ----------
- file : FileDataReidentifyFile
-
- vault_id : str
- ID of the vault where the entities are stored.
-
- format : typing.Optional[Format]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[ReidentifyFileResponse]
- OK
- """
- _response = self._client_wrapper.httpx_client.request(
- "v1/detect/reidentify/file",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataReidentifyFile, direction="write"
- ),
- "vault_id": vault_id,
- "format": convert_and_respect_annotation_metadata(object_=format, annotation=Format, direction="write"),
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- ReidentifyFileResponse,
- parse_obj_as(
- type_=ReidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- def get_run(
- self,
- run_id: str,
- *,
- vault_id: typing.Optional[str] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[DetectRunsResponse]:
- """
- Returns the status of a detect run.
-
- Parameters
- ----------
- run_id : str
-
- vault_id : typing.Optional[str]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[DetectRunsResponse]
- OK
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/detect/runs/{jsonable_encoder(run_id)}",
- method="GET",
- params={
- "vault_id": vault_id,
- },
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DetectRunsResponse,
- parse_obj_as(
- type_=DetectRunsResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
-
-class AsyncRawFilesClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- async def deidentify_file(
- self,
- *,
- file: FileData,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileRequestEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a file. This operation includes options applicable to all supported file types.
For more specific options, see the category-specific operations (like De-identify Document) and the file type-specific opertions (like De-identify PDF).
-
- Parameters
- ----------
- file : FileData
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(object_=file, annotation=FileData, direction="write"),
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def deidentify_audio(
- self,
- *,
- file: FileDataDeidentifyAudio,
- vault_id: str,
- output_transcription: typing.Optional[DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription] = OMIT,
- output_processed_audio: typing.Optional[bool] = OMIT,
- bleep_start_padding: typing.Optional[float] = OMIT,
- bleep_stop_padding: typing.Optional[float] = OMIT,
- bleep_frequency: typing.Optional[int] = OMIT,
- bleep_gain: typing.Optional[int] = OMIT,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from an audio file. This operation includes options applicable to all supported audio file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyAudio
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- output_transcription : typing.Optional[DeidentifyFileAudioRequestDeidentifyAudioOutputTranscription]
- Type of transcription to output.
-
- output_processed_audio : typing.Optional[bool]
- Whether to include the processed audio file in the response.
-
- bleep_start_padding : typing.Optional[float]
- Padding added to the beginning of a bleep, in seconds.
-
- bleep_stop_padding : typing.Optional[float]
- Padding added to the end of a bleep, in seconds.
-
- bleep_frequency : typing.Optional[int]
- The pitch of the bleep sound, in Hz. The higher the number, the higher the pitch.
-
- bleep_gain : typing.Optional[int]
- Relative loudness of the bleep in dB. Positive values increase its loudness, and negative values decrease it.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileAudioRequestDeidentifyAudioEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/audio",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyAudio, direction="write"
- ),
- "vault_id": vault_id,
- "output_transcription": output_transcription,
- "output_processed_audio": output_processed_audio,
- "bleep_start_padding": bleep_start_padding,
- "bleep_stop_padding": bleep_stop_padding,
- "bleep_frequency": bleep_frequency,
- "bleep_gain": bleep_gain,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def deidentify_document(
- self,
- *,
- file: FileDataDeidentifyDocument,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyDocumentEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a document file. This operation includes options applicable to all supported document file types.
For more specific options, see the file type-specific opertions (like De-identify PDF) where they're available. For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyDocument
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyDocumentEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/document",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyDocument, direction="write"
- ),
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def deidentify_pdf(
- self,
- *,
- file: FileDataDeidentifyPdf,
- vault_id: str,
- density: typing.Optional[int] = OMIT,
- max_resolution: typing.Optional[int] = OMIT,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a PDF file. This operation includes options specific to PDF files.
For broader file type support, see De-identify Document and De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyPdf
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- density : typing.Optional[int]
- Pixel density at which to process the PDF file.
-
- max_resolution : typing.Optional[int]
- Max resolution at which to process the PDF file.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileDocumentPdfRequestDeidentifyPdfEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/document/pdf",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyPdf, direction="write"
- ),
- "vault_id": vault_id,
- "density": density,
- "max_resolution": max_resolution,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def deidentify_image(
- self,
- *,
- file: FileDataDeidentifyImage,
- vault_id: str,
- output_processed_image: typing.Optional[bool] = OMIT,
- output_ocr_text: typing.Optional[bool] = OMIT,
- masking_method: typing.Optional[DeidentifyFileImageRequestDeidentifyImageMaskingMethod] = OMIT,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileImageRequestDeidentifyImageEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from an image file. This operation includes options applicable to all supported image file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyImage
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- output_processed_image : typing.Optional[bool]
- If `true`, includes processed image in the output.
-
- output_ocr_text : typing.Optional[bool]
- If `true`, includes text detected by OCR in the response.
-
- masking_method : typing.Optional[DeidentifyFileImageRequestDeidentifyImageMaskingMethod]
- Method to mask the entities in the image.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileImageRequestDeidentifyImageEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/image",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyImage, direction="write"
- ),
- "vault_id": vault_id,
- "output_processed_image": output_processed_image,
- "output_ocr_text": output_ocr_text,
- "masking_method": masking_method,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def deidentify_presentation(
- self,
- *,
- file: FileDataDeidentifyPresentation,
- vault_id: str,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileRequestDeidentifyPresentationEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a presentation file. This operation includes options applicable to all supported presentation file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyPresentation
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyPresentationEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/presentation",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyPresentation, direction="write"
- ),
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def deidentify_spreadsheet(
- self,
- *,
- file: FileDataDeidentifySpreadsheet,
- vault_id: str,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a spreadsheet file. This operation includes options applicable to all supported spreadsheet file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifySpreadsheet
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifySpreadsheetEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/spreadsheet",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifySpreadsheet, direction="write"
- ),
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def deidentify_structured_text(
- self,
- *,
- file: FileDataDeidentifyStructuredText,
- vault_id: str,
- entity_types: typing.Optional[
- typing.Sequence[DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem]
- ] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a structured text file. This operation includes options applicable to all supported structured text file types.
For broader file type support, see De-identify File.
-
- Parameters
- ----------
- file : FileDataDeidentifyStructuredText
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyStructuredTextEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[DeidentifyFileResponse]
- OK
- """
- _response = await self._client_wrapper.httpx_client.request(
- "v1/detect/deidentify/file/structured_text",
- method="POST",
- json={
- "file": convert_and_respect_annotation_metadata(
- object_=file, annotation=FileDataDeidentifyStructuredText, direction="write"
- ),
- "vault_id": vault_id,
- "entity_types": entity_types,
- "token_type": convert_and_respect_annotation_metadata(
- object_=token_type, annotation=TokenTypeMapping, direction="write"
- ),
- "allow_regex": allow_regex,
- "restrict_regex": restrict_regex,
- "transformations": convert_and_respect_annotation_metadata(
- object_=transformations, annotation=Transformations, direction="write"
- ),
- "configuration_id": configuration_id,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- DeidentifyFileResponse,
- parse_obj_as(
- type_=DeidentifyFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 400:
- raise BadRequestError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 401:
- raise UnauthorizedError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- if _response.status_code == 500:
- raise InternalServerError(
- headers=dict(_response.headers),
- body=typing.cast(
- ErrorResponse,
- parse_obj_as(
- type_=ErrorResponse, # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def deidentify_text(
- self,
- *,
- file: FileDataDeidentifyText,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyFileRequestDeidentifyTextEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[DeidentifyFileResponse]:
- """
- De-identifies sensitive data from a text file. This operation includes options applicable to all supported image text types.
If not specified, returns the first 25 records in the table.
- redaction : typing.Optional[RecordServiceBulkGetRecordRequestRedaction]
- Redaction level to enforce for the returned records. Subject to policies assigned to the API caller.
+ redaction : typing.Optional[GetRecordsRequestRedaction]
tokenization : typing.Optional[bool]
- If `true`, this operation returns tokens for fields with tokenization enabled. Only applicable if `skyflow_id` values are specified.
fields : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Fields to return for the record, with one value per `fields` URL parameter. For example, `?fields=abc&fields=123`.
If not specified, returns all fields.
offset : typing.Optional[str]
- Record position at which to start receiving data.
limit : typing.Optional[str]
- Number of record to return. Maximum 25.
download_url : typing.Optional[bool]
- If `true`, returns download URLs for fields with a file data type. URLs are valid for 15 minutes. If virus scanning is enabled, only returns if the file is clean.
column_name : typing.Optional[str]
- Name of the column. It must be configured as unique in the schema. If you provide both column name or column value, you cannot use `skyflow_ids`. Passing either of these parameters with `skyflow_ids` returns an error.
column_values : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Column values of the records to return, with one value per `column_values` URL parameter. For example, `?column_values=abc&column_values=123`.
`column_name` is mandatory when providing `column_values`. If you use column name or column value, you cannot use `skyflow_ids`. Passing either of these parameters with `skyflow_ids` returns an error.
- order_by : typing.Optional[RecordServiceBulkGetRecordRequestOrderBy]
- Order to return records, based on `skyflow_id` values. To disable, set to `NONE`.
+ order_by : typing.Optional[GetRecordsRequestOrderBy]
+
+ return_file_metadata : typing.Optional[bool]
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- V1BulkGetRecordResponse
- A successful response.
+ BulkGetRecordResponse
+ OK
Examples
--------
- from skyflow import Skyflow
+ from skyflow import SkyflowAuth
- client = Skyflow(
+ client = SkyflowAuth(
token="YOUR_TOKEN",
)
- client.records.record_service_bulk_get_record(
+ client.records.get_records(
vault_id="vaultID",
object_name="objectName",
- redaction="DEFAULT",
- tokenization=True,
- offset="offset",
- limit="limit",
- download_url=True,
- column_name="column_name",
- order_by="ASCENDING",
)
"""
- _response = self._raw_client.record_service_bulk_get_record(
+ _response = self._raw_client.get_records(
vault_id,
object_name,
skyflow_ids=skyflow_ids,
@@ -214,34 +194,33 @@ def record_service_bulk_get_record(
column_name=column_name,
column_values=column_values,
order_by=order_by,
+ return_file_metadata=return_file_metadata,
request_options=request_options,
)
return _response.data
- def record_service_insert_record(
+ def insert_records(
self,
vault_id: str,
object_name: str,
*,
- records: typing.Optional[typing.Sequence[V1FieldRecords]] = OMIT,
+ records: typing.Sequence[FieldRecords],
tokenization: typing.Optional[bool] = OMIT,
upsert: typing.Optional[str] = OMIT,
homogeneous: typing.Optional[bool] = OMIT,
- byot: typing.Optional[V1Byot] = OMIT,
+ byot: typing.Optional[InsertRecordRequestByot] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> V1InsertRecordResponse:
+ ) -> InsertRecordResponse:
"""
Inserts a record in the specified table.
The time-to-live (TTL) for a transient field begins when the field value is set during record insertion.
Columns that have a string data type and a uniqueness constraint accept strings up to 2500 characters. If an inserted string exceeds 2500 characters, the call returns a token insertion error.
Parameters
----------
vault_id : str
- ID of the vault.
object_name : str
- Name of the table.
- records : typing.Optional[typing.Sequence[V1FieldRecords]]
+ records : typing.Sequence[FieldRecords]
Record values and tokens.
tokenization : typing.Optional[bool]
@@ -253,28 +232,29 @@ def record_service_insert_record(
homogeneous : typing.Optional[bool]
If `true`, this operation mandates that all the records have the same fields. This parameter does not work with upsert.
- byot : typing.Optional[V1Byot]
+ byot : typing.Optional[InsertRecordRequestByot]
+ Token insertion behavior.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- V1InsertRecordResponse
- A successful response.
+ InsertRecordResponse
+ OK
Examples
--------
- from skyflow import Skyflow, V1FieldRecords
+ from skyflow import FieldRecords, SkyflowAuth
- client = Skyflow(
+ client = SkyflowAuth(
token="YOUR_TOKEN",
)
- client.records.record_service_insert_record(
+ client.records.insert_records(
vault_id="vaultID",
object_name="objectName",
records=[
- V1FieldRecords(
+ FieldRecords(
fields={
"drivers_license_number": "13456789",
"name": "John",
@@ -282,7 +262,7 @@ def record_service_insert_record(
"ssn": "123-45-6789",
},
),
- V1FieldRecords(
+ FieldRecords(
fields={
"drivers_license_number": "98765432",
"name": "James",
@@ -296,7 +276,7 @@ def record_service_insert_record(
homogeneous=False,
)
"""
- _response = self._raw_client.record_service_insert_record(
+ _response = self._raw_client.insert_records(
vault_id,
object_name,
records=records,
@@ -308,14 +288,14 @@ def record_service_insert_record(
)
return _response.data
- def record_service_bulk_delete_record(
+ def delete_records(
self,
vault_id: str,
object_name: str,
*,
skyflow_ids: typing.Optional[typing.Sequence[str]] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> V1BulkDeleteRecordResponse:
+ ) -> BulkDeleteRecordResponse:
"""
Deletes the specified records from a table.
@@ -335,17 +315,17 @@ def record_service_bulk_delete_record(
Returns
-------
- V1BulkDeleteRecordResponse
- A successful response.
+ BulkDeleteRecordResponse
+ OK
Examples
--------
- from skyflow import Skyflow
+ from skyflow import SkyflowAuth
- client = Skyflow(
+ client = SkyflowAuth(
token="YOUR_TOKEN",
)
- client.records.record_service_bulk_delete_record(
+ client.records.delete_records(
vault_id="vaultID",
object_name="objectName",
skyflow_ids=[
@@ -354,74 +334,67 @@ def record_service_bulk_delete_record(
],
)
"""
- _response = self._raw_client.record_service_bulk_delete_record(
+ _response = self._raw_client.delete_records(
vault_id, object_name, skyflow_ids=skyflow_ids, request_options=request_options
)
return _response.data
- def record_service_get_record(
+ def get_record_by_id(
self,
vault_id: str,
object_name: str,
id: str,
*,
- redaction: typing.Optional[RecordServiceGetRecordRequestRedaction] = None,
+ redaction: typing.Optional[GetRecordByIdRequestRedaction] = None,
tokenization: typing.Optional[bool] = None,
fields: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
download_url: typing.Optional[bool] = None,
+ return_file_metadata: typing.Optional[bool] = None,
request_options: typing.Optional[RequestOptions] = None,
- ) -> V1FieldRecords:
+ ) -> GetFieldRecords:
"""
Returns the specified record from a table.
Parameters
----------
vault_id : str
- ID of the vault.
object_name : str
- Name of the table.
id : str
- `skyflow_id` of the record.
- redaction : typing.Optional[RecordServiceGetRecordRequestRedaction]
- Redaction level to enforce for the returned record. Subject to policies assigned to the API caller.
+ redaction : typing.Optional[GetRecordByIdRequestRedaction]
tokenization : typing.Optional[bool]
- If `true`, this operation returns tokens for fields with tokenization enabled. Only applicable if `skyflow_id` values are specified.
fields : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Fields to return for the record, with one value per `fields` URL parameter. For example, `?fields=abc&fields=123`.
If not specified, returns all fields.
download_url : typing.Optional[bool]
- If `true`, returns download URLs for fields with a file data type. URLs are valid for 15 minutes. If virus scanning is enabled, only returns if the file is clean.
+
+ return_file_metadata : typing.Optional[bool]
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- V1FieldRecords
- A successful response.
+ GetFieldRecords
+ OK
Examples
--------
- from skyflow import Skyflow
+ from skyflow import SkyflowAuth
- client = Skyflow(
+ client = SkyflowAuth(
token="YOUR_TOKEN",
)
- client.records.record_service_get_record(
+ client.records.get_record_by_id(
vault_id="vaultID",
object_name="objectName",
id="ID",
- redaction="DEFAULT",
- tokenization=True,
- download_url=True,
)
"""
- _response = self._raw_client.record_service_get_record(
+ _response = self._raw_client.get_record_by_id(
vault_id,
object_name,
id,
@@ -429,62 +402,61 @@ def record_service_get_record(
tokenization=tokenization,
fields=fields,
download_url=download_url,
+ return_file_metadata=return_file_metadata,
request_options=request_options,
)
return _response.data
- def record_service_update_record(
+ def update_record(
self,
vault_id: str,
object_name: str,
id: str,
*,
- record: typing.Optional[V1FieldRecords] = OMIT,
+ record: typing.Optional[FieldRecords] = OMIT,
tokenization: typing.Optional[bool] = OMIT,
- byot: typing.Optional[V1Byot] = OMIT,
+ byot: typing.Optional[UpdateRecordRequestByot] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> V1UpdateRecordResponse:
+ ) -> UpdateRecordResponse:
"""
Updates the specified record in a table.
When you update a field, include the entire contents you want the field to store. For JSON fields, include all nested fields and values. If a nested field isn't included, it's removed.
The time-to-live (TTL) for a transient field resets when the field value is updated.
Parameters
----------
vault_id : str
- ID of the vault.
object_name : str
- Name of the table.
id : str
- `skyflow_id` of the record.
- record : typing.Optional[V1FieldRecords]
+ record : typing.Optional[FieldRecords]
tokenization : typing.Optional[bool]
If `true`, this operation returns tokens for fields with tokenization enabled.
- byot : typing.Optional[V1Byot]
+ byot : typing.Optional[UpdateRecordRequestByot]
+ Token insertion behavior.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- V1UpdateRecordResponse
- A successful response.
+ UpdateRecordResponse
+ OK
Examples
--------
- from skyflow import Skyflow, V1FieldRecords
+ from skyflow import FieldRecords, SkyflowAuth
- client = Skyflow(
+ client = SkyflowAuth(
token="YOUR_TOKEN",
)
- client.records.record_service_update_record(
+ client.records.update_record(
vault_id="vaultID",
object_name="objectName",
id="ID",
- record=V1FieldRecords(
+ record=FieldRecords(
fields={
"drivers_license_number": "89867453",
"name": "Steve Smith",
@@ -495,7 +467,7 @@ def record_service_update_record(
tokenization=True,
)
"""
- _response = self._raw_client.record_service_update_record(
+ _response = self._raw_client.update_record(
vault_id,
object_name,
id,
@@ -506,9 +478,9 @@ def record_service_update_record(
)
return _response.data
- def record_service_delete_record(
+ def delete_record(
self, vault_id: str, object_name: str, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> V1DeleteRecordResponse:
+ ) -> DeleteRecordResponse:
"""
Deletes the specified record from a table.
Note: This method doesn't delete transient field tokens. Transient field values are available until they expire based on the fields' time-to-live (TTL) setting.
@@ -528,253 +500,23 @@ def record_service_delete_record(
Returns
-------
- V1DeleteRecordResponse
- A successful response.
-
- Examples
- --------
- from skyflow import Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.records.record_service_delete_record(
- vault_id="vaultID",
- object_name="objectName",
- id="ID",
- )
- """
- _response = self._raw_client.record_service_delete_record(
- vault_id, object_name, id, request_options=request_options
- )
- return _response.data
-
- def file_service_upload_file(
- self,
- vault_id: str,
- object_name: str,
- id: str,
- *,
- file: typing.Optional[core.File] = OMIT,
- column_name: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> V1UpdateRecordResponse:
- """
- Uploads a file to the specified record.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- object_name : str
- Name of the table.
-
- id : str
- `skyflow_id` of the record.
-
- file : typing.Optional[core.File]
- See core.File for more documentation
-
- column_name : typing.Optional[str]
- Name of the column to store the file in. The column must have a file data type.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- V1UpdateRecordResponse
- A successful response.
+ DeleteRecordResponse
+ OK
Examples
--------
- from skyflow import Skyflow
+ from skyflow import SkyflowAuth
- client = Skyflow(
+ client = SkyflowAuth(
token="YOUR_TOKEN",
)
- client.records.file_service_upload_file(
+ client.records.delete_record(
vault_id="vaultID",
object_name="objectName",
id="ID",
)
"""
- _response = self._raw_client.file_service_upload_file(
- vault_id, object_name, id, file=file, column_name=column_name, request_options=request_options
- )
- return _response.data
-
- def file_service_delete_file(
- self,
- vault_id: str,
- table_name: str,
- id: str,
- column_name: str,
- *,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> V1DeleteFileResponse:
- """
- Deletes a file from the specified record.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- table_name : str
- Name of the table.
-
- id : str
- `skyflow_id` of the record.
-
- column_name : str
- Name of the column that contains the file.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- V1DeleteFileResponse
- A successful response.
-
- Examples
- --------
- from skyflow import Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.records.file_service_delete_file(
- vault_id="vaultID",
- table_name="tableName",
- id="ID",
- column_name="columnName",
- )
- """
- _response = self._raw_client.file_service_delete_file(
- vault_id, table_name, id, column_name, request_options=request_options
- )
- return _response.data
-
- def file_service_get_file_scan_status(
- self,
- vault_id: str,
- table_name: str,
- id: str,
- column_name: str,
- *,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> V1GetFileScanStatusResponse:
- """
- Returns the anti-virus scan status of a file.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- table_name : str
- Name of the table.
-
- id : str
- `skyflow_id` of the record.
-
- column_name : str
- Name of the column that contains the file.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- V1GetFileScanStatusResponse
- A successful response.
-
- Examples
- --------
- from skyflow import Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.records.file_service_get_file_scan_status(
- vault_id="vaultID",
- table_name="tableName",
- id="ID",
- column_name="columnName",
- )
- """
- _response = self._raw_client.file_service_get_file_scan_status(
- vault_id, table_name, id, column_name, request_options=request_options
- )
- return _response.data
-
- def upload_file_v_2(
- self,
- vault_id: str,
- *,
- table_name: str,
- column_name: str,
- file: core.File,
- skyflow_id: typing.Optional[str] = OMIT,
- return_file_metadata: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> UploadFileV2Response:
- """
- Uploads the specified file to a record. If an existing record isn't specified, creates a new record and uploads the file to that record.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- table_name : str
- Name of the table to upload the file to.
-
- column_name : str
- Name of the column to upload the file to. The column must have a `file` data type.
-
- file : core.File
- See core.File for more documentation
-
- skyflow_id : typing.Optional[str]
- Skyflow ID of the record to upload the file to. If `skyflowID` isn't specified, a new record will be created.
-
- return_file_metadata : typing.Optional[bool]
- If `true`, returns metadata about the uploaded file.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- UploadFileV2Response
- File uploaded successfully.
-
- Examples
- --------
- from skyflow import Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.records.upload_file_v_2(
- vault_id="d4410ea01d83473ca09a24c6b03096d4",
- table_name="tableName",
- column_name="columnName",
- )
- """
- _response = self._raw_client.upload_file_v_2(
- vault_id,
- table_name=table_name,
- column_name=column_name,
- file=file,
- skyflow_id=skyflow_id,
- return_file_metadata=return_file_metadata,
- request_options=request_options,
- )
+ _response = self._raw_client.delete_record(vault_id, object_name, id, request_options=request_options)
return _response.data
@@ -793,15 +535,14 @@ def with_raw_response(self) -> AsyncRawRecordsClient:
"""
return self._raw_client
- async def record_service_batch_operation(
+ async def batch_operation(
self,
vault_id: str,
*,
- records: typing.Optional[typing.Sequence[V1BatchRecord]] = OMIT,
+ records: typing.Sequence[BatchRecord],
continue_on_error: typing.Optional[bool] = OMIT,
- byot: typing.Optional[V1Byot] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> V1BatchOperationResponse:
+ ) -> BatchOperationResponse:
"""
Performs multiple record operations in a single transaction.
@@ -810,38 +551,36 @@ async def record_service_batch_operation(
vault_id : str
ID of the vault.
- records : typing.Optional[typing.Sequence[V1BatchRecord]]
+ records : typing.Sequence[BatchRecord]
Record operations to perform.
continue_on_error : typing.Optional[bool]
- Continue performing operations on partial errors.
-
- byot : typing.Optional[V1Byot]
+ If `true`, continues processing remaining operations when one operation returns an error. If `false`, stops processing remaining operations when one operation returns an error.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- V1BatchOperationResponse
- A successful response.
+ BatchOperationResponse
+ OK
Examples
--------
import asyncio
- from skyflow import AsyncSkyflow, V1BatchRecord
+ from skyflow import AsyncSkyflowAuth, BatchRecord
- client = AsyncSkyflow(
+ client = AsyncSkyflowAuth(
token="YOUR_TOKEN",
)
async def main() -> None:
- await client.records.record_service_batch_operation(
+ await client.records.batch_operation(
vault_id="vaultID",
records=[
- V1BatchRecord(
+ BatchRecord(
fields={
"drivers_license_number": "89867453",
"name": "Connor",
@@ -856,7 +595,8 @@ async def main() -> None:
download_url=False,
upsert="drivers_license_number",
),
- V1BatchRecord(
+ BatchRecord(
+ fields={"key": "value"},
table_name="persons",
method="GET",
batch_id="persons-12345",
@@ -871,18 +611,18 @@ async def main() -> None:
asyncio.run(main())
"""
- _response = await self._raw_client.record_service_batch_operation(
- vault_id, records=records, continue_on_error=continue_on_error, byot=byot, request_options=request_options
+ _response = await self._raw_client.batch_operation(
+ vault_id, records=records, continue_on_error=continue_on_error, request_options=request_options
)
return _response.data
- async def record_service_bulk_get_record(
+ async def get_records(
self,
vault_id: str,
object_name: str,
*,
skyflow_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- redaction: typing.Optional[RecordServiceBulkGetRecordRequestRedaction] = None,
+ redaction: typing.Optional[GetRecordsRequestRedaction] = None,
tokenization: typing.Optional[bool] = None,
fields: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
offset: typing.Optional[str] = None,
@@ -890,86 +630,70 @@ async def record_service_bulk_get_record(
download_url: typing.Optional[bool] = None,
column_name: typing.Optional[str] = None,
column_values: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- order_by: typing.Optional[RecordServiceBulkGetRecordRequestOrderBy] = None,
+ order_by: typing.Optional[GetRecordsRequestOrderBy] = None,
+ return_file_metadata: typing.Optional[bool] = None,
request_options: typing.Optional[RequestOptions] = None,
- ) -> V1BulkGetRecordResponse:
+ ) -> BulkGetRecordResponse:
"""
- Gets the specified records from a table.
+ Returns the specified records from a table.
Parameters
----------
vault_id : str
- ID of the vault.
object_name : str
- Name of the table that contains the records.
skyflow_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- `skyflow_id` values of the records to return, with one value per `skyflow_ids` URL parameter. For example, `?skyflow_ids=abc&skyflow_ids=123`.
If not specified, returns the first 25 records in the table.
- redaction : typing.Optional[RecordServiceBulkGetRecordRequestRedaction]
- Redaction level to enforce for the returned records. Subject to policies assigned to the API caller.
+ redaction : typing.Optional[GetRecordsRequestRedaction]
tokenization : typing.Optional[bool]
- If `true`, this operation returns tokens for fields with tokenization enabled. Only applicable if `skyflow_id` values are specified.
fields : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Fields to return for the record, with one value per `fields` URL parameter. For example, `?fields=abc&fields=123`.
If not specified, returns all fields.
offset : typing.Optional[str]
- Record position at which to start receiving data.
limit : typing.Optional[str]
- Number of record to return. Maximum 25.
download_url : typing.Optional[bool]
- If `true`, returns download URLs for fields with a file data type. URLs are valid for 15 minutes. If virus scanning is enabled, only returns if the file is clean.
column_name : typing.Optional[str]
- Name of the column. It must be configured as unique in the schema. If you provide both column name or column value, you cannot use `skyflow_ids`. Passing either of these parameters with `skyflow_ids` returns an error.
column_values : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Column values of the records to return, with one value per `column_values` URL parameter. For example, `?column_values=abc&column_values=123`.
`column_name` is mandatory when providing `column_values`. If you use column name or column value, you cannot use `skyflow_ids`. Passing either of these parameters with `skyflow_ids` returns an error.
- order_by : typing.Optional[RecordServiceBulkGetRecordRequestOrderBy]
- Order to return records, based on `skyflow_id` values. To disable, set to `NONE`.
+ order_by : typing.Optional[GetRecordsRequestOrderBy]
+
+ return_file_metadata : typing.Optional[bool]
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- V1BulkGetRecordResponse
- A successful response.
+ BulkGetRecordResponse
+ OK
Examples
--------
import asyncio
- from skyflow import AsyncSkyflow
+ from skyflow import AsyncSkyflowAuth
- client = AsyncSkyflow(
+ client = AsyncSkyflowAuth(
token="YOUR_TOKEN",
)
async def main() -> None:
- await client.records.record_service_bulk_get_record(
+ await client.records.get_records(
vault_id="vaultID",
object_name="objectName",
- redaction="DEFAULT",
- tokenization=True,
- offset="offset",
- limit="limit",
- download_url=True,
- column_name="column_name",
- order_by="ASCENDING",
)
asyncio.run(main())
"""
- _response = await self._raw_client.record_service_bulk_get_record(
+ _response = await self._raw_client.get_records(
vault_id,
object_name,
skyflow_ids=skyflow_ids,
@@ -982,34 +706,33 @@ async def main() -> None:
column_name=column_name,
column_values=column_values,
order_by=order_by,
+ return_file_metadata=return_file_metadata,
request_options=request_options,
)
return _response.data
- async def record_service_insert_record(
+ async def insert_records(
self,
vault_id: str,
object_name: str,
*,
- records: typing.Optional[typing.Sequence[V1FieldRecords]] = OMIT,
+ records: typing.Sequence[FieldRecords],
tokenization: typing.Optional[bool] = OMIT,
upsert: typing.Optional[str] = OMIT,
homogeneous: typing.Optional[bool] = OMIT,
- byot: typing.Optional[V1Byot] = OMIT,
+ byot: typing.Optional[InsertRecordRequestByot] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> V1InsertRecordResponse:
+ ) -> InsertRecordResponse:
"""
Inserts a record in the specified table.
The time-to-live (TTL) for a transient field begins when the field value is set during record insertion.
Columns that have a string data type and a uniqueness constraint accept strings up to 2500 characters. If an inserted string exceeds 2500 characters, the call returns a token insertion error.
Parameters
----------
vault_id : str
- ID of the vault.
object_name : str
- Name of the table.
- records : typing.Optional[typing.Sequence[V1FieldRecords]]
+ records : typing.Sequence[FieldRecords]
Record values and tokens.
tokenization : typing.Optional[bool]
@@ -1021,33 +744,34 @@ async def record_service_insert_record(
homogeneous : typing.Optional[bool]
If `true`, this operation mandates that all the records have the same fields. This parameter does not work with upsert.
- byot : typing.Optional[V1Byot]
+ byot : typing.Optional[InsertRecordRequestByot]
+ Token insertion behavior.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- V1InsertRecordResponse
- A successful response.
+ InsertRecordResponse
+ OK
Examples
--------
import asyncio
- from skyflow import AsyncSkyflow, V1FieldRecords
+ from skyflow import AsyncSkyflowAuth, FieldRecords
- client = AsyncSkyflow(
+ client = AsyncSkyflowAuth(
token="YOUR_TOKEN",
)
async def main() -> None:
- await client.records.record_service_insert_record(
+ await client.records.insert_records(
vault_id="vaultID",
object_name="objectName",
records=[
- V1FieldRecords(
+ FieldRecords(
fields={
"drivers_license_number": "13456789",
"name": "John",
@@ -1055,7 +779,7 @@ async def main() -> None:
"ssn": "123-45-6789",
},
),
- V1FieldRecords(
+ FieldRecords(
fields={
"drivers_license_number": "98765432",
"name": "James",
@@ -1072,7 +796,7 @@ async def main() -> None:
asyncio.run(main())
"""
- _response = await self._raw_client.record_service_insert_record(
+ _response = await self._raw_client.insert_records(
vault_id,
object_name,
records=records,
@@ -1084,14 +808,14 @@ async def main() -> None:
)
return _response.data
- async def record_service_bulk_delete_record(
+ async def delete_records(
self,
vault_id: str,
object_name: str,
*,
skyflow_ids: typing.Optional[typing.Sequence[str]] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> V1BulkDeleteRecordResponse:
+ ) -> BulkDeleteRecordResponse:
"""
Deletes the specified records from a table.
@@ -1111,22 +835,22 @@ async def record_service_bulk_delete_record(
Returns
-------
- V1BulkDeleteRecordResponse
- A successful response.
+ BulkDeleteRecordResponse
+ OK
Examples
--------
import asyncio
- from skyflow import AsyncSkyflow
+ from skyflow import AsyncSkyflowAuth
- client = AsyncSkyflow(
+ client = AsyncSkyflowAuth(
token="YOUR_TOKEN",
)
async def main() -> None:
- await client.records.record_service_bulk_delete_record(
+ await client.records.delete_records(
vault_id="vaultID",
object_name="objectName",
skyflow_ids=[
@@ -1138,82 +862,75 @@ async def main() -> None:
asyncio.run(main())
"""
- _response = await self._raw_client.record_service_bulk_delete_record(
+ _response = await self._raw_client.delete_records(
vault_id, object_name, skyflow_ids=skyflow_ids, request_options=request_options
)
return _response.data
- async def record_service_get_record(
+ async def get_record_by_id(
self,
vault_id: str,
object_name: str,
id: str,
*,
- redaction: typing.Optional[RecordServiceGetRecordRequestRedaction] = None,
+ redaction: typing.Optional[GetRecordByIdRequestRedaction] = None,
tokenization: typing.Optional[bool] = None,
fields: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
download_url: typing.Optional[bool] = None,
+ return_file_metadata: typing.Optional[bool] = None,
request_options: typing.Optional[RequestOptions] = None,
- ) -> V1FieldRecords:
+ ) -> GetFieldRecords:
"""
Returns the specified record from a table.
Parameters
----------
vault_id : str
- ID of the vault.
object_name : str
- Name of the table.
id : str
- `skyflow_id` of the record.
- redaction : typing.Optional[RecordServiceGetRecordRequestRedaction]
- Redaction level to enforce for the returned record. Subject to policies assigned to the API caller.
+ redaction : typing.Optional[GetRecordByIdRequestRedaction]
tokenization : typing.Optional[bool]
- If `true`, this operation returns tokens for fields with tokenization enabled. Only applicable if `skyflow_id` values are specified.
fields : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Fields to return for the record, with one value per `fields` URL parameter. For example, `?fields=abc&fields=123`.
If not specified, returns all fields.
download_url : typing.Optional[bool]
- If `true`, returns download URLs for fields with a file data type. URLs are valid for 15 minutes. If virus scanning is enabled, only returns if the file is clean.
+
+ return_file_metadata : typing.Optional[bool]
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- V1FieldRecords
- A successful response.
+ GetFieldRecords
+ OK
Examples
--------
import asyncio
- from skyflow import AsyncSkyflow
+ from skyflow import AsyncSkyflowAuth
- client = AsyncSkyflow(
+ client = AsyncSkyflowAuth(
token="YOUR_TOKEN",
)
async def main() -> None:
- await client.records.record_service_get_record(
+ await client.records.get_record_by_id(
vault_id="vaultID",
object_name="objectName",
id="ID",
- redaction="DEFAULT",
- tokenization=True,
- download_url=True,
)
asyncio.run(main())
"""
- _response = await self._raw_client.record_service_get_record(
+ _response = await self._raw_client.get_record_by_id(
vault_id,
object_name,
id,
@@ -1221,67 +938,66 @@ async def main() -> None:
tokenization=tokenization,
fields=fields,
download_url=download_url,
+ return_file_metadata=return_file_metadata,
request_options=request_options,
)
return _response.data
- async def record_service_update_record(
+ async def update_record(
self,
vault_id: str,
object_name: str,
id: str,
*,
- record: typing.Optional[V1FieldRecords] = OMIT,
+ record: typing.Optional[FieldRecords] = OMIT,
tokenization: typing.Optional[bool] = OMIT,
- byot: typing.Optional[V1Byot] = OMIT,
+ byot: typing.Optional[UpdateRecordRequestByot] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> V1UpdateRecordResponse:
+ ) -> UpdateRecordResponse:
"""
Updates the specified record in a table.
When you update a field, include the entire contents you want the field to store. For JSON fields, include all nested fields and values. If a nested field isn't included, it's removed.
The time-to-live (TTL) for a transient field resets when the field value is updated.
Parameters
----------
vault_id : str
- ID of the vault.
object_name : str
- Name of the table.
id : str
- `skyflow_id` of the record.
- record : typing.Optional[V1FieldRecords]
+ record : typing.Optional[FieldRecords]
tokenization : typing.Optional[bool]
If `true`, this operation returns tokens for fields with tokenization enabled.
- byot : typing.Optional[V1Byot]
+ byot : typing.Optional[UpdateRecordRequestByot]
+ Token insertion behavior.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- V1UpdateRecordResponse
- A successful response.
+ UpdateRecordResponse
+ OK
Examples
--------
import asyncio
- from skyflow import AsyncSkyflow, V1FieldRecords
+ from skyflow import AsyncSkyflowAuth, FieldRecords
- client = AsyncSkyflow(
+ client = AsyncSkyflowAuth(
token="YOUR_TOKEN",
)
async def main() -> None:
- await client.records.record_service_update_record(
+ await client.records.update_record(
vault_id="vaultID",
object_name="objectName",
id="ID",
- record=V1FieldRecords(
+ record=FieldRecords(
fields={
"drivers_license_number": "89867453",
"name": "Steve Smith",
@@ -1295,7 +1011,7 @@ async def main() -> None:
asyncio.run(main())
"""
- _response = await self._raw_client.record_service_update_record(
+ _response = await self._raw_client.update_record(
vault_id,
object_name,
id,
@@ -1306,9 +1022,9 @@ async def main() -> None:
)
return _response.data
- async def record_service_delete_record(
+ async def delete_record(
self, vault_id: str, object_name: str, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> V1DeleteRecordResponse:
+ ) -> DeleteRecordResponse:
"""
Deletes the specified record from a table.
Note: This method doesn't delete transient field tokens. Transient field values are available until they expire based on the fields' time-to-live (TTL) setting.
@@ -1328,22 +1044,22 @@ async def record_service_delete_record(
Returns
-------
- V1DeleteRecordResponse
- A successful response.
+ DeleteRecordResponse
+ OK
Examples
--------
import asyncio
- from skyflow import AsyncSkyflow
+ from skyflow import AsyncSkyflowAuth
- client = AsyncSkyflow(
+ client = AsyncSkyflowAuth(
token="YOUR_TOKEN",
)
async def main() -> None:
- await client.records.record_service_delete_record(
+ await client.records.delete_record(
vault_id="vaultID",
object_name="objectName",
id="ID",
@@ -1352,267 +1068,5 @@ async def main() -> None:
asyncio.run(main())
"""
- _response = await self._raw_client.record_service_delete_record(
- vault_id, object_name, id, request_options=request_options
- )
- return _response.data
-
- async def file_service_upload_file(
- self,
- vault_id: str,
- object_name: str,
- id: str,
- *,
- file: typing.Optional[core.File] = OMIT,
- column_name: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> V1UpdateRecordResponse:
- """
- Uploads a file to the specified record.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- object_name : str
- Name of the table.
-
- id : str
- `skyflow_id` of the record.
-
- file : typing.Optional[core.File]
- See core.File for more documentation
-
- column_name : typing.Optional[str]
- Name of the column to store the file in. The column must have a file data type.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- V1UpdateRecordResponse
- A successful response.
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.records.file_service_upload_file(
- vault_id="vaultID",
- object_name="objectName",
- id="ID",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.file_service_upload_file(
- vault_id, object_name, id, file=file, column_name=column_name, request_options=request_options
- )
- return _response.data
-
- async def file_service_delete_file(
- self,
- vault_id: str,
- table_name: str,
- id: str,
- column_name: str,
- *,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> V1DeleteFileResponse:
- """
- Deletes a file from the specified record.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- table_name : str
- Name of the table.
-
- id : str
- `skyflow_id` of the record.
-
- column_name : str
- Name of the column that contains the file.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- V1DeleteFileResponse
- A successful response.
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.records.file_service_delete_file(
- vault_id="vaultID",
- table_name="tableName",
- id="ID",
- column_name="columnName",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.file_service_delete_file(
- vault_id, table_name, id, column_name, request_options=request_options
- )
- return _response.data
-
- async def file_service_get_file_scan_status(
- self,
- vault_id: str,
- table_name: str,
- id: str,
- column_name: str,
- *,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> V1GetFileScanStatusResponse:
- """
- Returns the anti-virus scan status of a file.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- table_name : str
- Name of the table.
-
- id : str
- `skyflow_id` of the record.
-
- column_name : str
- Name of the column that contains the file.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- V1GetFileScanStatusResponse
- A successful response.
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.records.file_service_get_file_scan_status(
- vault_id="vaultID",
- table_name="tableName",
- id="ID",
- column_name="columnName",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.file_service_get_file_scan_status(
- vault_id, table_name, id, column_name, request_options=request_options
- )
- return _response.data
-
- async def upload_file_v_2(
- self,
- vault_id: str,
- *,
- table_name: str,
- column_name: str,
- file: core.File,
- skyflow_id: typing.Optional[str] = OMIT,
- return_file_metadata: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> UploadFileV2Response:
- """
- Uploads the specified file to a record. If an existing record isn't specified, creates a new record and uploads the file to that record.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- table_name : str
- Name of the table to upload the file to.
-
- column_name : str
- Name of the column to upload the file to. The column must have a `file` data type.
-
- file : core.File
- See core.File for more documentation
-
- skyflow_id : typing.Optional[str]
- Skyflow ID of the record to upload the file to. If `skyflowID` isn't specified, a new record will be created.
-
- return_file_metadata : typing.Optional[bool]
- If `true`, returns metadata about the uploaded file.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- UploadFileV2Response
- File uploaded successfully.
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.records.upload_file_v_2(
- vault_id="d4410ea01d83473ca09a24c6b03096d4",
- table_name="tableName",
- column_name="columnName",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.upload_file_v_2(
- vault_id,
- table_name=table_name,
- column_name=column_name,
- file=file,
- skyflow_id=skyflow_id,
- return_file_metadata=return_file_metadata,
- request_options=request_options,
- )
+ _response = await self._raw_client.delete_record(vault_id, object_name, id, request_options=request_options)
return _response.data
diff --git a/skyvault/skyflow/generated/rest/records/raw_client.py b/skyvault/skyflow/generated/rest/records/raw_client.py
index b42e0bc9..c3e3bf9c 100644
--- a/skyvault/skyflow/generated/rest/records/raw_client.py
+++ b/skyvault/skyflow/generated/rest/records/raw_client.py
@@ -3,11 +3,11 @@
import typing
from json.decoder import JSONDecodeError
-from .. import core
from ..core.api_error import ApiError
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.http_response import AsyncHttpResponse, HttpResponse
-from ..core.jsonable_encoder import jsonable_encoder
+from ..core.jsonable_encoder import encode_path_param
+from ..core.parse_error import ParsingError
from ..core.pydantic_utilities import parse_obj_as
from ..core.request_options import RequestOptions
from ..core.serialization import convert_and_respect_annotation_metadata
@@ -15,22 +15,22 @@
from ..errors.internal_server_error import InternalServerError
from ..errors.not_found_error import NotFoundError
from ..errors.unauthorized_error import UnauthorizedError
+from ..types.batch_operation_response import BatchOperationResponse
+from ..types.batch_record import BatchRecord
+from ..types.bulk_delete_record_response import BulkDeleteRecordResponse
+from ..types.bulk_get_record_response import BulkGetRecordResponse
+from ..types.delete_record_response import DeleteRecordResponse
from ..types.error_response import ErrorResponse
-from ..types.upload_file_v_2_response import UploadFileV2Response
-from ..types.v_1_batch_operation_response import V1BatchOperationResponse
-from ..types.v_1_batch_record import V1BatchRecord
-from ..types.v_1_bulk_delete_record_response import V1BulkDeleteRecordResponse
-from ..types.v_1_bulk_get_record_response import V1BulkGetRecordResponse
-from ..types.v_1_byot import V1Byot
-from ..types.v_1_delete_file_response import V1DeleteFileResponse
-from ..types.v_1_delete_record_response import V1DeleteRecordResponse
-from ..types.v_1_field_records import V1FieldRecords
-from ..types.v_1_get_file_scan_status_response import V1GetFileScanStatusResponse
-from ..types.v_1_insert_record_response import V1InsertRecordResponse
-from ..types.v_1_update_record_response import V1UpdateRecordResponse
-from .types.record_service_bulk_get_record_request_order_by import RecordServiceBulkGetRecordRequestOrderBy
-from .types.record_service_bulk_get_record_request_redaction import RecordServiceBulkGetRecordRequestRedaction
-from .types.record_service_get_record_request_redaction import RecordServiceGetRecordRequestRedaction
+from ..types.field_records import FieldRecords
+from ..types.get_field_records import GetFieldRecords
+from ..types.insert_record_response import InsertRecordResponse
+from ..types.update_record_response import UpdateRecordResponse
+from .types.get_record_by_id_request_redaction import GetRecordByIdRequestRedaction
+from .types.get_records_request_order_by import GetRecordsRequestOrderBy
+from .types.get_records_request_redaction import GetRecordsRequestRedaction
+from .types.insert_record_request_byot import InsertRecordRequestByot
+from .types.update_record_request_byot import UpdateRecordRequestByot
+from pydantic import ValidationError
# this is used as the default value for optional parameters
OMIT = typing.cast(typing.Any, ...)
@@ -40,15 +40,14 @@ class RawRecordsClient:
def __init__(self, *, client_wrapper: SyncClientWrapper):
self._client_wrapper = client_wrapper
- def record_service_batch_operation(
+ def batch_operation(
self,
vault_id: str,
*,
- records: typing.Optional[typing.Sequence[V1BatchRecord]] = OMIT,
+ records: typing.Sequence[BatchRecord],
continue_on_error: typing.Optional[bool] = OMIT,
- byot: typing.Optional[V1Byot] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[V1BatchOperationResponse]:
+ ) -> HttpResponse[BatchOperationResponse]:
"""
Performs multiple record operations in a single transaction.
@@ -57,31 +56,28 @@ def record_service_batch_operation(
vault_id : str
ID of the vault.
- records : typing.Optional[typing.Sequence[V1BatchRecord]]
+ records : typing.Sequence[BatchRecord]
Record operations to perform.
continue_on_error : typing.Optional[bool]
- Continue performing operations on partial errors.
-
- byot : typing.Optional[V1Byot]
+ If `true`, continues processing remaining operations when one operation returns an error. If `false`, stops processing remaining operations when one operation returns an error.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- HttpResponse[V1BatchOperationResponse]
- A successful response.
+ HttpResponse[BatchOperationResponse]
+ OK
"""
_response = self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}",
+ f"v1/vaults/{encode_path_param(vault_id)}",
method="POST",
json={
"records": convert_and_respect_annotation_metadata(
- object_=records, annotation=typing.Sequence[V1BatchRecord], direction="write"
+ object_=records, annotation=typing.Sequence[BatchRecord], direction="write"
),
"continueOnError": continue_on_error,
- "byot": byot,
},
headers={
"content-type": "application/json",
@@ -92,20 +88,53 @@ def record_service_batch_operation(
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- V1BatchOperationResponse,
+ BatchOperationResponse,
parse_obj_as(
- type_=V1BatchOperationResponse, # type: ignore
+ type_=BatchOperationResponse, # type: ignore
object_=_response.json(),
),
)
return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 404:
raise NotFoundError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -113,15 +142,19 @@ def record_service_batch_operation(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
- def record_service_bulk_get_record(
+ def get_records(
self,
vault_id: str,
object_name: str,
*,
skyflow_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- redaction: typing.Optional[RecordServiceBulkGetRecordRequestRedaction] = None,
+ redaction: typing.Optional[GetRecordsRequestRedaction] = None,
tokenization: typing.Optional[bool] = None,
fields: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
offset: typing.Optional[str] = None,
@@ -129,60 +162,51 @@ def record_service_bulk_get_record(
download_url: typing.Optional[bool] = None,
column_name: typing.Optional[str] = None,
column_values: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- order_by: typing.Optional[RecordServiceBulkGetRecordRequestOrderBy] = None,
+ order_by: typing.Optional[GetRecordsRequestOrderBy] = None,
+ return_file_metadata: typing.Optional[bool] = None,
request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[V1BulkGetRecordResponse]:
+ ) -> HttpResponse[BulkGetRecordResponse]:
"""
- Gets the specified records from a table.
+ Returns the specified records from a table.
Parameters
----------
vault_id : str
- ID of the vault.
object_name : str
- Name of the table that contains the records.
skyflow_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- `skyflow_id` values of the records to return, with one value per `skyflow_ids` URL parameter. For example, `?skyflow_ids=abc&skyflow_ids=123`.
If not specified, returns the first 25 records in the table.
- redaction : typing.Optional[RecordServiceBulkGetRecordRequestRedaction]
- Redaction level to enforce for the returned records. Subject to policies assigned to the API caller.
+ redaction : typing.Optional[GetRecordsRequestRedaction]
tokenization : typing.Optional[bool]
- If `true`, this operation returns tokens for fields with tokenization enabled. Only applicable if `skyflow_id` values are specified.
fields : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Fields to return for the record, with one value per `fields` URL parameter. For example, `?fields=abc&fields=123`.
If not specified, returns all fields.
offset : typing.Optional[str]
- Record position at which to start receiving data.
limit : typing.Optional[str]
- Number of record to return. Maximum 25.
download_url : typing.Optional[bool]
- If `true`, returns download URLs for fields with a file data type. URLs are valid for 15 minutes. If virus scanning is enabled, only returns if the file is clean.
column_name : typing.Optional[str]
- Name of the column. It must be configured as unique in the schema. If you provide both column name or column value, you cannot use `skyflow_ids`. Passing either of these parameters with `skyflow_ids` returns an error.
column_values : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Column values of the records to return, with one value per `column_values` URL parameter. For example, `?column_values=abc&column_values=123`.
When you update a field, include the entire contents you want the field to store. For JSON fields, include all nested fields and values. If a nested field isn't included, it's removed.
The time-to-live (TTL) for a transient field resets when the field value is updated.
Parameters
----------
vault_id : str
- ID of the vault.
object_name : str
- Name of the table.
id : str
- `skyflow_id` of the record.
- record : typing.Optional[V1FieldRecords]
+ record : typing.Optional[FieldRecords]
tokenization : typing.Optional[bool]
If `true`, this operation returns tokens for fields with tokenization enabled.
- byot : typing.Optional[V1Byot]
+ byot : typing.Optional[UpdateRecordRequestByot]
+ Token insertion behavior.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- HttpResponse[V1UpdateRecordResponse]
- A successful response.
+ HttpResponse[UpdateRecordResponse]
+ OK
"""
_response = self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(object_name)}/{jsonable_encoder(id)}",
+ f"v1/vaults/{encode_path_param(vault_id)}/{encode_path_param(object_name)}/{encode_path_param(id)}",
method="PUT",
json={
"record": convert_and_respect_annotation_metadata(
- object_=record, annotation=V1FieldRecords, direction="write"
+ object_=record, annotation=FieldRecords, direction="write"
),
"tokenization": tokenization,
"byot": byot,
@@ -523,20 +679,53 @@ def record_service_update_record(
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- V1UpdateRecordResponse,
+ UpdateRecordResponse,
parse_obj_as(
- type_=V1UpdateRecordResponse, # type: ignore
+ type_=UpdateRecordResponse, # type: ignore
object_=_response.json(),
),
)
return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 404:
raise NotFoundError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -544,11 +733,15 @@ def record_service_update_record(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
- def record_service_delete_record(
+ def delete_record(
self, vault_id: str, object_name: str, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> HttpResponse[V1DeleteRecordResponse]:
+ ) -> HttpResponse[DeleteRecordResponse]:
"""
Deletes the specified record from a table.
Note: This method doesn't delete transient field tokens. Transient field values are available until they expire based on the fields' time-to-live (TTL) setting.
@@ -568,31 +761,64 @@ def record_service_delete_record(
Returns
-------
- HttpResponse[V1DeleteRecordResponse]
- A successful response.
+ HttpResponse[DeleteRecordResponse]
+ OK
"""
_response = self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(object_name)}/{jsonable_encoder(id)}",
+ f"v1/vaults/{encode_path_param(vault_id)}/{encode_path_param(object_name)}/{encode_path_param(id)}",
method="DELETE",
request_options=request_options,
)
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- V1DeleteRecordResponse,
+ DeleteRecordResponse,
parse_obj_as(
- type_=V1DeleteRecordResponse, # type: ignore
+ type_=DeleteRecordResponse, # type: ignore
object_=_response.json(),
),
)
return HttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 404:
raise NotFoundError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -600,290 +826,79 @@ def record_service_delete_record(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
- def file_service_upload_file(
- self,
- vault_id: str,
- object_name: str,
- id: str,
- *,
- file: typing.Optional[core.File] = OMIT,
- column_name: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[V1UpdateRecordResponse]:
- """
- Uploads a file to the specified record.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- object_name : str
- Name of the table.
-
- id : str
- `skyflow_id` of the record.
-
- file : typing.Optional[core.File]
- See core.File for more documentation
-
- column_name : typing.Optional[str]
- Name of the column to store the file in. The column must have a file data type.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[V1UpdateRecordResponse]
- A successful response.
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(object_name)}/{jsonable_encoder(id)}/files",
- method="POST",
- data={
- "columnName": column_name,
- },
- files={
- **({"file": file} if file is not None else {}),
- },
- request_options=request_options,
- omit=OMIT,
- force_multipart=True,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- V1UpdateRecordResponse,
- parse_obj_as(
- type_=V1UpdateRecordResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 404:
- raise NotFoundError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- def file_service_delete_file(
- self,
- vault_id: str,
- table_name: str,
- id: str,
- column_name: str,
- *,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[V1DeleteFileResponse]:
- """
- Deletes a file from the specified record.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- table_name : str
- Name of the table.
-
- id : str
- `skyflow_id` of the record.
-
- column_name : str
- Name of the column that contains the file.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[V1DeleteFileResponse]
- A successful response.
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(table_name)}/{jsonable_encoder(id)}/files/{jsonable_encoder(column_name)}",
- method="DELETE",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- V1DeleteFileResponse,
- parse_obj_as(
- type_=V1DeleteFileResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 404:
- raise NotFoundError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- def file_service_get_file_scan_status(
- self,
- vault_id: str,
- table_name: str,
- id: str,
- column_name: str,
- *,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[V1GetFileScanStatusResponse]:
- """
- Returns the anti-virus scan status of a file.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- table_name : str
- Name of the table.
-
- id : str
- `skyflow_id` of the record.
-
- column_name : str
- Name of the column that contains the file.
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- HttpResponse[V1GetFileScanStatusResponse]
- A successful response.
- """
- _response = self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(table_name)}/{jsonable_encoder(id)}/files/{jsonable_encoder(column_name)}/scan-status",
- method="GET",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- V1GetFileScanStatusResponse,
- parse_obj_as(
- type_=V1GetFileScanStatusResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return HttpResponse(response=_response, data=_data)
- if _response.status_code == 404:
- raise NotFoundError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
+class AsyncRawRecordsClient:
+ def __init__(self, *, client_wrapper: AsyncClientWrapper):
+ self._client_wrapper = client_wrapper
- def upload_file_v_2(
+ async def batch_operation(
self,
vault_id: str,
*,
- table_name: str,
- column_name: str,
- file: core.File,
- skyflow_id: typing.Optional[str] = OMIT,
- return_file_metadata: typing.Optional[bool] = OMIT,
+ records: typing.Sequence[BatchRecord],
+ continue_on_error: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> HttpResponse[UploadFileV2Response]:
+ ) -> AsyncHttpResponse[BatchOperationResponse]:
"""
- Uploads the specified file to a record. If an existing record isn't specified, creates a new record and uploads the file to that record.
+ Performs multiple record operations in a single transaction.
Parameters
----------
vault_id : str
ID of the vault.
- table_name : str
- Name of the table to upload the file to.
-
- column_name : str
- Name of the column to upload the file to. The column must have a `file` data type.
-
- file : core.File
- See core.File for more documentation
-
- skyflow_id : typing.Optional[str]
- Skyflow ID of the record to upload the file to. If `skyflowID` isn't specified, a new record will be created.
+ records : typing.Sequence[BatchRecord]
+ Record operations to perform.
- return_file_metadata : typing.Optional[bool]
- If `true`, returns metadata about the uploaded file.
+ continue_on_error : typing.Optional[bool]
+ If `true`, continues processing remaining operations when one operation returns an error. If `false`, stops processing remaining operations when one operation returns an error.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- HttpResponse[UploadFileV2Response]
- File uploaded successfully.
+ AsyncHttpResponse[BatchOperationResponse]
+ OK
"""
- _response = self._client_wrapper.httpx_client.request(
- f"v2/vaults/{jsonable_encoder(vault_id)}/files/upload",
+ _response = await self._client_wrapper.httpx_client.request(
+ f"v1/vaults/{encode_path_param(vault_id)}",
method="POST",
- data={
- "tableName": table_name,
- "columnName": column_name,
- "skyflowID": skyflow_id,
- "returnFileMetadata": return_file_metadata,
+ json={
+ "records": convert_and_respect_annotation_metadata(
+ object_=records, annotation=typing.Sequence[BatchRecord], direction="write"
+ ),
+ "continueOnError": continue_on_error,
},
- files={
- "file": file,
+ headers={
+ "content-type": "application/json",
},
request_options=request_options,
omit=OMIT,
- force_multipart=True,
)
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- UploadFileV2Response,
+ BatchOperationResponse,
parse_obj_as(
- type_=UploadFileV2Response, # type: ignore
+ type_=BatchOperationResponse, # type: ignore
object_=_response.json(),
),
)
- return HttpResponse(response=_response, data=_data)
+ return AsyncHttpResponse(response=_response, data=_data)
if _response.status_code == 400:
raise BadRequestError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -892,9 +907,9 @@ def upload_file_v_2(
raise UnauthorizedError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -903,9 +918,9 @@ def upload_file_v_2(
raise NotFoundError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -924,95 +939,19 @@ def upload_file_v_2(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
-class AsyncRawRecordsClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._client_wrapper = client_wrapper
-
- async def record_service_batch_operation(
- self,
- vault_id: str,
- *,
- records: typing.Optional[typing.Sequence[V1BatchRecord]] = OMIT,
- continue_on_error: typing.Optional[bool] = OMIT,
- byot: typing.Optional[V1Byot] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[V1BatchOperationResponse]:
- """
- Performs multiple record operations in a single transaction.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- records : typing.Optional[typing.Sequence[V1BatchRecord]]
- Record operations to perform.
-
- continue_on_error : typing.Optional[bool]
- Continue performing operations on partial errors.
-
- byot : typing.Optional[V1Byot]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[V1BatchOperationResponse]
- A successful response.
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}",
- method="POST",
- json={
- "records": convert_and_respect_annotation_metadata(
- object_=records, annotation=typing.Sequence[V1BatchRecord], direction="write"
- ),
- "continueOnError": continue_on_error,
- "byot": byot,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- V1BatchOperationResponse,
- parse_obj_as(
- type_=V1BatchOperationResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 404:
- raise NotFoundError(
- headers=dict(_response.headers),
- body=typing.cast(
- typing.Optional[typing.Any],
- parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
- object_=_response.json(),
- ),
- ),
- )
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def record_service_bulk_get_record(
+ async def get_records(
self,
vault_id: str,
object_name: str,
*,
skyflow_ids: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- redaction: typing.Optional[RecordServiceBulkGetRecordRequestRedaction] = None,
+ redaction: typing.Optional[GetRecordsRequestRedaction] = None,
tokenization: typing.Optional[bool] = None,
fields: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
offset: typing.Optional[str] = None,
@@ -1020,60 +959,51 @@ async def record_service_bulk_get_record(
download_url: typing.Optional[bool] = None,
column_name: typing.Optional[str] = None,
column_values: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- order_by: typing.Optional[RecordServiceBulkGetRecordRequestOrderBy] = None,
+ order_by: typing.Optional[GetRecordsRequestOrderBy] = None,
+ return_file_metadata: typing.Optional[bool] = None,
request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[V1BulkGetRecordResponse]:
+ ) -> AsyncHttpResponse[BulkGetRecordResponse]:
"""
- Gets the specified records from a table.
+ Returns the specified records from a table.
Parameters
----------
vault_id : str
- ID of the vault.
object_name : str
- Name of the table that contains the records.
skyflow_ids : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- `skyflow_id` values of the records to return, with one value per `skyflow_ids` URL parameter. For example, `?skyflow_ids=abc&skyflow_ids=123`.
If not specified, returns the first 25 records in the table.
- redaction : typing.Optional[RecordServiceBulkGetRecordRequestRedaction]
- Redaction level to enforce for the returned records. Subject to policies assigned to the API caller.
+ redaction : typing.Optional[GetRecordsRequestRedaction]
tokenization : typing.Optional[bool]
- If `true`, this operation returns tokens for fields with tokenization enabled. Only applicable if `skyflow_id` values are specified.
fields : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Fields to return for the record, with one value per `fields` URL parameter. For example, `?fields=abc&fields=123`.
If not specified, returns all fields.
offset : typing.Optional[str]
- Record position at which to start receiving data.
limit : typing.Optional[str]
- Number of record to return. Maximum 25.
download_url : typing.Optional[bool]
- If `true`, returns download URLs for fields with a file data type. URLs are valid for 15 minutes. If virus scanning is enabled, only returns if the file is clean.
column_name : typing.Optional[str]
- Name of the column. It must be configured as unique in the schema. If you provide both column name or column value, you cannot use `skyflow_ids`. Passing either of these parameters with `skyflow_ids` returns an error.
column_values : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Column values of the records to return, with one value per `column_values` URL parameter. For example, `?column_values=abc&column_values=123`.
`column_name` is mandatory when providing `column_values`. If you use column name or column value, you cannot use `skyflow_ids`. Passing either of these parameters with `skyflow_ids` returns an error.
- order_by : typing.Optional[RecordServiceBulkGetRecordRequestOrderBy]
- Order to return records, based on `skyflow_id` values. To disable, set to `NONE`.
+ order_by : typing.Optional[GetRecordsRequestOrderBy]
+
+ return_file_metadata : typing.Optional[bool]
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- AsyncHttpResponse[V1BulkGetRecordResponse]
- A successful response.
+ AsyncHttpResponse[BulkGetRecordResponse]
+ OK
"""
_response = await self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(object_name)}",
+ f"v1/vaults/{encode_path_param(vault_id)}/{encode_path_param(object_name)}",
method="GET",
params={
"skyflow_ids": skyflow_ids,
@@ -1086,266 +1016,60 @@ async def record_service_bulk_get_record(
"column_name": column_name,
"column_values": column_values,
"order_by": order_by,
+ "returnFileMetadata": return_file_metadata,
},
request_options=request_options,
)
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- V1BulkGetRecordResponse,
+ BulkGetRecordResponse,
parse_obj_as(
- type_=V1BulkGetRecordResponse, # type: ignore
+ type_=BulkGetRecordResponse, # type: ignore
object_=_response.json(),
),
)
return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 404:
- raise NotFoundError(
+ if _response.status_code == 400:
+ raise BadRequestError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
)
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def record_service_insert_record(
- self,
- vault_id: str,
- object_name: str,
- *,
- records: typing.Optional[typing.Sequence[V1FieldRecords]] = OMIT,
- tokenization: typing.Optional[bool] = OMIT,
- upsert: typing.Optional[str] = OMIT,
- homogeneous: typing.Optional[bool] = OMIT,
- byot: typing.Optional[V1Byot] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[V1InsertRecordResponse]:
- """
- Inserts a record in the specified table.
The time-to-live (TTL) for a transient field begins when the field value is set during record insertion.
Columns that have a string data type and a uniqueness constraint accept strings up to 2500 characters. If an inserted string exceeds 2500 characters, the call returns a token insertion error.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- object_name : str
- Name of the table.
-
- records : typing.Optional[typing.Sequence[V1FieldRecords]]
- Record values and tokens.
-
- tokenization : typing.Optional[bool]
- If `true`, this operation returns tokens for fields with tokenization enabled.
-
- upsert : typing.Optional[str]
- Name of a unique column in the table. Uses upsert operations to check if a record exists based on the unique column's value. If a matching record exists, the record updates with the values you provide. If a matching record doesn't exist, the upsert operation inserts a new record.
When you upsert a field, include the entire contents you want the field to store. For JSON fields, include all nested fields and values. If a nested field isn't included, it's removed.
-
- homogeneous : typing.Optional[bool]
- If `true`, this operation mandates that all the records have the same fields. This parameter does not work with upsert.
-
- byot : typing.Optional[V1Byot]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[V1InsertRecordResponse]
- A successful response.
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(object_name)}",
- method="POST",
- json={
- "records": convert_and_respect_annotation_metadata(
- object_=records, annotation=typing.Sequence[V1FieldRecords], direction="write"
- ),
- "tokenization": tokenization,
- "upsert": upsert,
- "homogeneous": homogeneous,
- "byot": byot,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- V1InsertRecordResponse,
- parse_obj_as(
- type_=V1InsertRecordResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 404:
- raise NotFoundError(
+ if _response.status_code == 401:
+ raise UnauthorizedError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
)
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def record_service_bulk_delete_record(
- self,
- vault_id: str,
- object_name: str,
- *,
- skyflow_ids: typing.Optional[typing.Sequence[str]] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[V1BulkDeleteRecordResponse]:
- """
- Deletes the specified records from a table.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- object_name : str
- Name of the table.
-
- skyflow_ids : typing.Optional[typing.Sequence[str]]
- `skyflow_id` values of the records to delete. If `*` is specified, this operation deletes all records in the table.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[V1BulkDeleteRecordResponse]
- A successful response.
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(object_name)}",
- method="DELETE",
- json={
- "skyflow_ids": skyflow_ids,
- },
- headers={
- "content-type": "application/json",
- },
- request_options=request_options,
- omit=OMIT,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- V1BulkDeleteRecordResponse,
- parse_obj_as(
- type_=V1BulkDeleteRecordResponse, # type: ignore
- object_=_response.json(),
- ),
- )
- return AsyncHttpResponse(response=_response, data=_data)
if _response.status_code == 404:
raise NotFoundError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
)
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def record_service_get_record(
- self,
- vault_id: str,
- object_name: str,
- id: str,
- *,
- redaction: typing.Optional[RecordServiceGetRecordRequestRedaction] = None,
- tokenization: typing.Optional[bool] = None,
- fields: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
- download_url: typing.Optional[bool] = None,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[V1FieldRecords]:
- """
- Returns the specified record from a table.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- object_name : str
- Name of the table.
-
- id : str
- `skyflow_id` of the record.
-
- redaction : typing.Optional[RecordServiceGetRecordRequestRedaction]
- Redaction level to enforce for the returned record. Subject to policies assigned to the API caller.
-
- tokenization : typing.Optional[bool]
- If `true`, this operation returns tokens for fields with tokenization enabled. Only applicable if `skyflow_id` values are specified.
-
- fields : typing.Optional[typing.Union[str, typing.Sequence[str]]]
- Fields to return for the record, with one value per `fields` URL parameter. For example, `?fields=abc&fields=123`.
When you update a field, include the entire contents you want the field to store. For JSON fields, include all nested fields and values. If a nested field isn't included, it's removed.
The time-to-live (TTL) for a transient field resets when the field value is updated.
+ Inserts a record in the specified table.
The time-to-live (TTL) for a transient field begins when the field value is set during record insertion.
Columns that have a string data type and a uniqueness constraint accept strings up to 2500 characters. If an inserted string exceeds 2500 characters, the call returns a token insertion error.
Parameters
----------
vault_id : str
- ID of the vault.
object_name : str
- Name of the table.
-
- id : str
- `skyflow_id` of the record.
- record : typing.Optional[V1FieldRecords]
+ records : typing.Sequence[FieldRecords]
+ Record values and tokens.
tokenization : typing.Optional[bool]
If `true`, this operation returns tokens for fields with tokenization enabled.
- byot : typing.Optional[V1Byot]
+ upsert : typing.Optional[str]
+ Name of a unique column in the table. Uses upsert operations to check if a record exists based on the unique column's value. If a matching record exists, the record updates with the values you provide. If a matching record doesn't exist, the upsert operation inserts a new record.
When you upsert a field, include the entire contents you want the field to store. For JSON fields, include all nested fields and values. If a nested field isn't included, it's removed.
+
+ homogeneous : typing.Optional[bool]
+ If `true`, this operation mandates that all the records have the same fields. This parameter does not work with upsert.
+
+ byot : typing.Optional[InsertRecordRequestByot]
+ Token insertion behavior.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- AsyncHttpResponse[V1UpdateRecordResponse]
- A successful response.
+ AsyncHttpResponse[InsertRecordResponse]
+ OK
"""
_response = await self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(object_name)}/{jsonable_encoder(id)}",
- method="PUT",
+ f"v1/vaults/{encode_path_param(vault_id)}/{encode_path_param(object_name)}",
+ method="POST",
json={
- "record": convert_and_respect_annotation_metadata(
- object_=record, annotation=V1FieldRecords, direction="write"
+ "records": convert_and_respect_annotation_metadata(
+ object_=records, annotation=typing.Sequence[FieldRecords], direction="write"
),
"tokenization": tokenization,
+ "upsert": upsert,
+ "homogeneous": homogeneous,
"byot": byot,
},
headers={
@@ -1414,76 +1148,42 @@ async def record_service_update_record(
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- V1UpdateRecordResponse,
+ InsertRecordResponse,
parse_obj_as(
- type_=V1UpdateRecordResponse, # type: ignore
+ type_=InsertRecordResponse, # type: ignore
object_=_response.json(),
),
)
return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 404:
- raise NotFoundError(
+ if _response.status_code == 400:
+ raise BadRequestError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
)
- _response_json = _response.json()
- except JSONDecodeError:
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
- raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
-
- async def record_service_delete_record(
- self, vault_id: str, object_name: str, id: str, *, request_options: typing.Optional[RequestOptions] = None
- ) -> AsyncHttpResponse[V1DeleteRecordResponse]:
- """
- Deletes the specified record from a table.
Note: This method doesn't delete transient field tokens. Transient field values are available until they expire based on the fields' time-to-live (TTL) setting.
-
- Parameters
- ----------
- vault_id : str
- ID of the vault.
-
- object_name : str
- Name of the table.
-
- id : str
- `skyflow_id` of the record to delete.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- AsyncHttpResponse[V1DeleteRecordResponse]
- A successful response.
- """
- _response = await self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(object_name)}/{jsonable_encoder(id)}",
- method="DELETE",
- request_options=request_options,
- )
- try:
- if 200 <= _response.status_code < 300:
- _data = typing.cast(
- V1DeleteRecordResponse,
- parse_obj_as(
- type_=V1DeleteRecordResponse, # type: ignore
- object_=_response.json(),
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
),
)
- return AsyncHttpResponse(response=_response, data=_data)
- if _response.status_code == 404:
- raise NotFoundError(
+ if _response.status_code == 500:
+ raise InternalServerError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -1491,20 +1191,22 @@ async def record_service_delete_record(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
- async def file_service_upload_file(
+ async def delete_records(
self,
vault_id: str,
object_name: str,
- id: str,
*,
- file: typing.Optional[core.File] = OMIT,
- column_name: typing.Optional[str] = OMIT,
+ skyflow_ids: typing.Optional[typing.Sequence[str]] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[V1UpdateRecordResponse]:
+ ) -> AsyncHttpResponse[BulkDeleteRecordResponse]:
"""
- Uploads a file to the specified record.
+ Deletes the specified records from a table.
Parameters
----------
@@ -1514,53 +1216,79 @@ async def file_service_upload_file(
object_name : str
Name of the table.
- id : str
- `skyflow_id` of the record.
-
- file : typing.Optional[core.File]
- See core.File for more documentation
-
- column_name : typing.Optional[str]
- Name of the column to store the file in. The column must have a file data type.
+ skyflow_ids : typing.Optional[typing.Sequence[str]]
+ `skyflow_id` values of the records to delete. If `*` is specified, this operation deletes all records in the table.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- AsyncHttpResponse[V1UpdateRecordResponse]
- A successful response.
+ AsyncHttpResponse[BulkDeleteRecordResponse]
+ OK
"""
_response = await self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(object_name)}/{jsonable_encoder(id)}/files",
- method="POST",
- data={
- "columnName": column_name,
+ f"v1/vaults/{encode_path_param(vault_id)}/{encode_path_param(object_name)}",
+ method="DELETE",
+ json={
+ "skyflow_ids": skyflow_ids,
},
- files={
- **({"file": file} if file is not None else {}),
+ headers={
+ "content-type": "application/json",
},
request_options=request_options,
omit=OMIT,
- force_multipart=True,
)
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- V1UpdateRecordResponse,
+ BulkDeleteRecordResponse,
parse_obj_as(
- type_=V1UpdateRecordResponse, # type: ignore
+ type_=BulkDeleteRecordResponse, # type: ignore
object_=_response.json(),
),
)
return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 404:
raise NotFoundError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -1568,64 +1296,116 @@ async def file_service_upload_file(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
- async def file_service_delete_file(
+ async def get_record_by_id(
self,
vault_id: str,
- table_name: str,
+ object_name: str,
id: str,
- column_name: str,
*,
+ redaction: typing.Optional[GetRecordByIdRequestRedaction] = None,
+ tokenization: typing.Optional[bool] = None,
+ fields: typing.Optional[typing.Union[str, typing.Sequence[str]]] = None,
+ download_url: typing.Optional[bool] = None,
+ return_file_metadata: typing.Optional[bool] = None,
request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[V1DeleteFileResponse]:
+ ) -> AsyncHttpResponse[GetFieldRecords]:
"""
- Deletes a file from the specified record.
+ Returns the specified record from a table.
Parameters
----------
vault_id : str
- ID of the vault.
- table_name : str
- Name of the table.
+ object_name : str
id : str
- `skyflow_id` of the record.
- column_name : str
- Name of the column that contains the file.
+ redaction : typing.Optional[GetRecordByIdRequestRedaction]
+
+ tokenization : typing.Optional[bool]
+
+ fields : typing.Optional[typing.Union[str, typing.Sequence[str]]]
+
+ download_url : typing.Optional[bool]
+
+ return_file_metadata : typing.Optional[bool]
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- AsyncHttpResponse[V1DeleteFileResponse]
- A successful response.
+ AsyncHttpResponse[GetFieldRecords]
+ OK
"""
_response = await self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(table_name)}/{jsonable_encoder(id)}/files/{jsonable_encoder(column_name)}",
- method="DELETE",
+ f"v1/vaults/{encode_path_param(vault_id)}/{encode_path_param(object_name)}/{encode_path_param(id)}",
+ method="GET",
+ params={
+ "redaction": redaction,
+ "tokenization": tokenization,
+ "fields": fields,
+ "downloadURL": download_url,
+ "returnFileMetadata": return_file_metadata,
+ },
request_options=request_options,
)
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- V1DeleteFileResponse,
+ GetFieldRecords,
parse_obj_as(
- type_=V1DeleteFileResponse, # type: ignore
+ type_=GetFieldRecords, # type: ignore
object_=_response.json(),
),
)
return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 404:
raise NotFoundError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -1633,64 +1413,116 @@ async def file_service_delete_file(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
- async def file_service_get_file_scan_status(
+ async def update_record(
self,
vault_id: str,
- table_name: str,
+ object_name: str,
id: str,
- column_name: str,
*,
+ record: typing.Optional[FieldRecords] = OMIT,
+ tokenization: typing.Optional[bool] = OMIT,
+ byot: typing.Optional[UpdateRecordRequestByot] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[V1GetFileScanStatusResponse]:
+ ) -> AsyncHttpResponse[UpdateRecordResponse]:
"""
- Returns the anti-virus scan status of a file.
+ Updates the specified record in a table.
When you update a field, include the entire contents you want the field to store. For JSON fields, include all nested fields and values. If a nested field isn't included, it's removed.
The time-to-live (TTL) for a transient field resets when the field value is updated.
Parameters
----------
vault_id : str
- ID of the vault.
- table_name : str
- Name of the table.
+ object_name : str
id : str
- `skyflow_id` of the record.
- column_name : str
- Name of the column that contains the file.
+ record : typing.Optional[FieldRecords]
+
+ tokenization : typing.Optional[bool]
+ If `true`, this operation returns tokens for fields with tokenization enabled.
+
+ byot : typing.Optional[UpdateRecordRequestByot]
+ Token insertion behavior.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- AsyncHttpResponse[V1GetFileScanStatusResponse]
- A successful response.
+ AsyncHttpResponse[UpdateRecordResponse]
+ OK
"""
_response = await self._client_wrapper.httpx_client.request(
- f"v1/vaults/{jsonable_encoder(vault_id)}/{jsonable_encoder(table_name)}/{jsonable_encoder(id)}/files/{jsonable_encoder(column_name)}/scan-status",
- method="GET",
+ f"v1/vaults/{encode_path_param(vault_id)}/{encode_path_param(object_name)}/{encode_path_param(id)}",
+ method="PUT",
+ json={
+ "record": convert_and_respect_annotation_metadata(
+ object_=record, annotation=FieldRecords, direction="write"
+ ),
+ "tokenization": tokenization,
+ "byot": byot,
+ },
+ headers={
+ "content-type": "application/json",
+ },
request_options=request_options,
+ omit=OMIT,
)
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- V1GetFileScanStatusResponse,
+ UpdateRecordResponse,
parse_obj_as(
- type_=V1GetFileScanStatusResponse, # type: ignore
+ type_=UpdateRecordResponse, # type: ignore
object_=_response.json(),
),
)
return AsyncHttpResponse(response=_response, data=_data)
+ if _response.status_code == 400:
+ raise BadRequestError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 401:
+ raise UnauthorizedError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
if _response.status_code == 404:
raise NotFoundError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
+ parse_obj_as(
+ type_=ErrorResponse, # type: ignore
+ object_=_response.json(),
+ ),
+ ),
+ )
+ if _response.status_code == 500:
+ raise InternalServerError(
+ headers=dict(_response.headers),
+ body=typing.cast(
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -1698,72 +1530,48 @@ async def file_service_get_file_scan_status(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
- async def upload_file_v_2(
- self,
- vault_id: str,
- *,
- table_name: str,
- column_name: str,
- file: core.File,
- skyflow_id: typing.Optional[str] = OMIT,
- return_file_metadata: typing.Optional[bool] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> AsyncHttpResponse[UploadFileV2Response]:
+ async def delete_record(
+ self, vault_id: str, object_name: str, id: str, *, request_options: typing.Optional[RequestOptions] = None
+ ) -> AsyncHttpResponse[DeleteRecordResponse]:
"""
- Uploads the specified file to a record. If an existing record isn't specified, creates a new record and uploads the file to that record.
+ Deletes the specified record from a table.
Note: This method doesn't delete transient field tokens. Transient field values are available until they expire based on the fields' time-to-live (TTL) setting.
Parameters
----------
vault_id : str
ID of the vault.
- table_name : str
- Name of the table to upload the file to.
-
- column_name : str
- Name of the column to upload the file to. The column must have a `file` data type.
-
- file : core.File
- See core.File for more documentation
-
- skyflow_id : typing.Optional[str]
- Skyflow ID of the record to upload the file to. If `skyflowID` isn't specified, a new record will be created.
+ object_name : str
+ Name of the table.
- return_file_metadata : typing.Optional[bool]
- If `true`, returns metadata about the uploaded file.
+ id : str
+ `skyflow_id` of the record to delete.
request_options : typing.Optional[RequestOptions]
Request-specific configuration.
Returns
-------
- AsyncHttpResponse[UploadFileV2Response]
- File uploaded successfully.
+ AsyncHttpResponse[DeleteRecordResponse]
+ OK
"""
_response = await self._client_wrapper.httpx_client.request(
- f"v2/vaults/{jsonable_encoder(vault_id)}/files/upload",
- method="POST",
- data={
- "tableName": table_name,
- "columnName": column_name,
- "skyflowID": skyflow_id,
- "returnFileMetadata": return_file_metadata,
- },
- files={
- "file": file,
- },
+ f"v1/vaults/{encode_path_param(vault_id)}/{encode_path_param(object_name)}/{encode_path_param(id)}",
+ method="DELETE",
request_options=request_options,
- omit=OMIT,
- force_multipart=True,
)
try:
if 200 <= _response.status_code < 300:
_data = typing.cast(
- UploadFileV2Response,
+ DeleteRecordResponse,
parse_obj_as(
- type_=UploadFileV2Response, # type: ignore
+ type_=DeleteRecordResponse, # type: ignore
object_=_response.json(),
),
)
@@ -1772,9 +1580,9 @@ async def upload_file_v_2(
raise BadRequestError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -1783,9 +1591,9 @@ async def upload_file_v_2(
raise UnauthorizedError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -1794,9 +1602,9 @@ async def upload_file_v_2(
raise NotFoundError(
headers=dict(_response.headers),
body=typing.cast(
- typing.Optional[typing.Any],
+ ErrorResponse,
parse_obj_as(
- type_=typing.Optional[typing.Any], # type: ignore
+ type_=ErrorResponse, # type: ignore
object_=_response.json(),
),
),
@@ -1815,4 +1623,8 @@ async def upload_file_v_2(
_response_json = _response.json()
except JSONDecodeError:
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
+ except ValidationError as e:
+ raise ParsingError(
+ status_code=_response.status_code, headers=dict(_response.headers), body=_response.json(), cause=e
+ )
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
diff --git a/skyvault/skyflow/generated/rest/records/types/__init__.py b/skyvault/skyflow/generated/rest/records/types/__init__.py
index 62f7c5c2..b5f1bff1 100644
--- a/skyvault/skyflow/generated/rest/records/types/__init__.py
+++ b/skyvault/skyflow/generated/rest/records/types/__init__.py
@@ -2,12 +2,49 @@
# isort: skip_file
-from .record_service_bulk_get_record_request_order_by import RecordServiceBulkGetRecordRequestOrderBy
-from .record_service_bulk_get_record_request_redaction import RecordServiceBulkGetRecordRequestRedaction
-from .record_service_get_record_request_redaction import RecordServiceGetRecordRequestRedaction
+import typing
+from importlib import import_module
+
+if typing.TYPE_CHECKING:
+ from .get_record_by_id_request_redaction import GetRecordByIdRequestRedaction
+ from .get_records_request_order_by import GetRecordsRequestOrderBy
+ from .get_records_request_redaction import GetRecordsRequestRedaction
+ from .insert_record_request_byot import InsertRecordRequestByot
+ from .update_record_request_byot import UpdateRecordRequestByot
+_dynamic_imports: typing.Dict[str, str] = {
+ "GetRecordByIdRequestRedaction": ".get_record_by_id_request_redaction",
+ "GetRecordsRequestOrderBy": ".get_records_request_order_by",
+ "GetRecordsRequestRedaction": ".get_records_request_redaction",
+ "InsertRecordRequestByot": ".insert_record_request_byot",
+ "UpdateRecordRequestByot": ".update_record_request_byot",
+}
+
+
+def __getattr__(attr_name: str) -> typing.Any:
+ module_name = _dynamic_imports.get(attr_name)
+ if module_name is None:
+ raise AttributeError(f"No {attr_name} found in _dynamic_imports for module name -> {__name__}")
+ try:
+ module = import_module(module_name, __package__)
+ if module_name == f".{attr_name}":
+ return module
+ else:
+ return getattr(module, attr_name)
+ except ImportError as e:
+ raise ImportError(f"Failed to import {attr_name} from {module_name}: {e}") from e
+ except AttributeError as e:
+ raise AttributeError(f"Failed to get {attr_name} from {module_name}: {e}") from e
+
+
+def __dir__():
+ lazy_attrs = list(_dynamic_imports.keys())
+ return sorted(lazy_attrs)
+
__all__ = [
- "RecordServiceBulkGetRecordRequestOrderBy",
- "RecordServiceBulkGetRecordRequestRedaction",
- "RecordServiceGetRecordRequestRedaction",
+ "GetRecordByIdRequestRedaction",
+ "GetRecordsRequestOrderBy",
+ "GetRecordsRequestRedaction",
+ "InsertRecordRequestByot",
+ "UpdateRecordRequestByot",
]
diff --git a/skyvault/skyflow/generated/rest/records/types/get_record_by_id_request_redaction.py b/skyvault/skyflow/generated/rest/records/types/get_record_by_id_request_redaction.py
new file mode 100644
index 00000000..528d33a6
--- /dev/null
+++ b/skyvault/skyflow/generated/rest/records/types/get_record_by_id_request_redaction.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+GetRecordByIdRequestRedaction = typing.Union[typing.Literal["DEFAULT", "REDACTED", "MASKED", "PLAIN_TEXT"], typing.Any]
diff --git a/skyvault/skyflow/generated/rest/records/types/get_records_request_order_by.py b/skyvault/skyflow/generated/rest/records/types/get_records_request_order_by.py
new file mode 100644
index 00000000..5a6a1d78
--- /dev/null
+++ b/skyvault/skyflow/generated/rest/records/types/get_records_request_order_by.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+GetRecordsRequestOrderBy = typing.Union[typing.Literal["ASCENDING", "DESCENDING", "NONE"], typing.Any]
diff --git a/skyvault/skyflow/generated/rest/records/types/get_records_request_redaction.py b/skyvault/skyflow/generated/rest/records/types/get_records_request_redaction.py
new file mode 100644
index 00000000..a50cc679
--- /dev/null
+++ b/skyvault/skyflow/generated/rest/records/types/get_records_request_redaction.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+GetRecordsRequestRedaction = typing.Union[typing.Literal["DEFAULT", "REDACTED", "MASKED", "PLAIN_TEXT"], typing.Any]
diff --git a/skyvault/skyflow/generated/rest/records/types/insert_record_request_byot.py b/skyvault/skyflow/generated/rest/records/types/insert_record_request_byot.py
new file mode 100644
index 00000000..b8e9c55a
--- /dev/null
+++ b/skyvault/skyflow/generated/rest/records/types/insert_record_request_byot.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+InsertRecordRequestByot = typing.Union[typing.Literal["DISABLE", "ENABLE", "ENABLE_STRICT"], typing.Any]
diff --git a/skyvault/skyflow/generated/rest/records/types/record_service_bulk_get_record_request_order_by.py b/skyvault/skyflow/generated/rest/records/types/record_service_bulk_get_record_request_order_by.py
deleted file mode 100644
index 41f10c0b..00000000
--- a/skyvault/skyflow/generated/rest/records/types/record_service_bulk_get_record_request_order_by.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-RecordServiceBulkGetRecordRequestOrderBy = typing.Union[typing.Literal["ASCENDING", "DESCENDING", "NONE"], typing.Any]
diff --git a/skyvault/skyflow/generated/rest/records/types/record_service_bulk_get_record_request_redaction.py b/skyvault/skyflow/generated/rest/records/types/record_service_bulk_get_record_request_redaction.py
deleted file mode 100644
index 69bf6788..00000000
--- a/skyvault/skyflow/generated/rest/records/types/record_service_bulk_get_record_request_redaction.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-RecordServiceBulkGetRecordRequestRedaction = typing.Union[
- typing.Literal["DEFAULT", "REDACTED", "MASKED", "PLAIN_TEXT"], typing.Any
-]
diff --git a/skyvault/skyflow/generated/rest/records/types/update_record_request_byot.py b/skyvault/skyflow/generated/rest/records/types/update_record_request_byot.py
new file mode 100644
index 00000000..62ee48be
--- /dev/null
+++ b/skyvault/skyflow/generated/rest/records/types/update_record_request_byot.py
@@ -0,0 +1,5 @@
+# This file was auto-generated by Fern from our API Definition.
+
+import typing
+
+UpdateRecordRequestByot = typing.Union[typing.Literal["DISABLE", "ENABLE", "ENABLE_STRICT"], typing.Any]
diff --git a/skyvault/skyflow/generated/rest/strings/__init__.py b/skyvault/skyflow/generated/rest/strings/__init__.py
deleted file mode 100644
index 50bdd77e..00000000
--- a/skyvault/skyflow/generated/rest/strings/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-# isort: skip_file
-
-from .types import DeidentifyStringRequestEntityTypesItem
-
-__all__ = ["DeidentifyStringRequestEntityTypesItem"]
diff --git a/skyvault/skyflow/generated/rest/strings/client.py b/skyvault/skyflow/generated/rest/strings/client.py
deleted file mode 100644
index 88d8c2c2..00000000
--- a/skyvault/skyflow/generated/rest/strings/client.py
+++ /dev/null
@@ -1,296 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
-from ..core.request_options import RequestOptions
-from ..types.deidentify_string_response import DeidentifyStringResponse
-from ..types.format import Format
-from ..types.identify_response import IdentifyResponse
-from ..types.token_type_mapping import TokenTypeMapping
-from ..types.transformations import Transformations
-from .raw_client import AsyncRawStringsClient, RawStringsClient
-from .types.deidentify_string_request_entity_types_item import DeidentifyStringRequestEntityTypesItem
-
-# this is used as the default value for optional parameters
-OMIT = typing.cast(typing.Any, ...)
-
-
-class StringsClient:
- def __init__(self, *, client_wrapper: SyncClientWrapper):
- self._raw_client = RawStringsClient(client_wrapper=client_wrapper)
-
- @property
- def with_raw_response(self) -> RawStringsClient:
- """
- Retrieves a raw implementation of this client that returns raw responses.
-
- Returns
- -------
- RawStringsClient
- """
- return self._raw_client
-
- def deidentify_string(
- self,
- *,
- text: str,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyStringRequestEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyStringResponse:
- """
- De-identifies sensitive data from a string.
-
- Parameters
- ----------
- text : str
- Text to de-identify.
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyStringRequestEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyStringResponse
- OK
-
- Examples
- --------
- from skyflow import Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.strings.deidentify_string(
- text="text",
- vault_id="f4b3b3b3-3b3b-3b3b-3b3b-3b3b3b3b3b3b",
- )
- """
- _response = self._raw_client.deidentify_string(
- text=text,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- def reidentify_string(
- self,
- *,
- text: typing.Optional[str] = OMIT,
- vault_id: typing.Optional[str] = OMIT,
- format: typing.Optional[Format] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> IdentifyResponse:
- """
- Re-identifies tokens in a string.
-
- Parameters
- ----------
- text : typing.Optional[str]
- Text to reidentify.
-
- vault_id : typing.Optional[str]
- ID of the vault where the entities are stored.
-
- format : typing.Optional[Format]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- IdentifyResponse
- OK
-
- Examples
- --------
- from skyflow import Skyflow
-
- client = Skyflow(
- token="YOUR_TOKEN",
- )
- client.strings.reidentify_string()
- """
- _response = self._raw_client.reidentify_string(
- text=text, vault_id=vault_id, format=format, request_options=request_options
- )
- return _response.data
-
-
-class AsyncStringsClient:
- def __init__(self, *, client_wrapper: AsyncClientWrapper):
- self._raw_client = AsyncRawStringsClient(client_wrapper=client_wrapper)
-
- @property
- def with_raw_response(self) -> AsyncRawStringsClient:
- """
- Retrieves a raw implementation of this client that returns raw responses.
-
- Returns
- -------
- AsyncRawStringsClient
- """
- return self._raw_client
-
- async def deidentify_string(
- self,
- *,
- text: str,
- vault_id: str,
- entity_types: typing.Optional[typing.Sequence[DeidentifyStringRequestEntityTypesItem]] = OMIT,
- token_type: typing.Optional[TokenTypeMapping] = OMIT,
- allow_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- restrict_regex: typing.Optional[typing.Sequence[str]] = OMIT,
- transformations: typing.Optional[Transformations] = OMIT,
- configuration_id: typing.Optional[str] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> DeidentifyStringResponse:
- """
- De-identifies sensitive data from a string.
-
- Parameters
- ----------
- text : str
- Text to de-identify.
-
- vault_id : str
- ID of a vault that you have Detect Invoker or Vault Owner permissions for.
-
- entity_types : typing.Optional[typing.Sequence[DeidentifyStringRequestEntityTypesItem]]
- Entities to detect and de-identify.
-
- token_type : typing.Optional[TokenTypeMapping]
-
- allow_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to display in plaintext. Entities appear in plaintext if an expression matches either the entirety of a detected entity or a substring of it. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext.
-
- restrict_regex : typing.Optional[typing.Sequence[str]]
- Regular expressions to replace with '[RESTRICTED]'. Expressions must match the entirety of a detected entity, not just a substring, for the entity to be restricted. Expressions don't match across entity boundaries. If a string or entity matches both `allow_regex` and `restrict_regex`, the entity is displayed in plaintext. If a string is detected as an entity and a `restrict_regex` pattern matches the entire detected entity, the entity is replaced with '[RESTRICTED]'. If a string is detected as an entity but a `restrict_regex` pattern only matches a substring of it, the `restrict_regex` pattern is ignored, and the entity is processed according to the specified tokenization and transformation settings.
-
- transformations : typing.Optional[Transformations]
-
- configuration_id : typing.Optional[str]
- ID of the Detect configuration to use for de-identification. Can't be specified with fields other than `vault_id`, `text`, and `file`.
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- DeidentifyStringResponse
- OK
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.strings.deidentify_string(
- text="text",
- vault_id="f4b3b3b3-3b3b-3b3b-3b3b-3b3b3b3b3b3b",
- )
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.deidentify_string(
- text=text,
- vault_id=vault_id,
- entity_types=entity_types,
- token_type=token_type,
- allow_regex=allow_regex,
- restrict_regex=restrict_regex,
- transformations=transformations,
- configuration_id=configuration_id,
- request_options=request_options,
- )
- return _response.data
-
- async def reidentify_string(
- self,
- *,
- text: typing.Optional[str] = OMIT,
- vault_id: typing.Optional[str] = OMIT,
- format: typing.Optional[Format] = OMIT,
- request_options: typing.Optional[RequestOptions] = None,
- ) -> IdentifyResponse:
- """
- Re-identifies tokens in a string.
-
- Parameters
- ----------
- text : typing.Optional[str]
- Text to reidentify.
-
- vault_id : typing.Optional[str]
- ID of the vault where the entities are stored.
-
- format : typing.Optional[Format]
-
- request_options : typing.Optional[RequestOptions]
- Request-specific configuration.
-
- Returns
- -------
- IdentifyResponse
- OK
-
- Examples
- --------
- import asyncio
-
- from skyflow import AsyncSkyflow
-
- client = AsyncSkyflow(
- token="YOUR_TOKEN",
- )
-
-
- async def main() -> None:
- await client.strings.reidentify_string()
-
-
- asyncio.run(main())
- """
- _response = await self._raw_client.reidentify_string(
- text=text, vault_id=vault_id, format=format, request_options=request_options
- )
- return _response.data
diff --git a/skyvault/skyflow/generated/rest/strings/types/__init__.py b/skyvault/skyflow/generated/rest/strings/types/__init__.py
deleted file mode 100644
index 592fae37..00000000
--- a/skyvault/skyflow/generated/rest/strings/types/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-# isort: skip_file
-
-from .deidentify_string_request_entity_types_item import DeidentifyStringRequestEntityTypesItem
-
-__all__ = ["DeidentifyStringRequestEntityTypesItem"]
diff --git a/skyvault/skyflow/generated/rest/strings/types/deidentify_string_request_entity_types_item.py b/skyvault/skyflow/generated/rest/strings/types/deidentify_string_request_entity_types_item.py
deleted file mode 100644
index bde5d084..00000000
--- a/skyvault/skyflow/generated/rest/strings/types/deidentify_string_request_entity_types_item.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# This file was auto-generated by Fern from our API Definition.
-
-import typing
-
-DeidentifyStringRequestEntityTypesItem = typing.Union[
- typing.Literal[
- "age",
- "bank_account",
- "credit_card",
- "credit_card_expiration",
- "cvv",
- "date",
- "date_interval",
- "dob",
- "driver_license",
- "email_address",
- "healthcare_number",
- "ip_address",
- "location",
- "name",
- "numerical_pii",
- "phone_number",
- "ssn",
- "url",
- "vehicle_id",
- "medical_code",
- "name_family",
- "name_given",
- "account_number",
- "event",
- "filename",
- "gender",
- "language",
- "location_address",
- "location_city",
- "location_coordinate",
- "location_country",
- "location_state",
- "location_zip",
- "marital_status",
- "money",
- "name_medical_professional",
- "occupation",
- "organization",
- "organization_medical_facility",
- "origin",
- "passport_number",
- "password",
- "physical_attribute",
- "political_affiliation",
- "religion",
- "time",
- "username",
- "zodiac_sign",
- "blood_type",
- "condition",
- "dose",
- "drug",
- "injury",
- "medical_process",
- "statistics",
- "routing_number",
- "corporate_action",
- "financial_metric",
- "product",
- "trend",
- "duration",
- "location_address_street",
- "all",
- "sexuality",
- "effect",
- "project",
- "organization_id",
- "day",
- "month",
- "year",
- ],
- typing.Any,
-]
diff --git a/skyvault/skyflow/generated/rest/tokens/client.py b/skyvault/skyflow/generated/rest/tokens/client.py
index a5c35064..25ba7dff 100644
--- a/skyvault/skyflow/generated/rest/tokens/client.py
+++ b/skyvault/skyflow/generated/rest/tokens/client.py
@@ -4,10 +4,10 @@
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
from ..core.request_options import RequestOptions
-from ..types.v_1_detokenize_record_request import V1DetokenizeRecordRequest
-from ..types.v_1_detokenize_response import V1DetokenizeResponse
-from ..types.v_1_tokenize_record_request import V1TokenizeRecordRequest
-from ..types.v_1_tokenize_response import V1TokenizeResponse
+from ..types.detokenize_record_request import DetokenizeRecordRequest
+from ..types.detokenize_response import DetokenizeResponse
+from ..types.tokenize_record_request import TokenizeRecordRequest
+from ..types.tokenize_response import TokenizeResponse
from .raw_client import AsyncRawTokensClient, RawTokensClient
# this is used as the default value for optional parameters
@@ -29,24 +29,23 @@ def with_raw_response(self) -> RawTokensClient:
"""
return self._raw_client
- def record_service_detokenize(
+ def detokenize(
self,
vault_id: str,
*,
- detokenization_parameters: typing.Optional[typing.Sequence[V1DetokenizeRecordRequest]] = OMIT,
+ detokenization_parameters: typing.Sequence[DetokenizeRecordRequest],
download_url: typing.Optional[bool] = OMIT,
continue_on_error: typing.Optional[bool] = OMIT,
request_options: typing.Optional[RequestOptions] = None,
- ) -> V1DetokenizeResponse:
+ ) -> DetokenizeResponse:
"""
Returns records that correspond to the specified tokens.
Parameters
----------
vault_id : str
- ID of the vault.
- detokenization_parameters : typing.Optional[typing.Sequence[V1DetokenizeRecordRequest]]
+ detokenization_parameters : typing.Sequence[DetokenizeRecordRequest]
Detokenization details.
download_url : typing.Optional[bool]
@@ -60,32 +59,32 @@ def record_service_detokenize(
Returns
-------
- V1DetokenizeResponse
- A successful response.
+ DetokenizeResponse
+ OK
Examples
--------
- from skyflow import Skyflow, V1DetokenizeRecordRequest
+ from skyflow import DetokenizeRecordRequest, SkyflowAuth
- client = Skyflow(
+ client = SkyflowAuth(
token="YOUR_TOKEN",
)
- client.tokens.record_service_detokenize(
+ client.tokens.detokenize(
vault_id="vaultID",
detokenization_parameters=[
- V1DetokenizeRecordRequest(
- token="",
+ DetokenizeRecordRequest(
+ token="afbd1074-51c1-4a16-9eee-e2c0ecb52125",
redaction="PLAIN_TEXT",
),
- V1DetokenizeRecordRequest(
- token="",
+ DetokenizeRecordRequest(
+ token="05383487-fcae-42e5-a48e-5bd62a51af12",
redaction="DEFAULT",
),
],
download_url=False,
)
"""
- _response = self._raw_client.record_service_detokenize(
+ _response = self._raw_client.detokenize(
vault_id,
detokenization_parameters=detokenization_parameters,
download_url=download_url,
@@ -94,22 +93,22 @@ def record_service_detokenize(
)
return _response.data
- def record_service_tokenize(
+ def tokenize(
self,
vault_id: str,
*,
- tokenization_parameters: typing.Optional[typing.Sequence[V1TokenizeRecordRequest]] = OMIT,
+ tokenization_parameters: typing.Sequence[TokenizeRecordRequest],
request_options: typing.Optional[RequestOptions] = None,
- ) -> V1TokenizeResponse:
+ ) -> TokenizeResponse:
"""
- Returns tokens that correspond to the specified records. Only applicable for fields with deterministic tokenization.
Note: This endpoint doesn't insert records—it returns tokens for existing values. To insert records and tokenize that new record's values, see Insert Record and the tokenization parameter.
+ Returns tokens that correspond to the specified records. Only applicable for fields with deterministic tokenization.
Note: This endpoint doesn't insert records—it returns tokens for existing values. To insert records and tokenize that new record's values, see Insert Record and the tokenization parameter.
+ Returns tokens that correspond to the specified records. Only applicable for fields with deterministic tokenization.
Note: This endpoint doesn't insert records—it returns tokens for existing values. To insert records and tokenize that new record's values, see Insert Record and the tokenization parameter.
+ Returns tokens that correspond to the specified records. Only applicable for fields with deterministic tokenization.
Note: This endpoint doesn't insert records—it returns tokens for existing values. To insert records and tokenize that new record's values, see Insert Record and the tokenization parameter.
+ Returns tokens that correspond to the specified records. Only applicable for fields with deterministic tokenization.