a
    Ä38bá4  ã                   @   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 g d
¢Zeg d¢e ƒZdd„ Zd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.cxx)ú.pyz.pyxz.pxdc                 C   s.   t jj}tD ]}| | }||ƒr|  S qd S ©N)ÚosÚpathÚexistsÚC_FILE_EXTENSIONS)Ú	base_pathZfile_existsÚextÚ	file_name© r   ú.lib/python3.9/site-packages/Cython/Coverage.pyÚ_find_c_source   s    
r   Fc                 C   s¢   t j |¡}t j |¡sT| d¡s&|rTt j t j | ¡|¡}t j |¡rTt j |¡}t j |¡sštjD ]2}t j t j ||¡¡}t j |¡rft	|ƒ  S qft	|ƒS )Nú.pxi)
r   r   Úabspathr   ÚendswithÚjoinÚdirnameÚsysÚrealpathr   )Z	main_fileZ	file_pathÚrelative_path_searchÚabs_pathÚrel_file_pathZsys_pathZ	test_pathr   r   r   Ú_find_dep_file_path$   s    ÿ
r$   c                   @   sP   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d„ ZdS )ÚPluginNc                 C   s
   dt fgS )NzCython versionr   ©Ú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v rN| j| d }|du rˆ|  |¡\}}|sldS |  ||¡\}}|du rˆdS | jdu 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Ú_read_source_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v r2| j| \}}}n2|  |¡\}}|sHd S |  ||¡\}}|d u rdd S t||||ƒS r   )r   r   r   r   r+   r,   r-   ÚCythonModuleReporter)r'   r0   r1   r#   r4   r3   r   r   r   Úfile_reporter^   s    zPlugin.file_reporterc              	   C   sÖ  t j |¡\}}| ¡ }|tv 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v r¼| j| d d fS ndS |tv rÈ|nt|ƒ}|d u 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 }	zRt|dƒ2}
d|
 d¡vrŽW d   ƒ W dS W d   ƒ n1 s¤0    Y  W n ttfyÌ   d }Y n0 ||	fS )Nz.pydz[.]cp[0-9]+-win[_a-z0-9]*$z.soz&[.](?:cpython|pypy)-[0-9]+[-_a-z0-9]*$r   r   ©NNr   Ú.r   Ú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'   r0   Úbasenamer   Zplatform_suffixr1   Zpackage_rootÚpackage_pathZtest_basepathZpy_source_fileÚfr   r   r   r,   q   sH    


6
zPlugin._find_source_filesc                 C   s†   t j |¡sdS t jj}t  |¡D ]B}||ƒd  ¡ }|tv r"|  t j ||¡|¡ || j	v r" dS q"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   Úisdirr<   Úlistdirr=   r   r-   r   r+   r
   rC   r   )r'   Zdir_pathÚsource_filer<   r0   r   r   r   r   rC   £   s    
zPlugin._find_c_source_filesc                 C   sš   | j du ri | _ || j v r&| j | }n|  |¡}|| j |< | jdu rJi | _| ¡ D ]&\}}t||dd}|||f| j|< qR|| jvrˆd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.
        NT)r!   r8   r   )Ú_parsed_c_filesÚ_parse_cfile_linesr+   Úitemsr$   )r'   r1   Z
sourcefileÚ
code_linesr0   r4   r"   r   r   r   r-   µ   s     




ÿ
zPlugin._read_source_linesc                 C   sv  t  d¡j}t  d¡j}t  d¡j}t  d¡j}t  d¡j}ttƒ}ttƒ}d}	t|ƒÌ}
t|
ƒ}
|
D ]®}||ƒ}|s¬d|v rf|	durf||ƒ}|rf||	  t	| 
d¡ƒ¡ qf| ¡ \}}|}	t	|ƒ}|
D ]J}||ƒ}|r| 
d¡ ¡ }||ƒrô qf||| |<  qfqÈ||ƒrÈ qfqÈqfW d  ƒ n1 s,0    Y  | ¡ D ]2\}}
t|
ƒ | |d	¡¡}|D ]}|
|= q`q>|S )
zb
        Parse a C file and extract all source file lines that generated executable code.
        z */[*] +"(.*)":([0-9]+)$z *[*] (.*) # <<<<<<+$z *[*]/$z *__Pyx_TraceLine\(([0-9]+),zX\s*c(?:type)?def\s+(?:(?:public|external)\s+)?(?:struct|union|enum|class)(\s+[^:]+|)\s*:Nz__Pyx_TraceLine(r   r   )r?   ÚcompileÚmatchr   ÚdictÚsetrH   ÚiterÚaddÚintÚgroupÚgroupsÚrstriprT   Ú
differenceÚget)r'   r1   Zmatch_source_path_lineZmatch_current_code_lineZmatch_comment_endZmatch_trace_lineZnot_executablerU   Zexecutable_linesZcurrent_filenameÚlinesÚlinerW   Z
trace_liner0   ÚlinenoZcomment_lineÚ	code_lineZ
dead_linesr   r   r   rS   Ï   sL    ÿ
(zPlugin._parse_cfile_lines)Ú__name__Ú
__module__Ú__qualname__r.   r+   rR   r(   r5   r7   r,   rC   r-   rS   r   r   r   r   r%   5   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 r   )Úsuperr/   Ú__init__Úmodule_filer2   r1   r+   r.   )r'   rk   r2   r1   Zc_files_mapZfile_path_map©Ú	__class__r   r   rj     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}z| j| W S  ty&   Y n0 t||ƒ}| jr^|dd…  ¡ dkr^| j| j|< | jS | jduslJ ‚|| jvrˆ| j|df| j|< || j|< |S )zR
        Determine source file path.  Called by the function call tracer.
        éýÿÿÿNr   )	Úf_codeÚco_filenamer.   ÚKeyErrorr$   r2   r=   r+   r1   )r'   r0   ÚframerQ   r"   r   r   r   Údynamic_source_filename  s    


z*CythonModuleTracer.dynamic_source_filename)rf   rg   rh   Ú__doc__rj   rn   rt   Ú__classcell__r   r   rl   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 )r6   zP
    Provide detailed trace information for one source file to coverage.py.
    c                    s&   t t| ƒ |¡ || _|| _|| _d S r   )ri   r6   rj   Únamer1   Ú_code)r'   r1   rQ   r#   r4   rl   r   r   rj   -  s    zCythonModuleReporter.__init__c                 C   s
   t | jƒS )zJ
        Return set of line numbers that are possibly executable.
        )rY   rx   r&   r   r   r   rb   3  s    zCythonModuleReporter.linesc                 c   sL   d}t | j ¡ ƒD ]4\}}||kr2g V  |d7 }qd|fgV  |d7 }qd S )Nr   Útxt)Úsortedrx   rT   )r'   Zcurrent_lineZline_nore   r   r   r   Ú_iter_source_tokens9  s    
z(CythonModuleReporter._iter_source_tokensc                 C   s^   t j | j¡rBt| jƒ}| ¡ W  d  ƒ S 1 s60    Y  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>J  s   ÿz.CythonModuleReporter.source.<locals>.<genexpr>)r   r   r   r0   r   rI   r   r{   )r'   rN   r   r   r   ÚsourceB  s    (
þzCythonModuleReporter.sourcec                 c   st   t j | j¡rVt| jƒ,}|D ]}d| d¡fgV  qW d  ƒ qp1 sJ0    Y  n|  ¡ D ]}d|fgV  q^dS )z6
        Iterate over the source code tokens.
        ry   r|   N)r   r   r   r0   r   r_   r{   )r'   rN   rc   r   r   r   Úsource_token_linesN  s    4z'CythonModuleReporter.source_token_lines)
rf   rg   rh   ru   rj   rb   r{   r   r‚   rv   r   r   rl   r   r6   )  s   	r6   c                 C   s   |   tƒ ¡ d S r   )Zadd_file_tracerr%   )ZregZoptionsr   r   r   Úcoverage_init[  s    rƒ   )F)ru   Z
__future__r   r?   Úos.pathr   r   Úcollectionsr   Zcoverage.pluginr   r   r   Zcoverage.filesr   ZUtilsr	   r
   r   r}   r   r   rY   r>   r   r$   r%   r/   r6   rƒ   r   r   r   r   Ú<module>   s$   	
 O&2