B
    þ¦†\A!  ã               @   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m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 yddlZW n ek
r˜   dZY nX dZdZG dd„ deƒZddd„Zejddd„ƒZdS )z§Profiling support for unit and performance tests.

These are special purpose profiling methods which operate
in a more fine-grained way than nose's profiling plugin.

é    Né   )Úconfig)Ú
gc_collecté   )Újython)Úpypy)Úupdate_wrapper)Úwin32c               @   sT   e Zd ZdZdd„ Zedd„ ƒZdd„ Zdd	„ Zd
d„ Z	dd„ Z
dd„ Zdd„ ZdS )ÚProfileStatsFilez°"Store per-platform/fn profiling results in a file.

    We're still targeting Py2.5, 2.4 on 0.7 with no dependencies,
    so no json lib :(  need to roll something silly

    c             C   sz   t jd k	ot jj| _| jp*t jd k	o*t jj| _tj |¡| _	tj 
| j	¡d | _t dd„ ¡| _|  ¡  | jrv|  ¡  d S )Néÿÿÿÿc               S   s
   t  t¡S )N)ÚcollectionsÚdefaultdictÚdict© r   r   ú;lib/python3.7/site-packages/sqlalchemy/testing/profiling.pyÚ<lambda>:   s    z+ProfileStatsFile.__init__.<locals>.<lambda>)r   ZoptionsZforce_write_profilesÚforce_writeZwrite_profilesÚwriteÚosÚpathÚabspathÚfnameÚsplitÚshort_fnamer   r   ÚdataÚ_readÚ_write)ÚselfÚfilenamer   r   r   Ú__init__0   s    zProfileStatsFile.__init__c             C   sª   t jjd t jj }d dd„ tjdd… D ƒ¡}|g}| |¡ trP| d¡ t	r^| d¡ t
rl| d	¡ | t jjjr~d
nd¡ t j ¡ }| |ršdpœd¡ d |¡S )NÚ_Ú.c             S   s   g | ]}t |ƒ‘qS r   )Ústr)Ú.0Úvr   r   r   ú
<listcomp>H   s    z1ProfileStatsFile.platform_key.<locals>.<listcomp>r   r   r   r   ÚwinZnativeunicodeZdbapiunicodeZcextensionsZnocextensions)r   ZdbÚnameZdriverÚjoinÚsysÚversion_infoÚappendr   r   r	   ZdialectZconvert_unicodeZrequirementsZ_has_cextensions)r   Z	dbapi_keyZ
py_versionZplatform_tokensZ	_has_cextr   r   r   Úplatform_keyB   s     




zProfileStatsFile.platform_keyc             C   s   t }|| jko| j| j| kS )N)Ú_current_testr   r,   )r   Útest_keyr   r   r   Ú	has_stats[   s    zProfileStatsFile.has_statsc       	      C   s¦   t }| j| }|| j }d|kr.g  |d< }n|d }d|krLd |d< }n|d }t|ƒ|k}|s‚| |¡ | jr||  ¡  d }n|d || f}|d  d7  < |S )NÚcountsÚcurrent_countr   Úlinenor   )r-   r   r,   Úlenr+   r   r   )	r   Ú	callcountr.   Úper_fnÚper_platformr0   r1   Z	has_countÚresultr   r   r   r7   a   s$    


zProfileStatsFile.resultc             C   s\   t }| j| }|| j }|d }|d }|t|ƒk rB|||d < n||d< | jrX|  ¡  d S )Nr0   r1   r   r   )r-   r   r,   r3   r   r   )r   r4   r.   r5   r6   r0   r1   r   r   r   Úreplace|   s    

zProfileStatsFile.replacec             C   s
   d| j  S )Na  # %s
# This file is written out on a per-environment basis.
# For each test in aaa_profiling, the corresponding function and 
# environment is located within this file.  If it doesn't exist,
# the test is skipped.
# If a callcount does exist, it is compared to what we received. 
# assertions are raised if the counts do not match.
# 
# To add a new callcount test, apply the function_call_count 
# decorator and re-run the tests using the --write-profiles 
# option - this file will be rewritten including the new count.
# 
)r   )r   r   r   r   Ú_header‰   s    zProfileStatsFile._headerc       
      C   s®   yt | jƒ}W n tk
r"   d S X x|t|ƒD ]p\}}| ¡ }|r.| d¡rNq.| ¡ \}}}| j| }|| }dd„ | d¡D ƒ}	|	|d< |d |d< d|d	< q.W | ¡  d S )
Nú#c             S   s   g | ]}t |ƒ‘qS r   )Úint)r#   Úcountr   r   r   r%   ©   s    z*ProfileStatsFile._read.<locals>.<listcomp>ú,r0   r   r2   r   r1   )	Úopenr   ÚIOErrorÚ	enumerateÚstripÚ
startswithr   r   Úclose)
r   Ú	profile_fr2   Úliner.   r,   r0   r5   r6   Úcr   r   r   r   œ   s     
zProfileStatsFile._readc             C   s¦   t d| j ƒ t| jdƒ}| |  ¡ ¡ xpt| jƒD ]b}| j| }| d| ¡ xDt|ƒD ]8}|| }d dd„ |d D ƒ¡}| d|||f ¡ qZW q4W | ¡  d S )	NzWriting profile file %sÚwz
# TEST: %s

r=   c             s   s   | ]}t |ƒV  qd S )N)r"   )r#   r<   r   r   r   ú	<genexpr>¹   s    z*ProfileStatsFile._write.<locals>.<genexpr>r0   z	%s %s %s
)	Úprintr   r>   r   r9   Úsortedr   r(   rC   )r   rD   r.   r5   r,   r6   rF   r   r   r   r   ¯   s    
zProfileStatsFile._writeN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   Úpropertyr,   r/   r7   r8   r9   r   r   r   r   r   r   r
   (   s   r
   çš™™™™™©?c                s   ‡ fdd„}|S )a©  Assert a target for a test case's function call count.

    The main purpose of this assertion is to detect changes in
    callcounts for various functions - the actual number is not as important.
    Callcounts are stored in a file keyed to Python version and OS platform
    information.  This file is generated automatically for new tests,
    and versioned so that unexpected changes in callcounts will be detected.

    c                s   ‡ ‡fdd„}t |ˆ ƒS )Nc           	      s    t ˆd ˆ | |ŽS Q R X d S )N)Úvariance)Úcount_functions)ÚargsÚkw)ÚfnrQ   r   r   ÚwrapÊ   s    z3function_call_count.<locals>.decorate.<locals>.wrap)r   )rU   rV   )rQ   )rU   r   ÚdecorateÉ   s    z%function_call_count.<locals>.decorater   )rQ   rW   r   )rQ   r   Úfunction_call_count¾   s    rX   c       	      c   s
  t d krt d¡‚t ¡ s0tjs0t dtj ¡ tƒ  t  	¡ }| 
¡  d V  | ¡  tj|tjd}|j}t |¡}|d kr‚d }n|\}}td||f ƒ | d¡ | ¡  |rt||  ƒ}t|| ƒ|k}|sÚtjrtjrìt |¡ ntd|| d |tjf ƒ‚d S )NzcProfile is not installedzŒNo profiling stats available on this platform for this function.  Run tests with --write-profiles to add statistics to %s for this platform.)ÚstreamzPstats calls: %d Expected %sZ
cumulativez†Adjusted function call count %s not within %s%% of expected %s, platform %s. Rerun with --write-profiles to regenerate this callcount.éd   )ÚcProfiler   Z_skip_test_exceptionÚ_profile_statsr/   r   Z	skip_testr   r   ZProfileÚenableÚdisableÚpstatsZStatsr)   ÚstdoutZtotal_callsr7   rI   Z
sort_statsZprint_statsr;   Úabsr   r8   ÚAssertionErrorr,   )	rQ   ZprZstatsr4   ZexpectedZexpected_countZline_noZdevianceZfailedr   r   r   rR   Ó   s@    



rR   )rP   )rP   )rN   r   Ú
contextlibr   r_   r)   Ú r   Úutilr   r   r   r   r	   r[   ÚImportErrorr-   r\   Úobjectr
   rX   ÚcontextmanagerrR   r   r   r   r   Ú<module>   s,   
 
