o
    y¬´\@!  ã                   @   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 zddlZW n eyK   dZY nw 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   s~   t jd uot jj| _| jpt jd uot jj| _tj |¡| _	tj 
| j	¡d | _t dd„ ¡| _|  ¡  | jr=|  ¡  d S d S )Néÿÿÿÿc                   S   s
   t  t¡S ©N)ÚcollectionsÚdefaultdictÚdict© r   r   úN/var/www/html/env/lib/python3.10/site-packages/sqlalchemy/testing/profiling.pyÚ<lambda>9   s   
 z+ProfileStatsFile.__init__.<locals>.<lambda>)r   ÚoptionsÚforce_write_profilesÚforce_writeÚwrite_profilesÚwriteÚosÚpathÚabspathÚfnameÚsplitÚshort_fnamer   r   ÚdataÚ_readÚ_write)ÚselfÚfilenamer   r   r   Ú__init__/   s   ÿÿÿýzProfileStatsFile.__init__c                 C   sª   t jjd t jj }d dd„ tjdd… D ƒ¡}|g}| |¡ tr(| d¡ t	r/| d¡ t
r6| d	¡ | t jjjr?d
nd¡ t j ¡ }| |rMdpNd¡ d |¡S )NÚ_Ú.c                 S   ó   g | ]}t |ƒ‘qS r   ©Ústr)Ú.0Úvr   r   r   Ú
<listcomp>G   ó    z1ProfileStatsFile.platform_key.<locals>.<listcomp>r   r   r   r   ÚwinÚnativeunicodeÚdbapiunicodeÚcextensionsÚnocextensions)r   ÚdbÚnameÚdriverÚjoinÚsysÚversion_infoÚappendr   r   r
   ÚdialectÚconvert_unicodeÚrequirementsÚ_has_cextensions)r"   Ú	dbapi_keyÚ
py_versionÚplatform_tokensÚ	_has_cextr   r   r   Úplatform_keyA   s$   



ÿý

zProfileStatsFile.platform_keyc                 C   s   t }|| jv o| j| j| v S r   )Ú_current_testr   rB   )r"   Útest_keyr   r   r   Ú	has_statsZ   s   ÿzProfileStatsFile.has_statsc           	      C   s¦   t }| j| }|| j }d|vrg  |d< }n|d }d|vr&d |d< }n|d }t|ƒ|k}|sA| |¡ | jr>|  ¡  d }n|d || f}|d  d7  < |S )NÚcountsÚcurrent_countr   Úlinenor   )rC   r   rB   Úlenr9   r   r!   )	r"   Ú	callcountrD   Úper_fnÚper_platformrF   rG   Ú	has_countÚresultr   r   r   rN   `   s$   


zProfileStatsFile.resultc                 C   s`   t }| j| }|| j }|d }|d }|t|ƒk r!|||d < n||d< | jr.|  ¡  d S d S )NrF   rG   r   r   )rC   r   rB   rI   r   r!   )r"   rJ   rD   rK   rL   rF   rG   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ª   zt | jƒ}W n
 ty   Y d S w t|ƒD ]8\}}| ¡ }|r%| d¡r&q| ¡ \}}}| j| }|| }dd„ | d¡D ƒ}	|	|d< |d |d< d|d	< q| ¡  d S )
Nú#c                 S   r'   r   )Úint©r*   Úcountr   r   r   r,   ¨   r-   z*ProfileStatsFile._read.<locals>.<listcomp>ú,rF   r   rH   r   rG   )	Úopenr   ÚIOErrorÚ	enumerateÚstripÚ
startswithr   r   Úclose)
r"   Ú	profile_frH   ÚlinerD   rB   rF   rK   rL   Úcr   r   r   r    ›   s"   ÿ

zProfileStatsFile._readc                 C   sž   t d| j ƒ t| jdƒ}| |  ¡ ¡ t| jƒD ]/}| j| }| d| ¡ t|ƒD ]}|| }d dd„ |d D ƒ¡}| d|||f ¡ q+q| ¡  d S )	NzWriting profile file %sÚwz
# TEST: %s

rU   c                 s   s   � | ]}t |ƒV  qd S r   r(   rS   r   r   r   Ú	<genexpr>¸   s   € z*ProfileStatsFile._write.<locals>.<genexpr>rF   z	%s %s %s
)	Úprintr   rV   r   rP   Úsortedr   r6   r[   )r"   r\   rD   rK   rB   rL   r^   r   r   r   r!   ®   s   
ýzProfileStatsFile._writeN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r$   ÚpropertyrB   rE   rN   rO   rP   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�� ˆ | i |¤ŽW  d   ƒ S 1 sw   Y  d S )N©Úvariance)Úcount_functions)ÚargsÚkw)Úfnrj   r   r   ÚwrapÉ   s   $ÿz3function_call_count.<locals>.decorate.<locals>.wrapr   )rn   ro   ri   )rn   r   ÚdecorateÈ   s   
z%function_call_count.<locals>.decorater   )rj   rp   r   ri   r   Úfunction_call_count½   s   rq   c           	      c   s  � t d u r
t d¡‚t ¡ stjst dtj ¡ tƒ  t  	¡ }| 
¡  d V  | ¡  tj|tjd�}|j}t |¡}|d u rBd }n|\}}td||f ƒ | d¡ | ¡  |rƒt||  ƒ}t|| ƒ|k}|sltjr…tjrvt |¡ d S td|| d |tjf ƒ‚d S 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 %sÚ
cumulativez†Adjusted function call count %s not within %s%% of expected %s, platform %s. Rerun with --write-profiles to regenerate this callcount.éd   )ÚcProfiler   Ú_skip_test_exceptionÚ_profile_statsrE   r   Ú	skip_testr   r   ÚProfileÚenableÚdisableÚpstatsÚStatsr7   ÚstdoutÚtotal_callsrN   ra   Ú
sort_statsÚprint_statsrR   Úabsr   rO   ÚAssertionErrorrB   )	rj   ÚprÚstatsrJ   ÚexpectedÚexpected_countÚline_noÚdevianceÚfailedr   r   r   rk   Ò   sP   €
ýÿ


üüÿørk   )rh   )rf   r   Ú
contextlibr   r|   r7   Ú r   Úutilr   r   r   r	   r
   ru   ÚImportErrorrC   rw   Úobjectr   rq   Úcontextmanagerrk   r   r   r   r   Ú<module>   s0   ÿ 
