diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e10aee..f8bf1df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- feat(tables): add csv and json file format support for table loads - Regenerate the client from the updated Hotdata OpenAPI spec - chore: remove datasets API and related job types diff --git a/docs/ConnectionsApi.md b/docs/ConnectionsApi.md index c43e846..8341092 100644 --- a/docs/ConnectionsApi.md +++ b/docs/ConnectionsApi.md @@ -810,7 +810,7 @@ This endpoint does not need any parameter. Load managed table from upload -Publish a previously-uploaded parquet file as the new contents of a managed table. The upload must reference a parquet file. Only `mode = "replace"` is supported. Concurrent loads against the same upload return 409. +Publish a previously-uploaded file as the new contents of a managed table. CSV, JSON, and Parquet uploads are supported; the format is auto-detected from the upload's `Content-Type` and file contents, or set explicitly via the `format` field. Only `mode = "replace"` is supported. Concurrent loads against the same upload return 409. ### Example diff --git a/docs/DatabasesApi.md b/docs/DatabasesApi.md index d464b56..40151d3 100644 --- a/docs/DatabasesApi.md +++ b/docs/DatabasesApi.md @@ -12,6 +12,7 @@ Method | HTTP request | Description [**detach_database_catalog**](DatabasesApi.md#detach_database_catalog) | **DELETE** /v1/databases/{database_id}/catalogs/{connection_id} | Detach catalog from database [**get_database**](DatabasesApi.md#get_database) | **GET** /v1/databases/{database_id} | Get database [**list_databases**](DatabasesApi.md#list_databases) | **GET** /v1/databases | List databases +[**load_database_table**](DatabasesApi.md#load_database_table) | **POST** /v1/databases/{database_id}/schemas/{schema}/tables/{table}/loads | Load database table from upload # **add_database_schema** @@ -706,3 +707,98 @@ This endpoint does not need any parameter. [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **load_database_table** +> LoadManagedTableResponse load_database_table(database_id, var_schema, table, load_managed_table_request) + +Load database table from upload + +Publish a previously-uploaded file as the new contents of a table on the database's default catalog. The database-scoped equivalent of the connection-scoped managed-table load — addressed by `database_id`, so no `default_connection_id` is needed. CSV, JSON, and Parquet uploads are supported; the format is auto-detected or set via `format`. Only `mode = "replace"` is supported. Concurrent loads against the same upload return 409. + +### Example + +* Api Key Authentication (WorkspaceId): +* Bearer Authentication (BearerAuth): + +```python +import hotdata +from hotdata.models.load_managed_table_request import LoadManagedTableRequest +from hotdata.models.load_managed_table_response import LoadManagedTableResponse +from hotdata.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to https://api.hotdata.dev +# See configuration.py for a list of all supported configuration parameters. +configuration = hotdata.Configuration( + host = "https://api.hotdata.dev" +) + +# The client must configure the authentication and authorization parameters +# in accordance with the API server security policy. +# Examples for each auth method are provided below, use the example that +# satisfies your auth use case. + +# Configure API key authorization: WorkspaceId +configuration.api_key['WorkspaceId'] = os.environ["API_KEY"] + +# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +# configuration.api_key_prefix['WorkspaceId'] = 'Bearer' + +# Configure Bearer authorization: BearerAuth +configuration = hotdata.Configuration( + access_token = os.environ["BEARER_TOKEN"] +) + +# Enter a context with an instance of the API client +with hotdata.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = hotdata.DatabasesApi(api_client) + database_id = 'database_id_example' # str | Database ID + var_schema = 'var_schema_example' # str | Schema name + table = 'table_example' # str | Table name + load_managed_table_request = hotdata.LoadManagedTableRequest() # LoadManagedTableRequest | + + try: + # Load database table from upload + api_response = api_instance.load_database_table(database_id, var_schema, table, load_managed_table_request) + print("The response of DatabasesApi->load_database_table:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling DatabasesApi->load_database_table: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **database_id** | **str**| Database ID | + **var_schema** | **str**| Schema name | + **table** | **str**| Table name | + **load_managed_table_request** | [**LoadManagedTableRequest**](LoadManagedTableRequest.md)| | + +### Return type + +[**LoadManagedTableResponse**](LoadManagedTableResponse.md) + +### Authorization + +[WorkspaceId](../README.md#WorkspaceId), [BearerAuth](../README.md#BearerAuth) + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | Table loaded | - | +**400** | Invalid request (bad mode, bad parquet) | - | +**404** | Database, table, or upload not found | - | +**409** | Upload already consumed or in flight | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/docs/JobType.md b/docs/JobType.md index a7feb8a..a6d081f 100644 --- a/docs/JobType.md +++ b/docs/JobType.md @@ -14,6 +14,16 @@ Background job types returned by the API. * `MANAGED_LOAD` (value: `'managed_load'`) +* `DUCKLAKE_VACUUM` (value: `'ducklake_vacuum'`) + +* `DUCKLAKE_ORPHAN_CLEANUP` (value: `'ducklake_orphan_cleanup'`) + +* `RESULT_DELETION` (value: `'result_deletion'`) + +* `STALE_RESULT_CLEANUP` (value: `'stale_result_cleanup'`) + +* `RESULT_RETENTION` (value: `'result_retention'`) + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/docs/LoadManagedTableRequest.md b/docs/LoadManagedTableRequest.md index de03667..24184cb 100644 --- a/docs/LoadManagedTableRequest.md +++ b/docs/LoadManagedTableRequest.md @@ -1,13 +1,14 @@ # LoadManagedTableRequest -Request body for `POST /v1/connections/{connection_id}/schemas/{schema}/tables/{table}/loads`. Publishes a previously-uploaded parquet file as the new contents of the named managed table. `mode` is fixed to `\"replace\"` today; the field is kept in the request body so future modes (e.g. append) are an additive change. +Request body for `POST /v1/connections/{connection_id}/schemas/{schema}/tables/{table}/loads`. Publishes a previously-uploaded file as the new contents of the named managed table. CSV and JSON uploads are converted to columnar storage on load; Parquet uploads are published directly. `mode` is fixed to `\"replace\"` today; the field is kept in the request body so future modes (e.g. append) are an additive change. ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**format** | **str** | File format of the upload: `\"csv\"`, `\"json\"`, or `\"parquet\"`. Optional — when omitted, the format is auto-detected from the upload's `Content-Type` and, failing that, from the file contents. Provide it explicitly to override detection or when the contents are ambiguous. `\"json\"` expects newline-delimited JSON (one object per line), not a JSON array. | [optional] **mode** | **str** | Load mode. Only `\"replace\"` is supported in this release. | -**upload_id** | **str** | ID of a previously-staged upload (see `POST /v1/files`). The upload must reference a parquet file. The upload is claimed atomically; concurrent loads against the same `upload_id` return 409. | +**upload_id** | **str** | ID of a previously-staged upload (see `POST /v1/files`). The upload is claimed atomically; concurrent loads against the same `upload_id` return 409. | ## Example diff --git a/hotdata/api/connections_api.py b/hotdata/api/connections_api.py index 1eb0b0c..6e34fd6 100644 --- a/hotdata/api/connections_api.py +++ b/hotdata/api/connections_api.py @@ -2603,7 +2603,7 @@ def load_managed_table( ) -> LoadManagedTableResponse: """Load managed table from upload - Publish a previously-uploaded parquet file as the new contents of a managed table. The upload must reference a parquet file. Only `mode = \"replace\"` is supported. Concurrent loads against the same upload return 409. + Publish a previously-uploaded file as the new contents of a managed table. CSV, JSON, and Parquet uploads are supported; the format is auto-detected from the upload's `Content-Type` and file contents, or set explicitly via the `format` field. Only `mode = \"replace\"` is supported. Concurrent loads against the same upload return 409. :param connection_id: Connection ID (required) :type connection_id: str @@ -2685,7 +2685,7 @@ def load_managed_table_with_http_info( ) -> ApiResponse[LoadManagedTableResponse]: """Load managed table from upload - Publish a previously-uploaded parquet file as the new contents of a managed table. The upload must reference a parquet file. Only `mode = \"replace\"` is supported. Concurrent loads against the same upload return 409. + Publish a previously-uploaded file as the new contents of a managed table. CSV, JSON, and Parquet uploads are supported; the format is auto-detected from the upload's `Content-Type` and file contents, or set explicitly via the `format` field. Only `mode = \"replace\"` is supported. Concurrent loads against the same upload return 409. :param connection_id: Connection ID (required) :type connection_id: str @@ -2767,7 +2767,7 @@ def load_managed_table_without_preload_content( ) -> RESTResponseType: """Load managed table from upload - Publish a previously-uploaded parquet file as the new contents of a managed table. The upload must reference a parquet file. Only `mode = \"replace\"` is supported. Concurrent loads against the same upload return 409. + Publish a previously-uploaded file as the new contents of a managed table. CSV, JSON, and Parquet uploads are supported; the format is auto-detected from the upload's `Content-Type` and file contents, or set explicitly via the `format` field. Only `mode = \"replace\"` is supported. Concurrent loads against the same upload return 409. :param connection_id: Connection ID (required) :type connection_id: str diff --git a/hotdata/api/databases_api.py b/hotdata/api/databases_api.py index 85a5aec..a5c208c 100644 --- a/hotdata/api/databases_api.py +++ b/hotdata/api/databases_api.py @@ -25,6 +25,8 @@ from hotdata.models.create_database_response import CreateDatabaseResponse from hotdata.models.database_detail_response import DatabaseDetailResponse from hotdata.models.list_databases_response import ListDatabasesResponse +from hotdata.models.load_managed_table_request import LoadManagedTableRequest +from hotdata.models.load_managed_table_response import LoadManagedTableResponse from hotdata.models.managed_schema_response import ManagedSchemaResponse from hotdata.models.managed_table_response import ManagedTableResponse @@ -2291,3 +2293,332 @@ def _list_databases_serialize( ) + + + @validate_call + def load_database_table( + self, + database_id: Annotated[StrictStr, Field(description="Database ID")], + var_schema: Annotated[StrictStr, Field(description="Schema name")], + table: Annotated[StrictStr, Field(description="Table name")], + load_managed_table_request: LoadManagedTableRequest, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> LoadManagedTableResponse: + """Load database table from upload + + Publish a previously-uploaded file as the new contents of a table on the database's default catalog. The database-scoped equivalent of the connection-scoped managed-table load — addressed by `database_id`, so no `default_connection_id` is needed. CSV, JSON, and Parquet uploads are supported; the format is auto-detected or set via `format`. Only `mode = \"replace\"` is supported. Concurrent loads against the same upload return 409. + + :param database_id: Database ID (required) + :type database_id: str + :param var_schema: Schema name (required) + :type var_schema: str + :param table: Table name (required) + :type table: str + :param load_managed_table_request: (required) + :type load_managed_table_request: LoadManagedTableRequest + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._load_database_table_serialize( + database_id=database_id, + var_schema=var_schema, + table=table, + load_managed_table_request=load_managed_table_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "LoadManagedTableResponse", + '400': "ApiErrorResponse", + '404': "ApiErrorResponse", + '409': "ApiErrorResponse", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def load_database_table_with_http_info( + self, + database_id: Annotated[StrictStr, Field(description="Database ID")], + var_schema: Annotated[StrictStr, Field(description="Schema name")], + table: Annotated[StrictStr, Field(description="Table name")], + load_managed_table_request: LoadManagedTableRequest, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[LoadManagedTableResponse]: + """Load database table from upload + + Publish a previously-uploaded file as the new contents of a table on the database's default catalog. The database-scoped equivalent of the connection-scoped managed-table load — addressed by `database_id`, so no `default_connection_id` is needed. CSV, JSON, and Parquet uploads are supported; the format is auto-detected or set via `format`. Only `mode = \"replace\"` is supported. Concurrent loads against the same upload return 409. + + :param database_id: Database ID (required) + :type database_id: str + :param var_schema: Schema name (required) + :type var_schema: str + :param table: Table name (required) + :type table: str + :param load_managed_table_request: (required) + :type load_managed_table_request: LoadManagedTableRequest + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._load_database_table_serialize( + database_id=database_id, + var_schema=var_schema, + table=table, + load_managed_table_request=load_managed_table_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "LoadManagedTableResponse", + '400': "ApiErrorResponse", + '404': "ApiErrorResponse", + '409': "ApiErrorResponse", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def load_database_table_without_preload_content( + self, + database_id: Annotated[StrictStr, Field(description="Database ID")], + var_schema: Annotated[StrictStr, Field(description="Schema name")], + table: Annotated[StrictStr, Field(description="Table name")], + load_managed_table_request: LoadManagedTableRequest, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """Load database table from upload + + Publish a previously-uploaded file as the new contents of a table on the database's default catalog. The database-scoped equivalent of the connection-scoped managed-table load — addressed by `database_id`, so no `default_connection_id` is needed. CSV, JSON, and Parquet uploads are supported; the format is auto-detected or set via `format`. Only `mode = \"replace\"` is supported. Concurrent loads against the same upload return 409. + + :param database_id: Database ID (required) + :type database_id: str + :param var_schema: Schema name (required) + :type var_schema: str + :param table: Table name (required) + :type table: str + :param load_managed_table_request: (required) + :type load_managed_table_request: LoadManagedTableRequest + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._load_database_table_serialize( + database_id=database_id, + var_schema=var_schema, + table=table, + load_managed_table_request=load_managed_table_request, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + '200': "LoadManagedTableResponse", + '400': "ApiErrorResponse", + '404': "ApiErrorResponse", + '409': "ApiErrorResponse", + } + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _load_database_table_serialize( + self, + database_id, + var_schema, + table, + load_managed_table_request, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> RequestSerialized: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[ + str, Union[str, bytes, List[str], List[bytes], List[Tuple[str, bytes]]] + ] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + if database_id is not None: + _path_params['database_id'] = database_id + if var_schema is not None: + _path_params['schema'] = var_schema + if table is not None: + _path_params['table'] = table + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + if load_managed_table_request is not None: + _body_params = load_managed_table_request + + + # set the HTTP header `Accept` + if 'Accept' not in _header_params: + _header_params['Accept'] = self.api_client.select_header_accept( + [ + 'application/json' + ] + ) + + # set the HTTP header `Content-Type` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type + + # authentication setting + _auth_settings: List[str] = [ + 'WorkspaceId', + 'BearerAuth' + ] + + return self.api_client.param_serialize( + method='POST', + resource_path='/v1/databases/{database_id}/schemas/{schema}/tables/{table}/loads', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + diff --git a/hotdata/models/job_type.py b/hotdata/models/job_type.py index f9ef5da..74cb7b6 100644 --- a/hotdata/models/job_type.py +++ b/hotdata/models/job_type.py @@ -32,6 +32,11 @@ class JobType(str, Enum): DATA_REFRESH_CONNECTION = 'data_refresh_connection' CREATE_INDEX = 'create_index' MANAGED_LOAD = 'managed_load' + DUCKLAKE_VACUUM = 'ducklake_vacuum' + DUCKLAKE_ORPHAN_CLEANUP = 'ducklake_orphan_cleanup' + RESULT_DELETION = 'result_deletion' + STALE_RESULT_CLEANUP = 'stale_result_cleanup' + RESULT_RETENTION = 'result_retention' @classmethod def from_json(cls, json_str: str) -> Self: diff --git a/hotdata/models/load_managed_table_request.py b/hotdata/models/load_managed_table_request.py index 3313934..a0234cf 100644 --- a/hotdata/models/load_managed_table_request.py +++ b/hotdata/models/load_managed_table_request.py @@ -19,17 +19,18 @@ import json from pydantic import BaseModel, ConfigDict, Field, StrictStr -from typing import Any, ClassVar, Dict, List +from typing import Any, ClassVar, Dict, List, Optional from typing import Optional, Set from typing_extensions import Self class LoadManagedTableRequest(BaseModel): """ - Request body for `POST /v1/connections/{connection_id}/schemas/{schema}/tables/{table}/loads`. Publishes a previously-uploaded parquet file as the new contents of the named managed table. `mode` is fixed to `\"replace\"` today; the field is kept in the request body so future modes (e.g. append) are an additive change. + Request body for `POST /v1/connections/{connection_id}/schemas/{schema}/tables/{table}/loads`. Publishes a previously-uploaded file as the new contents of the named managed table. CSV and JSON uploads are converted to columnar storage on load; Parquet uploads are published directly. `mode` is fixed to `\"replace\"` today; the field is kept in the request body so future modes (e.g. append) are an additive change. """ # noqa: E501 + format: Optional[StrictStr] = Field(default=None, description="File format of the upload: `\"csv\"`, `\"json\"`, or `\"parquet\"`. Optional — when omitted, the format is auto-detected from the upload's `Content-Type` and, failing that, from the file contents. Provide it explicitly to override detection or when the contents are ambiguous. `\"json\"` expects newline-delimited JSON (one object per line), not a JSON array.") mode: StrictStr = Field(description="Load mode. Only `\"replace\"` is supported in this release.") - upload_id: StrictStr = Field(description="ID of a previously-staged upload (see `POST /v1/files`). The upload must reference a parquet file. The upload is claimed atomically; concurrent loads against the same `upload_id` return 409.") - __properties: ClassVar[List[str]] = ["mode", "upload_id"] + upload_id: StrictStr = Field(description="ID of a previously-staged upload (see `POST /v1/files`). The upload is claimed atomically; concurrent loads against the same `upload_id` return 409.") + __properties: ClassVar[List[str]] = ["format", "mode", "upload_id"] model_config = ConfigDict( populate_by_name=True, @@ -70,6 +71,11 @@ def to_dict(self) -> Dict[str, Any]: exclude=excluded_fields, exclude_none=True, ) + # set to None if format (nullable) is None + # and model_fields_set contains the field + if self.format is None and "format" in self.model_fields_set: + _dict['format'] = None + return _dict @classmethod @@ -82,6 +88,7 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ + "format": obj.get("format"), "mode": obj.get("mode"), "upload_id": obj.get("upload_id") }) diff --git a/test/test_databases_api.py b/test/test_databases_api.py index 920b905..f049135 100644 --- a/test/test_databases_api.py +++ b/test/test_databases_api.py @@ -83,6 +83,13 @@ def test_list_databases(self) -> None: """ pass + def test_load_database_table(self) -> None: + """Test case for load_database_table + + Load database table from upload + """ + pass + if __name__ == '__main__': unittest.main() diff --git a/test/test_load_managed_table_request.py b/test/test_load_managed_table_request.py index cfa2daf..d658ef7 100644 --- a/test/test_load_managed_table_request.py +++ b/test/test_load_managed_table_request.py @@ -36,6 +36,7 @@ def make_instance(self, include_optional) -> LoadManagedTableRequest: model = LoadManagedTableRequest() if include_optional: return LoadManagedTableRequest( + format = '', mode = '', upload_id = '' )