o
    [h%"                     @   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ZddlmZ ddl	m
Z
 ddl	mZ zddlZW n ey=   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   update_wrapperc                   @   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 )ProfileStatsFilezStore 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   /home/ubuntu/experiments/live_experiments/Pythonexperiments/Otree/venv/lib/python3.10/site-packages/sqlalchemy/testing/profiling.py<lambda>8   s   
 z+ProfileStatsFile.__init__.<locals>.<lambda>)r   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__.   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 }t
 t
  t
  ||g}|t jjjrFd	nd
 t j }||rTdpUd d|S )N_Zsqlite_file.c                 S      g | ]}t |qS r   str).0vr   r   r   
<listcomp>K       z1ProfileStatsFile.platform_key.<locals>.<listcomp>r   r   ZnativeunicodeZdbapiunicodeZcextensionsZnocextensions)r   dbnameZdriverdialectZ_is_url_file_dburljoinsysversion_infoplatformmachinesystemlowerpython_implementationappendZconvert_unicoderequirementsZ_has_cextensions)r   Z	dbapi_key
py_versionZplatform_tokensZ	_has_cextr   r   r   platform_key@   s(   



zProfileStatsFile.platform_keyc                 C   s   t }|| jv o| j| j| v S r
   )_current_testr   r9   )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   )r:   r   r9   lenr6   r   r   )	r   	callcountr;   per_fnper_platformr=   r>   Z	has_countresultr   r   r   rD   d   s$   


zProfileStatsFile.resultc                 C   s`   t }| j| }|| j }|d }|d }|t|k r!|||d < n||d< | jr.|   d S d S )Nr=   r>   r   r	   )r:   r   r9   r@   r   r   )r   rA   r;   rB   rC   r=   r>   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>,r=   r   r?   r   r>   )	openr   IOError	enumeratestrip
startswithr   r   close)
r   	profile_fr?   liner;   r9   r=   rB   rC   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

rK   c                 s   s    | ]}t |V  qd S r
   r$   rI   r   r   r   	<genexpr>   s    z*ProfileStatsFile._write.<locals>.<genexpr>r=   z	%s %s %s
)	printr   rL   r   rF   sortedr   r.   rQ   )r   rR   r;   rB   r9   rC   rT   r   r   r   r      s   
zProfileStatsFile._writeN)__name__
__module____qualname____doc__r   propertyr9   r<   rD   rE   rF   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kwZwarmZ	timerangetimerv)fntimesr_   warmupr   r   wrap   s   $z3function_call_count.<locals>.decorate.<locals>.wrapr   )rf   ri   rg   r_   rh   )rf   r   decorate   s   
	z%function_call_count.<locals>.decorater   )r_   rg   rh   rk   r   rj   r   function_call_count   s   rl   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 %sZ
cumulativezAdjusted 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_callsrD   rW   Z
sort_statsZprint_statsrH   absr   rE   AssertionErrorr9   )	r_   prstatsrA   expectedZexpected_countline_noZdevianceZfailedr   r   r   ra      sP   



ra   )r^   r   r   )r^   )r\   r   
contextlibr   r1   rs   r/    r   utilr   r   ro   ImportErrorr:   rp   objectr   rl   contextmanagerra   r   r   r   r   <module>   s,    
