
    <i\G                       S SK Jr  S SKrS SKrS SKrS SKrS SKrS SKrS SKrS SK	r	S SK
r
S SKrS SKrSSKJrJrJrJr  SSKJrJr  \R(                  " \5      rSrSrSr\R4                  R6                  \R4                  R8                  -  rS	S
/rSS.SS jjr\R@                   S     SS jj5       r! " S S\RD                  5      r# " S S	\#5      r$ " S S\$5      r% " S S\$5      r& " S S\#5      r' " S S\'5      r(g)    )annotationsN   )	constants
exceptionsportalockertypes)FilenameMode   g      ?FLockopen_atomic)
test_valuec                0   ^  [        U 4S jU 5       S5      $ )aN  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=[])
[]
c              3  4   >#    U  H  oTLd  M	  Uv   M     g 7fN ).0argr   s     K/home/james-whalen/.local/lib/python3.13/site-packages/portalocker/utils.py	<genexpr>coalesce.<locals>.<genexpr>5   s     >:(=s   	N)next)r   argss   ` r   coalescer      s    , >>EE    c              #    #    [        U [        R                  5      (       a  U nO[        R                  " U 5      nUR                  5       (       a   U< S35       eUR                  R                  SSS9  [        R                  " U=(       a    S=(       d    S[        UR                  5      SS9 nUv   UR                  5         [        R                  " UR                  5       5        SSS5         [        R                  " WR                  U5        [        R                   " ["        5         [        R$                  " UR                  5        SSS5        g! , (       d  f       Nt= f! , (       d  f       g= f! [        R                   " ["        5         [        R$                  " WR                  5        SSS5        f ! , (       d  f       f = f= f7f)	a  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 existsT)parentsexist_okwbwF)modedirdeleteN)
isinstancepathlibPathexistsparentmkdirtempfileNamedTemporaryFilestrflushosfsyncfilenorenamename
contextlibsuppress	Exceptionremove)filenamebinarypathtemp_fhs       r   r   r   8   s.    > (GLL))||H%{{}}000 	KKdT2		$	$o%#
 

!"
$
		',,%  +IIgll# ,+
 
 ,+Z  +IIgll# ,++sf   B.G09E)G2!E9 G-!E(	G
E%!G(
E62G9G!F>5	G>
GGGc                     \ rS rSr% S\S'   S\S'   S\S'      S       SS jjr\R                     S       SS	 jj5       r      SS
 jr	\R                  SS j5       r
SS jr        SS jrSS jrSrg)LockBaseq   floattimeoutcheck_intervalboolfail_when_lockedNc                    [        U[        5      U l        [        U[        5      U l        [        U[
        5      U l        g r   )r   DEFAULT_TIMEOUTr?   DEFAULT_CHECK_INTERVALr@   DEFAULT_FAIL_WHEN_LOCKEDrB   selfr?   r@   rB   s       r   __init__LockBase.__init__y   s5      9&~7MN ($!
r   c                    g r   r   rG   s       r   acquireLockBase.acquire   s     $'r   c              #    #    [        XR                  S5      n[        X R                  S5      nSv   Sn[        R                  " 5       nXc-   [        R                  " 5       :  ad  US-  nUv   [        R                  " 5       U-
  n[        R
                  " [        SXT-  U-
  5      5        Xc-   [        R                  " 5       :  a  Mc  g g 7f)Ng        r   r   gMbP?)r   r?   r@   timeperf_countersleepmax)rH   r?   r@   	f_timeoutf_check_intervali
start_timesince_start_times           r   _timeout_generatorLockBase._timeout_generator   s     
 WllC8	#N4G4GM&&(
$t'8'8'::FAG  $002Z?JJs51#7;K"KLM $t'8'8'::s   CC
C
c                    g r   r   rH   s    r   releaseLockBase.release   s    "r   c                "    U R                  5       $ r   rL   r[   s    r   	__enter__LockBase.__enter__       ||~r   c                $    U R                  5         g r   r\   )rH   exc_type	exc_value	tracebacks       r   __exit__LockBase.__exit__   s     	r   c                $    UR                  5         g r   rd   )rH   instances     r   
__delete__LockBase.__delete__   s    r   )r@   rB   r?   NNN)r?   float | Noner@   ro   rB   bool | NonereturnNoner?   ro   r@   ro   rB   rp   rq   typing.IO[typing.AnyStr])r?   ro   r@   ro   rq   ztyping.Iterator[int]rq   rr   rq   rt   )re   ztype[BaseException] | Nonerf   zBaseException | Nonerg   
typing.Anyrq   rp   )rk   r<   rq   rr   )__name__
__module____qualname____firstlineno____annotations__rI   abcabstractmethodrL   rX   r\   r`   rh   rl   __static_attributes__r   r   r   r<   r<   q   s   N !%'+(,	

 %
 &	

 

 	 !%'+(,	'' %' &	'
 
"' 'NN %N 
	N( 	" ", ( 	
 
r   r<   c                    ^  \ rS rSr% SrS\S'   S\S'   S\S'   S\S	'   S
\S'   S
\S'   S\S'   S\S'   S\S'   SS\\\4               SU 4S jjjr	   S       SS jjr
SS jrS S jrS!S jrS"S jrS"S jrSrU =r$ )#r      a7  Lock manager with built-in timeout

Args:
    filename: filename
    mode: the open mode, 'a' or 'ab' should be used for writing. When mode
        contains `w` the file will be truncated 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.
ztypes.IO | Nonefhr,   r7   r!   rA   truncater>   r?   r@   rB   constants.LockFlagsflagszdict[str, typing.Any]file_open_kwargsaNc                r  > SU;   a.  Sn[         R                  " [        UR                  SS5      5      nOSnUc  [        nO7U[
        R                  R                  -  (       d  [        R                  " SSS9  S U l
        [        U5      U l        X l        Xl        X`l        Xpl        ["        T	U ]I  X4U5        g )Nr    Tr   F&timeout has no effect in blocking moder   
stacklevel)typingcastr
   replacerD   r   	LockFlagsNON_BLOCKINGwarningswarnr   r,   r7   r!   r   r   r   superrI   )
rH   r7   r!   r?   r@   rB   r   r   r   	__class__s
            r   rI   Lock.__init__   s     $;H;;tT\\#s%;<DH?%G)--:::MM8
 H	 
 02BCr   c                x  ^ [        X0R                  5      nU R                  [        R                  R
                  -  (       d  Ub  [        R                  " SSS9  U R                  mT(       a6  [        R                  " [        R                  [        R                     T5      $ U R                  5       mSU4S jjnSnU R                  X5       H  nSn U R                  T5      m  O   U(       a	  U" 5         UeU R)                  T5      mTU l        [        R                  " [        R                  [        R                     T5      $ ! [         R"                   a2  nUnU(       a  U" 5         [         R$                  " U5      Ue SnAM  SnAf[&         a#  nU" 5         [         R"                  " U5      UeSnAff = f)zAcquire the locked filehandleNr   r   r   c                    > T b4  [         R                  " [        5         T R                  5         S S S 5        g g ! , (       d  f       g = fr   )r3   r4   r5   close)r   s   r   	try_closeLock.acquire.<locals>.try_close  s3    ~((3HHJ 43 33s	   :
Aru   )r   rB   r   r   r   r   r   r   r   r   r   IOAnyStr_get_fhrX   	_get_lockr   LockExceptionAlreadyLockedr5   _prepare_fh)	rH   r?   r@   rB   r   	exception_excr   s	           @r   rL   Lock.acquire   sl    $$46K6KL i11>>>#MM8 WW;;vyy7<< \\^	 	((AAI=^^B' B0 KO b!{{699V]]3R887 ++ 	G  	 $K$229=3F $  =  ..s3<	=s$   EF9'F		F9F44F9c                "    U R                  5       $ r   r_   r[   s    r   r`   Lock.__enter__;  rb   r   c                    U R                   (       aB  [        R                  " U R                   5        U R                   R                  5         SU l         gg)z)Releases the currently locked file handleN)r   r   unlockr   r[   s    r   r\   Lock.release>  s4    77tww'GGMMODG r   c                    [         R                  " [        R                  [	        U R
                  U R                  40 U R                  D65      $ )zGet a new filehandle)r   r   r   r   openr7   r!   r   r[   s    r   r   Lock._get_fhE  s@    {{HH		 ''
 	
r   c                F    [         R                  " XR                  5        U$ )zD
Try to lock the given filehandle

returns LockException if it fails)r   lockr   rH   r   s     r   r   Lock._get_lockP  s    
 	ZZ(	r   c                l    U R                   (       a"  UR                  S5        UR                  S5        U$ )zo
Prepare the filehandle for usage

If truncate is a number, the file will be truncated to that amount of
bytes
r   )r   seekr   s     r   r   Lock._prepare_fhX  s&     ==GGAJKKN	r   )r   r   r7   r   r!   r   )r7   r	   r!   r
   r?   ro   r@   r>   rB   rA   r   r   r   rw   rq   rr   rn   rs   rv   ru   )rq   types.IO)r   r   rq   r   )rx   ry   rz   r{   __doc__r|   rE   rF   LOCK_METHODrI   rL   r`   r\   r   r   r   r   __classcell__r   s   @r   r   r      s
   ( 	M
INN++
  $ 6!9%0DD D 	D
 D D #D 'D 
D DD !%'+(,	E9E9 %E9 &	E9
 
"E9N	
 r   c                     ^  \ rS rSrSrS\\S\4             S	U 4S jjjr   S
       SU 4S jjjr	SU 4S jjr
SrU =r$ )RLockif  z
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.
r   Fc                <   > [         TU ]  UUUUUU5        SU l        g )Nr   )r   rI   _acquire_count)rH   r7   r!   r?   r@   rB   r   r   s          r   rI   RLock.__init__m  s.     		
  r   c                   > U R                   S:  aA  [        R                  " [        R                  [        R                     U R
                  5      nO[        TU ]  XU5      nU =R                   S-  sl         Uc   eU$ )Nr   )r   r   r   r   r   r   r   rL   )rH   r?   r@   rB   r   r   s        r   rL   RLock.acquire  se     !#VYYv}}5tww?B:JKBq ~~	r   c                   > U R                   S:X  a  [        R                  " S5      eU R                   S:X  a  [        TU ]  5         U =R                   S-  sl         g )Nr   z'Cannot release more times than acquiredr   )r   r   r   r   r\   )rH   r   s    r   r\   RLock.release  sR    !#**9  !#GOq r   )r   )r7   r	   r!   r
   r?   r>   r@   r>   rB   rA   r   r   rq   rr   rn   rs   ru   )rx   ry   rz   r{   r   rD   rE   r   rI   rL   r\   r   r   r   s   @r   r   r   f  s     ( 6!&%0     	 
     #  
   * !%'+(,	 % &	
 
" ! !r   r   c                  Z   ^  \ rS rSrS\\S\4           SU 4S jjjrSS jrSr	U =r
$ )	TemporaryFileLocki  z.lockTc           	     j   > [         TU ]  USUUUUS9  [        R                  " U R                  5        g )Nr    )r7   r!   r?   r@   rB   r   )r   rI   atexitregisterr\   )rH   r7   r?   r@   rB   r   r   s         r   rI   TemporaryFileLock.__init__  s;     	)- 	 	
 	%r   c                    [         R                  U 5        [        R                  R	                  U R
                  5      (       a!  [        R                  " U R
                  5        g g r   )r   r\   r.   r9   isfiler7   unlinkr[   s    r   r\   TemporaryFileLock.release  s:    T77>>$--((IIdmm$ )r   r   )r7   r,   r?   r>   r@   r>   rB   rA   r   r   rq   rr   ru   )rx   ry   rz   r{   rD   rE   r   rI   r\   r   r   r   s   @r   r   r     sb      ( 6!%%0&& & 	&
 & #& 
& &$% %r   r   c                     ^  \ rS rSr% SrS\S'   SS\R                  " 5       \\	S4               SU 4S jjjr
SS	 jrSS
 jrSS jr   S       SS jjrSS jrSS jrSrU =r$ )BoundedSemaphorei  a  
Bounded semaphore to prevent too many parallel processes from running

This method is deprecated because multiple processes that are completely
unrelated could end up using the same semaphore.  To prevent this,
use `NamedBoundedSemaphore` instead. The
`NamedBoundedSemaphore` is a drop-in replacement for this class.

>>> semaphore = BoundedSemaphore(2, directory='')
>>> str(semaphore.get_filenames()[0])
'bounded_semaphore.00.lock'
>>> str(sorted(semaphore.get_random_filenames())[1])
'bounded_semaphore.01.lock'
Lock | Noner   bounded_semaphore{name}.{number:02d}.lockTc                   > Xl         X l        X0l        X@l        S U l        [
        TU ]  UUUS9  U(       a  US:X  a  [        R                  " S[        SS9  g g )N)r?   r@   rB   r   z_`BoundedSemaphore` without an explicit `name` argument is deprecated, use NamedBoundedSemaphorer   r   )
maximumr2   filename_pattern	directoryr   r   rI   r   r   DeprecationWarning	rH   r   r2   r   r   r?   r@   rB   r   s	           r   rI   BoundedSemaphore.__init__  sf     	 0"!%	)- 	 	
 t22MMD"	 3r   c                t    [        U R                  5       Vs/ s H  oR                  U5      PM     sn$ s  snf r   )ranger   get_filename)rH   ns     r   get_filenamesBoundedSemaphore.get_filenames  s.    .3DLL.AB.A!!!$.ABBBs   5c                d    [        U R                  5       5      n[        R                  " U5        U$ r   )listr   randomshuffle)rH   	filenamess     r   get_random_filenames%BoundedSemaphore.get_random_filenames  s'    ++-.	y!r   c                    [         R                  " U R                  5      U R                  R	                  U R
                  US9-  $ )N)r2   number)r%   r&   r   r   formatr2   )rH   r   s     r   r   BoundedSemaphore.get_filename  s?    ||DNN+d.C.C.J.J /K /
 
 	
r   c                \   U R                   (       a   S5       eU R                  5       nU R                  X5       H=  n[        R	                  SXT5        U R                  U5      (       d  M1  U R                   s  $    [        UU R                  5      =n(       a  [        R                  " 5       eg )NzAlready lockedztrying lock (attempt %d) %r)
r   r   rX   loggerdebugtry_lockr   rB   r   r   )rH   r?   r@   rB   r   r   s         r   rL   BoundedSemaphore.acquire  s     99...}&&(	((AALL6E}}Y''yy 	 B  (!! 
 
 
 **,,r   c                   U HY  n[         R                  SU5        [        USS9U l         U R                  R	                  5         [         R                  SU5          g   g! [
        R                   a    S U l         M|  f = f)Nztrying lock for %rT)rB   z	locked %rF)r   r   r   r   rL   r   r   )rH   r   r7   s      r   r   BoundedSemaphore.try_lock  st    !HLL-x8X=DI		!!# [(3 "  ++ ! 	!s   A!!B ?B c                b    U R                   b"  U R                   R                  5         S U l         g g r   )r   r\   r[   s    r   r\   BoundedSemaphore.release  s(    99 IIDI !r   )r   r   r   r   r2   )r   intr2   r,   r   r,   r   r,   r?   ro   r@   ro   rB   rp   rq   rr   )rq   ztyping.Sequence[pathlib.Path])r   r   rq   zpathlib.Pathrn   )r?   ro   r@   ro   rB   rp   rq   r   )r   ztyping.Sequence[Filename]rq   rA   ru   )rx   ry   rz   r{   r   r|   r*   
gettempdirrD   rE   rI   r   r   r   rL   r   r\   r   r   r   s   @r   r   r     s     
 ( :!,,. /'=(,  	
   % & 
 :C

 !%'+(,	 % &	
 
0 r   r   c                  |   ^  \ rS rSrSrSS\R                  " 5       \\S4               SU 4S jjjr	Sr
U =r$ )	NamedBoundedSemaphorei  a]  
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.

Because this works across multiple processes it's important to give the
semaphore a name.  This name is used to create the lock files.  If you
don't specify a name, a random name will be generated.  This means that
you can't use the same semaphore in multiple processes unless you pass the
semaphore object to the other processes.

>>> semaphore = NamedBoundedSemaphore(2, name='test')
>>> str(semaphore.get_filenames()[0])
'...test.00.lock'

>>> semaphore = NamedBoundedSemaphore(2)
>>> 'bounded_semaphore' in str(semaphore.get_filenames()[0])
True

Nr   Tc           	     l   > Uc  S[         R                  " SS5      S 3n[        TU ]  UUUUUUU5        g )Nzbounded_semaphore.r   i@B d)r   randintr   rI   r   s	           r   rI   NamedBoundedSemaphore.__init__6  sF     <'q'(B1'EFD	
r   r   )r   r   r2   z
str | Noner   r,   r   r,   r?   ro   r@   ro   rB   rp   rq   rr   )rx   ry   rz   r{   r   r*   r   rD   rE   rI   r   r   r   s   @r   r   r     s}    6   :!,,. /'=(,

 
 	

 
 
 %
 &
 

 
r   r   )r   rw   r   rw   rq   rw   )T)r7   r	   r8   rA   rq   ztyping.Iterator[types.IO]))
__future__r   r}   r   r3   loggingr.   r%   r   r*   rO   r   r    r   r   r   r   r	   r
   	getLoggerrx   r   rD   rE   rF   r   	EXCLUSIVEr   r   __all__r   contextmanagerr   ABCr<   r   r   r   r   r   r   r   r   <module>r     s    " 
    	       7 7 !			8	$   !!++i.A.A.N.NN  :> F2  5$5$5$ 5$ 5$pAsww AHn8 nb1!D 1!h% %2gx gT-
, -
r   