B
    [u\I                 @   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 ddddZd	d
 Zdd Zdd ZG dd deZG dd dejZdS )zV
This plugin provides advanced doctest support and enables the testing of .rst
files.
    N   )OutputCheckerFIX#%z\.\.)ZtxtZtexrstc             C   s   | j dddd | j dddd | j ddd	d
d | j ddddd | j dddd | dd | jdddddgd | dd | jddddd | jdddd  | jd!d	d
d  | jd"ddd  d S )#Nz--doctest-plus
store_truezWenable running doctests with additional features not found in the normal doctest plugin)actionhelpz--doctest-rstz-enable running doctests in .rst documentationz--doctest-plus-atolZstorez/set the absolute tolerance for float comparisong:0yE>)r	   r
   defaultz--doctest-plus-rtolz/set the relative tolerance for float comparisongh㈵>z--text-file-formatzZText file format for narrative documentation. Options accepted are 'txt', 'tex', and 'rst'text_file_formatz changing default format for docsdoctest_optionflagszoption flags for doctestsargsELLIPSISZNORMALIZE_WHITESPACE)typer   doctest_plusdoctest_norecursedirszDlike the norecursedirs option but applies only to doctest collection doctest_rstz)Run the doctests in the rst documentationF)r   doctest_plus_atoldoctest_plus_rtol)Z	addoptionZaddini)parserr   r   8lib/python3.7/site-packages/pytest_doctestplus/plugin.pypytest_addoption   s8    
r   c             C   s0   | j d}d}x|D ]}|tj| O }qW |S )Nr   r   )configgetinidoctestZOPTIONFLAGS_BY_NAME)parentZoptionflags_strZflag_intZflag_strr   r   r   get_optionflagsM   s
    
r   c          	      s$  t tdtdt_t tdtdt_tt_tdj	
djjoljj }d ks|sdsjjsd S G fdddj}G  fdd	d	jtj}G fd
ddtj j	t||dpjjjjpdd j	 d S )Nr   r   REMOTE_DATAr   r   c                   s   e Zd Z fddZdS )z+pytest_configure.<locals>.DocTestModulePlusc             3   s
  | j jdkrd S | j jdkrXy| jj| j }W q| tk
rT   | jj| j }Y q|X n$y| j  }W n t	k
rz   d S X t
| tB }t }tjd|t d}xd||D ]V}|jrdddkrx&|jD ]}|j rd|jtj< qW |j| ||V  qW d S )	Nzsetup.pyzconftest.pyF)verboseoptionflagsZcheckerremote_datanoneanyT)fspathbasenamer   Z	_conftestZimportconftestAttributeErrorpluginmanagerZ_importconftestZpyimportImportErrorr   r   DocTestFinderPlusr   ZDebugRunnerr   findZexamples	getoptionoptionsgetSKIPDoctestItemname)selfmoduler-   finderZrunnertestZexample)r   r   doctest_pluginr   r   collecto   s.    z3pytest_configure.<locals>.DocTestModulePlus.collectN)__name__
__module____qualname__r7   r   )r   r   r6   r   r   DocTestModulePlush   s   r;   c                   s*   e Zd Zdd Z fddZdd ZdS )z-pytest_configure.<locals>.DocTestTextfilePlusc             S   s   d S )Nr   )r2   r   r   r   obj   s    z1pytest_configure.<locals>.DocTestTextfilePlus.objc          
      sN   i | _ | }t| tB }tjt| jd|  t|j	ddddd\}}d S )NF)Z
getfixtureTzutf-8)Zmodule_relativer!   r   
extraglobsZraise_on_errorr    encoding)
ZfuncargsZ_setup_fixturesr   r   r   Ztestfilestrr%   dictZgetfuncargvalue)r2   Zfixture_requestr-   ZfailedZtot)DocTestParserPlusr6   r   r   runtest   s    


z5pytest_configure.<locals>.DocTestTextfilePlus.runtestc             S   s   | j dd| j fS )a]  
            Overwrite pytest's ``DoctestItem`` because
            ``DocTestTextfilePlus`` does not have a ``dtest`` attribute
            which is used by pytest>=3.2.0 to return the location of the
            tests.

            For details see `pytest-dev/pytest#2651
            <https://github.com/pytest-dev/pytest/pull/2651>`_.
            Nz[doctest] %s)r%   r1   )r2   r   r   r   
reportinfo   s    
z8pytest_configure.<locals>.DocTestTextfilePlus.reportinfoN)r8   r9   r:   r<   rB   rC   r   )rA   r6   r   r   DocTestTextfilePlus   s   rD   c                   s    e Zd ZdZd fdd	ZdS )z+pytest_configure.<locals>.DocTestParserPlusa  
        An extension to the builtin DocTestParser that handles the
        special directives for skipping tests.

        The directives are:

           - ``.. doctest-skip::``: Skip the next doctest chunk.

           - ``.. doctest-requires:: module1, module2``: Skip the next
             doctest chunk if the given modules/packages are not
             installed.

           - ``.. doctest-skip-all``: Skip all subsequent doctests.
        Nc                s  t jj| ||d}g }d}d}jjp.d}|tkrBt|  ntd	|td  td  x|D ]~}t
|tjr|rg }d}|  }	t fdd|	D rd}qht|	sqh|	d	d  }
 fd
d|
D }t|dkr|d p|d }n|d }|r:|d}|d ks4| dkr:tjdkr:d}qh fdd|
D }t|dkrn|d pj|d }n|d }|rtd|d}qht
|t jrh|s|st|sd|jt j< dddkrh|jrhd|jt j< qhW |S )N)r1   Fr   zKfile format '{}' is not recognized, assuming '{}' as the comment character.r   c                s"   g | ]}t d  | qS )z{} doctest-skip-all)rematchformatstrip).0x)comment_charr   r   
<listcomp>   s    zEpytest_configure.<locals>.DocTestParserPlus.parse.<locals>.<listcomp>Tc                s   g | ]}t d  |qS )z{}\s+doctest-skip\s*::(\s+.*)?)rE   rF   rG   )rI   	last_line)rK   r   r   rL      s   r   r   Zwin32c                s   g | ]}t d  |qS )z!{}\s+doctest-requires\s*::\s+(.*))rE   rF   rG   )rI   rN   )rK   r   r   rL      s   z\s*,?\s*r"   r#   r$   )r   DocTestParserparseoptionr   r   comment_characterswarningswarnrG   
isinstancesixZstring_typesrH   
splitlinesr$   lengroupsysplatformrE   splitZExampler*   check_required_modulesr-   r/   r,   r.   )r2   sr1   resultZrequiredZ	skip_nextZskip_allZfile_formatentrylinesZ
last_linesZmatchesrF   Zmarker)r   r   )rK   r   rP      s`    




z1pytest_configure.<locals>.DocTestParserPlus.parse)N)r8   r9   r:   __doc__rP   r   )r   r   r   r   rA      s   rA   r   r   Zdoctestplus)maxfloatr   r,   r   ZrtolZatolr   Zregister_optionflagr(   Z	getpluginrQ   Zdoctestmodulesr   ZDoctestModuler0   pytestZModulerO   registerDoctestPlusr   r   Z
unregister)r   Zrun_regular_doctestr;   rD   r   )rA   r   r   r6   r   pytest_configureU   s(    
)!\rh   c               @   s$   e Zd Zdd Zdd Zdd ZdS )rg   c             C   s4   || _ || _|| _|r$d|| _nd| _g | _dS )a  
        doctest_module_item_cls should be a class inheriting
        `pytest.doctest.DoctestItem` and `pytest.File`.  This class handles
        running of a single doctest found in a Python module.  This is passed
        in as an argument because the actual class to be used may not be
        available at import time, depending on whether or not the doctest
        plugin for py.test is available.
        z.{}z.rstN)_doctest_module_item_cls_doctest_textfile_item_cls_run_rst_doctestsrG   _text_file_ext_ignore_paths)r2   Zdoctest_module_item_clsZdoctest_textfile_item_clsZrun_rst_doctestsr   r   r   r   __init__  s    
zDoctestPlus.__init__c             C   sX   |j d| d}|dk	r&||kr&dS x,|dD ]}|j|dr2| j| P q2W dS )z@Skip paths that match any of the doctest_norecursedirs patterns.collect_ignore)pathNTr   )fnmatchF)Z_getconftest_pathlistdirpathr   Zcheckrm   append)r2   rp   r   ro   patternr   r   r   pytest_ignore_collect,  s    z!DoctestPlus.pytest_ignore_collectc             C   s   x | j D ]}|||krdS qW |jdkrF|jdkr:dS | ||S | jr|j| jkrt|t	j
j}|jdrzdS d|krt|d |ddd d }tdd	 ||d D rdS | ||S dS )
a  Implements an enhanced version of the doctest module from py.test
        (specifically, as enabled by the --doctest-modules option) which
        supports skipping all doctests in a specific docstring by way of a
        special ``__doctest_skip__`` module-level variable.  It can also skip
        tests that have special requirements by way of
        ``__doctest_requires__``.

        ``__doctest_skip__`` should be a list of functions, classes, or class
        methods whose docstrings should be ignored when collecting doctests.

        This also supports wildcard patterns.  For example, to run doctests in
        a class's docstring, but skip all doctests in its modules use, at the
        module level::

            __doctest_skip__ = ['ClassName.*']

        You may also use the string ``'.'`` in ``__doctest_skip__`` to refer
        to the module itself, in case its module-level docstring contains
        doctests.

        ``__doctest_requires__`` should be a dictionary mapping wildcard
        patterns (in the same format as ``__doctest_skip__``) to a list of one
        or more modules that should be *importable* in order for the tests to
        run.  For example, if some tests require the scipy module to work they
        will be skipped unless ``import scipy`` is possible.  It is also
        possible to use a tuple of wildcard patterns as a key in this dict::

            __doctest_requires__ = {('func1', 'func2'): ['scipy']}

        Nz.pyzconf.py_Zdocsr   c             s   s    | ]}| d p|dkV  qdS )rv   ZapiN)
startswith)rI   rJ   r   r   r   	<genexpr>}  s    z2DoctestPlus.pytest_collect_file.<locals>.<genexpr>)rm   commonZextr&   ri   rk   rl   r?   r\   osrp   seprx   rX   indexr$   rj   )r2   rp   r   Zignore_pathpartsZ
docs_indexr   r   r   pytest_collect_file@  s     

 zDoctestPlus.pytest_collect_fileN)r8   r9   r:   rn   ru   r   r   r   r   r   rg     s   rg   c               @   s*   e Zd ZdZi Zedd ZdddZdS )r*   zExtension to the default `doctest.DoctestFinder` that supports
    ``__doctest_skip__`` magic.  See `pytest_collect_file` for more details.
    c          	   C   sb   x\|D ]T}|| j kr"| j | s"dS yt| W n tk
rN   d| j |< dS X d| j |< qW dS )NFT)_import_cacheimpfind_moduler)   )clsmodsmodr   r   r   r]     s    



z(DocTestFinderPlus.check_required_modulesNc                sz   t j |||}tds*tdrv d krDtdrDj ntdtf fdd}tt	||}|S )N__doctest_skip____doctest_requires__r8   zLDocTestFinder.find: name must be given when obj.__name__ doesn't exist: {!r}c          	      s   xRt dg D ]B}|dkrdS |dkr4| j kr4dS t| jd |frdS qW t di }x\t|D ]N\}}t|ts|f}x4|D ],}t| jd |fsq|sdS qW qlW dS )Nr   *F.r   T)	getattrr1   rq   joinrV   Z	iteritemsrU   tupler]   )r5   ZpatZreqsZpatsr   )r1   r<   r2   r   r   test_filter  s$    


z+DocTestFinderPlus.find.<locals>.test_filter)
r   DocTestFinderr+   hasattrr8   
ValueErrorrG   r   listfilter)r2   r<   r1   r3   Zglobsr=   Ztestsr   r   )r1   r<   r2   r   r+     s    

zDocTestFinderPlus.find)NNNN)r8   r9   r:   rb   r   classmethodr]   r+   r   r   r   r   r*     s
    r*   )rb   rV   r   rq   r   r{   rE   rZ   rS   re   Zoutput_checkerr   r   rR   r   r   rh   objectrg   r   r*   r   r   r   r   <module>   s&   1 Cn