@@ -215,6 +215,42 @@ def _create_temp_file_format(
215215 return file_format_location
216216
217217
218+ def _convert_value_to_sql_option (value : Union [str , bool , int , float ]) -> str :
219+ if isinstance (value , str ):
220+ if len (value ) > 1 and value .startswith ("'" ) and value .endswith ("'" ):
221+ return value
222+ else :
223+ value = value .replace (
224+ "'" , "''"
225+ ) # escape single quotes before adding a pair of quotes
226+ return f"'{ value } '"
227+ else :
228+ return str (value )
229+
230+
231+ def _iceberg_config_statement_helper (iceberg_config : dict [str , str ]) -> str :
232+ ALLOWED_CONFIGS = {
233+ "EXTERNAL_VOLUME" ,
234+ "CATALOG" ,
235+ "BASE_LOCATION" ,
236+ "CATALOG_SYNC" ,
237+ "STORAGE_SERIALIZATION_POLICY" ,
238+ }
239+
240+ normalized = {
241+ k .upper (): _convert_value_to_sql_option (v )
242+ for k , v in iceberg_config .items ()
243+ if v is not None
244+ }
245+
246+ if invalid_configs := set (normalized .keys ()) - ALLOWED_CONFIGS :
247+ raise ProgrammingError (
248+ f"Invalid iceberg configurations option(s) provided { ', ' .join (sorted (invalid_configs ))} "
249+ )
250+
251+ return " " .join (f"{ k } ={ v } " for k , v in normalized .items ())
252+
253+
218254def write_pandas (
219255 conn : SnowflakeConnection ,
220256 df : pandas .DataFrame ,
@@ -231,6 +267,7 @@ def write_pandas(
231267 overwrite : bool = False ,
232268 table_type : Literal ["" , "temp" , "temporary" , "transient" ] = "" ,
233269 use_logical_type : bool | None = None ,
270+ iceberg_config : dict [str , str ] | None = None ,
234271 ** kwargs : Any ,
235272) -> tuple [
236273 bool ,
@@ -295,6 +332,14 @@ def write_pandas(
295332 Snowflake can interpret Parquet logical types during data loading. To enable Parquet logical types,
296333 set use_logical_type as True. Set to None to use Snowflakes default. For more information, see:
297334 https://docs.snowflake.com/en/sql-reference/sql/create-file-format
335+ iceberg_config: A dictionary that can contain the following iceberg configuration values:
336+ * external_volume: specifies the identifier for the external volume where
337+ the Iceberg table stores its metadata files and data in Parquet format
338+ * catalog: specifies either Snowflake or a catalog integration to use for this table
339+ * base_location: the base directory that snowflake can write iceberg metadata and files to
340+ * catalog_sync: optionally sets the catalog integration configured for Polaris Catalog
341+ * storage_serialization_policy: specifies the storage serialization policy for the table
342+
298343
299344
300345 Returns:
@@ -479,9 +524,14 @@ def drop_object(name: str, object_type: str) -> None:
479524 quote_identifiers ,
480525 )
481526
527+ iceberg = "ICEBERG " if iceberg_config else ""
528+ iceberg_config_statement = _iceberg_config_statement_helper (
529+ iceberg_config or {}
530+ )
531+
482532 create_table_sql = (
483- f"CREATE { table_type .upper ()} TABLE IF NOT EXISTS identifier(?) "
484- f"({ create_table_columns } )"
533+ f"CREATE { table_type .upper ()} { iceberg } TABLE IF NOT EXISTS identifier(?) "
534+ f"({ create_table_columns } ) { iceberg_config_statement } "
485535 f" /* Python:snowflake.connector.pandas_tools.write_pandas() */ "
486536 )
487537 params = (target_table_location ,)
0 commit comments