� ���g�;�!�0�ddlZddlZddlZddlZddlZddlZddlZddlZddlZddl m Z ddl m Z ddl mZddlmZddlmZddlmZmZmZmZmZmZmZmZmZmZddlZdd lm Z dd l!m"Z"m#Z#m$Z$m%Z%erdd lm&Z&d Z'ej(d ��Z)dddde ��ddddddddd� deee*fdee*edeffdeedfdeee*efdddeeee#gdfdeee"e*ge+fde,d e-d!e-d"ee+d#e-d$e-d%e+d&e+d'e-f d(�Z.dddde ��ddddddd)� deee*fdee*edeffdeedfdeee*efdddeeee#gefdeee"e*ge+fde,d e-d!e-d"ee+d%e+d&e+d'e-fd*�Z/e d+��Z0d,e*d'ee*fd-�Z1 d@dee*edeffdd.deedfdeee*efd/eee#d'd0f d1�Z2dee*edeffd'd.fd2�Z3Gd3�d0��Z4d4e*d5ee*deedfdee*efd'df d6�Z5d7e*d'efd8�Z6d'ee*fd9�Z7ej8d5ee*d'ed:fd;���Z9d<e-d=ed'dfd>�Z:dAd?�Z;dS)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_stringzwatchfiles.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 ��|dkrt|��}t�d||��t��t ||||��}d}|r*t�d|��t |�� t ||||| d| | d��D]>}|o ||��|�| | ���t |||||��}|dz }�? |���n#|���wxYw|S) 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_processrr�stop)r/r!r"r#r$r%r&r'r(r)r*r+r,r-r.�process�reloads�changess �^/home/asafur/pinokio/api/open-webui.git/app/env/lib/python3.11/site-packages/watchfiles/run.pyrrs3��@�f���(��0�0� � �L�L�%�v�{�;�;�;��O�O�O��F�K��v�>�>�G��G���� � �J�L�Y�Y�Y� �l������ �%����!��%=�  �  �  � � �G� � *���'�*�*�� �L�L���L� X� X� X�#�F�K��v�w�O�O�G� �q�L�G�G� � � � ������� � �������� �Ns �AC(�(C>) r!r"r#r$r%r&r'r(r)r,r-c ���K�ddl} |dkrt|��}t�d||��t ��t j�t||||���d{V��}d}|r5t�d|��t j |���d{V��t| |||| | | d��23d{V��}|�(||��}| � |��r|�d{V��t j�|j ���d{V��t j�t|||||���d{V��}|dz }��6t j�|j ���d{V��|S)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') ``` rNrr2r3)r%r'r(r)r,r-r) �inspectrr5r)r6�anyio� to_thread�run_syncr7rr� isawaitabler8)r/r!r"r#r$r%r&r'r(r)r,r-r.r>r9r:r;�rs r<rr�s�����Z�N�N�N��f���(��0�0� � �L�L�%�v�{�;�;�;��O�O�O��O�,�,�]�F�K�QU�W]�^�^�^�^�^�^�^�^�G��G��(�� � �J�L�Y�Y�Y��k�,�'�'�'�'�'�'�'�'�'�� �!�� ���!9�����������g� � ����!�!�A��"�"�1�%�%� ����������o�&�&�w�|�4�4�4�4�4�4�4�4�4���0�0��� �UY�[a�cj�k�k�k�k�k�k�k�k���1� ���!�" �/� "� "�7�<� 0� 0�0�0�0�0�0�0�0� �Ns�>E�spawn�cmdc��ddl}|���j���dk}t j||���S)Nr�windows)�posix)�platform�uname�system�lower�shlex�split)rErIrHs r<� split_cmdrO�sC���O�O�O� �N�N� � � #� )� )� +� +�y� 8�E� �;�s�%� (� (� (�(�zLiteral['function', 'command']r;�CombinedProcessc�"�|�d}ntjd�|D����}|tjd<|dkri|pi}t |t ��r|t ��||f}t}i}n|}t� |||���}|� ��n`|s|rt� d��t |t ��s Jd���t|��}tj|��}t!|��S)Nz[]c�@�g|]\}}|���|g��Sr)�raw_str)�.0�c�ps r<� <listcomp>z!start_process.<locals>.<listcomp>s)��%K�%K�%K�4�1�a�q�y�y�{�{�A�&6�%K�%K�%KrP�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�os�environ� isinstance�str� get_tty_path� run_function� spawn_context�Process�startr5�warningrO� subprocess�PopenrQ) r/r#r!r"r;�changes_env_var�target_r9� popen_argss r<r7r7�s��������*�%K�%K�7�%K�%K�%K�L�L��'6�B�J�#�$��j� � ���2�� �f�c� "� "� ��<�>�>�4��7�D�"�G��F�F��G��'�'�w�T�&�'�Q�Q��� � ����� � L�6� L� �N�N�J� K� K� K��&�#�&�&�U�U�(U�U�U�&��v�&�&� ��"�:�.�.�� �7� #� #�#rPc��t|t��sdS|�d��rdStjd|��rdSdS)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'` rZ)z.pyz.sh�commandz[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)+)r_r`�endswith�re� fullmatch)r/s r<rrsS��, �f�c� "� "���z� ���� (� (���y� ��8�&� A� A���z��yrPc��eZdZdd�Zddededd fd �Zdefd �Zedefd ���Z d edd fd�Z ede efd���Z d S)rQrW�,Union[SpawnProcess, subprocess.Popen[bytes]]c�6�||_|j� Jd���dS)Nzprocess not yet spawned��_p�pid)�selfrWs r<�__init__zCombinedProcess.__init__>s&������x�#�#�%>�#�#�#�#�#rPr rr*r+r0Nc��tj�dd��|���r�t�d��tj|jtj �� |� |��n0#tj $rt� d|��YnwxYw|j�Ut� d��tj|jtj��|� |��dSt�d��dSt� d|j��dS)NrYzstopping process...z!SIGINT timed out after %r secondsz+process has not terminated, sending SIGKILLzprocess stoppedz#process already dead, exit code: %d)r]r^�pop�is_aliver5r)�killrv�signal�SIGINT�joinrg�TimeoutExpiredrf�exitcode�SIGKILL)rwr*r+s r<r8zCombinedProcess.stopBs(�� � ���+�T�2�2�2� �=�=�?�?� Q� �L�L�.� /� /� /� �G�D�H�f�m� ,� ,� ,� �� � �.�)�)�)�)���,� � � ����B�N�S�S�S���  ���� �}�$����L�M�M�M�����&�.�1�1�1�� � �/�*�*�*�*�*�� � �.�/�/�/�/�/� �N�N�@�$�-� P� P� P� P� Ps�4B � *B7�6B7c��t|jt��r|j���S|j���duS�N)r_rurr{�poll�rws r<r{zCombinedProcess.is_aliveZs?�� �d�g�|� ,� ,� *��7�#�#�%�%� %��7�<�<�>�>�T�)� )rPc��|jjSr�rtr�s r<rvzCombinedProcess.pid`s���w�{�rP�timeoutc��t|jt��r|j�|��dS|j�|��dSr�)r_rurr�wait)rwr�s r<rzCombinedProcess.joinesJ�� �d�g�|� ,� ,� "� �G�L�L�� !� !� !� !� !� �G�L�L�� !� !� !� !� !rPc�f�t|jt��r |jjS|jjSr�)r_rurr�� returncoder�s r<r�zCombinedProcess.exitcodeks,�� �d�g�|� ,� ,� &��7�#� #��7�%� %rP)rWrr)r r) �__name__� __module__� __qualname__rx�intr8�boolr{�propertyrvrrr�rrPr<rQrQ=s�������?�?�?�?�Q�Q�3�Q�S�Q��Q�Q�Q�Q�0*�$�*�*�*�*� ��S�����X��"�C�"�D�"�"�"�"� �&�(�3�-�&�&�&��X�&�&�&rPrZ�tty_pathc��t|��5t|��}||i|��ddd��dS#1swxYwYdSr�)�set_ttyr)rZr�r!r"�funcs r<rbrbss��� �� � ����X�&�&�� ��d��f������������������������s �5�9�9� dotted_pathc�<� |�d���dd��\}}n&#t$r}td|�d���|�d}~wwxYwt |��} t ||��S#t $r}td|�d|�d ���|�d}~wwxYw) 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 pathNzModule "z" does not define a "z " attribute)�strip�rsplit� ValueError� ImportErrorr�getattr�AttributeError)r�� module_path� class_name�e�modules r<rrys��� V�"-�"3�"3�C�"8�"8�"?�"?��Q�"G�"G�� �Z�Z�� �V�V�V��M�k�M�M�M�N�N�TU�U�����V�����;� '� '�F�g��v�z�*�*�*�� �g�g�g��^�[�^�^�z�^�^�^�_�_�ef�f�����g���s,�,/� A�A � A�%A5�5 B�?B�Bc�� tjtj�����S#t $rYdSt $rYdSwxYw)zr Return the path to the current TTY, if any. Virtually impossible to test in pytest, hence no cover. z/dev/ttyN)r]�ttyname�sys�stdin�fileno�OSErrorr�rrPr<rara�s`�� ��z�#�)�*�*�,�,�-�-�-�� �����z�z� �����t�t����s�/2� A � A � A )NNNc#�K�|rP t|��5}|t_dV�ddd��dS#1swxYwYdS#t$rdV�YdSwxYwdV�dSr�)�openr�r�r�)r��ttys r<r�r��s������ � ��h��� �3��� ����� � � � � � � � � � � � ���� � � � � � ��� � � � �E�E�E�E�E�E� ���� �����s,�A�3� A�7�A�7�A�A�A�signum�_framec�j�t�dtj|����t�)Nz-received signal %s, raising KeyboardInterrupt)r5rfr}�Signals�KeyboardInterrupt)r�r�s r<�raise_keyboard_interruptr��s(�� �N�N�B�F�N�SY�DZ�DZ�[�[�[� �rPc��t�dtj����t jtjt ��dS)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)r5r)r]�getpidr}�SIGTERMr�rrPr<r6r6�s:�� �L�L�K�R�Y�[�[�Y�Y�Y� �M�&�.�":�;�;�;�;�;rPr�)r0N)<� contextlibr[�loggingr]rorMr}rgr�� importlibr�multiprocessingr�multiprocessing.contextr�pathlibr�timer�typingrr r r r r rrrrr?�filtersr�mainrrrrr�__all__� getLoggerr5r`r��floatr�rrrcrOr7rrQrbrra�contextmanagerr�r�r6rrPr<�<module>r�sI������ � � � ����� � � � � � � � � � � � � � � � ����� � � � �#�#�#�#�#�#�'�'�'�'�'�'�0�0�0�0�0�0�������������c�c�c�c�c�c�c�c�c�c�c�c�c�c�c�c�c�c�c�c�c�c�c�c� � � � �"�"�"�"�"�"�3�3�3�3�3�3�3�3�3�3�3�3��������� N�� �� �,� -� -�� �'+�<B�<@�<I�M�O�O���� ����%*�}�}�}� �$��)� �}� �#�x��S��)�)� *�}� ��S��/�}� �T�#�s�(�^� $� }� :� }� �x��Z�� 1�4� 7�8�9� }��8�V�S�M�4�$7�8�9�}��}��}� �}� �D�>�}��}��}��}�#�}�  �!}�}�}�}�F�'+�<B�;?�<I�M�O�O���� ��%*�M�M�M� �$��)� �M� �#�x��S��)�)� *�M� ��S��/�M� �T�#�s�(�^� $� M� :� M� �x��Z�� 1�3� 6�7�8� M��8�V�S�M�4�$7�8�9�M��M��M� �M� �D�>�M��M�#�M� �M�M�M�M�d� �G�$�$� �)�3�)�4��9�)�)�)�)�*.� !$�!$� �#�x��S��)�)� *�!$�1�!$� ��S��/�!$� �T�#�s�(�^� $� !$� �c�*�o� &� !$� � !$�!$�!$�!$�H�u�S�(�3��8�*<�%<�=��Bb�����@3&�3&�3&�3&�3&�3&�3&�3&�l�3��(�3�-��u�S�#�X���X\�]`�be�]e�Xf��ko����� g�s�g�s�g�g�g�g�" �h�s�m� � � � �  �� �h�s�m� � �2B�(C� � � ��� ��S��#��$����� <�<�<�<�<�<rP
Memory