
    Q`5                        d dl Z d dlZd dlZd dl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
 ddl	mZ ddl	mZ dZdZdZe
j                   j"                  e
j                   j$                  z  Zd	d
gZej*                  eej.                  f   ZdddZej4                  ddedefd       Z G d de j:                        Z G d d	e      Z G d de      Z  G d de      Z! G d de      Z"y)    N   )	constants)
exceptions)portalocker   g      ?FLockopen_atomic)
test_valuec                 "    |D ]
  }|| us|c S  y)a  Simple coalescing function that returns the first value that is not
    equal to the `test_value`. Or `None` if no value is valid. Usually this
    means that the last given value is the default value.

    Note that the `test_value` is compared using an identity check
    (i.e. `value is not test_value`) so changing the `test_value` won't work
    for all values.

    >>> coalesce(None, 1)
    1
    >>> coalesce()

    >>> coalesce(0, False, True)
    0
    >>> coalesce(0, False, True, test_value=0)
    False

    # This won't work because of the `is not test_value` type testing:
    >>> coalesce([], dict(spam='eggs'), test_value=[])
    []
    N )r
   argsargs      3/usr/lib/python3/dist-packages/portalocker/utils.pycoalescer      s     ,  j J    filenamebinaryc              #     K   t        j                  |       }|j                         r
J d|z         |j                  j	                  dd       t        j                  |xr dxs dt        |j                        d      }| |j                          t        j                  |j                                |j                          	 t        j                  |j                  |       	 t        j                  |j                         y# t         $ r Y yw xY w# 	 t        j                  |j                         w # t         $ r Y w w xY wxY ww)	a6  Open a file for atomic writing. Instead of locking this method allows
    you to write the entire file and move it to the actual location. Note that
    this makes the assumption that a rename is atomic on your platform which
    is generally the case but not a guarantee.

    http://docs.python.org/library/os.html#os.rename

    >>> filename = 'test_file.txt'
    >>> if os.path.exists(filename):
    ...     os.remove(filename)

    >>> with open_atomic(filename) as fh:
    ...     written = fh.write(b'test')
    >>> assert os.path.exists(filename)
    >>> os.remove(filename)

    >>> import pathlib
    >>> path_filename = pathlib.Path('test_file.txt')

    >>> with open_atomic(path_filename) as fh:
    ...     written = fh.write(b'test')
    >>> assert path_filename.exists()
    >>> path_filename.unlink()
    z	%r existsT)parentsexist_okwbwF)modedirdeleteN)pathlibPathexistsparentmkdirtempfileNamedTemporaryFilestrflushosfsyncfilenocloserenamenameremove	Exception)r   r   pathtemp_fhs       r   r	   r	   7   s    6 !h/D{{}0kD00 	KKdT2))_#G
 MMMOHHW^^MMO
		',,%	IIgll# 			IIgll# 		s`   CE
 D +D 
E	DEDEED<;E<	EEEEEc                   
   e Zd ZU eed<   eed<   eed<   	 	 	 ddej                  e   dej                  e   dej                  e   fdZe	j                  	 	 ddededefd       Zd Ze	j                  d        Zd	 Zd
 Zd Zy)LockBasetimeoutcheck_intervalfail_when_lockedNc                     t        |t              | _        t        |t              | _        t        |t
              | _        y N)r   DEFAULT_TIMEOUTr1   DEFAULT_CHECK_INTERVALr2   DEFAULT_FAIL_WHEN_LOCKEDr3   selfr1   r2   r3   s       r   __init__zLockBase.__init__s   s6      9&~7MN ()9)A!Cr   c                     t         S r5   NotImplementedr9   s       r   acquirezLockBase.acquire{   s
     r   c              #     K   t        || j                  d      }t        || j                  d      }d d}t        j                         }||z   t        j                         kD  ra|dz  }| t        j                         |z
  }t        j
                  t        d||z  |z
               ||z   t        j                         kD  r`y y w)Ng        r   r   gMbP?)r   r1   r2   timeperf_countersleepmax)r:   r1   r2   i
start_timesince_start_times         r   _timeout_generatorzLockBase._timeout_generator   s     7DLL#6!.$2E2EsK&&(
7"T%6%6%88FAG  $002Z?JJs51~#59I"IJK 7"T%6%6%88s   CCCc                     t         S r5   r=   r:   s    r   releasezLockBase.release   s    r   c                 "    | j                         S r5   )r?   rJ   s    r   	__enter__zLockBase.__enter__   s    ||~r   c                 $    | j                          y r5   rK   )r:   type_valuetbs       r   __exit__zLockBase.__exit__   s    r   c                 $    |j                          y r5   rO   )r:   instances     r   
__delete__zLockBase.__delete__   s    r   NNN)__name__
__module____qualname__float__annotations__booltypingOptionalr;   abcabstractmethodr?   rH   rK   rM   rS   rV   r   r   r   r0   r0   k   s    N9=:>;?C 6 C!'!7C#)??4#8C 	AE%) 9>" 
L  	 r   r0   c                      e Zd ZdZdeeeefdede	de
de
dedej                  fd	Z	 	 dde
de
dedej                   fdZd Zdej                   fdZdej                   dej                   fdZdej                   dej                   fdZy
)r   a  Lock manager with build-in timeout

    Args:
        filename: filename
        mode: the open mode, 'a' or 'ab' should be used for writing
        truncate: use truncate to emulate 'w' mode, None is disabled, 0 is
            truncate to 0 bytes
        timeout: timeout when trying to acquire a lock
        check_interval: check interval while waiting
        fail_when_locked: after the initial lock failed, return an error
            or lock the file. This does not wait for the timeout.
        **file_open_kwargs: The kwargs for the `open(...)` call

    fail_when_locked is useful when multiple threads/processes can race
    when creating a file. If set to true than the system will wait till
    the lock was acquired and then return an AlreadyLocked exception.

    Note that the file is opened first and locked later. So using 'w' as
    mode will result in truncate _BEFORE_ the lock is checked.
    ar   r   r1   r2   r3   flagsc                     d|v rd}|j                  dd      }nd}d | _        t        |      | _        || _        || _        || _        || _        || _        || _	        || _
        y )Nr   Trc   F)replacefhr#   r   r   truncater1   r2   r3   rd   file_open_kwargs)	r:   r   r   r1   r2   r3   rd   ri   rh   s	            r   r;   zLock.__init__   sk     $;H<<S)DH.2 ]	&%%3&6*/
 0r   Nreturnc                    t        || j                        }| j                  rS | j                         fd}d}| j	                  ||      D ]  }d}	 | j                         n |r |        t        j                  |      | j                        | _        S # t        j                  $ r*}|}|r |        t        j                  |      Y d}~d}~ww xY w)zAcquire the locked filehandlec                  F    	  j                          y # t        $ r Y y w xY wr5   )r(   r,   )rg   s   r   	try_closezLock.acquire.<locals>.try_close   s#    
 s    	  N)
r   r3   rg   _get_fhrH   	_get_lockr   LockExceptionAlreadyLocked_prepare_fh)	r:   r1   r2   r3   rm   	exception_excrg   s	           @r   r?   zLock.acquire   s    
 $$4d6K6KL WWI \\^	 	((.A 	>AI>^^B'	>& K**955 b!	- ++ 	>  	 $K$229== $	>s   B##C 6 CC c                     | j                   rAt        j                  | j                          | j                   j                          d| _         yy)z)Releases the currently locked file handleN)rg   r   unlockr(   rJ   s    r   rK   zLock.release  s4    77tww'GGMMODG r   c                 X    t        | j                  | j                  fi | j                  S )zGet a new filehandle)openr   r   ri   rJ   s    r   rn   zLock._get_fh
  s"    DMM499F0E0EFFr   rg   c                 F    t        j                  || j                         |S )zT
        Try to lock the given filehandle

        returns LockException if it fails)r   lockrd   r:   rg   s     r   ro   zLock._get_lock  s    
 	TZZ(	r   c                 b    | j                   r"|j                  d       |j                  d       |S )z
        Prepare the filehandle for usage

        If truncate is a number, the file will be truncated to that amount of
        bytes
        r   )rh   seekr|   s     r   rr   zLock._prepare_fh  s&     ==GGAJKKN	r   rW   )rX   rY   rZ   __doc__r6   r7   r8   LOCK_METHODFilenamer#   r[   r]   r   	LockFlagsr;   r^   IOr?   rK   rn   ro   rr   r   r   r   r   r      s    0 ,$:%=)411 1 	1
 "1 #1 &&12 BF%)4 49>4"4.4ii4lG GFII &)) fii FII r   c            	       n     e Zd ZdZdeedef fd	Z	 	 ddedede	de
j                  f fd	Z fd
Z xZS )RLockz
    A reentrant lock, functions in a similar way to threading.RLock in that it
    can be acquired multiple times.  When the corresponding number of release()
    calls are made the lock will finally release the underlying file lock.
    rc   Fc                 D    t         t        |   ||||||       d| _        y )Nr   )superr   r;   _acquire_count)r:   r   r   r1   r2   r3   rd   	__class__s          r   r;   zRLock.__init__+  s)     	eT#HdG^$4e	=r   r1   r2   r3   rj   c                     | j                   dk\  r| j                  }nt        t        |   |||      }| xj                   dz  c_         |sJ |S )Nr   )r   rg   r   r   r?   )r:   r1   r2   r3   rg   r   s        r   r?   zRLock.acquire3  sQ     !#Bud+G^,<>Bq 	r	r   c                     | j                   dk(  rt        j                  d      | j                   dk(  rt        t        |           | xj                   dz  c_         y )Nr   z'Cannot release more times than acquiredr   )r   r   rp   r   r   rK   )r:   r   s    r   rK   zRLock.release?  sU    !#**9; ; !#%&(q r   rW   )rX   rY   rZ   r   r6   r7   r   r;   r[   r]   r^   r   r?   rK   __classcell__)r   s   @r   r   r   $  sY     "%o1E  BF%)
 
9>
"
.4ii
! !r   r   c                   $    e Zd ZdeedefdZd Zy)TemporaryFileLockz.lockTc           	      z    t         j                  | |d||||       t        j                  | j                         y )Nr   )r   r   r1   r2   r3   rd   )r   r;   atexitregisterrK   )r:   r   r1   r2   r3   rd   s         r   r;   zTemporaryFileLock.__init__K  s8     	dXC%3'7u 	 	F 	%r   c                     t         j                  |        t        j                  j	                  | j
                        r t        j                  | j
                         y y r5   )r   rK   r%   r-   isfiler   unlinkrJ   s    r   rK   zTemporaryFileLock.releaseS  s7    T77>>$--(IIdmm$ )r   N)rX   rY   rZ   r6   r7   r   r;   rK   r   r   r   r   r   I  s     ' 6"&%r   r   c            
       v   e Zd ZU dZej
                  e   ed<   dd ej                         e
efdedededefd	Zd
ej                  ej"                     fdZd
ej                  ej"                     fdZd
ej"                  fdZ	 	 	 ddededed
ej
                  e   fdZdej                  e   d
efdZd Zy)BoundedSemaphorea%  
    Bounded semaphore to prevent too many parallel processes from running

    It's also possible to specify a timeout when acquiring the lock to wait
    for a resource to become available.  This is very similar to
    threading.BoundedSemaphore but works across multiple processes and across
    multiple operating systems.

    >>> semaphore = BoundedSemaphore(2, directory='')
    >>> str(semaphore.get_filenames()[0])
    'bounded_semaphore.00.lock'
    >>> str(sorted(semaphore.get_random_filenames())[1])
    'bounded_semaphore.01.lock'
    r{   bounded_semaphorez{name}.{number:02d}.lockmaximumr*   filename_pattern	directoryc                 f    || _         || _        || _        || _        d | _        || _        || _        y r5   )r   r*   r   r   r{   r1   r2   )r:   r   r*   r   r   r1   r2   s          r   r;   zBoundedSemaphore.__init__j  s7     	 0"+/	,r   rj   c                 p    t        | j                        D cg c]  }| j                  |       c}S c c}w r5   )ranger   get_filename)r:   ns     r   get_filenameszBoundedSemaphore.get_filenamesz  s*    .3DLL.AB!!!$BBBs   3c                 b    t        | j                               }t        j                  |       |S r5   )listr   randomshuffle)r:   	filenamess     r   get_random_filenamesz%BoundedSemaphore.get_random_filenames}  s'    ++-.	y!r   c                     t        j                  | j                        | j                  j	                  | j
                  |      z  S )N)r*   number)r   r   r   r   formatr*   )r:   r   s     r   r   zBoundedSemaphore.get_filename  s?    ||DNN+d.C.C.J.J /K /
 
 	
r   Nr1   r2   r3   c                    | j                   rJ d       | j                         }t        d|       | j                  ||      D ]-  }t        d|       | j	                  |      s!| j                   c S  t        j                         )NzAlready lockedr   ztrying lock)r{   r   printrH   try_lockr   rq   )r:   r1   r2   r3   r   rt   s         r   r?   zBoundedSemaphore.acquire  s{    
 99...}&&(	k9%((.A 	!A-+}}Y'yy 		! &&((r   r   c                     |D ]H  }t        d|       t        |d      | _        	 | j                  j                          t        d|        y y# t        j
                  $ r Y aw xY w)Nztrying lock forT)r3   lockedF)r   r   r{   r?   r   rq   )r:   r   r   s      r   r   zBoundedSemaphore.try_lock  sk    ! 	H#X.X=DI		!!#h)	  ++ s   &AA%$A%c                 F    | j                   j                          d | _         y r5   )r{   rK   rJ   s    r   rK   zBoundedSemaphore.release  s    			r   rW   )rX   rY   rZ   r   r^   r_   r   r\   r!   
gettempdirr6   r7   intr#   r;   Sequencer   r   r   r   r   r[   r]   r?   r   r   rK   r   r   r   r   r   Y  s    //$

 ,$>0X002#1-- - "	-
 - Cvw||< Cfoogll&C 

gll 
 "$(%)	)) ") #	) /5ood.C	)$&//(";  r   r   )T)#r`   r   
contextlibr%   r   r   r!   rA   r^    r   r   r   r6   r7   r8   r   	EXCLUSIVENON_BLOCKINGr   __all__Unionr#   r   r   r   contextmanagerr]   r	   ABCr0   r   r   r   r   r   r   r   <module>r      s    
   	           !!++i.A.A.N.NN 
 <<W\\)*  $ 6 0( 0D 0 0f1sww 1hB8 BJ"!D "!J% % Qx Qr   