o
    i"                     @   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 )zProfiling 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 )Nc                   S   s
   t tS N)collectionsdefaultdictdict r   r   W/var/www/edux/Edux_v2/venv/lib/python3.10/site-packages/sqlalchemy/testing/profiling.py<lambda>:   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__0   s   zProfileStatsFile.__init__c                 C   s   t jjd t jj }t jjdkrt jjt jjr|d7 }ddd tj	dd D }|g}|
| tr;|
d	 trB|
d
 trI|
d |
t jjjrRdnd t j }|
|r`dpad d|S )N_sqlite_file.c                 S      g | ]}t |qS r   str).0vr   r   r   
<listcomp>M       z1ProfileStatsFile.platform_key.<locals>.<listcomp>r   r   r   r   winnativeunicodedbapiunicodecextensionsnocextensions)r   dbnamedriverdialect_is_url_file_dburljoinsysversion_infoappendr   r   r
   convert_unicoderequirements_has_cextensions)r"   	dbapi_key
py_versionplatform_tokens	_has_cextr   r   r   platform_keyB   s,   





zProfileStatsFile.platform_keyc                 C   s   t }|| jv o| j| j| v S r   )_current_testr   rF   )r"   test_keyr   r   r   	has_stats`   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   )rG   r   rF   lenr>   r   r!   )	r"   	callcountrH   per_fnper_platformrJ   rK   	has_countresultr   r   r   rR   f   s$   


zProfileStatsFile.resultc                 C   s`   t }| j| }|| j }|d }|d }|t|k r!|||d < n||d< | jr.|   d S d S )NrJ   rK   r   r   )rG   r   rF   rM   r   r!   )r"   rN   rH   rO   rP   rJ   rK   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>,rJ   r   rL   r   rK   )	openr   IOError	enumeratestrip
startswithr   r   close)
r"   	profile_frL   linerH   rF   rJ   rO   rP   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

rY   c                 s   s    | ]}t |V  qd S r   r*   rW   r   r   r   	<genexpr>   s    z*ProfileStatsFile._write.<locals>.<genexpr>rJ   z	%s %s %s
)	printr   rZ   r   rT   sortedr   r;   r_   )r"   r`   rH   rO   rF   rP   rb   r   r   r   r!      s   
zProfileStatsFile._writeN)__name__
__module____qualname____doc__r$   propertyrF   rI   rR   rS   rT   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                     sn   t D ]	} | i | qt }td |D ]	} | i |}q|W  d    S 1 s0w   Y  d S )N)variance)rangecount_functions)argskwwarm	timerangetimerv)fntimesrm   warmupr   r   wrap   s   $z3function_call_count.<locals>.decorate.<locals>.wrapr   )rv   ry   rw   rm   rx   )rv   r   decorate   s   
	z%function_call_count.<locals>.decorater   )rm   rw   rx   r{   r   rz   r   function_call_count   s   r|   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 |  |rt||  }t|| |k}|sltjrtjrvt| d S td|| d |tjf d S d S )NzcProfile is not installedzNo 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
cumulativezAdjusted 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_statsrI   r   	skip_testr   r   ProfileenabledisablepstatsStatsr<   stdouttotal_callsrR   re   
sort_statsprint_statsrV   absr   rS   AssertionErrorrF   )	rm   prstatsrN   expectedexpected_countline_nodeviancefailedr   r   r   ro      sP   



ro   )rl   r   r   )rl   )rj   r   
contextlibr   r   r<    r   utilr   r   r   r	   r
   r   ImportErrorrG   r   objectr   r|   contextmanagerro   r   r   r   r   <module>   s0    
