B
    ] cp                 @   s   d Z ddg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ZddlZddlmZ ddlZdZG dd dZd	d
 Zdd ZG dd dZdd Zdd ZdddZdd ZG dd dZdd Zedkre  dS )a  program/module to trace Python program or function execution

Sample use, command line:
  trace.py -c -f counts --ignore-dir '$prefix' spam.py eggs
  trace.py -t --ignore-dir '$prefix' spam.py eggs
  trace.py --trackcalls spam.py eggs

Sample use, programmatically
  import sys

  # create a Trace object, telling it what to ignore, and whether to
  # do tracing or line-counting or both.
  tracer = trace.Trace(ignoredirs=[sys.base_prefix, sys.base_exec_prefix,],
                       trace=0, count=1)
  # run the new command using the given tracer
  tracer.run('main()')
  # make a report, placing output in /tmp
  r = tracer.results()
  r.write_results(show_missing=True, coverdir="/tmp")
TraceCoverageResults    N)	monotonicz#pragma NO COVERc               @   s   e Zd ZdddZdd ZdS )_IgnoreNc             C   s:   |s
t  nt || _|sg ndd |D | _ddi| _d S )Nc             S   s   g | ]}t j|qS  )ospathnormpath).0dr   r   lib/python3.7/trace.py
<listcomp>H   s   z$_Ignore.__init__.<locals>.<listcomp>z<string>   )set_mods_dirs_ignore)selfmodulesdirsr   r   r   __init__F   s    
z_Ignore.__init__c             C   s   || j kr| j | S || jkr,d| j |< dS x*| jD ] }||d r4d| j |< dS q4W |d krnd| j |< dS x,| jD ]"}||tj rvd| j |< dS qvW d| j |< dS )Nr   .r   )r   r   
startswithr   r   sep)r   filename
modulenamemodr   r   r   r   namesL   s$    







z_Ignore.names)NN)__name__
__module____qualname__r   r   r   r   r   r   r   E   s   
r   c             C   s    t j| }t j|\}}|S )z-Return a plausible module name for the patch.)r   r   basenamesplitext)r   baser   extr   r   r   _modnamew   s    r%   c             C   s   t j| }d}xJtjD ]@}t j|}||r|t| t jkrt|t|kr|}qW |rv| t|d d }n| }t j|\}}|t jd}t j	r|t j	d}t j
|\}}|dS )z,Return a plausible module name for the path. r   Nr   )r   r   normcasesysr   lenr   
splitdrivereplacealtsepr"   lstrip)r   ZcomparepathZlongestdirr#   Zdriver   r$   r   r   r   _fullmodname~   s     r/   c               @   s:   e Zd ZdddZdd Zdd Zdd
dZdddZdS )r   Nc          
   C   s   || _ | j d kri | _ | j  | _|| _| jd kr8i | _| j | _|| _| jd krZi | _| j | _|| _|| _| jry@t| jd}t	|\}}}W d Q R X | 
| ||| W n@ tttfk
r } ztd| j|f tjd W d d }~X Y nX d S )NrbzSkipping counts file %r: %s)file)countscopyZcountercalledfuncscallersinfileoutfileopenpickleloadupdate	__class__OSErrorEOFError
ValueErrorprintr(   stderr)r   r2   r4   r6   r5   r7   ferrr   r   r   r      s,    


zCoverageResults.__init__c             C   s   | do|dS )z_Return True if the filename does not refer to a file
        we want to have reported.
        <>)r   endswith)r   r   r   r   r   is_ignored_filename   s    z#CoverageResults.is_ignored_filenamec       	      C   sz   | j }| j}| j}|j }|j}|j}x$|D ]}||d||  ||< q*W x|D ]}d||< qPW x|D ]}d||< qfW dS )z.Merge in the data from another CoverageResultsr   r   N)r2   r4   r5   get)	r   otherr2   r4   r5   Zother_countsZother_calledfuncsZother_callerskeyr   r   r   r;      s    


zCoverageResults.updateTFc       !   
   C   s  | j rDt  td | j }x(t|D ]\}}}td|||f  q$W | jrt  td d }}	xvt| jD ]h\\}
}}\}}}|
|krt  td|
d |
}d}	||
kr|	|krtd| |}	td||||f  qlW i }x8| jD ].\}}||i  }||< | j||f ||< qW i }x$| D ]\}}| |r@q&|drX|d	d
 }|d	krt	j
t	j
|}t|}n$|}t	j
|st	| t|}|rt|}ni }t|}t	j
||d }t|d}t|j\}}W d	Q R X | |||||\}}|r&|r&td| | }||||f||< q&W |r|rtd x2t|D ]&}|| \}}}}td||   q`W | jry&t| j| j | jft| jdd W n6 tk
r }  ztd|  tj d W d	d	} ~ X Y nX d	S )af  
        Write the coverage results.

        :param show_missing: Show lines that had no hits.
        :param summary: Include coverage summary per module.
        :param coverdir: If None, the results of each module are placed in its
                         directory, otherwise it is included in the directory
                         specified.
        zfunctions called:z*filename: %s, modulename: %s, funcname: %szcalling relationships:r&   z***z  -->z    %s.%s -> %s.%sz.pycNz.coverr0   d   zlines   cov%   module   (path)z%5d   %3d%%   %s   (%s)wbr   z"Can't save counts files because %s)r1   )!r4   r@   sortedr5   r2   rH   itemsrG   rF   r   r   dirnameabspathr%   existsmakedirsr/   _find_executable_linenos	linecachegetlinesjoinr8   tokenizedetect_encodingreadlinewrite_results_fileintr7   r9   dumpr=   r(   rA   )!r   Zshow_missingsummarycoverdirZcallsr   r   funcnameZlastfileZ	lastcfileZpfileZpmodZpfunccfileZcmodZcfuncZper_filelineno	lines_hitZsumscountr.   lnotabsourceZ	coverpathfpencoding_n_hitsn_linesZpercentmrC   r   r   r   write_results   s|    






zCoverageResults.write_resultsc          
   C   s   yt |d|d}W n8 tk
rJ } ztd||f tjd dS d}~X Y nX d}d}	| xt|dD ]r\}
}|
|kr|d	||
   |	d7 }	|d7 }n.|
|krt|kr|d
 |d7 }n
|d ||d qfW W dQ R X |	|fS )z'Return a coverage results file in path.w)rh   z3trace: Could not open %r for writing: %s - skipping)r1   )r   r   Nr   r   z%5d: z>>>>>> z          )	r8   r=   r@   r(   rA   	enumeratewritePRAGMA_NOCOVER
expandtabs)r   r   linesre   rc   rh   r7   rC   rk   rj   rb   liner   r   r   r[   (  s(    



z"CoverageResults.write_results_file)NNNNN)TFN)N)r   r   r    r   rG   r;   rm   r[   r   r   r   r   r      s    

[c             C   s0   i }x&t | D ]\}}||krd||< qW |S )z:Return dict where keys are lines in the line number table.r   )disZfindlinestarts)codestrslinenosri   rb   r   r   r   _find_lines_from_codeH  s
    rz   c             C   s8   t | |}x(| jD ]}t|r|t|| qW |S )z<Return lineno dict for all code objects reachable from code.)rz   	co_constsinspectZiscoder;   _find_lines)rw   rx   ry   cr   r   r   r}   R  s
    

r}   c          	   C   s   i }t j}t| |dr}t|j}x^|D ]V\}}}}	}
|t jkr||t jkr||\}}|	\}}xt||d D ]}d||< qlW |}q*W W dQ R X |S )zReturn a dict of possible docstring positions.

    The dict maps line numbers to strings.  There is an entry for
    line that contains only a string or a part of a triple-quoted
    string.
    )rh   r   N)tokenINDENTr8   rX   generate_tokensrZ   STRINGrange)r   rh   r   Z
prev_ttyperB   tokZttypeZtstrstartendru   ZslineZscolZelineZecolir   r   r   _find_strings^  s    

r   c          
   C   s   y(t | }| }|j}W dQ R X W n8 tk
r` } ztd| |f tjd i S d}~X Y nX t|| d}t	| |}t
||S )zAReturn dict where keys are line numbers in the line number table.Nz%Not printing coverage data for %r: %s)r1   exec)rX   r8   readrh   r=   r@   r(   rA   compiler   r}   )r   rB   progrh   rC   rw   rx   r   r   r   rT   u  s    
rT   c            	   @   sp   e Zd ZdddZdd	 Zdd
dZdd Zd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 ) r   r   r   r   NFc
       
      C   s   || _ || _t||| _i | _i | _d| _|| _i | _i | _	i | _
d| _|	rTt | _|rb| j| _nZ|rp| j| _nL|r|r| j| _| j| _n2|r| j| _| j| _n|r| j| _| j| _nd| _dS )ax  
        @param count true iff it should count number of times each
                     line is executed
        @param trace true iff it should print out each line that is
                     being counted
        @param countfuncs true iff it should just output a list of
                     (filename, modulename, funcname,) for functions
                     that were called at least once;  This overrides
                     `count' and `trace'
        @param ignoremods a list of the names of modules to ignore
        @param ignoredirs a list of the names of directories to ignore
                     all of the (recursive) contents of
        @param infile file from which to read stored counts to be
                     added into the results
        @param outfile file in which to write the results
        @param timing true iff timing information be displayed
        r   Nr   )r6   r7   r   ignorer2   Zpathtobasename	donothingtrace_calledfuncs_callers_caller_cache
start_time_timeglobaltrace_trackcallersglobaltraceglobaltrace_countfuncsglobaltrace_ltlocaltrace_trace_and_count
localtracelocaltrace_tracelocaltrace_count)
r   rd   r   
countfuncscountcallers
ignoremods
ignoredirsr6   r7   timingr   r   r   r     s6    




zTrace.__init__c             C   s    dd l }|j}| ||| d S )Nr   )__main____dict__runctx)r   cmdr   dictr   r   r   run  s    z	Trace.runc          	   C   sh   |d kri }|d kri }| j s6t| j t| j zt||| W d | j sbtd  td  X d S )N)r   	threadingsettracer   r(   r   )r   r   globalslocalsr   r   r   r     s      
zTrace.runctxc           	   O   s   t | dkr| ^}}} n>| s&tdn0d|krB|d}| ^}} ntdt | d  d }|jslt|j z|| |}W d |jstd  X |S )N   z8descriptor 'runfunc' of 'Trace' object needs an argumentfuncz7runfunc expected at least 1 positional argument, got %dr   )r)   	TypeErrorpopr   r(   r   r   )argskwr   r   resultr   r   r   runfunc  s"    


zTrace.runfuncc       
      C   s   |j }|j}|rt|}nd }|j}d }|| jkrL| j| d k	r| j| }nd | j|< dd t|D }t|dkrdd t|d D }t|dkrdd t|d D }	t|	dkr|	d j}|| j|< |d k	rd||f }|||fS )Nc             S   s   g | ]}t |r|qS r   )r|   Z
isfunction)r
   rB   r   r   r   r     s    z1Trace.file_module_function_of.<locals>.<listcomp>r   c             S   s   g | ]}t |tr|qS r   )
isinstancer   )r
   r   r   r   r   r     s    r   c             S   s   g | ]}t |d r|qS )	__bases__)hasattr)r
   r~   r   r   r   r     s    z%s.%s)	f_codeco_filenamer%   co_namer   gcZget_referrersr)   r   )
r   framerw   r   r   r`   ZclsnameZfuncsZdictsclassesr   r   r   file_module_function_of  s,    




zTrace.file_module_function_ofc             C   s0   |dkr,|  |}|  |j}d| j||f< dS )zkHandler for call events.

        Adds information about who called who to the self._callers dict.
        callr   N)r   f_backr   )r   r   whyarg	this_funcZparent_funcr   r   r   r     s    
zTrace.globaltrace_trackcallersc             C   s    |dkr|  |}d| j|< dS )zoHandler for call events.

        Adds (filename, modulename, funcname) to the self._calledfuncs dict.
        r   r   N)r   r   )r   r   r   r   r   r   r   r   r     s    
zTrace.globaltrace_countfuncsc             C   sj   |dkrf|j }|jdd}|rbt|}|dk	rf| j||}|sf| jrZtd||jf  | j	S ndS dS )zHandler for call events.

        If the code block being entered is to be ignored, returns `None',
        else returns self.localtrace.
        r   __file__Nz! --- modulename: %s, funcname: %s)
r   	f_globalsrH   r%   r   r   r   r@   r   r   )r   r   r   r   rw   r   r   Z	ignore_itr   r   r   r     s    zTrace.globaltrace_ltc             C   s   |dkr~|j j}|j}||f}| j|dd | j|< | jrTtdt | j  dd tj	
|}td||t||f dd | jS )	Nru   r   r   z%.2f )r   z
%s(%d): %sr&   )r   r   f_linenor2   rH   r   r@   r   r   r   r!   rU   getliner   )r   r   r   r   r   rb   rJ   bnamer   r   r   r   3  s    z Trace.localtrace_trace_and_countc             C   sd   |dkr^|j j}|j}| jr4tdt | j  dd tj|}td||t	
||f dd | jS )Nru   z%.2fr   )r   z
%s(%d): %sr&   )r   r   r   r   r@   r   r   r   r!   rU   r   r   )r   r   r   r   r   rb   r   r   r   r   r   B  s    zTrace.localtrace_tracec             C   s<   |dkr6|j j}|j}||f}| j|dd | j|< | jS )Nru   r   r   )r   r   r   r2   rH   r   )r   r   r   r   r   rb   rJ   r   r   r   r   O  s    zTrace.localtrace_countc             C   s   t | j| j| j| j| jdS )N)r6   r7   r4   r5   )r   r2   r6   r7   r   r   )r   r   r   r   resultsW  s    
zTrace.results)	r   r   r   r   r   r   NNF)NN)r   r   r    r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r     s     
0
)	c                 st  dd l } |  }|jdddd |dd}|jd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 |jddd
dd |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-d.}|jd/d0g d1d2 |jd3d0g d4d2 |jd5d6d7d8 |jd9| jd:d8 | }|jrvt	d;t	d<  fd=d>d?d@ |j
D |_
fdAd@|jD |_|jr|js|dB t|j|jdC}||j|j|jS t|j|j|j|jgs|dD |jr0|js&|jr0|dE |jrJ|jsJ|dF |jd kr`|dG |jf|jt_tj|jtjd< t|j|j|j|j|j
|j|j|j|j dH	}yJt!|j}t"|# |jdI}W d Q R X |jdJd d dK}	|$||	|	 W nP t%k
r6 }
 zt&dLtjd |
f  W d d }
~
X Y n t'k
rJ   Y nX |( }|j)sp||j|j|j d S )MNr   z	--versionversionz	trace 2.0)actionr   zMain optionsz(One of these (or --report) must be givenz-cz--count
store_truezCount the number of times each line is executed and write the counts to <module>.cover for each module executed, in the module's directory. See also --coverdir, --file, --no-report below.)r   helpz-tz--tracez3Print each line to sys.stdout before it is executedz-lz--listfuncszKeep track of which functions are executed at least once and write the results to sys.stdout after the program exits. Cannot be specified alongside --trace or --count.z-Tz--trackcallsz^Keep track of caller/called pairs and write the results to sys.stdout after the program exits.Z	Modifiersz-rz--reportzGenerate a report from a counts file; does not execute any code. --file must specify the results file to read, which must have been created in a previous run with --count --file=FILEz-Rz--no-reportz^Do not generate the coverage report files. Useful if you want to accumulate over several runs.z-fz--filez+File to accumulate counts over several runs)r   z-Cz
--coverdirzDirectory where the report files go. The coverage report for <package>.<module> will be written to file <dir>/<package>/<module>.coverz-mz	--missingz?Annotate executable lines that were not executed with ">>>>>> "z-sz	--summaryz\Write a brief summary for each file to sys.stdout. Can only be used with --count or --reportz-gz--timingzQPrefix each line with the time since the program started. Only used while tracingZFilterszCan be specified multiple timesz--ignore-moduleappendzqIgnore the given module(s) and its submodules (if it is a package). Accepts comma separated list of module names.)r   defaultr   z--ignore-dirzWIgnore files in the given directory (multiple directories can be joined by os.pathsep).r   ?zfile to run as main program)nargsr   	argumentszarguments to the programZstdlibZ
platstdlibc                s4   t jt j| } | dd } t j| S )Nz$prefixz$exec_prefix)r   r   
expanduser
expandvarsr+   r	   )s)_exec_prefix_prefixr   r   parse_ignore_dir  s    zmain.<locals>.parse_ignore_dirc             S   s$   g | ]}| d D ]}| qqS ),)splitstrip)r
   r   r   r   r   r   r     s   zmain.<locals>.<listcomp>c                s&   g | ]}| tjD ]} |qqS r   )r   r   pathsep)r
   r   r   )r   r   r   r     s   z-r/--report requires -f/--file)r6   r7   zLmust specify one of --trace, --count, --report, --listfuncs, or --trackcallsz8cannot specify both --listfuncs and (--trace or --count)z3--summary can only be used with --count or --reportz3filename is missing: required with the main options)r   r   r   r   r6   r7   r   r   r   )r   r   __package__
__cached__zCannot run file %r because: %s)*argparseArgumentParseradd_argumentZadd_argument_groupZadd_mutually_exclusive_groupZ	REMAINDER
parse_argsZ
ignore_dir	sysconfigZget_pathZignore_moduleZreportr1   errorr   rm   Zmissingr^   r_   anyr   rd   Z	listfuncsZ
trackcallsr   r   r(   argvr   r   rP   r   r   r8   r   r   r   r=   exit
SystemExitr   Z	no_report)r   parserZgrpZ_grpZoptsr   trg   rw   ZglobsrC   r   )r   r   r   r   main]  s    




















(r   r   )N)__doc____all__rU   r   rer(   r   r   rX   r|   r   rv   r9   Ztimer   r   r   rr   r   r%   r/   r   rz   r}   r   rT   r   r   r   r   r   r   r   <module>1   s<   2 /

 [ 