B
    \y                 @   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	m
Z
 ddlmZ ddlmZ ddlmZ ddlmZmZmZmZmZmZmZmZmZ ddlmZmZ dd	lmZmZ ee Z!d
d Z"G dd de#Z$G dd dej%Z%G dd dej&Z'G dd dej(Z(G dd dej)Z*G dd dej)Z+G dd dej,Z-e.dZ/G dd deje#Z0G dd dej1Z1G dd  d ej2Z3G d!d" d"e3Z4dS )#a  Nose Plugin that supports IPython doctests.

Limitations:

- When generating examples for use as doctests, make sure that you have
  pretty-printing OFF.  This can be done either by setting the
  ``PlainTextFormatter.pprint`` option in your configuration file to  False, or
  by interactively disabling it with  %Pprint.  This is required so that IPython
  output matches that of normal Python, which is used by doctest for internal
  execution.

- Do not rely on specific prompt numbers for results (such as using
  '_34==True', for example).  For IPython tests run via an external process the
  prompt numbers may be different, and IPython tests run as normal python code
  won't even have these special _NN variables set at all.
    N)import_module)StringIO)modified_env)	getmodule)	REPORTING_FLAGSREPORT_ONLY_FIRST_FAILURE_unittest_reportflagsDocTestRunner_extract_future_flagspdb_OutputRedirectingPdb_exception_traceback	linecache)doctestsPlugin)anyptolistc             C   s   t j| d  dkS )zReturn whether the given filename is an extension module.

    This simply checks that the extension is either .so or .pyd.
       )z.soz.pyd)ospathsplitextlower)filename r   ?lib/python3.7/site-packages/IPython/testing/plugin/ipdoctest.pyis_extension_module<   s    r   c               @   s$   e Zd ZdZdZdd Zdd ZdS )DocTestSkipz*Object wrapper for doctests to be skipped.z/Doctest to skip.
    >>> 1 #doctest: +SKIP
    c             C   s
   || _ d S )N)obj)selfr   r   r   r   __init__K   s    zDocTestSkip.__init__c             C   s$   |dkrt jS tt| d|S d S )N__doc__r   )r   ds_skipgetattrobject__getattribute__)r   keyr   r   r   r$   N   s    zDocTestSkip.__getattribute__N)__name__
__module____qualname__r    r!   r   r$   r   r   r   r   r   D   s   r   c               @   s   e Zd Zdd Zdd ZdS )DocTestFinderc             C   s   |dkrdS t |r"|j|jkS t |r8|j|jkS t |rN|j|jkS t |rh|j|j	j
jkS t |dk	r|t |kS t|dr|j|jkS t|trdS t |rdS td| dS )zY
        Return true if the given object is defined in the given
        module.
        NTr'   Fz*object must be a class or function, got %r)inspect
isfunction__dict____globals__Z	isbuiltinr&   r'   isclassismethod__self__	__class__r   hasattr
isinstancepropertyZismethoddescriptor
ValueError)r   moduler#   r   r   r   _from_moduleX   s&    






zDocTestFinder._from_modulec          
   C   sh  t d||| t|dr t|}tj| ||||||| ddlm}m}	 t	|r| j
rxT|j D ]F\}
}d||
f }||s|	|rf| ||rf| ||||||| qfW t|rd| j
rdx|j D ]\}
}t|trt||
}t|trt||
j}t|s2t|s2t|s2t|tr| ||rd||
f }
| |||
|||| qW dS )zm
        Find tests for the given object and any contained objects, and
        add them to `tests`.
        z
_find for:Zskip_doctestr   )	isroutiner.   z%s.%sN)printr2   r   doctestr)   _findr*   r8   r.   ZismoduleZ_recurser,   itemsr7   r3   staticmethodr"   classmethod__func__r+   r/   r4   )r   testsr   namer6   source_linesglobsseenr8   r.   ZvalnamevalZvalname1r   r   r   r;   x   s4    




zDocTestFinder._findN)r&   r'   r(   r7   r;   r   r   r   r   r)   V   s    r)   c               @   s"   e Zd ZdZedZdd ZdS )IPDoctestOutputCheckerzSecond-chance checker with support for random tests.

    If the default comparison doesn't pass, this checker looks in the expected
    output string for flags that tell us to ignore the output.
    z#\s*random\s+c             C   s*   t j| |||}|s&| j|r&dS |S )zCheck output, accepting special markers embedded in the output.

        If the output didn't pass the default validation but the special string
        '#random' is included, we accept it.T)r:   OutputCheckercheck_output	random_research)r   wantZgotoptionflagsZretr   r   r   rH      s
    z#IPDoctestOutputChecker.check_outputN)r&   r'   r(   r    recompilerI   rH   r   r   r   r   rF      s   
rF   c                   s>   e Zd ZdZdddZdd Z fd	d
Z fddZ  ZS )DocTestCaseaN  Proxy for DocTestCase: provides an address() method that
    returns the correct address for the doctest case. Otherwise
    acts as a proxy to the test case. To provide hints for address(),
    an obj may also be passed -- this will be used as the test object
    for purposes of determining the test address, if it is provided.
    r   N_c       	      C   sl   || _ tjj| |||||d || _|| _|| _|j| _|| _	|| _
t||dd}|| _tj|j| _d S )N)rL   setUptearDowncheckerF)rL   rS   verbose)_result_varr   rO   r   _dt_optionflagsZ_dt_checker_dt_testrC   _dt_test_globs_oriZ	_dt_setUpZ_dt_tearDownIPDocTestRunner
_dt_runnerr   r   dirnamer   _ori_dir)	r   testrL   rQ   rR   rS   r   Z
result_varrunnerr   r   r   r      s    

zDocTestCase.__init__c       	   	   C   s   | j }| j}tj}t }| j}|t@ s.|tO }z4t	 }t
| j d|_|j||jdd\}}W d |t_t
| X |r| | | d S )NzF----------------------------------------------------------------------F)outclear_globs)rW   rZ   sysstdoutr   rV   r   r   r   getcwdchdirr\   ZDIVIDERrunwriteZfailureExceptionZformat_failuregetvalue)	r   r]   r^   oldnewrL   curdirZfailuresZtriesr   r   r   runTest   s"    
zDocTestCase.runTestc                sj   t | jjd trXi | _| jtj tj| jj tj	dd t
tjd< tj| j_tt|   dS )z5Modified test setup that syncs with ipython namespacer   rP   N__builtins__)r3   rW   examples	IPExampleuser_ns_origupdate_ipuser_nsrC   popbuiltin_modsuperrO   rQ   )r   )r1   r   r   rQ     s    

zDocTestCase.setUpc          
      s   t | jjd tr4| j| j_tj  tj	| j
 ytt|   W n4 tk
rz } z|jd | jkrj W d d }~X Y nX d S )Nr   )r3   rW   rm   rn   rX   rC   rq   rr   clearrp   ro   ru   rO   rR   AttributeErrorargsrU   )r   exc)r1   r   r   rR      s    

zDocTestCase.tearDown)r   NNNNrP   )	r&   r'   r(   r    r   rk   rQ   rR   __classcell__r   r   )r1   r   rO      s    
rO   c               @   s   e Zd ZdS )rn   N)r&   r'   r(   r   r   r   r   rn   A  s    rn   c               @   s   e Zd ZdZdddZdS )IPExternalExamplez2Doctest examples to be run in an external process.Nr   c          	   C   s*   t j| |||||| |  jd7  _d S )N
)r:   Exampler   source)r   r~   rK   exc_msglinenoindentoptionsr   r   r   r   G  s    zIPExternalExample.__init__)Nr   r   N)r&   r'   r(   r    r   r   r   r   r   r{   D  s    r{   c               @   s   e Zd ZdZdZdZdZdZdZe	
eeeeef e	je	jB Ze	
eeeeef e	je	jB Ze	
dZe	
dZd	d
 ZdddZdddZdd ZdS )IPDocTestParserz
    A class used to parse strings containing doctest examples.

    Note: This is a version modified to properly recognize IPython input and
    convert any IPython examples into valid Python ones.
    z>>>z\.\.\.zIn\ \[\d+\]:z\ \ \ \.\.\.+:a]  
        # Source consists of a PS1 line followed by zero or more PS2 lines.
        (?P<source>
            (?:^(?P<indent> [ ]*) (?P<ps1> %s) .*)    # PS1 line
            (?:\n           [ ]*  (?P<ps2> %s) .*)*)  # PS2 lines
        \n? # a newline
        # Want consists of any non-blank lines that do not start with PS1.
        (?P<want> (?:(?![ ]*$)    # Not a blank line
                     (?![ ]*%s)   # Not a line starting with PS1
                     (?![ ]*%s)   # Not a line starting with PS2
                     .*$\n?       # But any other line
                  )*)
                  z#\s*all-random\s+z#\s*ipdoctest:\s*EXTERNALc             C   s.   t j|}t| dkr&t |S |S dS )z/Convert input IPython source into valid Python.r   N)rq   Zinput_transformer_managerZtransform_celllen
splitlinesZ	prefilter)r   r~   blockr   r   r   ip2py  s    
zIPDocTestParser.ip2py<string>c                s  |  }| |  dkr8d fdd|dD }g }d\}}| j|rVd}nd}d}t| j|}|rzt	j
}	n*t| j|}| j|rt}	nt}	d	}x|D ]}
||||
   ||d||
 7 }| |
|||\}}}}||7 }|	tkrd	|t	j< |d7 }| |sJ||	|||| t|
d
 |d ||d|
 |
 7 }|
 }qW |||d  |S )a=  
        Divide the given string into examples and intervening text,
        and return them as a list of alternating Examples and strings.
        Line numbers for the Examples are 0-based.  The optional
        argument `name` is a name identifying this string, and is only
        used for error messages.
        r   r|   c                s   g | ]}| d  qS )Nr   ).0l)
min_indentr   r   
<listcomp>  s    z)IPDocTestParser.parse.<locals>.<listcomp>)r   r   z	
# random FTr   )r   r   r   N)
expandtabsZ_min_indentjoinsplit_RANDOM_TESTrJ   list_EXAMPLE_RE_PYfinditerr:   r}   _EXAMPLE_RE_IP_EXTERNAL_IPr{   rn   appendstartcount_parse_exampleNORMALIZE_WHITESPACEZ_IS_BLANK_OR_COMMENTr   groupend)r   stringrA   outputZcharnor   Zrandom_markerr   Ztermsr}   mr~   r   rK   r   r   )r   r   parse  sF    




zIPDocTestParser.parseFc                sT  t |d |dd}|d}|d}t || | || |rp| |dd d  | || d fd	d
|D }|r| |}|d}	|	d}
t |
dkrtd|
d r|
d= | |
d  ||t |  t	dd|
d |
d< d fdd
|
D }	| j
|	}|r6|d}nd}| |||}|||	|fS )a7  
        Given a regular expression match from `_EXAMPLE_RE` (`m`),
        return a pair `(source, want)`, where `source` is the matched
        example's source code (with prompts and indentation stripped);
        and `want` is the example's expected output (with indentation
        stripped).

        `name` is the string's name, and `lineno` is the line number
        where the example starts; both are used for error messages.

        Optional:
        `ip2py`: if true, filter the input via IPython to convert the syntax
        into valid python.
        r   r~   r|   ps1ps2r   N c                s    g | ]}|  d  d qS )r   Nr   )r   Zsl)r   ps1_lenr   r   r     s    z2IPDocTestParser._parse_example.<locals>.<listcomp>rK   z *$zOut\[\d+\]: \s*?\n?r   r   c                s   g | ]}| d  qS )Nr   )r   Zwl)r   r   r   r     s    msg)r   r   r   _check_prompt_blankZ_check_prefixr   r   rM   matchsubZ_EXCEPTION_REZ_find_options)r   r   rA   r   r   rB   r   r   r~   rK   Z
want_linesr   r   r   )r   r   r   r     s2    

 


zIPDocTestParser._parse_examplec       
      C   sf   || }|d }xPt |D ]D\}}	t|	|kr|	| dkrtd|| d ||	|| |	f qW dS )a  
        Given the lines of a source string (including prompts and
        leading indentation), check to make sure that every prompt is
        followed by a space character.  If any line is not followed by
        a space character, then raise ValueError.

        Note: IPython-modified version which takes the input prompt length as a
        parameter, so that prompts of variable length can be dealt with.
        r   r   z8line %r of the docstring for %s lacks blank after %s: %rN)	enumerater   r5   )
r   linesr   rA   r   r   Z	space_idxZmin_leniliner   r   r   r      s    
z#IPDocTestParser._check_prompt_blankN)r   )F)r&   r'   r(   r    Z_PS1_PYZ_PS2_PYZ_PS1_IPZ_PS2_IPZ_RE_TPLrM   rN   	MULTILINEVERBOSEr   r   r   r   r   r   r   r   r   r   r   r   r   P  s    


W
Ar   SKIPc                   s"   e Zd ZdZd fdd	Z  ZS )rY   zKTest runner that synchronizes the IPython namespace with test globals.
    NTc          	      s>   |j tj tddd tt| ||||S Q R X d S )NZ80Z24)ZCOLUMNSZLINES)rC   rp   rq   rr   r   ru   rY   re   )r   r]   Zcompileflagsr_   r`   )r1   r   r   re   ;  s    zIPDocTestRunner.run)NNT)r&   r'   r(   r    re   rz   r   r   )r1   r   rY   7  s   rY   c               @   s   e Zd ZdZdd ZdS )DocFileCasez"Overrides to provide filename
    c             C   s   | j jd d fS )N)rW   r   )r   r   r   r   addressQ  s    zDocFileCase.addressN)r&   r'   r(   r    r   r   r   r   r   r   N  s   r   c               @   sF   e Zd ZdZdZdZejfddZdd Z	dd	 Z
d
d Zdd ZdS )ExtensionDoctestz=Nose Plugin that supports doctests in extension modules.
    Z
extdoctestTc             C   sb   t | || |jddd|dddd |jdd	d
dd |d}|d k	r^|jt|d d S )Nz--doctest-tests
store_truedoctest_testsZNOSE_DOCTEST_TESTSTzAlso look for doctests in test modules. Note that classes, methods and functions should have either doctests or non-doctest tests, not both. [NOSE_DOCTEST_TESTS])actiondestdefaulthelpz--doctest-extensionr   doctestExtensionzLAlso look for doctests in files with this extension [NOSE_DOCTEST_EXTENSION])r   r   r   ZNOSE_DOCTEST_EXTENSION)r   )r   r   
add_optiongetset_defaultsr   )r   parserenvenv_settingr   r   r   r   [  s    

zExtensionDoctest.optionsc             C   sb   t | || dd |jjD |j_|j| _t|j| _t | _	t
 | _t | _d | _d | _d S )Nc             S   s   g | ]}|j d kr|qS )r:   )rA   )r   pr   r   r   r   s  s    z.ExtensionDoctest.configure.<locals>.<listcomp>)r   	configurepluginsr   r   r   	extensionr:   DocTestParserr   r)   finderrF   rS   rC   
extraglobs)r   r   configr   r   r   r   p  s    
zExtensionDoctest.configurec             C   sX   t j|\}}t j|d }z&tj| t|}t| |}W d tj	  X |S )Nr   )
r   r   r   r   ra   r   r   r   loadTestsFromModulers   )r   r   Zbpathmodmodnamer6   r@   r   r   r   loadTestsFromExtensionModule  s    z-ExtensionDoctest.loadTestsFromExtensionModulec             c   s   |  |jstd| d S | jj|| j| jd}|s:d S tj	tj
B }|  |j}|dd  dkrp|d d }x2|D ]*}|jsqv|js||_t||| jdV  qvW d S )NzDoctest doesn't want module %s)rC   r   )z.pycz.pyor   )rL   rS   )Zmatchesr&   logdebugr   findrC   r   r:   r   ELLIPSISsort__file__rm   r   rO   rS   )r   r6   r@   rL   Zmodule_filer]   r   r   r   r     s(    

z$ExtensionDoctest.loadTestsFromModulec          	   c   s   t |r$x| |D ]
}|V  qW nn| jrt|j| jrtj|}t|}|	 }W d Q R X | j
j|d|i||dd}|jrt|V  ndV  d S )Nr   r   )rC   rA   r   r   F)r   r   r   r   endswithr   r   basenameopenreadr   Zget_doctestrm   r   )r   r   trA   Zdhdocr]   r   r   r   loadTestsFromFile  s    


z"ExtensionDoctest.loadTestsFromFileN)r&   r'   r(   r    rA   enabledr   environr   r   r   r   r   r   r   r   r   r   U  s   r   c               @   s6   e Zd ZdZdZdZdd ZejfddZ	dd	 Z
d
S )IPythonDoctestz=Nose Plugin that supports doctests in extension modules.
    Z	ipdoctestTc             c   sZ   t jt jB }| jj|t|d}|rVx0|D ](}t|jdkr>q*t|||| j	dV  q*W dS )zbLook for doctests in the given object, which will be a
        function, method or class.
        )r6   r   )r   rL   rS   N)
r:   r   r   r   r   r   r   rm   rO   rS   )r   r   parentrL   r   r]   r   r   r   makeTest  s    
zIPythonDoctest.makeTestc             C   sb   t | || |jddd|dddd |jdd	d
dd |d}|d k	r^|jt|d d S )Nz--ipdoctest-testsr   ipdoctest_testsZNOSE_IPDOCTEST_TESTSTzAlso look for doctests in test modules. Note that classes, methods and functions should have either doctests or non-doctest tests, not both. [NOSE_IPDOCTEST_TESTS])r   r   r   r   z--ipdoctest-extensionr   ipdoctest_extensionzNAlso look for doctests in files with this extension [NOSE_IPDOCTEST_EXTENSION])r   r   r   ZNOSE_IPDOCTEST_EXTENSION)r   )r   r   r   r   r   r   )r   r   r   r   r   r   r   r     s    

zIPythonDoctest.optionsc             C   sf   t | || dd |jjD |j_|j| _t|j| _t | _	t
| j	d| _t | _d | _d | _d S )Nc             S   s   g | ]}|j d kr|qS )r:   )rA   )r   r   r   r   r   r     s    z,IPythonDoctest.configure.<locals>.<listcomp>)r   )r   r   r   r   r   r   r   r   r   r   r)   r   rF   rS   rC   r   )r   r   r   r   r   r   r     s    zIPythonDoctest.configureN)r&   r'   r(   r    rA   r   r   r   r   r   r   r   r   r   r   r     s   r   )5r    builtinsrt   r:   r*   Zloggingr   rM   ra   	importlibr   ior   Ztestpathr   r   r   r   r   r	   r
   r   r   r   r   Znose.pluginsr   r   Z	nose.utilr   r   Z	getLoggerr&   r   r   r#   r   r)   rG   rF   rO   r}   rn   r{   r   r   Zregister_optionflagr   rY   r   ZDoctestr   r   r   r   r   r   <module>   s:   ,
T} e
j