B
    \5E              	   @   s  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mZmZmZmZ ddlmZ ddlmZ ddlmZ ddlmZ d	d
 ZG dd deZG dd deZdd Zd9ddZdd Zdd Z ej!ddZ"e"j#dddd e"j#ddd d! e"j#d"d#d$ e"j#d%d&d'dde$d(d) e"j#d*dd+d! e"j#d,d'dd-d.d/ e"j#d0d1d2d3 d4d5 Z%d6d7 Z&e'd8kre&  dS ):z|IPython Test Process Controller

This module runs one or more subprocesses which will actually run the IPython
test suite.

    N   )havetest_group_namestest_sectionsStreamCapturer)compress_user)decode)get_sys_info)TemporaryDirectoryc             C   s
   |  |S )N)wait)pZtimeout r   ?lib/python3.7/site-packages/IPython/testing/iptestcontroller.py
popen_wait   s    r   c               @   sf   e Zd ZdZdZdZdZdZdZdZ	dd Z
dd Zddd	Zd
d Zdd Zdd Zdd ZeZdS )TestControllerzRun tests in a subprocess
    Nc             C   s   g | _ i | _g | _d S )N)cmdenvdirs)selfr   r   r   __init__2   s    zTestController.__init__c             C   s   dS )zCreate temporary directories etc.
        
        This is only called when we know the test group will be run. Things
        created here may be cleaned up by self.cleanup().
        Nr   )r   r   r   r   setup7   s    zTestController.setupFc             C   sn   t j }|| j |rd}t| d | _}|  |rB|jnd }|rPt	j
nd }t	j| j|||d| _d S )NT)Zecho)stdoutstderrr   )osenvironcopyupdater   r   stdout_capturerstartZwritefd
subprocessZSTDOUTPopenr   process)r   buffer_outputZcapture_outputr   cr   r   r   r   r   launch?   s    

zTestController.launchc             C   s(   | j   | j  | j | _| j jS )N)r!   r   r   ZhaltZ
get_bufferr   
returncode)r   r   r   r   r   M   s    

zTestController.waitc             C   s   dS )a^  Print extra information about this test run.
        
        If we're running in parallel and showing the concise view, this is only
        called if the test group fails. Otherwise, it's called before the test
        group is started.
        
        The base implementation does nothing, but it can be overridden by
        subclasses.
        Nr   )r   r   r   r   print_extra_infoS   s    
zTestController.print_extra_infoc             C   s   | j }|dks| dk	rdS ytd|j  |  W n   Y n.X x*tdD ]}| dkrltd qPP qPW | dkrtd dS )z2Cleanup on exit by killing any leftover processes.NzCleaning up stale PID: %d
   g?z+... failed. Manual cleanup may be required.)r!   ZpollprintpidkillrangetimeZsleep)r   Zsubpir   r   r   cleanup_process_   s    zTestController.cleanup_processc             C   s$   |    x| jD ]}|  qW dS )zDKill process if it's still alive, and clean up temporary directoriesN)r.   r   cleanup)r   Ztdr   r   r   r/   w   s    zTestController.cleanup)FF)__name__
__module____qualname____doc__sectionr   r   r   r!   r   r   r   r$   r   r&   r.   r/   __del__r   r   r   r   r   "   s   
r   c                   sZ   e Zd ZdZdZdd Zdd Zdd Zed	d
 Z	dd Z
dd Zd fdd	Z  ZS )PyTestControllerz-Run Python tests using IPython.testing.iptestNc             C   s0   t |  || _tjdd|g| _d| _|| _dS )zCreate new test runner.z-cNz;from IPython.testing.iptest import run_iptest; run_iptest())r   r   r4   sys
executabler   pycmdoptions)r   r4   r:   r   r   r   r      s
    
zPyTestController.__init__c             C   s   t  }| j| |j| jd< t   | _}| j| |j| jd< |j| jd< |j| jd< tj| jjd}|| _	t
|d tjdd}|r|tj | }n|}|| jd< | jjr|   | jjr|   | jj| jd	< | j| jj d S )
NZ
IPYTHONDIRZIPTEST_WORKING_DIRZMPLCONFIGDIRZTMPDIRZ_no_access_r   PATH ZIPTEST_SUBPROC_STREAMS)r
   r   appendnamer   
workingdirr   pathjoinnoaccessmkdirr   getpathsepr:   Zxunit	add_xunitcoverageadd_coverageZsubproc_streamsr   extend
extra_args)r   Zipydirr?   rB   r;   r   r   r   r      s,    
zPyTestController.setupc             C   s   t | jtj t|  dS )z
        Make the non-accessible directory created in setup() accessible
        again, otherwise deleting the workingdir will fail.
        N)r   chmodrB   statS_IRWXUr   r/   )r   r   r   r   r/      s    zPyTestController.cleanupc             C   s&   yt | j jS  tk
r    dS X d S )NT)r   r4   will_runKeyError)r   r   r   r   rN      s    zPyTestController.will_runc             C   s(   t j| jd }| jdd|g d S )Nz
.xunit.xmlz--with-xunitz--xunit-file)r   r@   abspathr4   r   rI   )r   Z
xunit_filer   r   r   rF      s    zPyTestController.add_xunitc          	   C   s   yt | j j}W n tk
r*   dg}Y nX djtjd| j d|d}tj| j	j
d}t|d}|| W d Q R X || jd< d	| j | _d S )
NIPythonz2[run]
data_file = {data_file}
source =
  {source}
z
.coverage.z
  )	data_filesourcez.coveragercwZCOVERAGE_PROCESS_STARTz-import coverage; coverage.process_startup(); )r   r4   ZincludesrO   formatr   r@   rP   rA   r?   r>   openwriter   r9   )r   ZsourcesZcoverage_rcZconfig_filefr   r   r   rH      s    
zPyTestController.add_coverageFc                s"   | j | jd< tt| j|d d S )N   )r"   )r9   r   superr6   r$   )r   r"   )	__class__r   r   r$      s    zPyTestController.launch)F)r0   r1   r2   r3   r9   r   r   r/   propertyrN   rF   rH   r$   __classcell__r   r   )r[   r   r6      s   	!r6   c                sD    j }|st} fdd|D }dd |D }dd |D }||fS )zVReturns two lists of TestController instances, those to run, and those
    not to run.c                s   g | ]}t | qS r   )r6   ).0r>   )r:   r   r   
<listcomp>   s    z'prepare_controllers.<locals>.<listcomp>c             S   s   g | ]}|j r|qS r   )rN   )r^   r#   r   r   r   r_      s    c             S   s   g | ]}|j s|qS r   )rN   )r^   r#   r   r   r   r_      s    )
testgroupspy_test_group_names)r:   r`   Zcontrollersto_runnot_runr   )r:   r   prepare_controllers   s    rd   Tc             C   s   zy^y$|    |s|   | j|d W n( tk
rP   ddl}|  | dfS X |  }| |fS  tk
r|   | tj	 fS X W d| 
  X dS )a  Setup and run a test controller.
    
    If buffer_output is True, no output is displayed, to avoid it appearing
    interleaved. In this case, the caller is responsible for displaying test
    output on failure.
    
    Returns
    -------
    controller : TestController
      The same controller as passed in, as a convenience for using map() type
      APIs.
    exitcode : int
      The exit code of the test subprocess. Non-zero indicates failure.
    )r"   r   Nr   )r   r&   r$   	Exception	traceback	print_excr   KeyboardInterruptsignalSIGINTr/   )
controllerr"   rf   Zexitcoder   r   r   do_run   s    
rl   c                 sL  t  } g   fdd}|d| d  |dd| d | d  |d	t| d
  |d| d dd |dt| d  |d| d  tdd  D fdd D  g }g }x.t D ]"\}}|r|| q|| qW |r d |   dd	| d  |rB d |   dd	| d  d	 S )z@Return a string with a summary report of test-related variables.c                s     | |f d S )N)r=   )r>   value)outr   r   _add  s    zreport.<locals>._addzIPython versionZipython_versionzIPython commitz{} ({})Zcommit_hashZcommit_sourcezIPython packageZipython_pathzPython versionsys_version
r<   zsys.executableZsys_executableZPlatformplatformc             s   s   | ]\}}t |V  qd S )N)len)r^   nvr   r   r   	<genexpr>  s    zreport.<locals>.<genexpr>c                s    g | ]\}}d j || dqS )z{:<{width}}: {}
)width)rU   )r^   rt   ru   )rw   r   r   r_     s    zreport.<locals>.<listcomp>z-
Tools and libraries available at test time:
z    z1
Tools and libraries NOT available at test time:
)
r	   rU   r   replacemaxr   itemsr=   sortrA   )infro   ZavailZ	not_availkZis_availr   )rn   rw   r   report	  s4    

r   c          
      s>  t | \}}d0dd}g }t }t  | jdkrx\|D ]T}td|j tj  t|dd\}}|r|	| |t
j krtd	 P t  q8W nytj| j}xv|t|D ]f\}}|d
krdnd}	t|d|j |	 |r|  tt|j |	| |t
j krtd	 P qW W n tk
r2   dS X x"|D ]}t|d|j d q:W t }
|
| }t|}t|}td td tt  d| }tddd |std| | nHdd |D }td||d|| t  td td1|  t  | jr*d
dlm}m} |dd}|  |  | jd krd!}tj|d"d# td$| dd tj  d
d%lm} G  fd&d'd'| |  |j j!d(t"j#|d)d*  ||j }|d td+ nZ| jd,kr*y|j$d-d. W n< |k
r( } ztd/ d
dl%}|&  W dd}~X Y nX |r:t'd dS )2a  Run the entire IPython test suite by calling nose and trial.

    This function constructs :class:`IPTester` instances for all IPython
    modules and package and then runs each of them.  This causes the modules
    and packages of IPython to be tested each in their own subprocess using
    nose.

    Parameters
    ----------

    All parameters are passed as attributes of the options object.

    testgroups : list of str
      Run only these sections of the test suite. If empty, run all the available
      sections.

    fast : int or None
      Run the test suite in parallel, using n simultaneous processes. If None
      is passed, one process is used per CPU core. Default 1 (i.e. sequential)

    inc_slow : bool
      Include slow tests. By default, these tests aren't run.

    url : unicode
      Address:port to use when running the JS tests.

    xunit : bool
      Produce Xunit XML output. This is written to multiple foo.xunit.xml files.

    coverage : bool or str
      Measure code coverage from tests. True will store the raw coverage data,
      or pass 'html' or 'xml' to get reports.

    extra_args : list
      Extra arguments to pass to the test subprocesses, e.g. '-v'
    F   -c             S   s(   | d7 } d|  |t|  |}| | S )Nrx   )rjustrs   )ZltextZrtextrw   Zfillr   r   r   justifyV  s    zrun_iptestall.<locals>.justifyr   zTest group:F)r"   ZInterruptedr   ZOKZFAILEDzTest group: NzNOT RUNZF______________________________________________________________________z?Test suite completed for system with the following information:zTook %.3fs.zStatus: r<   )endzOK (%d test groups).c             S   s   g | ]
}|j qS r   )r4   )r^   r#   r   r   r   r_     s    z!run_iptestall.<locals>.<listcomp>z-ERROR - {} out of {} test groups failed ({}).z, z"You may wish to rerun these, with:  iptest)rG   CoverageExceptionz	.coverage)rR   ZhtmlZipy_htmlcovT)ignore_errorsz(Writing HTML coverage report to %s/ ... )HtmlReporterc                   s   e Zd Z fddZ  ZS )z)run_iptestall.<locals>.CustomHtmlReporterc                sZ   t  | | xD| jD ]:}|jtj}d|kr4q|d}d||d  |_qW d S )NrQ   .)	rZ   find_code_unitsZ
code_unitsr>   splitr   sepindexrA   )r   ZmorfsZcuZ	namepartsix)CustomHtmlReporterr[   r   r   r     s    
z9run_iptestall.<locals>.CustomHtmlReporter.find_code_units)r0   r1   r2   r   r]   r   )r   )r[   r   r     s   r   z*{0}tests{0}*zIPython test coverage)Zomithtml_dirZ
html_titlezdone.Zxmlzipy_coverage.xml)ZoutfilezIGenerating coverage report failed. Are you running javascript tests only?)r   r   )r   )(rd   r,   r(   Zfastr4   r7   r   flushrl   r=   ri   rj   multiprocessingpoolZ
ThreadPoolZimap_unorderedr&   r   rh   rs   r   rU   rA   rG   r   ZcombineZsaveshutilZrmtreeZcoverage.htmlr   get_dataZconfigZ	from_argsr   r   Z
xml_reportrf   rg   exit)r:   rb   rc   r   ZfailedZt_startrk   Zresr   Z
res_stringZt_endZt_testsZnrunnersZnfailZtookZfailed_sectionsrG   r   Zcovr   r   Zreportererf   r   )r   r   run_iptestall/  s    %












r   zRun IPython test suite)Zdescriptionr`   *z9Run specified groups of tests. If omitted, run all tests.)nargshelpz--all
store_truez&Include slow tests not run by default.)actionr   z--urlzURL to use for the JS tests.)r   z-jz--fast?zlRun test sections in parallel. This starts as many processes as you have cores, or you can specify a number.)r   constdefaulttyper   z--xunitzProduce Xunit XML resultsz
--coverageFz>Measure test coverage. Specify 'html' or 'xml' to get reports.)r   r   r   r   z--subproc-streamsZcapturezkWhat to do with stdout/stderr from subprocesses. 'capture' (default), 'show' and 'discard' are the options.)r   r   c              C   s   t g } g | _| S )zgGet an argparse Namespace object with the default arguments, to pass to
    :func:`run_iptestall`.
    )	argparser
parse_argsrJ   )r:   r   r   r   default_options  s    
r   c              C   s   t jt jt  dddr6tdtjd td ytj	
d} W n& tk
rl   tj	dd  }g }Y n"X tj	d|  }tj	| d d  }t|}||_t| d S )NrQ   Ztestingz__main__.pyz2Don't run iptest from the IPython source directory)filer   z--)r   r@   existsrA   getcwdr(   r7   r   r   argvr   
ValueErrorr   r   rJ   r   )r   Zto_parserJ   r:   r   r   r   main  s    



r   __main__)T)(r3   argparseZmultiprocessing.poolr   r   rL   r   ri   r7   r   r,   Ziptestr   r   ra   r   r   ZIPython.utils.pathr   ZIPython.utils.py3compatr   ZIPython.utils.sysinfor	   ZIPython.utils.tempdirr
   r   objectr   r6   rd   rl   r   r   ArgumentParserr   add_argumentintr   r   r0   r   r   r   r   <module>   sP   ^Z
"& 
