From baeb4cf1a5498431586d9d4475f3d06cacd925a1 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Wed, 20 May 2026 23:20:28 +0530 Subject: [PATCH 1/3] SK-2838: fix warn logs structure --- skyflow/client/skyflow.py | 14 +++++--------- skyflow/utils/_skyflow_messages.py | 7 ++++--- skyflow/utils/logger/__init__.py | 2 +- skyflow/utils/logger/_log_helpers.py | 12 ++++++++++++ skyflow/vault/data/_file_upload_request.py | 9 ++------- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/skyflow/client/skyflow.py b/skyflow/client/skyflow.py index 2255ee50..ebd5ef7d 100644 --- a/skyflow/client/skyflow.py +++ b/skyflow/client/skyflow.py @@ -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 @@ -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.""" + log_warn(SkyflowMessages.Warning.UPDATE_LOG_LEVEL_DEPRECATED.value) return self.set_log_level(log_level) def get_log_level(self): @@ -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) @@ -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) diff --git a/skyflow/utils/_skyflow_messages.py b/skyflow/utils/_skyflow_messages.py index 01e15579..8e65ebac 100644 --- a/skyflow/utils/_skyflow_messages.py +++ b/skyflow/utils/_skyflow_messages.py @@ -4,6 +4,7 @@ error_prefix = f"Skyflow Python SDK {SDK_VERSION}" INFO = "INFO" +WARN = "WARN" ERROR = "ERROR" class SkyflowMessages: @@ -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=...)." ) diff --git a/skyflow/utils/logger/__init__.py b/skyflow/utils/logger/__init__.py index 2993b8fc..bce55608 100644 --- a/skyflow/utils/logger/__init__.py +++ b/skyflow/utils/logger/__init__.py @@ -1,2 +1,2 @@ from ._logger import Logger -from ._log_helpers import log_error, log_info, log_error_log \ No newline at end of file +from ._log_helpers import log_error, log_info, log_warn, log_error_log, set_active_log_level \ No newline at end of file diff --git a/skyflow/utils/logger/_log_helpers.py b/skyflow/utils/logger/_log_helpers.py index 3fff980b..1343b55f 100644 --- a/skyflow/utils/logger/_log_helpers.py +++ b/skyflow/utils/logger/_log_helpers.py @@ -2,6 +2,13 @@ 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: @@ -9,6 +16,11 @@ def log_info(message, logger = None): 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) diff --git a/skyflow/vault/data/_file_upload_request.py b/skyflow/vault/data/_file_upload_request.py index 6a632b67..c5c08b51 100644 --- a/skyflow/vault/data/_file_upload_request.py +++ b/skyflow/vault/data/_file_upload_request.py @@ -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: @@ -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 From f02f9822a55b937a30dd257e43fc1a4300757a6e Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Thu, 21 May 2026 00:02:20 +0530 Subject: [PATCH 2/3] SK-2838: fix unit tests and update readme --- samples/vault_api/upload_file.py | 42 +++++++++++++-------- tests/client/test_skyflow.py | 64 ++++++++++++++------------------ 2 files changed, 54 insertions(+), 52 deletions(-) diff --git a/samples/vault_api/upload_file.py b/samples/vault_api/upload_file.py index df3e8cd0..7c762b4b 100644 --- a/samples/vault_api/upload_file.py +++ b/samples/vault_api/upload_file.py @@ -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(): @@ -35,8 +39,8 @@ def perform_file_upload(): # Step 2: Configure Vault primary_vault_config = { - 'vault_id': '', - 'cluster_id': '', + 'vault_id': '', + 'cluster_id': '', 'env': Env.PROD, 'credentials': credentials } @@ -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('', 'rb') as file_obj: - file_upload_request = FileUploadRequest( - table='', # Table to upload file to - column_name='', # Column to upload file into - file_object=file_obj, # Pass file object - skyflow_id='' # Record ID to associate the file with + upload_request = FileUploadRequest( + table='', + column_name='', + skyflow_id='', + file_object=file_obj ) - # Step 5: Perform File Upload - response = skyflow_client.vault('').upload_file(file_upload_request) + response = skyflow_client.vault('').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('', 'rb') as file_obj: + upload_request = FileUploadRequest( + table='', + column_name='', + file_object=file_obj + ) + + response = skyflow_client.vault('').upload_file(upload_request) + print('File upload with new record:', response) except SkyflowError as error: print('Skyflow Specific Error: ', { diff --git a/tests/client/test_skyflow.py b/tests/client/test_skyflow.py index 1122448a..5b7ea675 100644 --- a/tests/client/test_skyflow.py +++ b/tests/client/test_skyflow.py @@ -1,5 +1,4 @@ import unittest -import warnings from unittest.mock import patch, Mock from skyflow import LogLevel, Env @@ -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) From c1e4a7e75eb398d7377c8bd258723e1a24a01d05 Mon Sep 17 00:00:00 2001 From: saileshwar-skyflow Date: Thu, 21 May 2026 00:13:50 +0530 Subject: [PATCH 3/3] SK-2838: update readme for file upload --- README.md | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 23326cca..dbe86ee7 100644 --- a/README.md +++ b/README.md @@ -410,7 +410,9 @@ 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 @@ -418,13 +420,26 @@ 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 of the record - file_object=file_obj # Pass file object + table='', + column_name='', + skyflow_id='', + file_object=file_obj + ) + + response = skyflow_client.vault('').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('').upload_file(upload_request) print('File upload:', response) ```