
    9h=              !       T   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
  S SKJr  S SKJr  S SKJr  S SKJr  S SKJrJrJrJrJrJrJrJrJrJr  S SKrSS	KJ r   SS
K!J"r"J#r#J$r$J%r%  \(       a  S SKJ&r&  Sr'\RP                  " S5      r)SSSS\ " 5       S SSSSSSSS.S\\\*4   S\\*\S\4   4   S\\S4   S\\\*\4      SSS\\\\#   /S4      S\\\"\*/\+4      S\,S \-S!\-S"\\+   S#\-S$\-S%\+S&\+S'\-4 S( jjr.SSSS\ " 5       S SSSSSS).S\\\*4   S\\*\S\4   4   S\\S4   S\\\*\4      SSS\\\\#   /\4      S\\\"\*/\+4      S\,S \-S!\-S"\\+   S%\+S&\+S'\-4S* jjr/\" S+5      r0S,\*S'\\*   4S- jr1 S@S\\*\S\4   4   SS.S\\S4   S\\\*\4      S/\\\#      S'S04S1 jjr2S\\*\S\4   4   S'S.4S2 jr3 " S3 S05      r4S4\*S5\\*   S\\S4   S\\*\4   S'S4
S6 jr5S7\*S'\4S8 jr6S'\\*   4S9 jr7\ Rp                  S5\\*   S'\S:   4S; j5       r9S<\-S=\S'S4S> jr:SAS? jr;g)B    N)import_module)get_context)SpawnProcess)Path)sleep)
TYPE_CHECKINGAnyCallableDict	GeneratorListOptionalSetTupleUnion   )DefaultFilter)Change
FileChangeawatchwatch)Literal)run_processarun_processdetect_target_typeimport_stringzwatchfiles.main autoi@  2      TF)argskwargstarget_typecallbackwatch_filtergrace_perioddebouncestepdebugsigint_timeoutsigkill_timeout	recursiveignore_permission_deniedpathstarget.r!   r"   r#   z&Literal['function', 'command', 'auto']r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   returnc                    US:X  a  [        U 5      n[        R                  SX5        [        5         [	        XX5      nSnU(       a!  [        R                  SU5        [        U5         [        UUUUU	SUUS.6 H5  nU=(       a    U" U5        UR                  XS9  [	        XXU5      nUS-  nM7     UR                  5         U$ ! UR                  5         f = f)	u  
Run a process and restart it upon file changes.

`run_process` can work in two ways:

* Using `multiprocessing.Process` † to run a python function
* Or, using `subprocess.Popen` to run a command

!!! note

    **†** technically `multiprocessing.get_context('spawn').Process` to avoid forking and improve
    code reload/import.

Internally, `run_process` uses [`watch`][watchfiles.watch] with `raise_interrupt=False` so the function
exits cleanly upon `Ctrl+C`.

Args:
    *paths: matches the same argument of [`watch`][watchfiles.watch]
    target: function or command to run
    args: arguments to pass to `target`, only used if `target` is a function
    kwargs: keyword arguments to pass to `target`, only used if `target` is a function
    target_type: type of target. Can be `'function'`, `'command'`, or `'auto'` in which case
        [`detect_target_type`][watchfiles.run.detect_target_type] is used to determine the type.
    callback: function to call on each reload, the function should accept a set of changes as the sole argument
    watch_filter: matches the same argument of [`watch`][watchfiles.watch]
    grace_period: number of seconds after the process is started before watching for changes
    debounce: matches the same argument of [`watch`][watchfiles.watch]
    step: matches the same argument of [`watch`][watchfiles.watch]
    debug: matches the same argument of [`watch`][watchfiles.watch]
    sigint_timeout: the number of seconds to wait after sending sigint before sending sigkill
    sigkill_timeout: the number of seconds to wait after sending sigkill before raising an exception
    recursive: matches the same argument of [`watch`][watchfiles.watch]

Returns:
    number of times the function was reloaded.

```py title="Example of run_process running a function"
from watchfiles import run_process

def callback(changes):
    print('changes detected:', changes)

def foobar(a, b):
    print('foobar called with:', a, b)

if __name__ == '__main__':
    run_process('./path/to/dir', target=foobar, args=(1, 2), callback=callback)
```

As well as using a `callback` function, changes can be accessed from within the target function,
using the `WATCHFILES_CHANGES` environment variable.

```py title="Example of run_process accessing changes"
from watchfiles import run_process

def foobar(a, b, c):
    # changes will be an empty list "[]" the first time the function is called
    changes = os.getenv('WATCHFILES_CHANGES')
    changes = json.loads(changes)
    print('foobar called due to changes:', changes)

if __name__ == '__main__':
    run_process('./path/to/dir', target=foobar, args=(1, 2, 3))
```

Again with the target as `command`, `WATCHFILES_CHANGES` can be used
to access changes.

```bash title="example.sh"
echo "changers: ${WATCHFILES_CHANGES}"
```

```py title="Example of run_process running a command"
from watchfiles import run_process

if __name__ == '__main__':
    run_process('.', target='./example.sh')
```
r   running "%s" as %sr   3sleeping for %s seconds before watching for changesF)r%   r'   r(   r)   raise_interruptr,   r-   )r*   r+   r   )r   loggerr)   catch_sigtermstart_processr   r   stop)r/   r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   processreloadschangess                     SC:\Suresh\moveshuttle\MDcreated\moveengine\venv\Lib\site-packages\watchfiles/run.pyr   r      s    @ f(0
LL%v;OF>GGJLYl%!%=	
G *'*LLLX#FwOGqLG	
 	N 	s   )A
C C)r!   r"   r#   r$   r%   r&   r'   r(   r)   r,   r-   c           
        #    SSK nUS:X  a  [        U 5      n[        R                  SX5        [	        5         [
        R                  R                  [        XX5      I Sh  vN nSnU(       a4  [        R                  SU5        [
        R                  " U5      I Sh  vN   [        UUUUU	U
US.6  Sh  vN nUb(  U" U5      nUR                  U5      (       a
  UI Sh  vN   [
        R                  R                  UR                  5      I Sh  vN   [
        R                  R                  [        XXU5      I Sh  vN nUS-  nM   N N N Np NA N
 [
        R                  R                  UR                  5      I Sh  vN    U$ 7f)a  
Async equivalent of [`run_process`][watchfiles.run_process], all arguments match those of `run_process` except
`callback` which can be a coroutine.

Starting and stopping the process and watching for changes is done in a separate thread.

As with `run_process`, internally `arun_process` uses [`awatch`][watchfiles.awatch], however `KeyboardInterrupt`
cannot be caught and suppressed in `awatch` so these errors need to be caught separately, see below.

```py title="Example of arun_process usage"
import asyncio
from watchfiles import arun_process

async def callback(changes):
    await asyncio.sleep(0.1)
    print('changes detected:', changes)

def foobar(a, b):
    print('foobar called with:', a, b)

async def main():
    await arun_process('.', target=foobar, args=(1, 2), callback=callback)

if __name__ == '__main__':
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print('stopped via KeyboardInterrupt')
```
r   Nr   r2   r3   )r%   r'   r(   r)   r,   r-   r   )inspectr   r5   r)   r6   anyio	to_threadrun_syncr7   r   r   isawaitabler8   )r/   r!   r"   r#   r$   r%   r&   r'   r(   r)   r,   r-   r.   r>   r9   r:   r;   rs                     r<   r   r      sK    Z f(0
LL%v;OOO,,]FQU^^GGJLYkk,'''	!!9 g !A""1%%oo&&w||44400UYcjkk1/ _
 	( 4k" //
"
"7<<
000Ns   AF E!<FEF2E6E7E:'F!E"0FE-F EFFEFFF-FFFspawncmdc                     SS K nUR                  5       R                  R                  5       S:g  n[        R
                  " XS9$ )Nr   windows)posix)platformunamesystemlowershlexsplit)rE   rI   rH   s      r<   	split_cmdrO      s4    NN##))+y8E;;s((    zLiteral['function', 'command']r;   CombinedProcessc                 R   Uc  SnO;[         R                  " U VVs/ s H  u  pgUR                  5       U/PM     snn5      nU[        R                  S'   US:X  a]  U=(       d    0 n[        U [        5      (       a  U [        5       X#4n[        n0 nOU n[        R                  XUS9n	U	R                  5         O`U(       d  U(       a  [        R                  S5        [        U [        5      (       d   S5       e[        U 5      n
[        R                   " U
5      n	[#        U	5      $ s  snnf )Nz[]WATCHFILES_CHANGESfunction)r/   r!   r"   z-ignoring args and kwargs for "command" targetz+target must be a string to run as a command)jsondumpsraw_strosenviron
isinstancestrget_tty_pathrun_functionspawn_contextProcessstartr5   warningrO   
subprocessPopenrQ   )r/   r#   r!   r"   r;   changes_env_varcptarget_r9   
popen_argss              r<   r7   r7      s     **7%K741qyy{A&67%KL'6BJJ#$ j 2fc""<>47D"GFG''w&'Q6NNJK&#&&U(UU&v&
"":.7##/ &Ls   D#
c                     [        U [        5      (       d  gU R                  S5      (       a  g[        R                  " SU 5      (       a  gg)a&  
Used by [`run_process`][watchfiles.run_process], [`arun_process`][watchfiles.arun_process]
and indirectly the CLI to determine the target type with `target_type` is `auto`.

Detects the target type - either `function` or `command`. This method is only called with `target_type='auto'`.

The following logic is employed:

* If `target` is not a string, it is assumed to be a function
* If `target` ends with `.py` or `.sh`, it is assumed to be a command
* Otherwise, the target is assumed to be a function if it matches the regex `[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)+`

If this logic does not work for you, specify the target type explicitly using the `target_type` function argument
or `--target-type` command line argument.

Args:
    target: The target value

Returns:
    either `'function'` or `'command'`
rT   )z.pyz.shcommandz[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)+)rZ   r[   endswithre	fullmatch)r/   s    r<   r   r     s>    , fc""		(	(	8&	A	ArP   c                       \ rS rSrSS jrSS\S\SS4S jjrS\4S jr\	S\4S	 j5       r
S
\SS4S jr\	S\\   4S j5       rSrg)rQ   i=  c                 8    Xl         U R                  c   S5       eg )Nzprocess not yet spawned_ppid)selfrf   s     r<   __init__CombinedProcess.__init__>  s    xx#>%>>#rP   r*   r+   r0   Nc                    [         R                  R                  SS 5        U R                  5       (       a  [        R                  S5        [         R                  " U R                  [        R                  5         U R                  U5        U R                  cV  [        R                  S5        [         R                  " U R                  [        R                  5        U R                  U5        g [        R                  S5        g [        R                  SU R                  5        g ! [        R                   a    [        R                  SU5         Nf = f)NrS   zstopping process...z!SIGINT timed out after %r secondsz+process has not terminated, sending SIGKILLzprocess stoppedz#process already dead, exit code: %d)rX   rY   popis_aliver5   r)   killrr   signalSIGINTjoinrb   TimeoutExpiredra   exitcodeSIGKILL)rs   r*   r+   s      r<   r8   CombinedProcess.stopB  s    


+T2==??LL./GGDHHfmm,		.) }}$LM&..1		/*./NN@$--P ,,  BNS	s   ;D& &*EEc                     [        U R                  [        5      (       a  U R                  R                  5       $ U R                  R	                  5       S L $ N)rZ   rq   r   rx   pollrs   s    r<   rx   CombinedProcess.is_aliveZ  s;    dgg|,,77##%%77<<>T))rP   c                 .    U R                   R                  $ r   rp   r   s    r<   rr   CombinedProcess.pid`  s     ww{{rP   timeoutc                     [        U R                  [        5      (       a  U R                  R                  U5        g U R                  R	                  U5        g r   )rZ   rq   r   r|   wait)rs   r   s     r<   r|   CombinedProcess.joine  s3    dgg|,,GGLL!GGLL!rP   c                     [        U R                  [        5      (       a  U R                  R                  $ U R                  R                  $ r   )rZ   rq   r   r~   
returncoder   s    r<   r~   CombinedProcess.exitcodek  s3    dgg|,,77###77%%%rP   )rq   )rf   z,Union[SpawnProcess, subprocess.Popen[bytes]])r    r   )__name__
__module____qualname____firstlineno__rt   intr8   boolrx   propertyrr   r|   r   r~   __static_attributes__r   rP   r<   rQ   rQ   =  s~    ?Q3 QS Q Q0*$ * S  "C "D " &(3- & &rP   rT   tty_pathc                 t    [        U5         [        U 5      nU" U0 UD6  S S S 5        g ! , (       d  f       g = fr   )set_ttyr   )rT   r   r!   r"   funcs        r<   r]   r]   s  s-    		X&df 
		s   )
7dotted_pathc                     U R                  S5      R                  SS5      u  p[	        U5      n [        XB5      $ ! [         a  n[        SU  S35      UeSnAff = f! [         a  n[        SU SU S	35      UeSnAff = f)
z
Stolen approximately from django. Import a dotted module path and return the attribute/class designated by the
last name in the path. Raise ImportError if the import fails.
 .r   "z!" doesn't look like a module pathNzModule "z" does not define a "z" attribute)striprsplit
ValueErrorImportErrorr   getattrAttributeError)r   module_path
class_nameemodules        r<   r   r   y  s    
V"-"3"3C"8"?"?Q"G ;'Fgv**  VAk]*LMNTUUV  gH[M1FzlR]^_effgs,   #< 
A 
AAA
B (A;;B c                       [         R                  " [        R                  R	                  5       5      $ ! [
         a     g[         a     gf = f)zf
Return the path to the current TTY, if any.

Virtually impossible to test in pytest, hence no cover.
z/dev/ttyN)rX   ttynamesysstdinfilenoOSErrorr   r   rP   r<   r\   r\     s@    zz#))**,--  s   14 
A 	AA)NNNc              #      #    U (       a%   [        U 5       nU[        l        S v   S S S 5        g S v   g ! , (       d  f       g = f! [         a    S v    g f = f7fr   )openr   r   r   )r   ttys     r<   r   r     sF     	h3	   	    		sF   AA 4A A
AA AA AAAAsignum_framec                 b    [         R                  S[        R                  " U 5      5        [        e)Nz-received signal %s, raising KeyboardInterrupt)r5   ra   rz   SignalsKeyboardInterrupt)r   r   s     r<   raise_keyboard_interruptr     s!    
NNBFNNSYDZ[
rP   c                      [         R                  S[        R                  " 5       5        [        R                  " [        R
                  [        5        g)a  
Catch SIGTERM and raise KeyboardInterrupt instead. This means watchfiles will stop quickly
on `docker compose stop` and other cases where SIGTERM is sent.

Without this the watchfiles process will be killed while a running process will continue uninterrupted.
z8registering handler for SIGTERM on watchfiles process %dN)r5   r)   rX   getpidrz   SIGTERMr   r   rP   r<   r6   r6     s,     LLKRYY[Y
MM&..":;rP   r   )r0   N)<
contextlibrU   loggingrX   rl   rM   rz   rb   r   	importlibr   multiprocessingr   multiprocessing.contextr   pathlibr   timer   typingr   r	   r
   r   r   r   r   r   r   r   r?   filtersr   mainr   r   r   r   r   __all__	getLoggerr5   r[   r   floatr   r   r   r^   rO   r7   r   rQ   r]   r   r\   contextmanagerr   r   r6   r   rP   r<   <module>r      s?      	 	    
 # ' 0   c c c  " 3 3
N			,	- '+<B<@<IO %*}$)}#xS))*} S/} T#s(^$	}
 :} xZ 14 789} 8VSM4$789} } } } D>} } } } #}  	!}F '+<B;?<IO %*M$)M#xS))*M S/M T#s(^$	M
 :M xZ 13 678M 8VSM4$789M M M M D>M M #M 	Md G$)3 )49 ) *.!$#xS))*!$1!$ S/!$ T#s(^$	!$
 c*o&!$ !$HuS(38*<%<= Bb @3& 3&l3 (3- uS#X X\]`be]eXf ko gs gs g"hsm   hsm 	2B(C  S # $ 
<rP   