a
     ³Ša±,  ã                   @   s¾   d Z ddlmZ ddlZddlZddlmZmZmZm	Z	m
Z
mZ ddlmZmZ ejdkZdd„ ZG d	d
„ d
eƒZG dd„ deƒZG dd„ deƒZdd„ Zddd„Zdd„ Zedkrºeƒ  dS )zZ
Worker manager and workers for running files long processes in non GUI
blocking threads.
é    )ÚdequeN)Ú
QByteArrayÚQObjectÚQProcessÚQThreadÚQTimerÚSignal)ÚPY2Úto_text_stringÚntc                 C   s   t | tƒr|  ¡ } t| |dS )z"Qt/Python2/3 compatibility helper.)Úencoding)Ú
isinstancer   Údatar
   )Úobjr   © r   ú3lib/python3.9/site-packages/spyder/utils/workers.pyÚhandle_qbytearray   s    
r   c                       sT   e Zd ZdZeeƒZeeeeƒZ‡ fdd„Zdd„ Z	dd„ Z
dd	„ Zd
d„ Z‡  ZS )ÚPythonWorkerz„
    Generic python worker for running python code on threads.

    For running processes (via QProcess) use the ProcessWorker.
    c                    s0   t t| ƒ ¡  || _|| _|| _d| _d| _dS )z9Generic python worker for running python code on threads.FN)Úsuperr   Ú__init__ÚfuncÚargsÚkwargsÚ_is_finishedÚ_started)Úselfr   r   r   ©Ú	__class__r   r   r   .   s    zPythonWorker.__init__c                 C   s   | j S )z@Return True if worker status is finished otherwise return False.©r   ©r   r   r   r   Úis_finished7   s    zPythonWorker.is_finishedc                 C   s   | j s| j | ¡ d| _ dS )z?Start the worker (emits sig_started signal with worker as arg).TN©r   Úsig_startedÚemitr   r   r   r   Ústart;   s    zPythonWorker.startc                 C   s
   d| _ dS )zMark the worker as finished.TNr   r   r   r   r   Ú	terminateA   s    zPythonWorker.terminatec              
   C   sj   d}d}z| j | ji | j¤Ž}W n( tyH } z|}W Y d}~n
d}~0 0 | js`| j | ||¡ d| _dS )z6Start process worker for given method args and kwargs.NT)r   r   r   Ú	Exceptionr   Úsig_finishedr#   )r   ÚerrorÚoutputÚerrr   r   r   Ú_startE   s    zPythonWorker._start)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   Úobjectr"   r'   r   r    r$   r%   r+   Ú__classcell__r   r   r   r   r   %   s   	r   c                       s’   e Zd ZdZeeƒZeeeeƒZeeeeƒZd‡ fdd„	Z	dd„ Z
dd„ Zd	d
„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Z‡  ZS )ÚProcessWorkerz7Process worker based on a QProcess for non blocking UI.Nc                    s|   t t| ƒ ¡  d| _|| _d| _d| _d| _d| _t	ƒ | _
tƒ | _|  |¡ | j
 d¡ | j
j | j¡ | jj | j¡ dS )zö
        Process worker based on a QProcess for non blocking UI.

        Parameters
        ----------
        cmd_list : list of str
            Command line arguments to execute.
        environ : dict
            Process environment,
        NFé–   )r   r2   r   Ú_resultÚ	_cmd_listÚ_firedÚ_communicate_firstÚ_partial_stdoutr   r   Ú_timerr   Ú_processÚ_set_environmentÚsetIntervalÚtimeoutÚconnectÚ_communicateZreadyReadStandardOutputÚ_partial)r   Úcmd_listÚenvironr   r   r   r   [   s    
zProcessWorker.__init__c                 C   s,   d}t r(ddl}t|jj ¡ ƒ}d| }|S )z$Return the encoding/codepage to use.zutf-8r   NZcp)ÚWINÚctypesr
   ZcdllZkernel32ZGetACP)r   ÚencorD   Zcodepager   r   r   Ú_get_encodingv   s    zProcessWorker._get_encodingc                 C   s<   |r8| j  ¡ }| ¡ D ]\}}| ||¡ q| j  |¡ dS )z$Set the environment on the QProcess.N)r:   ZprocessEnvironmentÚitemsÚinsertZsetProcessEnvironment)r   rB   Z	q_environÚkÚvr   r   r   r;   ƒ   s
    
zProcessWorker._set_environmentc                 C   sL   | j  ¡ }t||  ¡ ƒ}| jdu r*|| _n|  j|7  _| j | |d¡ dS )zCallback for partial output.N)r:   ÚreadAllStandardOutputr   rF   r8   Úsig_partialr#   )r   Ú
raw_stdoutÚstdoutr   r   r   r@   ‹   s    

zProcessWorker._partialc                 C   s4   | j s | j ¡ tjkr |  ¡  n| jr0| j ¡  dS )zCallback for communicate.N)	r7   r:   Ústater   Ú
NotRunningÚcommunicater6   r9   Ústopr   r   r   r   r?   —   s    ÿ
zProcessWorker._communicatec                 C   s¨   d| _ | j ¡  |  ¡ }| jdu r8| j ¡ }t||ƒ}n| j}| j ¡ }t||ƒ}| |¡| |¡g}t	rr| 
¡ }d|d< || _| jsž| j | |d |d ¡ d| _|S )zRetrieve information.TNÚ éÿÿÿÿr   )r7   r:   ZwaitForFinishedrF   r8   rK   r   ZreadAllStandardErrorÚencoder	   Údecoder4   r6   r'   r#   )r   rE   rM   rN   Z
raw_stderrÚstderrÚresultr   r   r   rQ   Ÿ   s$    




zProcessWorker.communicatec                 C   s   | j  ¡  dS )zClose the running process.N)r:   Úcloser   r   r   r   rY   ¼   s    zProcessWorker.closec                 C   s   | j  ¡ tjko| jS )z.Return True if worker has finished processing.)r:   rO   r   rP   r6   r   r   r   r   r    À   s    zProcessWorker.is_finishedc                 C   s8   | j s4d| _| j | jd | jdd… ¡ | j ¡  dS )zStart process.Nr   é   )r6   Z_partial_ouputr:   r$   r5   r9   r   r   r   r   r+   Ä   s    zProcessWorker._startc                 C   s<   | j  ¡ tjkr2z| j  ¡  W n ty0   Y n0 d| _dS )zTerminate running processes.TN)r:   rO   r   ZRunningr%   r&   r6   r   r   r   r   r%   Ë   s    zProcessWorker.terminatec                 C   s   | j s| j | ¡ d| _ dS )zStart worker.TNr!   r   r   r   r   r$   Ô   s    zProcessWorker.start)N)r,   r-   r.   r/   r   r0   r"   r'   rL   r   rF   r;   r@   r?   rQ   rY   r    r+   r%   r$   r1   r   r   r   r   r2   T   s   	r2   c                       sV   e Zd ZdZd‡ fdd„	Zdd„ Zddd	„Zd
d„ Zddd„Zdd„ Z	dd„ Z
‡  ZS )ÚWorkerManagerú*Spyder Worker Manager for Generic Workers.é
   c                    sŠ   t t| ƒ ¡  tƒ | _tƒ | _g | _g | _tƒ | _	tƒ | _
d| _|| _tƒ | _| j	 d¡ | j	j | j¡ | j
 d¡ | j
j | j¡ dS )r\   r   iM  iˆ  N)r   r   r   r   Z_queueÚ_queue_workersÚ_threadsÚ_workersr   r9   Ú_timer_worker_deleteÚ_running_threadsÚ_max_threadsÚ_bag_collectorr<   r=   r>   r+   Ú_clean_workers)r   Úmax_threadsr   r   r   r   Þ   s    zWorkerManager.__init__c                 C   s    | j r| j  ¡  q | j ¡  dS )z+Delete periodically workers in workers bag.N)rd   Úpopleftra   rR   r   r   r   r   re   ó   s    zWorkerManager._clean_workersNc                 C   sL  |r| j  |¡ | j r¢| j| jk r¢|  jd7  _| j  ¡ }tƒ }t|tƒrz| |¡ |j	 
|j¡ |j 
|j¡ | ¡  nt|tƒr”| ¡  | ¡  | j |¡ n
| j ¡  | jrÞ| jD ]$}| ¡ r¸| j |¡ | j |¡ q¸| jr| jD ]&}| ¡ rì| j |¡ |  jd8  _qìt| jƒdkrHt| jƒdkrH| j ¡  | j ¡  dS )z-Start threads and check for inactive workers.rZ   r   N)r^   Úappendrb   rc   rg   r   r   r   ZmoveToThreadr'   r>   ÚquitZstartedr+   r$   r2   r_   r9   r`   r    rd   ÚremoveZ
isFinishedÚlenrR   ra   )r   ÚworkerÚthreadÚwÚtr   r   r   r+   ù   s:    







 
zWorkerManager._startc                 O   s   t |||ƒ}|  |¡ |S )z$Create a new python worker instance.)r   Ú_create_worker)r   r   r   r   rl   r   r   r   Úcreate_python_worker#  s    
z"WorkerManager.create_python_workerc                 C   s   t ||d}|  |¡ |S )z%Create a new process worker instance.)rB   )r2   rp   )r   rA   rB   rl   r   r   r   Úcreate_process_worker)  s    
z#WorkerManager.create_process_workerc                 C   s    | j D ]}| ¡  qtƒ | _dS )zTerminate all worker processes.N)r`   r%   r   r^   ©r   rl   r   r   r   Úterminate_all/  s    

zWorkerManager.terminate_allc                 C   s   |j  | j¡ | j |¡ dS )zCommon worker setup.N)r"   r>   r+   r`   rh   rs   r   r   r   rp   <  s    zWorkerManager._create_worker)r]   )N)N)r,   r-   r.   r/   r   re   r+   rq   rr   rt   rp   r1   r   r   r   r   r[   Û   s   
*
r[   c                 C   s   t | ||ƒ dS )zPrint worker output for tests.N)Úprint)rl   r)   r(   r   r   r   Úready_printC  s    rv   r]   c                 C   s.   ddl }| |¡ |dur&| | ¡ n| S dS )z5This methods illustrates how the workers can be used.r   N)ÚtimeÚsleepZput)ÚargÚsecsZresult_queuerw   r   r   r   Úsleeping_funcH  s
    
r{   c                  C   s¬   ddl m}  | ƒ }tdd}tdƒD ].}|jtd |¡dd}|j t	¡ | 
¡  q$|jtd	dd}|j t	¡ | 
¡  | g d
¢¡}|j t	¡ | 
¡  t | ¡ ¡ dS )zMain local test.r   )Úqapplicationé   )rf   é   zBOOM! {}é   )rz   zBOOM!)ZcondaÚinfoz--jsonN)Zspyder.utils.qthelpersr|   r[   Úrangerq   r{   Úformatr'   r>   rv   r$   rr   ÚsysÚexitZexec_)r|   ZappZwmÚirl   r   r   r   Ú
local_testR  s     
ÿ
r†   Ú__main__)r]   N)r/   Úcollectionsr   Úosrƒ   Zqtpy.QtCorer   r   r   r   r   r   Zspyder.py3compatr	   r
   ÚnamerC   r   r   r2   r[   rv   r{   r†   r,   r   r   r   r   Ú<module>   s     
/ h

