skyflow-flowvault-python 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- common/.coveragerc +4 -0
- common/__init__.py +3 -0
- common/client/__init__.py +0 -0
- common/client/base_skyflow.py +345 -0
- common/client/utils/__init__.py +1 -0
- common/client/utils/_utils.py +127 -0
- common/errors/__init__.py +1 -0
- common/errors/_skyflow_error.py +17 -0
- common/generated/__init__.py +0 -0
- common/generated/rest/__init__.py +24 -0
- common/generated/rest/authentication/__init__.py +4 -0
- common/generated/rest/authentication/client.py +181 -0
- common/generated/rest/authentication/raw_client.py +241 -0
- common/generated/rest/client.py +153 -0
- common/generated/rest/core/__init__.py +52 -0
- common/generated/rest/core/api_error.py +23 -0
- common/generated/rest/core/client_wrapper.py +86 -0
- common/generated/rest/core/datetime_utils.py +28 -0
- common/generated/rest/core/file.py +67 -0
- common/generated/rest/core/force_multipart.py +16 -0
- common/generated/rest/core/http_client.py +543 -0
- common/generated/rest/core/http_response.py +55 -0
- common/generated/rest/core/jsonable_encoder.py +100 -0
- common/generated/rest/core/pydantic_utilities.py +255 -0
- common/generated/rest/core/query_encoder.py +58 -0
- common/generated/rest/core/remove_none_from_dict.py +11 -0
- common/generated/rest/core/request_options.py +35 -0
- common/generated/rest/core/serialization.py +276 -0
- common/generated/rest/environment.py +8 -0
- common/generated/rest/errors/__init__.py +9 -0
- common/generated/rest/errors/bad_request_error.py +14 -0
- common/generated/rest/errors/not_found_error.py +14 -0
- common/generated/rest/errors/unauthorized_error.py +14 -0
- common/generated/rest/py.typed +0 -0
- common/generated/rest/types/__init__.py +9 -0
- common/generated/rest/types/googlerpc_status.py +22 -0
- common/generated/rest/types/protobuf_any.py +21 -0
- common/generated/rest/types/v_1_get_auth_token_response.py +33 -0
- common/generated/rest/version.py +6 -0
- common/service_account/__init__.py +1 -0
- common/service_account/_utils.py +248 -0
- common/service_account/client/__init__.py +0 -0
- common/service_account/client/auth_client.py +13 -0
- common/utils/__init__.py +4 -0
- common/utils/_helpers.py +18 -0
- common/utils/_skyflow_messages.py +445 -0
- common/utils/_utils.py +50 -0
- common/utils/constants.py +291 -0
- common/utils/enums/__init__.py +12 -0
- common/utils/enums/content_types.py +9 -0
- common/utils/enums/detect_entities.py +73 -0
- common/utils/enums/detect_output_transcriptions.py +8 -0
- common/utils/enums/env.py +13 -0
- common/utils/enums/log_level.py +8 -0
- common/utils/enums/masking_method.py +5 -0
- common/utils/enums/redaction_type.py +7 -0
- common/utils/enums/request_method.py +8 -0
- common/utils/enums/token_mode.py +6 -0
- common/utils/enums/token_type.py +6 -0
- common/utils/logger/__init__.py +2 -0
- common/utils/logger/_log_helpers.py +47 -0
- common/utils/logger/_logger.py +50 -0
- common/utils/validations/__init__.py +11 -0
- common/utils/validations/_validations.py +267 -0
- common/vault/base_vault_client.py +122 -0
- common/vault/base_vault_controller.py +58 -0
- common/vault/data/__init__.py +2 -0
- common/vault/data/_base_insert_request.py +7 -0
- common/vault/data/_base_insert_response.py +11 -0
- skyflow/__init__.py +2 -0
- skyflow/client/__init__.py +1 -0
- skyflow/client/_http_config_builder.py +45 -0
- skyflow/client/skyflow.py +15 -0
- skyflow/error/__init__.py +3 -0
- skyflow/generated/__init__.py +0 -0
- skyflow/generated/rest/__init__.py +164 -0
- skyflow/generated/rest/_default_clients.py +32 -0
- skyflow/generated/rest/client.py +385 -0
- skyflow/generated/rest/core/__init__.py +127 -0
- skyflow/generated/rest/core/api_error.py +23 -0
- skyflow/generated/rest/core/client_wrapper.py +148 -0
- skyflow/generated/rest/core/datetime_utils.py +70 -0
- skyflow/generated/rest/core/file.py +67 -0
- skyflow/generated/rest/core/force_multipart.py +18 -0
- skyflow/generated/rest/core/http_client.py +940 -0
- skyflow/generated/rest/core/http_response.py +63 -0
- skyflow/generated/rest/core/http_sse/__init__.py +42 -0
- skyflow/generated/rest/core/http_sse/_api.py +455 -0
- skyflow/generated/rest/core/http_sse/_decoders.py +74 -0
- skyflow/generated/rest/core/http_sse/_exceptions.py +7 -0
- skyflow/generated/rest/core/http_sse/_models.py +17 -0
- skyflow/generated/rest/core/jsonable_encoder.py +133 -0
- skyflow/generated/rest/core/logging.py +107 -0
- skyflow/generated/rest/core/parse_error.py +36 -0
- skyflow/generated/rest/core/pydantic_utilities.py +486 -0
- skyflow/generated/rest/core/query_encoder.py +58 -0
- skyflow/generated/rest/core/remove_none_from_dict.py +11 -0
- skyflow/generated/rest/core/request_options.py +40 -0
- skyflow/generated/rest/core/serialization.py +347 -0
- skyflow/generated/rest/environment.py +8 -0
- skyflow/generated/rest/errors/__init__.py +53 -0
- skyflow/generated/rest/errors/bad_request_error.py +11 -0
- skyflow/generated/rest/errors/forbidden_error.py +11 -0
- skyflow/generated/rest/errors/internal_server_error.py +11 -0
- skyflow/generated/rest/errors/not_found_error.py +11 -0
- skyflow/generated/rest/errors/too_many_requests_error.py +11 -0
- skyflow/generated/rest/errors/unauthorized_error.py +11 -0
- skyflow/generated/rest/py.typed +0 -0
- skyflow/generated/rest/query/__init__.py +4 -0
- skyflow/generated/rest/query/client.py +139 -0
- skyflow/generated/rest/query/raw_client.py +239 -0
- skyflow/generated/rest/raw_client.py +86 -0
- skyflow/generated/rest/records/__init__.py +34 -0
- skyflow/generated/rest/records/client.py +685 -0
- skyflow/generated/rest/records/raw_client.py +988 -0
- skyflow/generated/rest/records/types/__init__.py +34 -0
- skyflow/generated/rest/records/types/update_request_update_type.py +5 -0
- skyflow/generated/rest/tokens/__init__.py +4 -0
- skyflow/generated/rest/tokens/client.py +246 -0
- skyflow/generated/rest/tokens/raw_client.py +507 -0
- skyflow/generated/rest/types/__init__.py +116 -0
- skyflow/generated/rest/types/column_redactions.py +33 -0
- skyflow/generated/rest/types/delete_response.py +23 -0
- skyflow/generated/rest/types/delete_response_object.py +42 -0
- skyflow/generated/rest/types/detokenize_response.py +23 -0
- skyflow/generated/rest/types/detokenize_response_object.py +54 -0
- skyflow/generated/rest/types/error_response.py +20 -0
- skyflow/generated/rest/types/error_response_error.py +28 -0
- skyflow/generated/rest/types/execute_query_record_response.py +22 -0
- skyflow/generated/rest/types/execute_query_response.py +26 -0
- skyflow/generated/rest/types/execute_query_response_metadata.py +26 -0
- skyflow/generated/rest/types/get_request_data.py +60 -0
- skyflow/generated/rest/types/get_response.py +23 -0
- skyflow/generated/rest/types/get_tokens_from_values_request_object.py +30 -0
- skyflow/generated/rest/types/get_tokens_from_values_response.py +23 -0
- skyflow/generated/rest/types/google_protobuf_value.py +8 -0
- skyflow/generated/rest/types/http_code.py +6 -0
- skyflow/generated/rest/types/insert_record_data.py +36 -0
- skyflow/generated/rest/types/insert_response.py +23 -0
- skyflow/generated/rest/types/record_response_object.py +70 -0
- skyflow/generated/rest/types/token_group_redactions.py +33 -0
- skyflow/generated/rest/types/tokenize_response_object.py +49 -0
- skyflow/generated/rest/types/unique_value.py +22 -0
- skyflow/generated/rest/types/update_record_data.py +52 -0
- skyflow/generated/rest/types/update_record_data_update_type.py +5 -0
- skyflow/generated/rest/types/update_response.py +23 -0
- skyflow/generated/rest/types/upsert.py +45 -0
- skyflow/generated/rest/types/upsert_update_type.py +5 -0
- skyflow/generated/rest/version.py +6 -0
- skyflow/service_account/__init__.py +15 -0
- skyflow/utils/__init__.py +9 -0
- skyflow/utils/_http_config.py +36 -0
- skyflow/utils/_response_parsing.py +66 -0
- skyflow/utils/_retry.py +97 -0
- skyflow/utils/_skyflow_messages.py +114 -0
- skyflow/utils/_utils.py +54 -0
- skyflow/utils/_version.py +1 -0
- skyflow/utils/enums/__init__.py +3 -0
- skyflow/utils/enums/_custom_header_key.py +10 -0
- skyflow/utils/enums/_env_urls.py +9 -0
- skyflow/utils/enums/_upsert_type.py +7 -0
- skyflow/utils/validations/__init__.py +9 -0
- skyflow/utils/validations/_validations.py +195 -0
- skyflow/vault/__init__.py +0 -0
- skyflow/vault/client/__init__.py +0 -0
- skyflow/vault/client/client.py +102 -0
- skyflow/vault/controller/__init__.py +1 -0
- skyflow/vault/controller/_vault.py +475 -0
- skyflow/vault/data/__init__.py +30 -0
- skyflow/vault/data/_column_redactions.py +4 -0
- skyflow/vault/data/_delete_options.py +8 -0
- skyflow/vault/data/_delete_request.py +5 -0
- skyflow/vault/data/_delete_response.py +9 -0
- skyflow/vault/data/_delete_response_record.py +9 -0
- skyflow/vault/data/_detokenize_options.py +8 -0
- skyflow/vault/data/_detokenize_request.py +9 -0
- skyflow/vault/data/_detokenize_response.py +9 -0
- skyflow/vault/data/_detokenize_response_record.py +16 -0
- skyflow/vault/data/_detokenize_response_record_metadata.py +10 -0
- skyflow/vault/data/_get_options.py +8 -0
- skyflow/vault/data/_get_request.py +17 -0
- skyflow/vault/data/_get_request_record.py +13 -0
- skyflow/vault/data/_get_response.py +9 -0
- skyflow/vault/data/_get_response_record.py +17 -0
- skyflow/vault/data/_insert_options.py +8 -0
- skyflow/vault/data/_insert_request.py +11 -0
- skyflow/vault/data/_insert_request_record.py +9 -0
- skyflow/vault/data/_insert_response.py +9 -0
- skyflow/vault/data/_insert_response_record.py +17 -0
- skyflow/vault/data/_request_context.py +16 -0
- skyflow/vault/data/_token.py +8 -0
- skyflow/vault/data/_token_group_redactions.py +4 -0
- skyflow/vault/data/_update_options.py +8 -0
- skyflow/vault/data/_update_request.py +11 -0
- skyflow/vault/data/_update_request_record.py +6 -0
- skyflow/vault/data/_update_response.py +9 -0
- skyflow/vault/data/_update_response_record.py +17 -0
- skyflow/vault/data/_upsert_options.py +7 -0
- skyflow_flowvault_python-1.0.0.dist-info/METADATA +896 -0
- skyflow_flowvault_python-1.0.0.dist-info/RECORD +202 -0
- skyflow_flowvault_python-1.0.0.dist-info/WHEEL +5 -0
- skyflow_flowvault_python-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from common.errors import SkyflowError
|
|
4
|
+
from common.utils import SkyflowMessages as CommonMessages
|
|
5
|
+
from common.utils.constants import SKY_META_DATA_HEADER
|
|
6
|
+
from common.utils.logger import log_info, log_error_log
|
|
7
|
+
from common.vault.base_vault_controller import BaseVaultController
|
|
8
|
+
from skyflow.generated.rest import (
|
|
9
|
+
ColumnRedactions,
|
|
10
|
+
GetRequestData,
|
|
11
|
+
InsertRecordData,
|
|
12
|
+
TokenGroupRedactions as WireTokenGroupRedactions,
|
|
13
|
+
UniqueValue,
|
|
14
|
+
UpdateRecordData,
|
|
15
|
+
Upsert,
|
|
16
|
+
)
|
|
17
|
+
from skyflow.generated.rest.core import ApiError, ParsingError
|
|
18
|
+
from skyflow.utils import SkyflowMessages, get_metrics
|
|
19
|
+
from skyflow.utils.enums import UpsertType
|
|
20
|
+
from skyflow.utils._response_parsing import parse_tokens, parse_hashed_data, parse_metadata
|
|
21
|
+
from skyflow.utils.validations import (
|
|
22
|
+
validate_insert_request,
|
|
23
|
+
validate_get_request,
|
|
24
|
+
validate_update_request,
|
|
25
|
+
validate_delete_request,
|
|
26
|
+
validate_detokenize_request,
|
|
27
|
+
)
|
|
28
|
+
from skyflow.vault.data import (
|
|
29
|
+
InsertRequest,
|
|
30
|
+
InsertResponse,
|
|
31
|
+
InsertResponseRecord,
|
|
32
|
+
GetRequest,
|
|
33
|
+
GetResponse,
|
|
34
|
+
GetResponseRecord,
|
|
35
|
+
UpdateRequest,
|
|
36
|
+
UpdateResponse,
|
|
37
|
+
UpdateResponseRecord,
|
|
38
|
+
DeleteRequest,
|
|
39
|
+
DeleteResponse,
|
|
40
|
+
DeleteResponseRecord,
|
|
41
|
+
DetokenizeRequest,
|
|
42
|
+
DetokenizeResponse,
|
|
43
|
+
DetokenizeResponseRecord,
|
|
44
|
+
InsertOptions,
|
|
45
|
+
GetOptions,
|
|
46
|
+
UpdateOptions,
|
|
47
|
+
DeleteOptions,
|
|
48
|
+
DetokenizeOptions,
|
|
49
|
+
RequestContext,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
REQUEST_ID_HEADER = "x-request-id"
|
|
53
|
+
ADDITIONAL_HEADERS_KEY = "additional_headers"
|
|
54
|
+
UNKNOWN_ERROR_MESSAGE = "Unknown error"
|
|
55
|
+
OPERATION_INSERT = "INSERT"
|
|
56
|
+
OPERATION_GET = "GET"
|
|
57
|
+
OPERATION_UPDATE = "UPDATE"
|
|
58
|
+
OPERATION_DELETE = "DELETE"
|
|
59
|
+
OPERATION_DETOKENIZE = "DETOKENIZE"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class VaultController(BaseVaultController):
|
|
63
|
+
_skyflow_messages = SkyflowMessages
|
|
64
|
+
|
|
65
|
+
def __init__(self, vault_client):
|
|
66
|
+
super().__init__(vault_client)
|
|
67
|
+
|
|
68
|
+
def insert(self, request: InsertRequest, options: InsertOptions = None) -> InsertResponse:
|
|
69
|
+
log_info(SkyflowMessages.Info.VALIDATE_INSERT_REQUEST.value, self._vault_client.get_logger())
|
|
70
|
+
validate_insert_request(self._vault_client.get_logger(), request)
|
|
71
|
+
self._validate_table_name_if_present(request.table_name)
|
|
72
|
+
for record in request.records:
|
|
73
|
+
self._validate_table_name_if_present(record.table_name)
|
|
74
|
+
self._validate_field_values(record.data)
|
|
75
|
+
log_info(SkyflowMessages.Info.INSERT_REQUEST_RESOLVED.value, self._vault_client.get_logger())
|
|
76
|
+
self._vault_client.initialize_client_configuration()
|
|
77
|
+
|
|
78
|
+
records_api = self._vault_client.get_records_api()
|
|
79
|
+
|
|
80
|
+
needs_per_record_table = any(r.table_name is not None for r in request.records)
|
|
81
|
+
needs_per_record_upsert = any(r.upsert is not None for r in request.records)
|
|
82
|
+
|
|
83
|
+
wire_records = [
|
|
84
|
+
self.__build_wire_record(record, request, needs_per_record_table, needs_per_record_upsert)
|
|
85
|
+
for record in request.records
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
log_info(SkyflowMessages.Info.INSERT_TRIGGERED.value, self._vault_client.get_logger())
|
|
90
|
+
upsert_kwargs = self.__omit_none(
|
|
91
|
+
upsert=None if needs_per_record_upsert else self.__to_upsert(request.upsert),
|
|
92
|
+
)
|
|
93
|
+
raw_response = records_api.with_raw_response.insert_records(
|
|
94
|
+
vault_id=self._vault_client.get_vault_id(),
|
|
95
|
+
table_name=request.table_name,
|
|
96
|
+
records=wire_records,
|
|
97
|
+
request_options=self.__unary_request_options(OPERATION_INSERT, options),
|
|
98
|
+
**upsert_kwargs,
|
|
99
|
+
)
|
|
100
|
+
request_id = self.__extract_request_id(raw_response.headers)
|
|
101
|
+
records = [
|
|
102
|
+
InsertResponseRecord(**self.__record_kwargs(record, include_data=True, request_id=request_id))
|
|
103
|
+
for record in (raw_response.data.records or [])
|
|
104
|
+
]
|
|
105
|
+
except Exception as e:
|
|
106
|
+
log_error_log(SkyflowMessages.ErrorLogs.INSERT_RECORDS_REJECTED.value, self._vault_client.get_logger())
|
|
107
|
+
error_records, request_id = self.__unary_error_records(e)
|
|
108
|
+
if error_records is None:
|
|
109
|
+
raise self.__to_skyflow_error(e)
|
|
110
|
+
records = [
|
|
111
|
+
InsertResponseRecord(**self.__record_kwargs(record, include_data=True, request_id=request_id))
|
|
112
|
+
for record in error_records
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
log_info(SkyflowMessages.Info.INSERT_SUCCESS.value, self._vault_client.get_logger())
|
|
116
|
+
return InsertResponse(records=records)
|
|
117
|
+
|
|
118
|
+
def get(self, request: GetRequest, options: GetOptions = None) -> GetResponse:
|
|
119
|
+
log_info(SkyflowMessages.Info.VALIDATE_GET_REQUEST.value, self._vault_client.get_logger())
|
|
120
|
+
validate_get_request(self._vault_client.get_logger(), request)
|
|
121
|
+
self._validate_table_name_if_present(request.table_name)
|
|
122
|
+
log_info(SkyflowMessages.Info.GET_REQUEST_RESOLVED.value, self._vault_client.get_logger())
|
|
123
|
+
self._vault_client.initialize_client_configuration()
|
|
124
|
+
|
|
125
|
+
records_api = self._vault_client.get_records_api()
|
|
126
|
+
|
|
127
|
+
if request.records is not None:
|
|
128
|
+
call_kwargs = {'records': self.__to_get_request_data(request.records)}
|
|
129
|
+
error_count = len(request.records)
|
|
130
|
+
else:
|
|
131
|
+
call_kwargs = {
|
|
132
|
+
'table_name': request.table_name,
|
|
133
|
+
'skyflow_i_ds': request.skyflow_ids,
|
|
134
|
+
'unique_values': self.__to_unique_values(request.unique_values),
|
|
135
|
+
'columns': request.columns,
|
|
136
|
+
'column_redactions': self.__to_column_redactions(request.column_redactions),
|
|
137
|
+
'limit': request.limit,
|
|
138
|
+
'offset': request.offset,
|
|
139
|
+
}
|
|
140
|
+
error_count = len(request.skyflow_ids or request.unique_values or [])
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
log_info(SkyflowMessages.Info.GET_TRIGGERED.value, self._vault_client.get_logger())
|
|
144
|
+
raw_response = records_api.with_raw_response.get_records(
|
|
145
|
+
vault_id=self._vault_client.get_vault_id(),
|
|
146
|
+
request_options=self.__unary_request_options(OPERATION_GET, options),
|
|
147
|
+
**call_kwargs,
|
|
148
|
+
)
|
|
149
|
+
request_id = self.__extract_request_id(raw_response.headers)
|
|
150
|
+
records = [
|
|
151
|
+
GetResponseRecord(**self.__record_kwargs(record, include_data=True, request_id=request_id))
|
|
152
|
+
for record in (raw_response.data.records or [])
|
|
153
|
+
]
|
|
154
|
+
except Exception as e:
|
|
155
|
+
log_error_log(SkyflowMessages.ErrorLogs.GET_RECORDS_REJECTED.value, self._vault_client.get_logger())
|
|
156
|
+
error_records, request_id = self.__unary_error_records(e)
|
|
157
|
+
if error_records is None:
|
|
158
|
+
raise self.__to_skyflow_error(e)
|
|
159
|
+
records = [
|
|
160
|
+
GetResponseRecord(**self.__record_kwargs(record, include_data=True, request_id=request_id))
|
|
161
|
+
for record in error_records
|
|
162
|
+
]
|
|
163
|
+
|
|
164
|
+
log_info(SkyflowMessages.Info.GET_SUCCESS.value, self._vault_client.get_logger())
|
|
165
|
+
return GetResponse(records=records)
|
|
166
|
+
|
|
167
|
+
def update(self, request: UpdateRequest, options: UpdateOptions = None) -> UpdateResponse:
|
|
168
|
+
log_info(SkyflowMessages.Info.VALIDATE_UPDATE_REQUEST.value, self._vault_client.get_logger())
|
|
169
|
+
validate_update_request(self._vault_client.get_logger(), request)
|
|
170
|
+
self._validate_table_name_if_present(request.table_name)
|
|
171
|
+
for record in request.records:
|
|
172
|
+
self._validate_table_name_if_present(record.table_name)
|
|
173
|
+
if record.data is not None:
|
|
174
|
+
self._validate_field_values(record.data)
|
|
175
|
+
log_info(SkyflowMessages.Info.UPDATE_REQUEST_RESOLVED.value, self._vault_client.get_logger())
|
|
176
|
+
self._vault_client.initialize_client_configuration()
|
|
177
|
+
|
|
178
|
+
records_api = self._vault_client.get_records_api()
|
|
179
|
+
|
|
180
|
+
try:
|
|
181
|
+
needs_per_record_table = any(r.table_name is not None for r in request.records)
|
|
182
|
+
|
|
183
|
+
wire_records = [
|
|
184
|
+
self.__build_update_wire_record(record, request, needs_per_record_table)
|
|
185
|
+
for record in request.records
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
log_info(SkyflowMessages.Info.UPDATE_TRIGGERED.value, self._vault_client.get_logger())
|
|
189
|
+
update_type_kwargs = self.__omit_none(update_type=self.__to_update_type(request.update_type))
|
|
190
|
+
raw_response = records_api.with_raw_response.update_records(
|
|
191
|
+
vault_id=self._vault_client.get_vault_id(),
|
|
192
|
+
table_name=request.table_name,
|
|
193
|
+
records=wire_records,
|
|
194
|
+
request_options=self.__unary_request_options(OPERATION_UPDATE, options),
|
|
195
|
+
**update_type_kwargs,
|
|
196
|
+
)
|
|
197
|
+
request_id = self.__extract_request_id(raw_response.headers)
|
|
198
|
+
records = [
|
|
199
|
+
UpdateResponseRecord(**self.__record_kwargs(record, include_data=True, request_id=request_id))
|
|
200
|
+
for record in (raw_response.data.records or [])
|
|
201
|
+
]
|
|
202
|
+
except Exception as e:
|
|
203
|
+
log_error_log(SkyflowMessages.ErrorLogs.UPDATE_RECORDS_REJECTED.value, self._vault_client.get_logger())
|
|
204
|
+
error_records, request_id = self.__unary_error_records(e)
|
|
205
|
+
if error_records is None:
|
|
206
|
+
raise self.__to_skyflow_error(e)
|
|
207
|
+
records = [
|
|
208
|
+
UpdateResponseRecord(**self.__record_kwargs(record, include_data=True, request_id=request_id))
|
|
209
|
+
for record in error_records
|
|
210
|
+
]
|
|
211
|
+
|
|
212
|
+
log_info(SkyflowMessages.Info.UPDATE_SUCCESS.value, self._vault_client.get_logger())
|
|
213
|
+
return UpdateResponse(records=records)
|
|
214
|
+
|
|
215
|
+
def delete(self, request: DeleteRequest, options: DeleteOptions = None) -> DeleteResponse:
|
|
216
|
+
log_info(SkyflowMessages.Info.VALIDATE_DELETE_REQUEST.value, self._vault_client.get_logger())
|
|
217
|
+
validate_delete_request(self._vault_client.get_logger(), request)
|
|
218
|
+
self._validate_table_name_if_present(request.table_name)
|
|
219
|
+
log_info(SkyflowMessages.Info.DELETE_REQUEST_RESOLVED.value, self._vault_client.get_logger())
|
|
220
|
+
self._vault_client.initialize_client_configuration()
|
|
221
|
+
|
|
222
|
+
records_api = self._vault_client.get_records_api()
|
|
223
|
+
items = request.ids or request.unique_values or []
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
log_info(SkyflowMessages.Info.DELETE_TRIGGERED.value, self._vault_client.get_logger())
|
|
227
|
+
raw_response = records_api.with_raw_response.delete_records(
|
|
228
|
+
vault_id=self._vault_client.get_vault_id(),
|
|
229
|
+
table_name=request.table_name,
|
|
230
|
+
skyflow_i_ds=request.ids,
|
|
231
|
+
unique_values=self.__to_unique_values(request.unique_values),
|
|
232
|
+
request_options=self.__unary_request_options(OPERATION_DELETE, options),
|
|
233
|
+
)
|
|
234
|
+
request_id = self.__extract_request_id(raw_response.headers)
|
|
235
|
+
records = [self.__delete_row(record, request_id) for record in (raw_response.data.records or [])]
|
|
236
|
+
except Exception as e:
|
|
237
|
+
log_error_log(SkyflowMessages.ErrorLogs.DELETE_RECORDS_REJECTED.value, self._vault_client.get_logger())
|
|
238
|
+
error_records, request_id = self.__unary_error_records(e)
|
|
239
|
+
if error_records is None:
|
|
240
|
+
raise self.__to_skyflow_error(e)
|
|
241
|
+
records = [self.__delete_row(record, request_id) for record in error_records]
|
|
242
|
+
|
|
243
|
+
log_info(SkyflowMessages.Info.DELETE_SUCCESS.value, self._vault_client.get_logger())
|
|
244
|
+
return DeleteResponse(records=records)
|
|
245
|
+
|
|
246
|
+
def detokenize(self, request: DetokenizeRequest, options: DetokenizeOptions = None) -> DetokenizeResponse:
|
|
247
|
+
log_info(SkyflowMessages.Info.VALIDATE_DETOKENIZE_REQUEST.value, self._vault_client.get_logger())
|
|
248
|
+
validate_detokenize_request(self._vault_client.get_logger(), request)
|
|
249
|
+
log_info(SkyflowMessages.Info.DETOKENIZE_REQUEST_RESOLVED.value, self._vault_client.get_logger())
|
|
250
|
+
self._vault_client.initialize_client_configuration()
|
|
251
|
+
|
|
252
|
+
tokens_api = self._vault_client.get_tokens_api()
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
log_info(SkyflowMessages.Info.DETOKENIZE_TRIGGERED.value, self._vault_client.get_logger())
|
|
256
|
+
raw_response = tokens_api.with_raw_response.detokenize(
|
|
257
|
+
vault_id=self._vault_client.get_vault_id(),
|
|
258
|
+
tokens=request.tokens,
|
|
259
|
+
token_group_redactions=self.__to_token_group_redactions(request.token_group_redactions),
|
|
260
|
+
request_options=self.__unary_request_options(OPERATION_DETOKENIZE, options),
|
|
261
|
+
)
|
|
262
|
+
request_id = self.__extract_request_id(raw_response.headers)
|
|
263
|
+
records = [self.__detokenize_row(resp, request_id) for resp in (raw_response.data.response or [])]
|
|
264
|
+
except Exception as e:
|
|
265
|
+
log_error_log(SkyflowMessages.ErrorLogs.DETOKENIZE_RECORDS_REJECTED.value, self._vault_client.get_logger())
|
|
266
|
+
error_records, request_id = self.__unary_error_records(e)
|
|
267
|
+
if error_records is None:
|
|
268
|
+
raise self.__to_skyflow_error(e)
|
|
269
|
+
records = [self.__detokenize_row(resp, request_id) for resp in error_records]
|
|
270
|
+
|
|
271
|
+
log_info(SkyflowMessages.Info.DETOKENIZE_SUCCESS.value, self._vault_client.get_logger())
|
|
272
|
+
return DetokenizeResponse(records=records)
|
|
273
|
+
|
|
274
|
+
def __error_body_records(self, e):
|
|
275
|
+
body = getattr(e, 'body', None)
|
|
276
|
+
if isinstance(body, dict):
|
|
277
|
+
records = body.get('records')
|
|
278
|
+
if records is None:
|
|
279
|
+
records = body.get('response')
|
|
280
|
+
else:
|
|
281
|
+
records = getattr(body, 'records', None) or getattr(body, 'response', None)
|
|
282
|
+
if records is None:
|
|
283
|
+
extra = getattr(body, '__pydantic_extra__', None)
|
|
284
|
+
if isinstance(extra, dict):
|
|
285
|
+
records = extra.get('records') or extra.get('response')
|
|
286
|
+
return records if isinstance(records, list) and records else None
|
|
287
|
+
|
|
288
|
+
def __unary_error_records(self, e):
|
|
289
|
+
records = self.__error_body_records(e)
|
|
290
|
+
if not records:
|
|
291
|
+
return None, None
|
|
292
|
+
return records, self.__extract_request_id(getattr(e, 'headers', None))
|
|
293
|
+
|
|
294
|
+
def __wire_record_value(self, record, wire_key, attr):
|
|
295
|
+
if isinstance(record, dict):
|
|
296
|
+
return record.get(wire_key)
|
|
297
|
+
return getattr(record, attr, None)
|
|
298
|
+
|
|
299
|
+
def __build_wire_record(self, record, request, needs_per_record_table, needs_per_record_upsert):
|
|
300
|
+
return InsertRecordData(data=record.data, **self.__omit_none(
|
|
301
|
+
tokens=record.tokens,
|
|
302
|
+
table_name=(record.table_name or request.table_name) if needs_per_record_table else None,
|
|
303
|
+
upsert=self.__to_upsert(record.upsert or request.upsert) if needs_per_record_upsert else None,
|
|
304
|
+
))
|
|
305
|
+
|
|
306
|
+
def __build_update_wire_record(self, record, request, needs_per_record_table):
|
|
307
|
+
return UpdateRecordData(
|
|
308
|
+
skyflow_id=record.skyflow_id,
|
|
309
|
+
data=record.data,
|
|
310
|
+
**self.__omit_none(
|
|
311
|
+
tokens=record.tokens,
|
|
312
|
+
table_name=(record.table_name or request.table_name) if needs_per_record_table else None,
|
|
313
|
+
),
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
def __omit_none(self, **kwargs):
|
|
317
|
+
return {k: v for k, v in kwargs.items() if v is not None}
|
|
318
|
+
|
|
319
|
+
def __to_update_type(self, update_type):
|
|
320
|
+
if update_type is None:
|
|
321
|
+
return None
|
|
322
|
+
return update_type.value if isinstance(update_type, UpsertType) else update_type
|
|
323
|
+
|
|
324
|
+
def __build_headers(self):
|
|
325
|
+
headers = {SKY_META_DATA_HEADER: json.dumps(get_metrics())}
|
|
326
|
+
token = self._vault_client.get_current_bearer_token()
|
|
327
|
+
if token:
|
|
328
|
+
headers['Authorization'] = f'Bearer {token}'
|
|
329
|
+
return headers
|
|
330
|
+
|
|
331
|
+
def __request_options(self, custom_headers=None):
|
|
332
|
+
headers = self.__build_headers()
|
|
333
|
+
if custom_headers:
|
|
334
|
+
headers.update(custom_headers)
|
|
335
|
+
return {ADDITIONAL_HEADERS_KEY: headers}
|
|
336
|
+
|
|
337
|
+
def __unary_request_options(self, operation, options):
|
|
338
|
+
interceptor = options.interceptor if options is not None else None
|
|
339
|
+
custom_headers = None
|
|
340
|
+
if interceptor is not None:
|
|
341
|
+
context = RequestContext(operation)
|
|
342
|
+
interceptor(context)
|
|
343
|
+
custom_headers = {str(key): value for key, value in context.headers.items()}
|
|
344
|
+
return self.__request_options(custom_headers)
|
|
345
|
+
|
|
346
|
+
def __to_upsert(self, upsert):
|
|
347
|
+
if upsert is None:
|
|
348
|
+
return None
|
|
349
|
+
update_type = upsert.update_type
|
|
350
|
+
return Upsert(
|
|
351
|
+
update_type=update_type.value if update_type else None,
|
|
352
|
+
unique_columns=upsert.unique_columns,
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
def __to_unique_values(self, unique_values):
|
|
356
|
+
if unique_values is None:
|
|
357
|
+
return None
|
|
358
|
+
return [UniqueValue(data=value) for value in unique_values]
|
|
359
|
+
|
|
360
|
+
def __to_column_redactions(self, column_redactions):
|
|
361
|
+
if column_redactions is None:
|
|
362
|
+
return None
|
|
363
|
+
return [
|
|
364
|
+
ColumnRedactions(column_name=entry.column_name, redaction=entry.redaction)
|
|
365
|
+
for entry in column_redactions
|
|
366
|
+
]
|
|
367
|
+
|
|
368
|
+
def __to_token_group_redactions(self, token_group_redactions):
|
|
369
|
+
if token_group_redactions is None:
|
|
370
|
+
return None
|
|
371
|
+
return [
|
|
372
|
+
WireTokenGroupRedactions(token_group_name=entry.token_group_name, redaction=entry.redaction)
|
|
373
|
+
for entry in token_group_redactions
|
|
374
|
+
]
|
|
375
|
+
|
|
376
|
+
def __extract_request_id(self, headers):
|
|
377
|
+
return headers.get(REQUEST_ID_HEADER) if headers else None
|
|
378
|
+
|
|
379
|
+
def __record_kwargs(self, record, include_data, request_id=None):
|
|
380
|
+
error = self.__wire_record_value(record, 'error', 'error')
|
|
381
|
+
kwargs = {
|
|
382
|
+
'table_name': self.__wire_record_value(record, 'tableName', 'table_name'),
|
|
383
|
+
'skyflow_id': self.__wire_record_value(record, 'skyflowID', 'skyflow_id'),
|
|
384
|
+
'tokens': parse_tokens(self.__wire_record_value(record, 'tokens', 'tokens')),
|
|
385
|
+
'hashed_data': parse_hashed_data(self.__wire_record_value(record, 'hashedData', 'hashed_data')),
|
|
386
|
+
'http_code': self.__wire_record_value(record, 'httpCode', 'http_code'),
|
|
387
|
+
'error': error,
|
|
388
|
+
'request_id': request_id if error is not None else None,
|
|
389
|
+
}
|
|
390
|
+
if include_data:
|
|
391
|
+
kwargs['data'] = self.__wire_record_value(record, 'data', 'data')
|
|
392
|
+
return kwargs
|
|
393
|
+
|
|
394
|
+
def __to_skyflow_error(self, e):
|
|
395
|
+
if isinstance(e, SkyflowError):
|
|
396
|
+
return e
|
|
397
|
+
if isinstance(e, (ApiError, ParsingError)):
|
|
398
|
+
message, grpc_code, http_status, details = self.__parse_api_error_body(e.body)
|
|
399
|
+
return SkyflowError(
|
|
400
|
+
message=message,
|
|
401
|
+
http_code=e.status_code,
|
|
402
|
+
request_id=self.__extract_request_id(e.headers),
|
|
403
|
+
grpc_code=grpc_code,
|
|
404
|
+
http_status=http_status,
|
|
405
|
+
details=details,
|
|
406
|
+
)
|
|
407
|
+
return SkyflowError(
|
|
408
|
+
message=str(e) if e else CommonMessages.Error.GENERIC_API_ERROR.value,
|
|
409
|
+
http_code=None,
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
def __parse_api_error_body(self, body):
|
|
413
|
+
error = getattr(body, 'error', None) if body is not None and not isinstance(body, dict) else None
|
|
414
|
+
if error is not None and not isinstance(error, dict):
|
|
415
|
+
return (
|
|
416
|
+
getattr(error, 'message', None) or UNKNOWN_ERROR_MESSAGE,
|
|
417
|
+
getattr(error, 'grpc_code', None),
|
|
418
|
+
getattr(error, 'http_status', None),
|
|
419
|
+
getattr(error, 'details', None) or [],
|
|
420
|
+
)
|
|
421
|
+
if isinstance(body, dict):
|
|
422
|
+
records = body.get('records')
|
|
423
|
+
if isinstance(records, list) and records:
|
|
424
|
+
first = records[0] if isinstance(records[0], dict) else {}
|
|
425
|
+
message = first.get('error') or first.get('message') or UNKNOWN_ERROR_MESSAGE
|
|
426
|
+
return (message, None, None, [record for record in records if isinstance(record, dict)])
|
|
427
|
+
error = body.get('error')
|
|
428
|
+
if isinstance(error, dict):
|
|
429
|
+
return (
|
|
430
|
+
error.get('message') or UNKNOWN_ERROR_MESSAGE,
|
|
431
|
+
error.get('grpc_code', error.get('grpcCode')),
|
|
432
|
+
error.get('http_status', error.get('httpStatus')),
|
|
433
|
+
error.get('details') or [],
|
|
434
|
+
)
|
|
435
|
+
if error is not None:
|
|
436
|
+
return (str(error), None, None, [])
|
|
437
|
+
return (UNKNOWN_ERROR_MESSAGE, None, None, [])
|
|
438
|
+
|
|
439
|
+
def __to_get_request_data(self, records):
|
|
440
|
+
return [
|
|
441
|
+
GetRequestData(
|
|
442
|
+
table_name=record.table_name,
|
|
443
|
+
skyflow_i_ds=record.skyflow_ids or [],
|
|
444
|
+
**self.__omit_none(
|
|
445
|
+
columns=record.columns,
|
|
446
|
+
column_redactions=self.__to_column_redactions(record.column_redactions),
|
|
447
|
+
unique_values=self.__to_unique_values(record.unique_values),
|
|
448
|
+
),
|
|
449
|
+
)
|
|
450
|
+
for record in records
|
|
451
|
+
]
|
|
452
|
+
|
|
453
|
+
def __delete_row(self, record, request_id=None):
|
|
454
|
+
error = self.__wire_record_value(record, 'error', 'error')
|
|
455
|
+
return DeleteResponseRecord(
|
|
456
|
+
skyflow_id=self.__wire_record_value(record, 'skyflowID', 'skyflow_id'),
|
|
457
|
+
http_code=self.__wire_record_value(record, 'httpCode', 'http_code'),
|
|
458
|
+
error=error,
|
|
459
|
+
request_id=request_id if error is not None else None,
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
def __detokenize_row(self, resp, request_id=None):
|
|
463
|
+
error = self.__wire_record_value(resp, 'error', 'error')
|
|
464
|
+
return DetokenizeResponseRecord(
|
|
465
|
+
token=self.__wire_record_value(resp, 'token', 'token'),
|
|
466
|
+
value=self.__wire_record_value(resp, 'value', 'value'),
|
|
467
|
+
token_group_name=self.__wire_record_value(resp, 'tokenGroupName', 'token_group_name'),
|
|
468
|
+
metadata=parse_metadata(self.__wire_record_value(resp, 'metadata', 'metadata')),
|
|
469
|
+
http_code=self.__wire_record_value(resp, 'httpCode', 'http_code'),
|
|
470
|
+
error=error,
|
|
471
|
+
request_id=request_id if error is not None else None,
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from ._upsert_options import UpsertOptions
|
|
2
|
+
from ._column_redactions import ColumnRedactions
|
|
3
|
+
from ._insert_request_record import InsertRequestRecord
|
|
4
|
+
from ._insert_request import InsertRequest
|
|
5
|
+
from ._insert_response import InsertResponse
|
|
6
|
+
from ._get_request_record import GetRequestRecord
|
|
7
|
+
from ._get_request import GetRequest
|
|
8
|
+
from ._get_response import GetResponse
|
|
9
|
+
from ._update_request_record import UpdateRequestRecord
|
|
10
|
+
from ._update_request import UpdateRequest
|
|
11
|
+
from ._update_response import UpdateResponse
|
|
12
|
+
from ._delete_request import DeleteRequest
|
|
13
|
+
from ._delete_response import DeleteResponse
|
|
14
|
+
from ._token_group_redactions import TokenGroupRedactions
|
|
15
|
+
from ._detokenize_request import DetokenizeRequest
|
|
16
|
+
from ._token import Token
|
|
17
|
+
from ._insert_response_record import InsertResponseRecord
|
|
18
|
+
from ._get_response_record import GetResponseRecord
|
|
19
|
+
from ._update_response_record import UpdateResponseRecord
|
|
20
|
+
from ._delete_response_record import DeleteResponseRecord
|
|
21
|
+
from ._detokenize_response import DetokenizeResponse
|
|
22
|
+
from ._detokenize_response_record import DetokenizeResponseRecord
|
|
23
|
+
from ._detokenize_response_record_metadata import DetokenizeResponseRecordMetadata
|
|
24
|
+
from ._request_context import RequestContext
|
|
25
|
+
from ._insert_options import InsertOptions
|
|
26
|
+
from ._get_options import GetOptions
|
|
27
|
+
from ._update_options import UpdateOptions
|
|
28
|
+
from ._delete_options import DeleteOptions
|
|
29
|
+
from ._detokenize_options import DetokenizeOptions
|
|
30
|
+
from skyflow.utils.enums import CustomHeaderKey
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
class DeleteResponseRecord:
|
|
2
|
+
def __init__(self, skyflow_id=None, http_code=None, error=None, request_id=None):
|
|
3
|
+
self.skyflow_id = skyflow_id
|
|
4
|
+
self.http_code = http_code
|
|
5
|
+
self.error = error
|
|
6
|
+
self.request_id = request_id
|
|
7
|
+
|
|
8
|
+
def __repr__(self):
|
|
9
|
+
return f"DeleteResponseRecord(skyflow_id={self.skyflow_id}, http_code={self.http_code}, error={self.error}, request_id={self.request_id})"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from ._token_group_redactions import TokenGroupRedactions
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DetokenizeRequest:
|
|
7
|
+
def __init__(self, tokens: list, token_group_redactions: List[TokenGroupRedactions] = None):
|
|
8
|
+
self.tokens = tokens
|
|
9
|
+
self.token_group_redactions = token_group_redactions
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class DetokenizeResponseRecord:
|
|
2
|
+
def __init__(self, token=None, value=None, token_group_name=None, metadata=None,
|
|
3
|
+
http_code=None, error=None, request_id=None):
|
|
4
|
+
self.token = token
|
|
5
|
+
self.value = value
|
|
6
|
+
self.token_group_name = token_group_name
|
|
7
|
+
self.metadata = metadata
|
|
8
|
+
self.http_code = http_code
|
|
9
|
+
self.error = error
|
|
10
|
+
self.request_id = request_id
|
|
11
|
+
|
|
12
|
+
def __repr__(self):
|
|
13
|
+
return ("DetokenizeResponseRecord(token={}, value={}, token_group_name={}, metadata={}, "
|
|
14
|
+
"http_code={}, error={}, request_id={})").format(
|
|
15
|
+
self.token, self.value, self.token_group_name, self.metadata,
|
|
16
|
+
self.http_code, self.error, self.request_id)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
class DetokenizeResponseRecordMetadata:
|
|
2
|
+
def __init__(self, skyflow_id: str = None, table_name: str = None):
|
|
3
|
+
self.skyflow_id = skyflow_id
|
|
4
|
+
self.table_name = table_name
|
|
5
|
+
|
|
6
|
+
def __repr__(self):
|
|
7
|
+
return f"DetokenizeResponseRecordMetadata(skyflow_id={self.skyflow_id}, table_name={self.table_name})"
|
|
8
|
+
|
|
9
|
+
def __str__(self):
|
|
10
|
+
return self.__repr__()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from ._column_redactions import ColumnRedactions
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class GetRequest:
|
|
7
|
+
def __init__(self, table_name: str = None, skyflow_ids: list = None, unique_values: list = None, columns: list = None,
|
|
8
|
+
column_redactions: List[ColumnRedactions] = None, limit: int = None, offset: int = None,
|
|
9
|
+
records: list = None):
|
|
10
|
+
self.table_name = table_name
|
|
11
|
+
self.skyflow_ids = skyflow_ids
|
|
12
|
+
self.unique_values = unique_values
|
|
13
|
+
self.columns = columns
|
|
14
|
+
self.column_redactions = column_redactions
|
|
15
|
+
self.limit = limit
|
|
16
|
+
self.offset = offset
|
|
17
|
+
self.records = records
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from ._column_redactions import ColumnRedactions
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class GetRequestRecord:
|
|
7
|
+
def __init__(self, table_name: str, skyflow_ids: list = None, columns: list = None,
|
|
8
|
+
column_redactions: List[ColumnRedactions] = None, unique_values: list = None):
|
|
9
|
+
self.table_name = table_name
|
|
10
|
+
self.skyflow_ids = skyflow_ids
|
|
11
|
+
self.columns = columns
|
|
12
|
+
self.column_redactions = column_redactions
|
|
13
|
+
self.unique_values = unique_values
|