U
    Cvf/                     @  s  U d dl mZ d dlZd dlZd dlZd dlZd dlZd dlmZm	Z	 d dl
mZ d dlmZ d dlmZ d dlmZ eed d	d
 dZded< ejstdi Zded< edZG dd dZG dd deZG dd dZG dd deZG dd deZdS )    )annotationsN)AnyHashable)acquire)LRUCache)utils)OPTIONSZfile_cache_maxsizec                 C  s   |  S N)close)kv r   @/tmp/pip-unpacked-wheel-h316xyqg/xarray/backends/file_manager.py<lambda>       r   )maxsizeZon_evictzLRUCache[Any, io.IOBase]
FILE_CACHEz$file cache must be at least size onezdict[Any, int]
REF_COUNTSz<unused>c                   @  s.   e Zd ZdZd
ddZdddZdddZd	S )FileManagera  Manager for acquiring and closing a file object.

    Use FileManager subclasses (CachingFileManager in particular) on backend
    storage classes to automatically handle issues related to keeping track of
    many open files and transferring them between multiple processes.
    Tc                 C  s
   t  dS )z*Acquire the file object from this manager.NNotImplementedErrorself
needs_lockr   r   r   r   "   s    zFileManager.acquirec                 C  s
   t  dS )a  Context manager for acquiring a file. Yields a file object.

        The context manager unwinds any actions taken as part of acquisition
        (i.e., removes it from any cache) if an exception is raised from the
        context. It *does not* automatically close the file.
        Nr   r   r   r   r   acquire_context&   s    zFileManager.acquire_contextc                 C  s
   t  dS )z>Close the file object associated with this manager, if needed.Nr   r   r   r   r   r
   /   s    zFileManager.closeN)T)T)T)__name__
__module____qualname____doc__r   r   r
   r   r   r   r   r      s   

	r   c                   @  s   e Zd ZdZeddddddddddZdd	 Zejd
d Z	d ddZ
ejd!ddZd"ddZd#ddZddddZdd ZddddZddddZdS )$CachingFileManagera  Wrapper for automatically opening and closing file objects.

    Unlike files, CachingFileManager objects can be safely pickled and passed
    between processes. They should be explicitly closed to release resources,
    but a per-process least-recently-used cache for open files ensures that you
    can safely create arbitrarily large numbers of FileManager objects.

    Don't directly close files acquired from a FileManager. Instead, call
    FileManager.close(), which ensures that closed files are removed from the
    cache as well.

    Example usage:

        manager = FileManager(open, 'example.txt', mode='w')
        f = manager.acquire()
        f.write(...)
        manager.close()  # ensures file is closed

    Note that as long as previous files are still cached, acquiring a file
    multiple times from the same FileManager is essentially free:

        f1 = manager.acquire()
        f2 = manager.acquire()
        assert f1 is f2

    N)modekwargslockcache
manager_id
ref_countszHashable | None)r$   c          	      G  s   || _ || _|| _|dkri nt|| _|dkp6|dk| _| jrHt n|| _|dkrZt	}|| _
|dkrttt }|| _|  | _|dkrt}t|| _| j| j dS )ay  Initialize a CachingFileManager.

        The cache, manager_id and ref_counts arguments exist solely to
        facilitate dependency injection, and should only be set for tests.

        Parameters
        ----------
        opener : callable
            Function that when called like ``opener(*args, **kwargs)`` returns
            an open file object. The file object must implement a ``close()``
            method.
        *args
            Positional arguments for opener. A ``mode`` argument should be
            provided as a keyword argument (see below). All arguments must be
            hashable.
        mode : optional
            If provided, passed as a keyword argument to ``opener`` along with
            ``**kwargs``. ``mode='w' `` has special treatment: after the first
            call it is replaced by ``mode='a'`` in all subsequent function to
            avoid overriding the newly created file.
        kwargs : dict, optional
            Keyword arguments for opener, excluding ``mode``. All values must
            be hashable.
        lock : duck-compatible threading.Lock, optional
            Lock to use when modifying the cache inside acquire() and close().
            By default, uses a new threading.Lock() object. If set, this object
            should be pickleable.
        cache : MutableMapping, optional
            Mapping to use as a cache for open files. By default, uses xarray's
            global LRU file cache. Because ``cache`` typically points to a
            global variable and contains non-picklable file objects, an
            unpickled FileManager objects will be restored with the default
            cache.
        manager_id : hashable, optional
            Identifier for this CachingFileManager.
        ref_counts : dict, optional
            Optional dict to use for keeping track the number of references to
            the same file.
        NF)_opener_args_modedict_kwargs_use_default_lock	threadingLock_lockr   _cachestruuidZuuid4_manager_id	_make_key_keyr   _RefCounter_ref_counter	increment)	r   openerr    r!   r"   r#   r$   r%   argsr   r   r   __init__P   s"    2

zCachingFileManager.__init__c                 C  s:   | j | j| jdkrdn| jtt| j | jf}t|S )z.Make a key for caching files in the LRU cache.wa)	r&   r'   r(   tuplesortedr*   itemsr2   _HashedSequencer   valuer   r   r   r3      s    zCachingFileManager._make_keyc              	   c  s(   |r| j  dV  W 5 Q R X ndV  dS )z0Context manager for optionally acquiring a lock.N)r.   r   r   r   r   _optional_lock   s    z!CachingFileManager._optional_lockTc                 C  s   |  |\}}|S )a  Acquire a file object from the manager.

        A new file is only opened if it has expired from the
        least-recently-used cache.

        This method uses a lock, which ensures that it is thread-safe. You can
        safely acquire a file in multiple threads at the same time, as long as
        the underlying file object is thread-safe.

        Returns
        -------
        file-like
            An open file object, as returned by ``opener(*args, **kwargs)``.
        )_acquire_with_cache_info)r   r   file_r   r   r   r      s    zCachingFileManager.acquirec                 c  sB   |  |\}}z
|V  W n$ tk
r<   |s6| |  Y nX dS )z%Context manager for acquiring a file.N)rD   	Exceptionr
   )r   r   rE   cachedr   r   r   r      s    

z"CachingFileManager.acquire_contextc              
   C  s   |  | z| j| j }W nt tk
r   | j}| jtk	rN| }| j|d< | j| j	|}| jdkrld| _|| j| j< |df Y W  5 Q R  S X |dfW  5 Q R  S W 5 Q R X dS )z=Acquire a file, returning the file and whether it was cached.r    r;   r<   FTN)
rC   r/   r4   KeyErrorr*   r(   _DEFAULT_MODEcopyr&   r'   )r   r   rE   r!   r   r   r   rD      s    


z+CachingFileManager._acquire_with_cache_infoc              	   C  s>   |  |* d}| j| j|}|dk	r0|  W 5 Q R X dS )z;Explicitly close any associated file object (if necessary).N)rC   r/   popr4   r
   )r   r   defaultrE   r   r   r   r
      s
    zCachingFileManager.closeNone)returnc                 C  sn   | j | j}|sj| j| jkrjt| jddrJz| jdd W 5 | j  X td rjt	j
d|  dtdd d S )	NF)blocking)r   Zwarn_for_unclosed_fileszdeallocating z:, but file is not already closed. This may indicate a bug.   )
stacklevel)r6   	decrementr4   r/   r   r.   releaser
   r   warningswarnRuntimeWarning)r   Z	ref_countr   r   r   __del__   s    
zCachingFileManager.__del__c                 C  s*   | j r
dn| j}| j| j| j| j|| jfS )zState for pickling.N)r+   r.   r&   r'   r(   r*   r2   )r   r"   r   r   r   __getstate__  s    zCachingFileManager.__getstate__c                 C  s0   |\}}}}}}| j |f|||||d dS )zRestore from a pickle.)r    r!   r"   r$   N)r:   )r   stater8   r9   r    r!   r"   r$   r   r   r   __setstate__  s       zCachingFileManager.__setstate__r0   c              
   C  sZ   d tt| j}| jtk	r,|d| j7 }t| j d| jd| d| j	 d| j
d
S )Nz, z, mode=(z	, kwargs=z, manager_id=))joinmapreprr'   r(   rJ   typer   r&   r*   r2   )r   args_stringr   r   r   __repr__  s
    
,zCachingFileManager.__repr__)T)T)T)T)r   r   r   r   rJ   r:   r3   
contextlibcontextmanagerrC   r   r   rD   r
   rX   rY   r[   rc   r   r   r   r   r   4   s(   L





r   c                   @  s(   e Zd ZdZdd Zdd Zdd ZdS )	r5   z,Class for keeping track of reference counts.c                 C  s   || _ t | _d S r	   )_countsr,   r-   r.   )r   countsr   r   r   r:   &  s    z_RefCounter.__init__c              	   C  s2   | j " | j|dd  }| j|< W 5 Q R X |S )Nr      )r.   rf   getr   namecountr   r   r   r7   *  s    &z_RefCounter.incrementc              	   C  s<   | j , | j| d }|r&|| j|< n| j|= W 5 Q R X |S )Nrh   )r.   rf   rj   r   r   r   rS   /  s    z_RefCounter.decrementN)r   r   r   r   r:   r7   rS   r   r   r   r   r5   #  s   r5   c                   @  s    e Zd ZdZdd Zdd ZdS )r@   zSpeedup repeated look-ups by caching hash values.

    Based on what Python uses internally in functools.lru_cache.

    Python doesn't perform this optimization automatically:
    https://bugs.python.org/issue1462796
    c                 C  s   || d d < t || _d S r	   )hash	hashvalue)r   Ztuple_valuer   r   r   r:   B  s    z_HashedSequence.__init__c                 C  s   | j S r	   )rn   )r   r   r   r   __hash__F  s    z_HashedSequence.__hash__N)r   r   r   r   r:   ro   r   r   r   r   r@   9  s   r@   c                   @  s<   e Zd ZdZdd ZdddZejdddZdd	d
Z	dS )DummyFileManagerzHFileManager that simply wraps an open file in the FileManager interface.c                 C  s
   || _ d S r	   _valuerA   r   r   r   r:   M  s    zDummyFileManager.__init__Tc                 C  s   ~| j S r	   rq   r   r   r   r   r   P  s    zDummyFileManager.acquirec                 c  s   ~| j V  d S r	   rq   r   r   r   r   r   T  s    z DummyFileManager.acquire_contextc                 C  s   ~| j   d S r	   )rr   r
   r   r   r   r   r
   Y  s    zDummyFileManager.closeN)T)T)T)
r   r   r   r   r:   r   rd   re   r   r
   r   r   r   r   rp   J  s   
rp   )
__future__r   rd   ior,   r1   rU   typingr   r   Zxarray.backends.locksr   Zxarray.backends.lru_cacher   Zxarray.corer   Zxarray.core.optionsr   r   __annotations__r   AssertionErrorr   Z
ReprObjectrJ   r   r   r5   listr@   rp   r   r   r   r   <module>   s0     
 p