
    ɯeik                         d dl Z d dlZd dlZd dlZd dlmZmZmZmZm	Z	m
Z
 d dlZd dlmZmZ d dlmZ d dlmZmZmZmZmZmZmZmZ  G d de      Z G d d	e      Z G d
 de      Z G d d      Zy)    N)IODictList
NamedTupleOptionalUnion)OperationalErrorProgrammingError)SnowparkClientExceptionMessages)get_local_file_pathis_in_stored_procedureis_single_quotednormalize_local_filenormalize_remote_file_or_dirresult_set_to_rows
split_pathvalidate_stage_locationc                   b    e Zd ZU dZeed<   eed<   eed<   eed<   eed<   eed<   eed<   eed	<   y
)	PutResultzERepresents the results of uploading a local file to a stage location.sourcetargetsource_sizetarget_sizesource_compressiontarget_compressionstatusmessageN)__name__
__module____qualname____doc__str__annotations__int     c/var/www/html/glpi_dashboard/venv/lib/python3.12/site-packages/snowflake/snowpark/file_operation.pyr   r      s1    OKKKLr&   r   c                   :    e Zd ZU dZeed<   eed<   eed<   eed<   y)	GetResultz\Represents the results of downloading a file from a stage location to the local file system.filesizer   r   N)r   r   r    r!   r"   r#   r%   r&   r'   r)   r)   '   s    f
I
IKLr&   r)   c                   P    e Zd ZU dZeed<   eed<   ee   ed<   ee   ed<   eed<   y)
ListResultz>Represents the results of listing files from a stage location.namer+   md5sha1last_modifiedN)r   r   r    r!   r"   r#   r$   r   r%   r&   r'   r-   r-   0   s9    H
I
I	
    r&   r-   c                   $   e Zd ZdZd)dZdee   deeef   ddfdZdd	d
ddddedede	de
dede
deeeef      dee   fdZdddddedede	dee   deeeef      dee   fdZdd	d
dddee   dede	de
dede
defdZdddddede	de
deeeef      dee   f
dZddd	ddd eed!f   d"ed#eee      dee   d$e
deeeef      deee   e	f   fd%Zddd&dedee   deeeef      dee   fd'Zddd&dedee   deeeef      dee   fd(Zy)*FileOperationzwProvides methods for working on files in a stage.
    To access an object of this class, use :attr:`Session.file`.
    returnNc                     || _         y )N)_session)selfsessions     r'   __init__zFileOperation.__init__C   s	    r&   patternoptionsc                 Z    |)t        |      s|j                  dd      }d| d}||d<   yy)z@Helper method to process and add pattern to options if provided.N'z\'r:   )r   replace)r7   r:   r;   pattern_escape_single_quotes       r'   _process_patternzFileOperation._process_patternF   s@    #G,.5ooc5.I+9:!<!(GI	 r&      TAUTO_DETECTF)parallelauto_compressr   	overwritestatement_paramslocal_file_namestage_locationrC   rD   r   rE   rF   c          	         ||||d}t               r]	 | j                  j                  j                  }	|	j	                  |||       |	j
                  }
|	j                         }t        ||
      }n| j                  j                  j                  j!                  dt#        |      t%        |      |      }t&        j(                  j*                  j-                  | j                  |      j/                  |      }|D cg c]  }t1        di |j3                          c}S # t        $ rC}t        j                         d   }t        j                  |      }|j                  |      dd}~ww xY wc c}w )a:  Uploads local files to the stage.

        References: `Snowflake PUT command <https://docs.snowflake.com/en/sql-reference/sql/put.html>`_.

        Example::

            >>> # Create a temp stage.
            >>> _ = session.sql("create or replace temp stage mystage").collect()
            >>> # Upload a file to a stage.
            >>> put_result = session.file.put("tests/resources/t*.csv", "@mystage/prefix1")
            >>> put_result[0].status
            'UPLOADED'

        Args:
            local_file_name: The path to the local files to upload. To match multiple files in the path,
                you can specify the wildcard characters ``*`` and ``?``.
            stage_location: The stage and prefix where you want to upload the files.
            parallel: Specifies the number of threads to use for uploading files. The upload process separates batches of data files by size:

                  - Small files (< 64 MB compressed or uncompressed) are staged in parallel as individual files.
                  - Larger files are automatically split into chunks, staged concurrently, and reassembled in the target stage. A single thread can upload multiple chunks.

                Increasing the number of threads can improve performance when uploading large files.
                Supported values: Any integer value from 1 (no parallelism) to 99 (use 99 threads for uploading files).
            auto_compress: Specifies whether Snowflake uses gzip to compress files during upload.
            source_compression: Specifies the method of compression used on already-compressed files that are being staged.
                Values can be 'AUTO_DETECT', 'GZIP', 'BZ2', 'BROTLI', 'ZSTD', 'DEFLATE', 'RAW_DEFLATE', 'NONE'.
            overwrite: Specifies whether Snowflake will overwrite an existing file with the same name during upload.
            statement_params: Dictionary of statement level parameters to be set while executing this action.

        Returns:
            A ``list`` of :class:`PutResult` instances, each of which represents the results of an uploaded file.
        rC   r   rD   rE      NputrF   r%   )r   r6   _conn_cursor_uploaddescriptionfetchallr   r
   sysexc_infor   $SQL_EXCEPTION_FROM_PROGRAMMING_ERRORwith_traceback	_analyzerplan_builderfile_operation_planr   r   	snowflakesnowpark	dataframe	DataFrame_internal_collect_with_tagr   asDict)r7   rG   rH   rC   rD   r   rE   rF   r;   cursorresult_metaresult_data
put_resultpetbneplanfile_results                     r'   rL   zFileOperation.putN   sS   Z !"4*"	
 "#6,,44H$00$oo//[I
 ==**77KK$_5,^<	D #++55??t((:J(K  FPPk	1K..01PP! $ 6\\^A&4YY ''+56  Qs   AD ; E-	E*'>E%%E*
   )rC   r:   rF   target_directoryc          	      R   d|i}| j                  ||       	 t               r]	 | j                  j                  j                  }|j                  |||       |j                  }|j                         }	t        |	|      }
n| j                  j                  j!                  dt#        |      t%        |      |      }t'        j(                  t+        |      d       t,        j.                  j0                  j3                  | j                  |      j5                  |      }
|
D cg c]  }t7        di |j9                          c}S # t        $ rC}t        j                         d   }t        j                  |      }|j                  |      dd}~ww xY wc c}w # t:        $ r g cY S w xY w)	aD	  Downloads the specified files from a path in a stage to a local directory.

        References: `Snowflake GET command <https://docs.snowflake.com/en/sql-reference/sql/get.html>`_.

        Examples:

            >>> # Create a temp stage.
            >>> _ = session.sql("create or replace temp stage mystage").collect()
            >>> # Upload a file to a stage.
            >>> _ = session.file.put("tests/resources/t*.csv", "@mystage/prefix1")
            >>> # Download one file from a stage.
            >>> get_result1 = session.file.get("@myStage/prefix1/test2CSV.csv", "tests/downloaded/target1")
            >>> assert len(get_result1) == 1
            >>> # Download all the files from @myStage/prefix.
            >>> get_result2 = session.file.get("@myStage/prefix1", "tests/downloaded/target2")
            >>> assert len(get_result2) > 1
            >>> # Download files with names that match a regular expression pattern.
            >>> get_result3 = session.file.get("@myStage/prefix1", "tests/downloaded/target3", pattern=".*test.*.csv.gz")
            >>> assert len(get_result3) > 1

        Args:
            stage_location: A directory or filename on a stage, from which you want to download the files.
            target_directory: The path to the local directory where the files should be downloaded.
                If ``target_directory`` does not already exist, the method creates the directory.
            parallel: Specifies the number of threads to use for downloading the files.
                The granularity unit for downloading is one file.
                Increasing the number of threads might improve performance when downloading large files.
                Supported values: Any integer value from 1 (no parallelism) to 99 (use 99 threads for downloading files).
            pattern: Specifies a regular expression pattern for filtering files to download.
                The command lists all files in the specified path and applies the regular expression pattern on each of the files found.
                Default: ``None`` (all files in the specified stage are downloaded).
            statement_params: Dictionary of statement level parameters to be set while executing this action.

        Returns:
            A ``list`` of :class:`GetResult` instances, each of which represents the result of a downloaded file.

        rC   rK   NgetT)exist_okrM   r%   )r@   r   r6   rN   rO   	_downloadrQ   rR   r   r
   rS   rT   r   rU   rV   _plan_builderrY   r   r   osmakedirsr   rZ   r[   r\   r]   r^   r)   r_   
IndexError)r7   rH   rj   rC   r:   rF   r;   r`   ra   rb   
get_resultrd   re   rf   rg   rh   s                   r'   rl   zFileOperation.get   s   \ x(gw/	%':!]]0088F$$^5EwO"("4"4K"(//"3K!3K!MJ }}22FF()9:0@	 /0@ADQ&//99CCMM4,,>N,O  JTT+I5 2 2 45TT' ( :*B8]]B ++B/T9:& U 	I	sB   
F AE >B#F ! FF 	F>FFF F&%F&)rC   rD   r   rE   input_streamc          	      H   t        |      }| j                  j                  j                  }t	               r,	 ||||d}|j                  |||       |j                         }	n?t        |      \  }}| j                  j                  j                  |||||||      }|d   }	|j                  }t!        |	|      d   }t#        di |j%                         S # t        $ rC}
t        j                         d   }t        j                  |
      }|j                  |      dd}
~
ww xY w)a*  Uploads local files to the stage via a file stream.

        Args:
            input_stream: The input stream from which the data will be uploaded.
            stage_location: The full stage path with prefix and file name where you want the file to be uploaded.
            parallel: Specifies the number of threads to use for uploading files. The upload process separates batches of data files by size:

                  - Small files (< 64 MB compressed or uncompressed) are staged in parallel as individual files.
                  - Larger files are automatically split into chunks, staged concurrently, and reassembled in the target stage. A single thread can upload multiple chunks.

                Increasing the number of threads can improve performance when uploading large files.
                Supported values: Any integer value from 1 (no parallelism) to 99 (use 99 threads for uploading files).
                Defaults to 4.
            auto_compress: Specifies whether Snowflake uses gzip to compress files during upload. Defaults to True.
            source_compression: Specifies the method of compression used on already-compressed files that are being staged.
                Values can be 'AUTO_DETECT', 'GZIP', 'BZ2', 'BROTLI', 'ZSTD', 'DEFLATE', 'RAW_DEFLATE', 'NONE'. Defaults to "AUTO_DETECT".
            overwrite: Specifies whether Snowflake will overwrite an existing file with the same name during upload. Defaults to False.

        Returns:
            An object of :class:`PutResult` which represents the results of an uploaded file.
        rJ   rK   N)rt   rH   dest_filenamerC   compress_datar   rE   datar   r%   )r   r6   rN   rO   r   _upload_streamrR   r
   rS   rT   r   rU   rV   r   upload_streamrQ   r   r   r_   )r7   rt   rH   rC   rD   r   rE   r`   r;   rb   rd   re   rf   stage_with_prefixrv   rc   ra   s                    r'   
put_streamzFileOperation.put_stream   s0   > 1@$$,,!#6 (*<%2!*	 %%lNGL$oo/ 0:./I,},,::)0+!+#5# ; J %V,K(('[A!D
/:,,.//+ $ 6\\^A&4YY ''+56s   *C 	D!>DD!)rC   
decompressrF   r}   c                   t        |      }t               r1	 | j                  j                  j                  j                  ||      S d|i}t        j                         }	t        |      d   }
t        j                   j#                  |	|
      }| j                  j$                  j'                  dt)        |	      t+        |      |      }	 t,        j.                  j0                  j3                  | j                  |      j5                  |       |rt;        j<                  |d      S t=        |d      S # t        $ rC}t        j                         d   }t        j                  |      }|j                  |      dd}~ww xY w# t6        $ rC}t        j                         d   }t        j8                  |      }|j                  |      dd}~ww xY w)	a  Downloads the specified files from a path in a stage and expose it through a stream.

        Args:
            stage_location: The full stage path with prefix and file name, from which you want to download the file.
            parallel: Specifies the number of threads to use for downloading the files.
                The granularity unit for downloading is one file.
                Increasing the number of threads might improve performance when downloading large files.
                Supported values: Any integer value from 1 (no parallelism) to 99 (use 99 threads for downloading files). Defaults to 10.
            statement_params: Dictionary of statement level parameters to be set while executing this action. Defaults to None.
            decompress: Specifies whether to use gzip to decompress file after download. Defaults to False.

        Examples:

            >>> # Create a temp stage.
            >>> _ = session.sql("create or replace temp stage mystage").collect()
            >>> # Upload a file to a stage.
            >>> _ = session.file.put("tests/resources/testCSV.csv", "@mystage/prefix1")
            >>> # Download one file from a stage.
            >>> fd = session.file.get_stream("@myStage/prefix1/testCSV.csv.gz", decompress=True)
            >>> assert fd.read(5) == b"1,one"
            >>> fd.close()

        Returns:
            An ``BytesIO`` object which points to the downloaded file.
        rK   NrC      rl   )r;   rM   rb)r   r   r6   rN   rO   _download_streamr
   rS   rT   r   rU   rV   tempfile
gettempdirr   rp   pathjoinro   rY   r   r   rZ   r[   r\   r]   r^   r	   $SQL_EXCEPTION_FROM_OPERATIONAL_ERRORgzipopen)r7   rH   rC   r}   rF   rd   re   rf   r;   tmp_dirsrc_file_namerG   rg   oes                 r'   
get_streamzFileOperation.get_stream+  s   D 1@!#	6}}**22CC"J  "8,G))+G&~6q9M ggll7MBO==..BB$W-,^<	 C D	6"",,66MM4,,>N,O  		/40 /409 $ 6\\^A&4YY ''+56* $ 6\\^A&4YY ''+56s0   /D1 	AF  1	E=:>E88E= 	G	>GG)filesr:   detailed_outputrF   r   z&snowflake.snowpark.dataframe.DataFrametarget_stage_locationr   r   c                   d|i}|||d<   | j                  ||       t        |t        j                  j                  j
                        r||t        d      t        |t              rt        |      n4d|j                  j                  d   j                  j                          d}| j                  j                  j                  j!                  d|t        |      |      }t        j                  j                  j                  | j                  |      j#                  |      }	|r|	D 
cg c]  }
|
d	   	 c}
S |	d	   d	   S c c}
w )
u  Copy files from a source location to an output stage.

        You can use either a stage location (``str``) or a DataFrame as the source:

        - DataFrame source: The DataFrame must have exactly one or two columns of string type.
          Column names are not significant; Snowflake interprets columns by position:

              - First column (required): The existing url of the source file location (scoped URL, stage name, or stage URL).
              - Second column (optional): Then new file name which is the relative output path from the ``target`` stage. The file is
                copied to ``@[<namespace>.]<stage_name>[/<path>]<new_filename>``.

          If the second column is not provided, Snowflake uses the relative path of the first column's value.
          Invalid input (for example, missing the first column, non-string values, or extra columns) is
          rejected by Snowflake and results in a server-side error.

        - Stage location source: Provide a stage location string for ``source``. You can optionally
          use ``files`` or ``pattern`` to restrict which files are copied.

        References: `Snowflake COPY FILES command <https://docs.snowflake.com/en/sql-reference/sql/copy-files.html>`_.

        Args:
            source: The source to copy from. Either a stage location string, or a DataFrame with
                1–2 string columns where the first column is required (existing url) and the
                second column is optional (new file name).
            target: The target stage and path where files will be copied.
            files: Optional list of specific file names to copy; only applicable when ``source``
                is a stage location string.
            pattern: Optional regular expression pattern for filtering files to copy; only
                applicable when ``source`` is a stage location string.
            detailed_output: If True, returns details for each file; if False, returns only the
                number of files copied. Defaults to True.
            statement_params: Dictionary of statement level parameters to be set while executing this action.

        Examples:
            >>> # Create a temp stage.
            >>> _ = session.sql("create or replace temp stage source_stage").collect()
            >>> _ = session.sql("create or replace temp stage target_stage").collect()
            >>> # Upload a file to a stage.
            >>> _ = session.file.put("tests/resources/testCSV.csv", "@source_stage", auto_compress=False)
            >>> # Copy files from source stage to target stage.
            >>> session.file.copy_files("@source_stage", "@target_stage")
            ['testCSV.csv']
            >>> # Copy files from source stage to target stage using a DataFrame.
            >>> df = session.create_dataframe(
            ...     [["@source_stage/testCSV.csv", "new_file_1"]],
            ...     schema=["existing_url", "new_file_name"],
            ... )
            >>> session.file.copy_files(df, "@target_stage", detailed_output=False)
            1

        Returns:
            If ``detailed_output`` is True, a ``list[str]`` of copied file paths. Otherwise, an ``int``
            indicating the number of files copied.
        r   r   z>files and pattern are not supported when source is a dataframe()
copy_filesrM   r   )r@   
isinstancerZ   r[   r\   r]   
ValueErrorr"   r   _planqueriessqlstripr6   rW   rX   rY   r^   )r7   r   r   r   r:   r   rF   r;   rg   copy_resultrh   s              r'   r   zFileOperation.copy_filesu  sJ   @ %o6$GGgw/fi00::DDE G$7 T  &#& )0V\\))"-11779:!< 	 }}&&33GG()>?	
  ((22<<MM4

$
$6F
$
G 	 6AB{KNBB q>!$$ Cs   0E)r:   rF   c                X   i }| j                  ||       | j                  j                  j                  j	                  ddt        |      |      }t        j                  j                  j                  | j                  |      j                  |      }|D cg c]  }|d   	 c}S c c}w )al  Removes files from a stage.

        References: `Snowflake REMOVE command <https://docs.snowflake.com/en/sql-reference/sql/remove>`_.

        Example::

            >>> # Create a temp stage and upload files.
            >>> _ = session.sql("create or replace temp stage mystage").collect()
            >>> _ = session.file.put("tests/resources/testCSV.csv", "@mystage/prefix1")
            >>> _ = session.file.put("tests/resources/testCSV.csv", "@mystage/prefix2")
            >>> # Remove all files from the stage.
            >>> session.file.remove("@mystage/prefix1")
            ['mystage/prefix1/testCSV.csv.gz']
            >>> # Remove files matching a pattern.
            >>> session.file.remove("@mystage/prefix2", pattern=".*test.*")
            ['mystage/prefix2/testCSV.csv.gz']

        Args:
            stage_location: The stage and path where you want to remove files.
            pattern: Specifies a regular expression pattern for filtering files to remove.
                The command lists all files in the specified path and applies the regular expression pattern on each of the files found.
                Default: ``None`` (all files in the specified stage path are removed).
            statement_params: Dictionary of statement level parameters to be set while executing this action.

        Returns:
            A ``list`` of removed file paths.
        removeNrM   r   )r@   r6   rW   rX   rY   r   rZ   r[   r\   r]   r^   )r7   rH   r:   rF   r;   rg   remove_resultrh   s           r'   r   zFileOperation.remove  s    D gw/}}&&33GG(8	
 "**44>>MM4

$
$6F
$
G 	 3@@;A@@@s   B'c                   i }| j                  ||       | j                  j                  j                  j	                  ddt        |      |      }t        j                  j                  j                  | j                  |      j                  |      }g }|D ]V  }|j                         }	|	j                  dd      |	d<   |	j                  dd      |	d<   |j                  t        di |	       X |S )az  Returns a list of files from a stage.

        References: `Snowflake LIST command <https://docs.snowflake.com/en/sql-reference/sql/list>`_.

        Example::

            >>> # Create a temp stage and upload files.
            >>> _ = session.sql("create or replace temp stage mystage").collect()
            >>> _ = session.file.put("tests/resources/t*.csv", "@mystage/prefix1")
            >>> # List all files in the stage.
            >>> list_result = session.file.list("@mystage/prefix1")
            >>> assert len(list_result) > 0
            >>> # List files matching a pattern.
            >>> filtered_result = session.file.list("@mystage/prefix1", pattern=".*test.*")
            >>> assert len(filtered_result) > 0

        Args:
            stage_location: The stage and path from which you want to list files.
            pattern: Specifies a regular expression pattern for filtering files from the output.
                The command lists all files in the specified path and applies the regular expression pattern on each of the files found.
                Default: ``None`` (all files in the specified stage path are listed).
            statement_params: Dictionary of statement level parameters to be set while executing this action.

        Returns:
            A ``list`` of :class:`ListResult` instances, each of which represents the metadata of a file in the stage.
        listNrM   r/   r0   r%   )r@   r6   rW   rX   rY   r   rZ   r[   r\   r]   r^   r_   rl   appendr-   )
r7   rH   r:   rF   r;   rg   list_resultresultsrh   rx   s
             r'   r   zFileOperation.list  s    B gw/}}&&33GG(8	
  ((22<<MM4

$
$6F
$
G 	 & 	/K%%'D((tDK  88FD1DLNN:--.	/ r&   )r8   z"snowflake.snowpark.session.Sessionr4   N)r   r   r    r!   r9   r   r"   r   r@   r$   boolr   r   rL   r)   rl   r   bytesr|   r   r   r   r   r-   r   r%   r&   r'   r3   r3   >   s    ) )S#X )SW ) ""/59IQIQ IQ
 IQ IQ  IQ IQ #4S>2IQ 
iIQ` !%59NN N
 N #N #4S>2N 
iNj ""/@0i@0 @0
 @0 @0  @0 @0 
@0L  59HH 	H
 H #4S>2H 
EH^ &*!% $59`%cCCD`%  #`%
 S	"`% #`% `% #4S>2`% 
tCy#~	`%L "&59/A/A #	/A
 #4S>2/A 
c/Aj "&5966 #	6
 #4S>26 
j	6r&   r3   )r   rp   rS   r   typingr   r   r   r   r   r   snowflake.snowparkrZ   snowflake.connectorr	   r
   *snowflake.snowpark._internal.error_messager   "snowflake.snowpark._internal.utilsr   r   r   r   r   r   r   r   r   r)   r-   r3   r%   r&   r'   <module>r      sa   
  	 
  > >  B V	 	 	

 

  @ @r&   