B
    ž†\1  ã               @   sÞ   d Z ddlm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mZmZ dd	lmZ d
dddgZedddge ƒZdd„ 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S )zv
A Cython plugin for coverage.py

Requires the coverage package at least in version 4.0 (which added the plugin API).
é    )Úabsolute_importN)Údefaultdict)ÚCoveragePluginÚ
FileTracerÚFileReporter)Úcanonical_filenameé   )Úfind_root_package_dirÚis_package_dirÚopen_source_file)Ú__version__z.cz.cppz.ccz.cxxz.pyz.pyxz.pxdc             C   s.   t jj}x tD ]}| | }||ƒr|S qW d S )N)ÚosÚpathÚexistsÚC_FILE_EXTENSIONS)Ú	base_pathZfile_existsÚextÚ	file_name© r   ú.lib/python3.7/site-packages/Cython/Coverage.pyÚ_find_c_source   s    
r   c             C   sž   t j |¡}| d¡rPt j |¡sPt j t j | ¡|¡}t j |¡rPt j |¡}t j |¡s–x8tjD ].}t j t j ||¡¡}t j |¡rdt	|ƒS qdW t	|ƒS )Nz.pxi)
r   r   ÚabspathÚendswithr   ÚjoinÚdirnameÚsysÚrealpathr   )Z	main_fileZ	file_pathÚabs_pathZpxi_file_pathZsys_pathZ	test_pathr   r   r   Ú_find_dep_file_path$   s    r   c               @   sH   e Zd ZdZdZdZdd„ Zdd„ Zdd„ Zdd	„ Z	d
d„ Z
dd„ ZdS )ÚPluginNc             C   s
   dt fgS )NzCython version)r   )Úselfr   r   r   Úsys_info<   s    zPlugin.sys_infoc             C   s¬   |  d¡s|  d¡rdS d }}ttj |¡ƒ}| jrN|| jkrN| j| d }|dkrˆ|  |¡\}}|sldS |  ||¡\}}|dkrˆdS | jdkr˜i | _t	|||| j| jƒS )zR
        Try to find a C source file for a file path found by the tracer.
        ú<zmemory:Nr   )
Ú
startswithr   r   r   r   Ú_c_files_mapÚ_find_source_filesÚ_parse_linesÚ_file_path_mapÚCythonModuleTracer)r    ÚfilenameÚc_fileÚpy_fileÚ_Úcoder   r   r   Úfile_tracer?   s     
zPlugin.file_tracerc             C   sr   t tj |¡ƒ}| jr2|| jkr2| j| \}}}n2|  |¡\}}|sHd S |  ||¡\}}|d krdd S t||||ƒS )N)r   r   r   r   r$   r%   r&   ÚCythonModuleReporter)r    r)   r*   Úrel_file_pathr-   r,   r   r   r   Úfile_reporter]   s    zPlugin.file_reporterc          	   C   s´  t j |¡\}}| ¡ }|tkr"nš|dkrPt d|tj¡}|r¼|d | ¡ … }nl|dkr~t d|tj¡}|r¼|d | ¡ … }n>|dkr¸|  	t j 
|¡|¡ || jkr¼| j| d d fS ndS |tkrÈ|nt|ƒ}|d kr.t |¡}t j ||¡ t jj¡}t|ƒdkr.t j t j 
|¡d	 |¡¡}t|ƒ}d }	|r¬t j |¡d d
 }	t j |	¡s^d }	y.t|dƒ}
d|
 d¡kr€dS W d Q R X W n ttfk
rª   d }Y nX ||	fS )Nz.pydz[.]cp[0-9]+-win[_a-z0-9]*$z.soz&[.](?:cpython|pypy)-[0-9]+[-_a-z0-9]*$z.pxir   )NNr   Ú.z.pyÚrbs   /* Generated by Cython é   )r   r   ÚsplitextÚlowerÚMODULE_FILE_EXTENSIONSÚreÚsearchÚIÚstartÚ_find_c_source_filesr   r$   r   r   r	   ZuncachedÚrelpathÚsplitÚsepÚlenr   r   ÚopenÚreadÚIOErrorÚOSError)r    r)   Úbasenamer   Zplatform_suffixr*   Zpackage_rootZpackage_pathZtest_basepathZpy_source_fileÚfr   r   r   r%   p   sH    



zPlugin._find_source_filesc             C   sˆ   t j |¡sdS t jj}xNt  |¡D ]@}||ƒd  ¡ }|tkr$|  t j ||¡|¡ || j	kr$dS q$W t
|ƒr„|  t j |¡|¡ dS )z¦
        Desperately parse all C files in the directory or its package parents
        (not re-descending) to find the (included) source file in one of them.
        Nr   )r   r   Úisdirr5   Úlistdirr6   r   r&   r   r$   r
   r<   r   )r    Zdir_pathÚsource_filer5   r)   r   r   r   r   r<   ¢   s    
zPlugin._find_c_source_filesc          	   C   sv  | j dkri | _ || j kr&| j | }nêt d¡j}t d¡j}t d¡j}t d¡j}ttƒ}tƒ }t|ƒ”}	t|	ƒ}	x„|	D ]|}
||
ƒ}|sŽq|| 	¡ \}}| 
|¡ t|ƒ}xJ|	D ]B}||ƒ}|rê| d¡ ¡ }||ƒrÚP ||| |< P q²||ƒr²P q²W q|W W dQ R X || j |< | jdkr"i | _x0| ¡ D ]$\}}t||ƒ}|||f| j|< q,W || jkrddS | j| dd… S )zý
        Parse a Cython generated C/C++ source file and find the executable lines.
        Each executable line starts with a comment header that states source file
        and line number, as well as the surrounding range of source code lines.
        Nz */[*] +"(.*)":([0-9]+)$z *[*] (.*) # <<<<<<+$z *[*]/$zX\s*c(?:type)?def\s+(?:(?:public|external)\s+)?(?:struct|union|enum|class)(\s+[^:]+|)\s*:r   )NN)Ú_parsed_c_filesr8   ÚcompileÚmatchr   ÚdictÚsetrA   ÚiterÚgroupsÚaddÚintÚgroupÚrstripr$   Úitemsr   )r    r*   Z
sourcefileZ
code_linesZmatch_source_path_lineZmatch_current_code_lineZmatch_comment_endZnot_executableÚ	filenamesÚlinesÚlinerL   r)   ÚlinenoZcomment_lineÚ	code_liner-   r   r   r   r   r&   ´   sN    







zPlugin._parse_lines)Ú__name__Ú
__module__Ú__qualname__r'   r$   rJ   r!   r.   r1   r%   r<   r&   r   r   r   r   r   4   s   2r   c                   s0   e Zd ZdZ‡ fdd„Zdd„ Zdd„ Z‡  ZS )r(   zA
    Find the Python/Cython source file for a Cython module.
    c                s0   t t| ƒ ¡  || _|| _|| _|| _|| _d S )N)Úsuperr(   Ú__init__Úmodule_filer+   r*   r$   r'   )r    r`   r+   r*   Zc_files_mapZfile_path_map)Ú	__class__r   r   r_   ò   s    zCythonModuleTracer.__init__c             C   s   dS )NTr   )r    r   r   r   Úhas_dynamic_source_filenameú   s    z.CythonModuleTracer.has_dynamic_source_filenamec             C   s–   |j j}y
| j| S  tk
r&   Y nX t||ƒ}| jr^|dd…  ¡ dkr^| j| j|< | jS | jdk	slt‚|| jkrˆ| j	|df| j|< || j|< |S )zR
        Determine source file path.  Called by the function call tracer.
        éýÿÿÿNz.py)
Úf_codeÚco_filenamer'   ÚKeyErrorr   r+   r6   r$   ÚAssertionErrorr*   )r    r)   ÚframerI   r   r   r   r   Údynamic_source_filenameý   s    



z*CythonModuleTracer.dynamic_source_filename)r[   r\   r]   Ú__doc__r_   rb   ri   Ú__classcell__r   r   )ra   r   r(   î   s   r(   c                   s@   e Zd ZdZ‡ fdd„Zdd„ Zdd„ Zdd	„ Zd
d„ Z‡  Z	S )r/   zP
    Provide detailed trace information for one source file to coverage.py.
    c                s&   t t| ƒ |¡ || _|| _|| _d S )N)r^   r/   r_   Únamer*   Ú_code)r    r*   rI   r0   r-   )ra   r   r   r_     s    zCythonModuleReporter.__init__c             C   s
   t | jƒS )zJ
        Return set of line numbers that are possibly executable.
        )rN   rm   )r    r   r   r   rW     s    zCythonModuleReporter.linesc             c   sT   d}xJt | j ¡ ƒD ]8\}}x||kr6g V  |d7 }qW d|fgV  |d7 }qW d S )Nr   Útxt)Úsortedrm   rU   )r    Zcurrent_lineZline_norZ   r   r   r   Ú_iter_source_tokens$  s    
z(CythonModuleReporter._iter_source_tokensc          	   C   sF   t j | j¡r*t| jƒ
}| ¡ S Q R X nd dd„ |  ¡ D ƒ¡S dS )zA
        Return the source code of the file as a string.
        NÚ
c             s   s"   | ]}|r|d  d ndV  qdS )r   r   Ú Nr   )Ú.0Útokensr   r   r   ú	<genexpr>6  s   z.CythonModuleReporter.source.<locals>.<genexpr>)r   r   r   r)   r   rB   r   rp   )r    rF   r   r   r   Úsource-  s    zCythonModuleReporter.sourcec          	   c   sh   t j | j¡rFt| jƒ&}x|D ]}d| d¡fgV  q W W dQ R X nx|  ¡ D ]}d|fgV  qPW dS )z6
        Iterate over the source code tokens.
        rn   rq   N)r   r   r   r)   r   rT   rp   )r    rF   rX   r   r   r   Úsource_token_lines9  s    
"z'CythonModuleReporter.source_token_lines)
r[   r\   r]   rj   r_   rW   rp   rv   rw   rk   r   r   )ra   r   r/     s   	r/   c             C   s   |   tƒ ¡ d S )N)Zadd_file_tracerr   )ZregZoptionsr   r   r   Úcoverage_initF  s    rx   )rj   Z
__future__r   r8   Úos.pathr   r   Úcollectionsr   Zcoverage.pluginr   r   r   Zcoverage.filesr   ZUtilsr	   r
   r   rr   r   r   rN   r7   r   r   r   r(   r/   rx   r   r   r   r   Ú<module>   s$   	 ;&2