o
    wiX9                     @  s  d Z ddlmZ ddlZddlZddlmZmZmZ ddl	m
Z
 ddlmZ ddlZddlmZ ddlmZ dd	lmZ dd
lmZ ddlmZ ddlmZ ddlmZmZ ddlmZ ddlm Z m!Z!m"Z"m#Z# erxddl$m%Z% ddlm&Z&m'Z' dZ(G dd ded Z)G dd deZ*dS )aq  W&B Public API for File objects.

This module provides classes for interacting with files stored in W&B.

Example:
```python
from wandb.apis.public import Api

# Get files from a specific run
run = Api().run("entity/project/run_id")
files = run.files()

# Work with files
for file in files:
    print(f"File: {file.name}")
    print(f"Size: {file.size} bytes")
    print(f"Type: {file.mimetype}")

    # Download file
    if file.size < 1000000:  # Less than 1MB
        file.download(root="./downloads")

    # Get S3 URI for large files
    if file.size >= 1000000:
        print(f"S3 URI: {file.path_uri}")
```

Note:
    This module is part of the W&B Public API and provides methods to access,
    download, and manage files stored in W&B. Files are typically associated
    with specific runs and can include model weights, datasets, visualizations,
    and other artifacts.
    )annotationsN)TYPE_CHECKINGAnyCallable)gql)
RetryError)nameof)Attrs)normalize_exceptions)SizedPaginator)utils)RETRY_TIMEDELTA)Run(_server_provides_internal_id_for_project)retry)POW_2_BYTESdownload_file_from_urlno_retry_authto_human_size)Document)ApiRetryingClienta  fragment RunFilesFragment on Run {
    files(names: $fileNames, after: $fileCursor, first: $fileLimit, pattern: $pattern) {
        edges {
            node {
                id
                name
                url(upload: $upload)
                directUrl
                sizeBytes
                mimetype
                updatedAt
                md5
            }
            cursor
        }
        pageInfo {
            endCursor
            hasNextPage
        }
    }
}c                      s   e Zd ZdZd(ddZ				d)d* fddZd+ddZed,ddZed-ddZ	ed.ddZ
d+d d!Zd/d#d$Zd0d&d'Z  ZS )1Filesa  A lazy iterator over a collection of `File` objects.

    Access and manage files uploaded to W&B during a run. Handles pagination
    automatically when iterating through large collections of files.

    Example:
    ```python
    from wandb.apis.public.files import Files
    from wandb.apis.public.api import Api

    # Example run object
    run = Api().run("entity/project/run-id")

    # Create a Files object to iterate over files in the run
    files = Files(api.client, run)

    # Iterate over files
    for file in files:
        print(file.name)
        print(file.url)
        print(file.size)

        # Download the file
        file.download(root="download_directory", replace=True)
    ```
    returnr   c                 C  s(   t | j}td|rdnd dt dS )z8Generate query dynamically based on server capabilities.a(  
            query RunFiles($project: String!, $entity: String!, $name: String!, $fileCursor: String,
                $fileLimit: Int = 50, $fileNames: [String] = [], $upload: Boolean = false, $pattern: String) {
                project(name: $project, entityName: $entity) {
                    
internalId z
                    run(name: $name) {
                        fileCount
                        ...RunFilesFragment
                    }
                }
            }
            z
            )r   clientr   FILE_FRAGMENT)selfwith_internal_id r    K/home/ubuntu/.local/lib/python3.10/site-packages/wandb/apis/public/files.py
_get_queryo   s   

zFiles._get_queryN2   Fr   r   runr   nameslist[str] | Noneper_pageintuploadboolpattern
str | Nonec                   sF   |r|rt d|| _|j|j|j|pg ||d}t ||| dS )a(  Initialize a lazy iterator over a collection of `File` objects.

        Files are retrieved in pages from the W&B server as needed.

        Args:
            client: The run object that contains the files
            run: The run object that contains the files
            names (list, optional): A list of file names to filter the files
            per_page (int, optional): The number of files to fetch per page
            upload (bool, optional): If `True`, fetch the upload URL for each file
            pattern (str, optional): Pattern to match when returning files from W&B
                This pattern uses mySQL's LIKE syntax,
                so matching all files that end with .json would be "%.json".
                If both names and pattern are provided, a ValueError will be raised.
        z{Querying for files by both names and pattern is not supported. Please provide either a list of names or a pattern to match.)projectentityname	fileNamesr)   r+   N)
ValueErrorr$   r-   r.   idsuper__init__)r   r   r$   r%   r'   r)   r+   	variables	__class__r    r!   r4      s   zFiles.__init__Nonec                 C  s   | j j|  | jd| _dS )zHFetch and store the response data for the next page using dynamic query.variable_valuesN)r   executer"   r5   last_responser   r    r    r!   _update_response   s   
zFiles._update_responsec                 C  s    | j s|   | j d d d S )z[
        Returns total number of files.

        <!-- lazydoc-ignore: internal -->
        r-   r$   	fileCount)r<   
_load_pager=   r    r    r!   _length   s   zFiles._lengthc                 C  s$   | j r| j d d d d d S dS )zbReturns whether there are more files to fetch.

        <!-- lazydoc-ignore: internal -->
        r-   r$   filespageInfohasNextPageTr<   r=   r    r    r!   more   s
   z
Files.morec                 C  s(   | j r| j d d d d d d S dS )zoReturns the cursor position for pagination of file results.

        <!-- lazydoc-ignore: internal -->
        r-   r$   rB   edgescursorNrE   r=   r    r    r!   rI      s   zFiles.cursorc                 C  s   | j | j| jd dS )zgUpdates the GraphQL query variables for pagination.

        <!-- lazydoc-ignore: internal -->
        )	fileLimit
fileCursorN)r5   updater'   rI   r=   r    r    r!   update_variables   s   zFiles.update_variables
list[File]c                   s$    fdd j d d d d D S )z[Converts GraphQL edges to File objects.

        <!-- lazydoc-ignore: internal -->
        c                   s    g | ]}t  j|d   jqS )node)Filer   r$   ).0rr=   r    r!   
<listcomp>   s    z)Files.convert_objects.<locals>.<listcomp>r-   r$   rB   rG   rE   r=   r    r=   r!   convert_objects   s   
zFiles.convert_objectsstrc                 C  s.   dt t|  dd| jj dt|  dS )N< / (z)>)r   typejoinr$   pathlenr=   r    r    r!   __repr__   s   .zFiles.__repr__)r   r   )Nr#   FN)r   r   r$   r   r%   r&   r'   r(   r)   r*   r+   r,   r   r8   r   r(   r   r*   )r   r,   )r   rN   r   rU   )__name__
__module____qualname____doc__r"   r4   r>   propertyrA   rF   rI   rM   rT   r^   __classcell__r    r    r6   r!   r   S   s$    

)



r   rP   c                      s   e Zd ZdZ	d'd( fd	d
Zed)ddZed*ddZd+ddZe					d,d-ddZ
e	d.d!d"Zd*d#d$Ze	d/d%d&Z  ZS )0rP   ax  File saved to W&B.

    Represents a single file stored in W&B. Includes access to file metadata.
    Files are associated with a specific run and
    can include text files, model weights, datasets, visualizations, and other
    artifacts. You can download the file, delete the file, and access file
    properties.

    Specify one or more attributes in a dictionary to fine a specific
    file logged to a specific run. You can search using the following keys:

    - id (str): The ID of the run that contains the file
    - name (str): Name of the file
    - url (str): path to file
    - direct_url (str): path to file in the bucket
    - sizeBytes (int): size of file in bytes
    - md5 (str): md5 of file
    - mimetype (str): mimetype of file
    - updated_at (str): timestamp of last update
    - path_uri (str): path to file in the bucket, currently only available for S3 objects and reference files

    Args:
        client: The run object that contains the file
        attrs (dict): A dictionary of attributes that define the file
        run: The run object that contains the file

    <!-- lazydoc-ignore-init: internal -->
    Nr   r   attrsdict[str, Any]r$   
Run | Nonec                   s2   || _ || _|| _d | _d | _t t| d S N)r   _attrsr$   +server_supports_delete_file_with_project_id_download_decoratedr3   r4   dict)r   r   ri   r$   r6   r    r!   r4     s   zFile.__init__r   r(   c                 C  s   | j d }|durt|S dS )z&Returns the size of the file in bytes.	sizeBytesNr   )rm   r(   )r   
size_bytesr    r    r!   size  s   
z	File.sizerU   c                 C  s^   | j d }std dS || j dkr|S zt|W S  ty.   td Y dS w )a  Returns the URI path to the file in the storage bucket.

        Returns:
            str: The S3 URI (e.g., 's3://bucket/path/to/file') if the file is stored in S3,
                 the direct URL if it's a reference file, or an empty string if unavailable.
        	directUrlz!Unable to find direct_url of filer   urlz1path_uri is only available for files stored in S3)rm   getwandbtermwarnr   parse_s3_url_to_s3_urir1   )r   
direct_urlr    r    r!   path_uri  s   

zFile.path_uriCallable[..., io.TextIOWrapper]c                   s:   dd l }tjttt|jfd				 dd fdd}|S )Nr   )retry_timedeltacheck_retry_fnretryable_exceptions.FrootrU   replacer*   exist_okapi
Api | Noner   io.TextIOWrapperc                   s\   |d u rt  }tj|  j}tj|r"|s"|rt|S tdt	| j
|j t|S )NzgFile already exists, pass replace=True to overwrite or exist_ok=True to leave it as is and don't error.)rw   r   osr\   r[   r/   existsopenr1   r   ru   api_key)r   r   r   r   r\   r=   r    r!   _impl6  s   z+File._build_download_wrapper.<locals>._implr   FFN
r   rU   r   r*   r   r*   r   r   r   r   )requestsr   	retriabler   r   r   RequestException)r   r   r   r    r=   r!   _build_download_wrapper3  s   zFile._build_download_wrapperr   Fr   r   r*   r   r   r   r   c                 C  s$   | j du r
|  | _ |  ||||S )a  Downloads a file previously saved by a run from the wandb server.

        Args:
            root: Local directory to save the file. Defaults to the
                current working directory (".").
            replace: If `True`, download will overwrite a local file
                if it exists. Defaults to `False`.
            exist_ok: If `True`, will not raise ValueError if file already
                exists and will not re-download unless replace=True.
                Defaults to `False`.
            api: If specified, the `Api` instance used to download the file.

        Raises:
            `ValueError` if file already exists, `replace=False` and
            `exist_ok=False`.
        N)ro   r   )r   r   r   r   r   r    r    r!   downloadR  s   

zFile.downloadr8   c                 C  sX   d}d}d| j gi}|  r| jj|d< d}d}d||}t|}| jj||d dS )	z$Delete the file from the W&B server.r   rB   	projectIdz, $projectId: IntzprojectId: $projectIdz
            mutation deleteFiles($files: [ID!]!{}) {{
                deleteFiles(input: {{
                    files: $files
                    {}
                }}) {{
                    success
                }}
            }}
            r9   N)r2   *_server_accepts_project_id_for_delete_filer$   _project_internal_idformatr   r   r;   )r   project_id_mutation_fragmentproject_id_variable_fragmentr:   mutation_stringmutationr    r    r!   deleten  s    	

zFile.deletec              	   C  s<   t t| }t| jtd}d| d| j d| j d| d	S )N)unitsrV   rW   rY   z) >)r   rZ   r   rs   r   r/   mimetype)r   	classnamers   r    r    r!   r^     s   "zFile.__repr__c                 C  sN   d}| j du r$t|}| j|}ddd |di di gD v | _ | j S )zReturns True if the server supports deleting files with a projectId.

        This check is done by utilizing GraphQL introspection in the available fields on the DeleteFiles API.
        a   
           query ProbeDeleteFilesProjectIdInput {
                DeleteFilesProjectIdInputType: __type(name:"DeleteFilesInput") {
                    inputFields{
                        name
                    }
                }
            }
        Nr   c                 S  s   g | ]}|d  qS )r/   r    )rQ   xr    r    r!   rS     s    zCFile._server_accepts_project_id_for_delete_file.<locals>.<listcomp>DeleteFilesProjectIdInputTypeinputFields)rn   r   r   r;   rv   )r   query_stringqueryresr    r    r!   r     s   

	z/File._server_accepts_project_id_for_delete_filerl   )r   r   ri   rj   r$   rk   r`   rb   )r   r|   r   r   r_   ra   )rc   rd   re   rf   r4   rg   rs   r{   r   r
   r   r   r^   r   rh   r    r    r6   r!   rP      s(    !

 )+rf   
__future__r   ior   typingr   r   r   	wandb_gqlr   wandb_gql.clientr   rw   wandb._strutilsr   wandb.apis.attrsr	   wandb.apis.normalizer
   wandb.apis.paginatorr   wandb.apis.publicr   wandb.apis.public.constr   wandb.apis.public.runsr   r   wandb.sdk.libr   
wandb.utilr   r   r   r   wandb_graphql.language.astr   r   r   r   r   rP   r    r    r    r!   <module>   s0    " 