B
    nôb\Å,  ã               @   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.7/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Úemit)r   r   r   r   Ústart;   s    zPythonWorker.startc             C   s
   d| _ dS )zMark the worker as finished.TN)r   )r   r   r   r   Ú	terminateA   s    zPythonWorker.terminatec          
   C   sd   d}d}y| j | j| jŽ}W n& tk
rB } z|}W dd}~X Y nX | jsZ| 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   r.   r   Ú_resultÚ	_cmd_listÚ_firedÚ_communicate_firstÚ_partial_stdoutr   r   Ú_timerr   Ú_processÚ_set_environmentÚsetIntervalÚtimeoutÚconnectÚ_communicateZreadyReadStandardOutputÚ_partial)r   Úcmd_listÚenviron)r   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   Úencor@   Zcodepager   r   r   Ú_get_encodingv   s    zProcessWorker._get_encodingc             C   s@   |r<| j  ¡ }x | ¡ D ]\}}| ||¡ qW | j  |¡ dS )z$Set the environment on the QProcess.N)r6   ZprocessEnvironmentÚitemsÚinsertZsetProcessEnvironment)r   r>   Z	q_environÚkÚvr   r   r   r7   ƒ   s
    
zProcessWorker._set_environmentc             C   sL   | j  ¡ }t||  ¡ ƒ}| jdkr*|| _n|  j|7  _| j | |d¡ dS )zCallback for partial output.N)r6   ÚreadAllStandardOutputr   rB   r4   Ú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)	r3   r6   Ústater   Ú
NotRunningÚcommunicater2   r5   Ústop)r   r   r   r   r;   —   s
    
zProcessWorker._communicatec             C   s¨   d| _ | j ¡  |  ¡ }| jdkr8| j ¡ }t||ƒ}n| j}| j ¡ }t||ƒ}| |¡| |¡g}t	rr| 
¡ }d|d< || _| jsž| j | |d |d ¡ d| _|S )zRetrieve information.TNÚ éÿÿÿÿr   )r3   r6   ZwaitForFinishedrB   r4   rG   r   ZreadAllStandardErrorÚencoder	   Údecoder0   r2   r#   r   )r   rA   rI   rJ   Z
raw_stderrÚstderrÚresultr   r   r   rM   Ÿ   s$    




zProcessWorker.communicatec             C   s   | j  ¡  dS )zClose the running process.N)r6   Úclose)r   r   r   r   rU   ¼   s    zProcessWorker.closec             C   s   | j  ¡ tjko| jS )z.Return True if worker has finished processing.)r6   rK   r   rL   r2   )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   é   )r2   Z_partial_ouputr6   r    r1   r5   )r   r   r   r   r'   Ä   s    zProcessWorker._startc             C   s>   | j  ¡ tjkr4y| j  ¡  W n tk
r2   Y nX d| _dS )zTerminate running processes.TN)r6   rK   r   ZRunningr!   r"   r2   )r   r   r   r   r!   Ë   s    zProcessWorker.terminatec             C   s   | j s| j | ¡ d| _ dS )zStart worker.TN)r   r   r   )r   r   r   r   r    Ô   s    zProcessWorker.start)N)r(   r)   r*   r+   r   r,   r   r#   rH   r   rB   r7   r<   r;   rM   rU   r   r'   r!   r    r-   r   r   )r   r   r.   T   s   	r.   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 )ÚWorkerManagerz*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 )z*Spyder Worker Manager for Generic Workers.r   iM  iˆ  N)r   r   r   r   Z_queueÚ_queue_workersÚ_threadsÚ_workersr   r5   Ú_timer_worker_deleteÚ_running_threadsÚ_max_threadsÚ_bag_collectorr8   r9   r:   r'   Ú_clean_workers)r   Úmax_threads)r   r   r   r   Þ   s    zWorkerManager.__init__c             C   s$   x| j r| j  ¡  qW | j ¡  dS )z+Delete periodically workers in workers bag.N)r_   Úpopleftr\   rN   )r   r   r   r   r`   ó   s    zWorkerManager._clean_workersNc             C   sT  |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âx.| jD ]$}| ¡ rº| j |¡ | j |¡ qºW | jrx0| jD ]&}| ¡ rò| j |¡ |  jd8  _qòW t| jƒdkrPt| jƒdkrP| j ¡  | j ¡  dS )z-Start threads and check for inactive workers.rV   r   N)rY   Úappendr]   r^   rb   r   r   r   ZmoveToThreadr#   r:   ÚquitZstartedr'   r    r.   rZ   r5   r[   r   r_   ÚremoveZ
isFinishedÚlenrN   r\   )r   ÚworkerZ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   rg   r   r   r   Úcreate_python_worker#  s    
z"WorkerManager.create_python_workerc             C   s   t ||d}|  |¡ |S )z%Create a new process worker instance.)r>   )r.   rj   )r   r=   r>   rg   r   r   r   Úcreate_process_worker)  s    
z#WorkerManager.create_process_workerc             C   s$   x| j D ]}| ¡  qW tƒ | _dS )zTerminate all worker processes.N)r[   r!   r   rY   )r   rg   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[   rc   )r   rg   r   r   r   rj   <  s    zWorkerManager._create_worker)rX   )N)N)r(   r)   r*   r+   r   r`   r'   rk   rl   rm   rj   r-   r   r   )r   r   rW   Û   s   
*
rW   c             C   s   t | ||ƒ dS )zPrint worker output for tests.N)Úprint)rg   r%   r$   r   r   r   Úready_printC  s    ro   rX   c             C   s.   ddl }| |¡ |dk	r&| | ¡ n| S dS )z5This methods illustrates how the workers can be used.r   N)ÚtimeZsleepZput)ÚargÚsecsZresult_queuerp   r   r   r   Úsleeping_funcH  s
    
rs   c              C   s²   ddl m}  | ƒ }tdd}x:tdƒD ].}|jtd |¡dd}|j t	¡ | 
¡  q&W |jtd	dd}|j t	¡ | 
¡  | d
ddg¡}|j t	¡ | 
¡  t | ¡ ¡ dS )zMain local test.r   )Úqapplicationé   )ra   é   zBOOM! {}é   )rr   zBOOM!ZcondaÚinfoz--jsonN)Zspyder.utils.qthelpersrt   rW   Úrangerk   rs   Úformatr#   r:   ro   r    rl   ÚsysÚexitZexec_)rt   ZappZwmÚirg   r   r   r   Ú
local_testR  s    
r~   Ú__main__)rX   N)r+   Úcollectionsr   Úosr{   Zqtpy.QtCorer   r   r   r   r   r   Zspyder.py3compatr	   r
   Únamer?   r   r   r.   rW   ro   rs   r~   r(   r   r   r   r   Ú<module>   s     
/ h

