a
    a8:                     @   s  d Z ddlmZ dZg dZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlZddlmZ ddlmZmZmZ ddlmZ dd	lmZ zdd
lmZmZ W n ey   dZdZY n0 edZdd Zd ZZz ej !edZej !edZW nT e"yb   z ej !edZej !edZW n e"y\   e \ZZY n0 Y n0 dZ#dZ$e%ej&ddp~dZ'e'( dkrdZ'd+ddZ)e dd Z*G dd dZ+ee$e$e'dfddZ,e'dfd d!Z-da.e/ Z0e'dfd"d#Z1d$d% Z2d&a3d'd( Z4d)d* Z5dS ),zhCapture C-level FD output on pipes

Use `wurlitzer.pipes` or `wurlitzer.sys_pipes` as context managers.
    )print_functionz3.0.2)pipes	sys_pipessys_pipes_foreverstop_sys_pipes	WurlitzerN)contextmanager)F_GETFLF_SETFLfcntl)	lru_cache)Queue)F_GETPIPE_SZF_SETPIPE_SZi  i  c               
   C   s   zddl } W n ty&   tdY n0 zP|  }|d |d |dg d}t| }t|	 }W n6 t
y } ztd| W Y d}~d	S d}~0 0 ||fS dS )
zeUse CFFI to lookup stdout/stderr pointers

    Should work ~everywhere, but requires compilation
    r   Nz@Failed to lookup stdout symbols in libc. Fallback requires cffi.zconst size_t c_stdout_p();zconst size_t c_stderr_p();
)z#include <stdio.h>z=const size_t c_stdout_p() { return (size_t) (void*) stdout; }z=const size_t c_stderr_p() { return (size_t) (void*) stderr; }zBFailed to lookup stdout with cffi: {}.
Streams may not be flushed.)NN)cffiImportErrorZFFIZcdefZverifyjoinctypesc_void_p
c_stdout_p
c_stderr_p	Exceptionwarningswarnformat)r   Z_ffiZ_libr   r   e r   (lib/python3.9/site-packages/wurlitzer.py_get_streams_cffi*   s2    


	r   stdoutstderrZ	__stdoutpZ	__stderrp      encodingutf8asciic                 C   s|   d}t td| D ]Z}zt| |W   S  tyl } z*|}|jtjkrVtd n W Y d}~qd}~0 0 q|rx|dS )z Like os.dup2, but retry on EBUSYN
   g?)	rangeintosdup2OSErrorerrnoZEBUSYtimesleep)abZtimeoutZdup_errir   r   r   r   r+   f   s    r+   c                  C   s~   t  dkrdS z:tdd} t|  }W d   n1 s>0    Y  W n ty\   Y n0 |dkrjdS |dkrvdS |S dS )a  Get max pipe size

    Reads /proc/sys/fs/pipe-max-size on Linux.
    Always returns None elsewhere.

    Returns integer (up to 1MB),
    or None if no value can be determined.

    Adapted from wal-e, (c) 2018, WAL-E Contributors
    used under BSD-3-clause
    ZLinuxNz/proc/sys/fs/pipe-max-sizeri   i   )platformsystemopenr)   readr   )fZpipe_max_sizer   r   r   _get_max_pipe_sizew   s    .r9   c                   @   sp   e Zd ZdZdZddee 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S )r   zcClass for Capturing Process-level FD output via dup2

    Typically used via `wurlitzer.pipes`
    g?Nc                 C   sf   || _ |tkr| j | _n|| _|| _|du r2t }|| _i | _i | _i | _| j	| jd< | j
| jd< dS )a  
        Parameters
        ----------
        stdout: stream or None
            The stream for forwarding stdout.
        stderr = stream or None
            The stream for forwarding stderr.
        encoding: str or None
            The encoding to use, if streams should be interpreted as text.
        bufsize: int or None
            Set pipe buffer size using fcntl F_SETPIPE_SZ (linux only)
            default: use /proc/sys/fs/pipe-max-size up to a max of 1MB
            if 0, will do nothing.
        Nr!   r    )_stdoutSTDOUT_stderrr$   r9   _bufsize	_save_fds	_real_fdsZ	_handlers_handle_stderr_handle_stdout)selfr    r!   r$   bufsizer   r   r   __init__   s    
zWurlitzer.__init__c                 C   s   t td|  }t|}|| j|< t \}}| jrjzt|t	| j W n t
yh   tdt Y n0 t|| t| || j|< t|t}t|t|tjB  |S )Nz__%s__zFailed to set pipe buffer size)getattrsysfilenor*   dupr>   piper=   r   r   r,   r   r   RuntimeWarningr+   closer?   r	   r
   
O_NONBLOCK)rB   namereal_fdsave_fdZpipe_outZpipe_inflagsr   r   r   _setup_pipe   s    





zWurlitzer._setup_pipec                 C   s   | j r|| j d}|S )zTDecode data, if any

        Called before passing to stdout/stderr streams
        replace)r$   decoderB   datar   r   r   _decode   s    zWurlitzer._decodec                 C   s   | j r| j | | d S N)r:   writerV   rT   r   r   r   rA      s    zWurlitzer._handle_stdoutc                 C   s   | j r| j | | d S rW   )r<   rX   rV   rT   r   r   r   r@      s    zWurlitzer._handle_stderrc                 C   s   | j | jf| _dS )zSetup handle for output, if anyN)r:   r<   handlerB   r   r   r   _setup_handle   s    zWurlitzer._setup_handlec                 C   s   dS )zCFinish handle, if anything should be done when it's all wrapped up.Nr   rZ   r   r   r   _finish_handle   s    zWurlitzer._finish_handlec                 C   sT   | j rtjrtj  | jr,tjr,tj  tdur>tt t	durPtt	 dS )z&flush sys.stdout/err and low-level FDsN)
r:   rF   r    flushr<   r!   r   libcZfflushr   rZ   r   r   r   _flush   s    


zWurlitzer._flushc                    s        t \__jgjdijrTd}| d|< j	rvd}| d|< t
   fdd}tj|dd_   fdd	}tj|d_dj_j  jS )
NZcontrolr    r!   c                     s"      } | dkrd S   q d S )Nstop)getr_   )msg)flush_queuerB   r   r   
flush_main  s    z'Wurlitzer.__enter__.<locals>.flush_main)targetTc                     s$  d} d}t  }D ]}||t j qr||}|r@d}n| rHqn d j}q(|D ]\}}|j}|jkrd} 	j |
j tj q^| }t|d}	|	s؈	| |
| t| q^td| }
|
|	 q^s(qq( d   dd	 D  |  d
S )z*Forward bytes on a pipe to stream messagesFr   r]   Ti   z
_handle_%sr`   c                 S   s   g | ]}t |qS r   )r*   rK   ).0rI   r   r   r   
<listcomp>Y      z:Wurlitzer.__enter__.<locals>.forwarder.<locals>.<listcomp>N)	selectorsZDefaultSelectorregisterZ
EVENT_READZselectZputflush_intervalfd
_control_rremove
unregisterr*   rK   r7   rE   r   )Zdrainingrk   ZpollerZpipe_eventsZselector_keyrP   rl   rM   rU   Zhandlerrc   Zflush_threadnamesr   rB   r   r   	forwarder$  sH    






z&Wurlitzer.__enter__.<locals>.forwarder)r_   r[   r*   rI   rm   
_control_wr:   rQ   appendr<   r   	threadingZThreadZdaemonstartthreadrY   )rB   rI   rd   rs   r   rq   r   	__enter__  s.    




8
zWurlitzer.__enter__c                 C   sj   |    t| jd | j  t| j | j D ]&\}}| j	| }t
|| t| q6|   d S )N   )r_   r*   rX   rt   rx   r   rK   r?   itemsr>   r+   r\   )rB   exc_type	exc_value	tracebackrM   rN   rO   r   r   r   __exit__b  s    


zWurlitzer.__exit__)__name__
__module____qualname____doc__rk   _default_encodingr9   rD   rQ   rV   rA   r@   r[   r\   r_   ry   r   r   r   r   r   r      s    
$	`r   c              	   c   s   d }}|rt j}nt j}| tkr2|  }}d}n|  }}|tkrLd}	|}
n |tkrd|  }	}
d}n| }	}
t||
||d}zN| ||	fV  W d   n1 s0    Y  W |r|d |r|	d n|r|d |r|	d 0 dS )ah  Capture C-level stdout/stderr in a context manager.

    The return value for the context manager is (stdout, stderr).

    .. versionchanged:: 3.0

        when using `PIPE` (default), the type of captured output
        is `io.StringIO/BytesIO` instead of an OS pipe.
        This eliminates max buffer size issues (and hang when output exceeds 65536 bytes),
        but also means the buffer cannot be read with `.read()` methods
        until after the context exits.

    Examples
    --------

    >>> with capture() as (stdout, stderr):
    ...     printf("C-level stdout")
    ... output = stdout.read()
    FTN)r    r!   r$   rC   r   )ioStringIOBytesIOPIPEr;   r   seek)r    r!   r$   rC   Zstdout_pipeZstderr_pipeZPipeIOZstdout_rZstdout_wZstderr_rZstderr_wwr   r   r   r   t  s6    

*

r   c                 C   s   t tjtj| |dS )zRedirect C-level stdout/stderr to sys.stdout/stderr

    This is useful of sys.sdout/stderr are already being forwarded somewhere.

    DO NOT USE THIS if sys.stdout and sys.stderr are not already being forwarded.
    r$   rC   )r   rF   r    r!   r   r   r   r   r     s    r   c                 C   sB   t * tdu r t| |at  W d   n1 s40    Y  dS )zvRedirect all C output to sys.stdout/err

    This is not a context manager; it turns on C-forwarding permanently.
    N)_mighty_lock_mighty_wurlitzerr   ry   r   r   r   r   r     s    
r   c                   C   sB   t * tdur tddd daW d   n1 s40    Y  dS )z7Stop permanent redirection started by sys_pipes_foreverN)r   r   r   r   r   r   r   r     s    r   Fc                 C   sf   t | ddstd dS dD ]"}t t|du rtd  dS q| jdt | jdt dadS )	zRegister me as an IPython extension

    Captures all C output during execution and forwards to sys.

    Does nothing on terminal IPython.

    Use: %load_ext wurlitzer
    ZkernelNz;wurlitzer extension doesn't do anything in terminal IPython)
__stdout__
__stderr__z:sys.{} is None. Wurlitzer can't capture output without it.pre_executepost_executeT)	rE   r   r   rF   rp   rj   r   r   _extension_enabled)iprM   r   r   r   load_ipython_extension  s    

r   c                 C   s2   t sdS | jdt | jdt t  da dS )zFUnload me as an IPython extension

    Use: %unload_ext wurlitzer
    Nr   r   F)r   rp   ro   r   r   )r   r   r   r   unload_ipython_extension  s    r   )r#   )6r   Z
__future__r   __version____all__r   r-   r   r*   r4   ri   rF   rv   r.   r   
contextlibr   r   r	   r
   	functoolsr   Zqueuer   r   r   r   ZCDLLr^   r   r   r   r   Zin_dll
ValueErrorr;   r   rE   stdinr   lowerr+   r9   r   r   r   r   ZLockr   r   r   r   r   r   r   r   r   r   <module>   sl   

&

" [6
	