Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -410,21 +410,36 @@ Refer to [Query your data](https://docs.skyflow.com/query-data/) and [Execute Qu

### Upload File

Upload files to a Skyflow vault using the `upload_file` method. Create a file upload request with the `FileUploadRequest` class, which accepts parameters such as the table name, column name, and Skyflow ID.
Upload files to a Skyflow vault using the `upload_file` method. Create a file upload request with the `FileUploadRequest` class.

**Upload a file to an existing record:**

```python
from skyflow.vault.data import FileUploadRequest

# Open the file in binary read mode
with open('path/to/file.pdf', 'rb') as file_obj:
upload_request = FileUploadRequest(
table='documents', # Table name
column_name='attachment', # Column name to store file
skyflow_id='<SKYFLOW_ID>', # Skyflow ID of the record
file_object=file_obj # Pass file object
table='<TABLE_NAME>',
column_name='<COLUMN_NAME>',
skyflow_id='<SKYFLOW_ID>',
file_object=file_obj
)

response = skyflow_client.vault('<VAULT_ID>').upload_file(upload_request)
print('File upload:', response)
```

**Upload a file and create a new record (omit `skyflow_id`):**

```python
with open('path/to/file.pdf', 'rb') as file_obj:
upload_request = FileUploadRequest(
table='documents',
column_name='attachment',
file_object=file_obj
)

# Perform File Upload

response = skyflow_client.vault('<VAULT_ID>').upload_file(upload_request)
print('File upload:', response)
```
Expand Down
42 changes: 27 additions & 15 deletions samples/vault_api/upload_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@

"""
* Skyflow File Upload Example
*
*
* This example demonstrates how to:
* 1. Configure Skyflow client credentials
* 2. Set up vault configuration
* 3. Create a file upload request
* 4. Handle response and errors
* 3. Upload a file to an existing record (with skyflow_id)
* 4. Upload a file and create a new record (without skyflow_id)
* 5. Handle response and errors
*
* Note: All FileUploadRequest parameters must be
* passed as keyword arguments.
"""

def perform_file_upload():
Expand All @@ -35,8 +39,8 @@ def perform_file_upload():

# Step 2: Configure Vault
primary_vault_config = {
'vault_id': '<YOUR_VAULT_ID1>',
'cluster_id': '<YOUR_CLUSTER_ID1>',
'vault_id': '<YOUR_VAULT_ID>',
'cluster_id': '<YOUR_CLUSTER_ID>',
'env': Env.PROD,
'credentials': credentials
}
Expand All @@ -50,20 +54,28 @@ def perform_file_upload():
.build()
)

# Step 4: Prepare File Upload Data
# Step 4a: Upload a file to an existing record
with open('<PATH_TO_FILE>', 'rb') as file_obj:
file_upload_request = FileUploadRequest(
table='<TABLE_NAME>', # Table to upload file to
column_name='<COLUMN_NAME>', # Column to upload file into
file_object=file_obj, # Pass file object
skyflow_id='<SKYFLOW_ID>' # Record ID to associate the file with
upload_request = FileUploadRequest(
table='<TABLE_NAME>',
column_name='<COLUMN_NAME>',
skyflow_id='<SKYFLOW_ID>',
file_object=file_obj
)

# Step 5: Perform File Upload
response = skyflow_client.vault('<VAULT_ID>').upload_file(file_upload_request)
response = skyflow_client.vault('<YOUR_VAULT_ID>').upload_file(upload_request)
print('File upload to existing record:', response)

# Handle Successful Response
print('File upload successful: ', response)
# Step 4b: Upload a file and create a new record (omit skyflow_id)
with open('<PATH_TO_FILE>', 'rb') as file_obj:
upload_request = FileUploadRequest(
table='<TABLE_NAME>',
column_name='<COLUMN_NAME>',
file_object=file_obj
)

response = skyflow_client.vault('<YOUR_VAULT_ID>').upload_file(upload_request)
print('File upload with new record:', response)

except SkyflowError as error:
print('Skyflow Specific Error: ', {
Expand Down
14 changes: 5 additions & 9 deletions skyflow/client/skyflow.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import warnings
from collections import OrderedDict
from typing_extensions import deprecated
from skyflow import LogLevel
from skyflow.error import SkyflowError
from skyflow.utils import SkyflowMessages
from skyflow.utils.logger import log_info, Logger
from skyflow.utils.logger import log_info, log_warn, set_active_log_level, Logger
from skyflow.utils.constants import OptionField
from skyflow.utils.validations import validate_vault_config, validate_connection_config, validate_update_vault_config, \
validate_update_connection_config, validate_credentials, validate_log_level
Expand Down Expand Up @@ -61,13 +59,9 @@ def set_log_level(self, log_level):
self.__builder._Builder__set_log_level(log_level)
return self

@deprecated("[DEPRECATED] Use set_log_level() instead.")
def update_log_level(self, log_level):
warnings.warn(
SkyflowMessages.Warning.UPDATE_LOG_LEVEL_DEPRECATED.value,
DeprecationWarning,
stacklevel=2,
)
""".. deprecated:: Use set_log_level() instead. Will be removed in a future release."""
Comment thread
saileshwar-skyflow marked this conversation as resolved.
log_warn(SkyflowMessages.Warning.UPDATE_LOG_LEVEL_DEPRECATED.value)
return self.set_log_level(log_level)

def get_log_level(self):
Expand Down Expand Up @@ -227,6 +221,7 @@ def __set_log_level(self, log_level):
validate_log_level(self.__logger, log_level)
self.__log_level = log_level
self.__logger.set_log_level(log_level)
set_active_log_level(log_level)
self.__update_vault_client_logger(log_level, self.__logger)
log_info(SkyflowMessages.Info.LOGGER_SETUP_DONE.value, self.__logger)
log_info(SkyflowMessages.Info.CURRENT_LOG_LEVEL.value.format(self.__log_level), self.__logger)
Expand All @@ -243,6 +238,7 @@ def __add_skyflow_credentials(self, credentials):
def build(self):
validate_log_level(self.__logger, self.__log_level)
self.__logger.set_log_level(self.__log_level)
set_active_log_level(self.__log_level)

for config in self.__vault_list:
self.__add_vault_config(config)
Expand Down
7 changes: 4 additions & 3 deletions skyflow/utils/_skyflow_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

error_prefix = f"Skyflow Python SDK {SDK_VERSION}"
INFO = "INFO"
WARN = "WARN"
ERROR = "ERROR"

class SkyflowMessages:
Expand Down Expand Up @@ -417,11 +418,11 @@ class HttpStatus(Enum):

class Warning(Enum):
UPDATE_LOG_LEVEL_DEPRECATED = (
"[DEPRECATED] Skyflow.update_log_level() is deprecated. "
"Use Skyflow.set_log_level() instead — identical behavior."
f"{WARN}: [{error_prefix}] Skyflow.update_log_level() is deprecated. "
"Use Skyflow.set_log_level() instead."
)
FILE_UPLOAD_REQUEST_ARG_ORDER_DEPRECATED = (
"[DEPRECATED] FileUploadRequest: argument order changed. "
f"{WARN}: [{error_prefix}] FileUploadRequest: argument order changed. "
"Old positional order: (table, skyflow_id, column_name). "
"New order: FileUploadRequest(table, column_name=..., skyflow_id=...)."
)
Expand Down
2 changes: 1 addition & 1 deletion skyflow/utils/logger/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
from ._logger import Logger
from ._log_helpers import log_error, log_info, log_error_log
from ._log_helpers import log_error, log_info, log_warn, log_error_log, set_active_log_level
12 changes: 12 additions & 0 deletions skyflow/utils/logger/_log_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,25 @@
from . import Logger
from ..constants import ResponseField

_active_log_level = LogLevel.ERROR


def set_active_log_level(level):
global _active_log_level
_active_log_level = level


def log_info(message, logger = None):
if not logger:
logger = Logger(LogLevel.INFO)

logger.info(message)

def log_warn(message, logger=None):
if not logger:
logger = Logger(_active_log_level)
logger.warn(message)

def log_error_log(message, logger=None):
if not logger:
logger = Logger(LogLevel.ERROR)
Expand Down
9 changes: 2 additions & 7 deletions skyflow/vault/data/_file_upload_request.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import warnings
from typing import BinaryIO, Optional

from skyflow.utils import SkyflowMessages
from skyflow.utils.logger import log_warn


class FileUploadRequest:
Expand All @@ -15,12 +15,7 @@ def __init__(self,
file_object: Optional[BinaryIO] = None,
file_name: Optional[str] = None):
if args:
warnings.warn(
SkyflowMessages.Warning.FILE_UPLOAD_REQUEST_ARG_ORDER_DEPRECATED.value,
DeprecationWarning,
stacklevel=2,
)
# Old positional order was: (table, skyflow_id, column_name, ...)
log_warn(SkyflowMessages.Warning.FILE_UPLOAD_REQUEST_ARG_ORDER_DEPRECATED.value)
skyflow_id = args[0] if args else skyflow_id
column_name = args[1] if len(args) > 1 else column_name
self.table = table
Expand Down
64 changes: 27 additions & 37 deletions tests/client/test_skyflow.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import unittest
import warnings
from unittest.mock import patch, Mock

from skyflow import LogLevel, Env
Expand Down Expand Up @@ -427,68 +426,59 @@ def _build_client(self):

def test_update_log_level_emits_deprecation_warning(self):
client = self._build_client()
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
with patch('skyflow.client.skyflow.log_warn') as mock_warn:
client.update_log_level(LogLevel.INFO)
deprecation_warnings = [w for w in caught if issubclass(w.category, DeprecationWarning)]
self.assertGreaterEqual(len(deprecation_warnings), 1)
self.assertTrue(any("set_log_level" in str(w.message) for w in deprecation_warnings))

def test_update_log_level_warning_points_at_caller(self):
client = self._build_client()
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
client.update_log_level(LogLevel.INFO)
self.assertEqual(caught[0].filename, __file__)
mock_warn.assert_called_once()
self.assertIn("set_log_level", mock_warn.call_args[0][0])

def test_update_log_level_delegates_to_set_log_level(self):
client = self._build_client()
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
client.update_log_level(LogLevel.INFO)
client.update_log_level(LogLevel.INFO)
self.assertEqual(client.get_log_level(), LogLevel.INFO)


class TestFileUploadRequestDeprecation(unittest.TestCase):
def test_keyword_args_no_warning(self):
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
with patch('skyflow.vault.data._file_upload_request.log_warn') as mock_warn:
req = FileUploadRequest(
table="table",
column_name="col",
skyflow_id="sky123",
)
self.assertEqual(len(caught), 0)
mock_warn.assert_not_called()
self.assertEqual(req.table, "table")
self.assertEqual(req.column_name, "col")
self.assertEqual(req.skyflow_id, "sky123")

def test_only_table_positional_no_warning(self):
with patch('skyflow.vault.data._file_upload_request.log_warn') as mock_warn:
req = FileUploadRequest("table", column_name="col", skyflow_id="sky123")
mock_warn.assert_not_called()
self.assertEqual(req.table, "table")

def test_old_positional_order_emits_deprecation_warning(self):
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
with patch('skyflow.vault.data._file_upload_request.log_warn') as mock_warn:
req = FileUploadRequest("table", "sky123", "col")
self.assertEqual(len(caught), 1)
self.assertTrue(issubclass(caught[0].category, DeprecationWarning))
self.assertIn("FileUploadRequest", str(caught[0].message))
mock_warn.assert_called_once()
self.assertIn("FileUploadRequest", mock_warn.call_args[0][0])

def test_old_positional_order_remaps_args_correctly(self):
with warnings.catch_warnings(record=True):
warnings.simplefilter("always")
req = FileUploadRequest("table", "sky123", "col")
req = FileUploadRequest("table", "sky123", "col")
self.assertEqual(req.skyflow_id, "sky123")
self.assertEqual(req.column_name, "col")

def test_old_positional_order_warning_points_at_caller(self):
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
FileUploadRequest("table", "sky123", "col")
self.assertEqual(caught[0].filename, __file__)

def test_single_positional_arg_emits_warning_and_sets_skyflow_id(self):
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
with patch('skyflow.vault.data._file_upload_request.log_warn') as mock_warn:
req = FileUploadRequest("table", "sky123")
self.assertEqual(len(caught), 1)
self.assertTrue(issubclass(caught[0].category, DeprecationWarning))
mock_warn.assert_called_once()
self.assertEqual(req.skyflow_id, "sky123")
self.assertIsNone(req.column_name)

def test_optional_fields_default_to_none(self):
req = FileUploadRequest(table="table")
self.assertIsNone(req.skyflow_id)
self.assertIsNone(req.column_name)
self.assertIsNone(req.file_path)
self.assertIsNone(req.base64)
self.assertIsNone(req.file_object)
self.assertIsNone(req.file_name)
Loading