o
    i[                     @   sV  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ZddlZddl	Z	ddl
mZmZmZmZmZm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mZ dedefddZdedefddZ dedede!fddZ"dedefddZ#dedefddZ$de%eef de%eef fddZ&dedefd d!Z'd"edefd#d$Z(d%eddfd&d'Z)d(eddfd)d*Z*defd+d,Z+d-eddfd.d/Z,de%eef ddfd0d1Z-ej.d2d3d(eded fd4d5Z/ej0d2d3d(eded fd6d7Z1G d8d9 d9eZ2G d:d; d;eZ3G d<d= d=eZ4G d>d? d?eZ5G d@d3 d3eZ6dS )AzReplay API client.    N)AnyLiteralOptionalUnionIteratorAsyncIterator   )errors)BaseApiClient)HttpRequest)HttpResponse)	BaseModel)HttpOptionsHttpOptionsOrDictnamereturnc                 C   s2   t | ts	t| } tdd| }tdd| S )z=Converts a string from camelCase or PascalCase to snake_case.z(.)([A-Z][a-z]+)z\1_\2z([a-z0-9])([A-Z]))
isinstancestrresublower)r   s1 r   W/home/livre-enfant/venv/lib/python3.10/site-packages/google/genai/_replay_api_client.pyto_snake_case'   s   
r   objc                 C   sh   t | trdd |  D S t | trdd | D S t | tjr#| jS t | tr2d| v r2| ddS | S )Nc                 S   s   i | ]\}}t |t|qS r   )r   _normalize_json_case).0kvr   r   r   
<dictcomp>2   s    z(_normalize_json_case.<locals>.<dictcomp>c                 S   s   g | ]}t |qS r   r   )r   itemr   r   r   
<listcomp>7   s    z(_normalize_json_case.<locals>.<listcomp>zdivision by zeroz"integer division or modulo by zero)	r   dictitemslistenumEnumvaluer   replace)r   r   r   r   r   0   s   


r   obj1obj2c                 C   s    t | }t |}||krdS dS )a  Compares two Python objects for equality ignoring key casing.

  Returns:
      bool: True if the two objects are equal regardless of key casing
  (camelCase vs. snake_case). For example, the following are considered equal:

  {'my_key': 'my_value'}
  {'myKey': 'my_value'}

  This also considers enums and strings with the same value as equal.
  For example, the following are considered equal:

  {'type': <Type.STRING: 'STRING'>}}
  {'type': 'STRING'}
  TFr!   )r+   r,   normalized_obj_1normalized_obj_2r   r   r   _equals_ignore_key_caseC   s
   r/   version_stringc                 C      t dd| S )z8Redacts version numbers in the form x.y.z from a string.z\d+\.\d+\.\d+[a-zA-Z0-9]*z{VERSION_NUMBER}r   r   )r0   r   r   r   _redact_version_numbers]      r3   language_labelc                 C   r1   )z;Removed because replay requests are used for all languages.z
gl-python/z{LANGUAGE_LABEL}/r2   )r5   r   r   r   _redact_language_labelb   r4   r6   headersc                 C   s   i }|   D ]?\}}| dkrd||< q| dkr$tt|||< q| dkr3tt|||< q| dkr:q| dkrAq|||< q|S )z,Redacts headers that should not be recorded.zx-goog-api-keyz
{REDACTED}z
user-agentzx-goog-api-clientzx-goog-user-projectauthorization)r%   r   r6   r3   )r7   redacted_headersheader_nameheader_valuer   r   r   _redact_request_headersg   s$   



r<   urlc                 C   s<   t dd| }t dd|}t dd|}t dd|}|S )Nz".*/projects/[^/]+/locations/[^/]+/z{VERTEX_URL_PREFIX}/z#.*-aiplatform.googleapis.com/[^/]+/z".*aiplatform.googleapis.com/[^/]+/z+.*generativelanguage.*.googleapis.com/[^/]+z{MLDEV_URL_PREFIX}r2   )r=   resultr   r   r   _redact_request_url~   s*   r?   pathc                 C   s&   d| v rd| v rt dd| }|S | S )Nz	projects/z
locations/zprojects/[^/]+/locations/[^/]+/z{PROJECT_AND_LOCATION_PATH}/r2   )r@   r>   r   r   r   _redact_project_location_path   s   rA   bodyc                 C   s   t | tr0|  D ]$\}}t |tr"t|}tdd|}|| |< q	t |ttfr-t| q	dS t | tr^t	| D ]&\}}t |trRt|}tdd|}|| |< q9t |ttfr]t| q9dS dS )z,Redacts fields in the request body in place.z<[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}z{UUID}N)
r   r$   r%   r   rA   r   r   r&   _redact_request_body	enumerate)rB   keyr)   ir   r   r   rC      s:   





rC   http_requestc                 C   s6   t | j| _t| j| _t| jtst| j d S d S N)r<   r7   r?   r=   r   databytesrC   )rG   r   r   r   redact_http_request   s
   rK   c                  C   sR   t  } | dur'| jdur'| jjdur'| jj}t |}|j}d| d| S dS )z-Prints the current file path and line number.NzFile: z, Line:  )inspectcurrentframef_backgetfilef_lineno)current_frameframefilepathlinenor   r   r   _current_file_path_and_line   s   

rV   messagec                 C   s    t dtjddt d|  d S )NzDEBUG (testPYTEST_CURRENT_TEST)z:
    )printosenvirongetrV   )rW   r   r   r   _debug_print   s   
r^   c                 C   s   |  dd |  dd dS )z*Remove headers that are not deterministic.DateNzServer-Timing)pop)r7   r   r   r   pop_undeterministic_headers   s   ra   clientReplayApiClientc              
   c   s:    zd V  W d S  t jy } z| || |d }~ww rH   r	   APIError_record_interactionrb   rG   er   r   r   _record_on_api_error      ri   c              
   C  s:   zd V  W d S  t jy } z| || |d }~ww rH   rd   rg   r   r   r   _async_record_on_api_error   rj   rk   c                   @   sF   e Zd ZU dZeed< eed< eeef ed< eeeef  ed< dS )ReplayRequestz(Represents a single request in a replay.methodr=   r7   body_segmentsN)	__name__
__module____qualname____doc__r   __annotations__r$   r&   objectr   r   r   r   rl      s   
 rl   c                   @   s|   e Zd ZU dZdZeed< eeef ed< e	eee
f  ed< dZee	e  ed< e	eee
f  ed< d	ed
dfddZdS )ReplayResponsez)Represents a single response in a replay.   status_coder7   rn   Nbyte_segmentssdk_response_segments_ReplayResponse__contextr   c                 C   s   t | j d S rH   )ra   r7   )selfrz   r   r   r   model_post_init  s   zReplayResponse.model_post_init)ro   rp   rq   rr   rw   intrs   r$   r   r&   rt   rx   r   rJ   r   r|   r   r   r   r   ru     s   
 ru   c                   @   s"   e Zd ZU dZeed< eed< dS )ReplayInteractionzBRepresents a single interaction, request and response in a replay.requestresponseN)ro   rp   rq   rr   rl   rs   ru   r   r   r   r   r~     s   
 r~   c                   @   s&   e Zd ZU dZeed< ee ed< dS )
ReplayFilezRepresents a recorded session.	replay_idinteractionsN)ro   rp   rq   rr   r   rs   r&   r~   r   r   r   r   r     s   
 r   c                       s\  e Zd ZdZ								dAded dedee ded	ee d
eej	j
j dee dee dee def fddZdeddfddZdefddZdefddZdefddZdBddZdBddZdee dedefdd ZdBd!d"Zd#ed$eeejef ddfd%d&Zd#ed'eddfd(d)Zd#edefd*d+Zd,e ddfd-d.Z!		dCd#edee" d/edef fd0d1Z#		dCd#edee" d/edef fd2d3Z$dd4d5eee%j&f d6ed7e'dee" def
 fd8d9Z(dd4d5eee%j&f d6ed7e'dee" def
 fd:d;Z)dd4d<edee" deeee*f f fd=d>Z+dd4d<edee" de*f fd?d@Z,  Z-S )Drc   zFFor integration testing, send recorded response or records a response.NFmode)recordreplayautoapir   replays_directoryvertexaiapi_keycredentialsprojectlocationhttp_optionsprivatec                    sP   t  j||||||	d || _| jstjdd | _d | _|| _|| _|
| _	d S )N)r   r   r   r   r   r   GOOGLE_GENAI_REPLAYS_DIRECTORY)
super__init__r   r[   r\   r]   replay_session_mode
_replay_id_private)r{   r   r   r   r   r   r   r   r   r   r   	__class__r   r   r      s"   
zReplayApiClient.__init__r   c                 C   s   || _ |   d S rH   )r   _initialize_replay_session)r{   r   r   r   r   initialize_replay_session@  s   z)ReplayApiClient.initialize_replay_sessionc                 C   s   |  | j| jS rH   )"_generate_file_path_from_replay_idr   r   r{   r   r   r   _get_replay_file_pathD  s   z%ReplayApiClient._get_replay_file_pathc                 C   s&   | j dv p| j dkotj|   S )N)r   r   r   )r   r[   r@   isfiler   r   r   r   r   _should_call_apiI  s   

z ReplayApiClient._should_call_apic                 C   s   |   o| jdkS )Nr   )r   r   r   r   r   r   _should_update_replayO  s   z%ReplayApiClient._should_update_replayc                 C   s   | j s	|   d S d S rH   )r   r   r   r   r   r   (_initialize_replay_session_if_not_loadedR  s   z8ReplayApiClient._initialize_replay_session_if_not_loadedc                 C   s   t d| j  d| _d| _|  }tj|}| jdkr%|s%t	d| j | jdv rL|rLt
|d}tt| | _W d    n1 sGw   Y  |  rZt| jg d| _d S d S )NzTest is using replay id: r   r   z)Replay files do not exist for replay id: )r   r   r)r   r   )r^   r   _replay_index_sdk_response_indexr   r[   r@   r   r   
ValueErroropenr   model_validatejsonloadsreadr   r   )r{   replay_file_pathreplay_file_existsfr   r   r   r   V  s$   z*ReplayApiClient._initialize_replay_sessionreplay_directoryc                 C   sR   | d}t|dk rt| d|d u rg }n|g}|| tjj| d S )N/   zD: Session ID must be in the format of module/function/[vertex|mldev]z.json)splitlenr   extendr[   r@   join)r{   r   r   session_parts
path_partsr   r   r   r   k  s   

z2ReplayApiClient._generate_file_path_from_replay_idc                 C   sz   |   r| js	d S |  }tjtj|dd t|d}|| jj	ddd W d    n1 s3w   Y  d | _d S )NT)exist_okw   )exclude_unsetindent)
r   r   r   r[   makedirsr@   dirnamer   writemodel_dump_json)r{   r   r   r   r   r   closey  s   
zReplayApiClient.closerG   http_responsec                 C   s   |   sd S t| t|j|j|j|jgd}t|tr5t	t
|jt| dd | D |jg d}n0t|tjrLt	t
|jj| g|jg d}nt|tr[t	i g |gg d}n
tdtt| | jd u rntd| jjt||d	 d S )
N)rm   r=   r7   rn   c                 S   s   g | ]
}|d d d qS )Nd   s   ...r   )r   segr   r   r   r#     s    z7ReplayApiClient._record_interaction.<locals>.<listcomp>)r7   rn   rx   rw   ry   )r7   rn   rw   ry   )r7   rn   rx   ry   z Unsupported http_response type: No replay session found.)r   r   )r   rK   rl   rm   r=   r7   rI   r   r   ru   r$   r&   segmentsrx   rw   r	   re   r   _to_replay_recordcoderJ   r   r   typer   r   appendr~   )r{   rG   r   r   r   r   r   r   rf     sR   

	



z#ReplayApiClient._record_interactioninteractionc                 C   s   t d|j  t d|jj  |j|jjksJ |j|jjks.J d|j d|jj |j|jjks7J t|j}t|t	sFt
| |g}t|jj}|D ]}t|t	s]t
| qRt||smJ d| d| d S )Nzhttp_request.url: zinteraction.request.url: z"Request headers mismatch:
Actual: 
Expected: zRequest body mismatch:
Actual: )r^   r=   r   r7   rm   copydeepcopyrI   r   rJ   rC   rn   r/   )r{   rG   r   request_data_copyactual_request_bodyexpected_request_bodysegmentr   r   r   _match_request  s6   

zReplayApiClient._match_requestc                 C   s   t | | jd u rtd| jj| j }| || |  jd7  _d| _tj	|j
 t|j
jdd |j
jD |j
jd}|jdgkrGdg|_|S )	Nr   r   r   c                 S   s   g | ]}t |qS r   )r   dumps)r   r   r   r   r   r#     s    z?ReplayApiClient._build_response_from_replay.<locals>.<listcomp>)r7   response_streambyte_streamz{}rL   )rK   r   r   r   r   r   r   r	   re   raise_for_responser   r   r7   rn   rx   r   )r{   rG   r   r   r   r   r   _build_response_from_replay  s$   
z+ReplayApiClient._build_response_from_replayresponse_modelc                 C   s  | j dkrd S | jstd| jj| jd  }|  rIt|tr$|d }t|dd }|r<|d ur<t|dd }|r<t	| |j
j|jdd d S t|trR|d }td	|jdd  |jdd
d}|j
j| j }t|trd|v rt|d trd|d v r|d d }tdt|  td|  t|tr|dkrt|}t|}||d d< | js||ksJ d| d| n
td| d|  |  jd7  _d S )Nr   r   r   r   sdk_http_responser7   T)exclude_nonezresponse_model: r   )r   r   rB   zraw_body length: z
raw_body: rL   zSDK response mismatch:
Actual: r   z(Expected SDK response mismatch:
Actual: )r   r   r   r   r   r   r   r&   getattrra   r   ry   r   
model_dumpr^   r   r$   r   r   r   r   r   r   )r{   r   r   sdk_response_responser7   actualexpectedraw_bodyr   r   r   _verify_response  s^   








z ReplayApiClient._verify_responsestreamc                    s   |    |  rZtd|  t| | t |||}W d    n1 s&w   Y  |rKg }| D ]
}|t	| q3t
|j|}| || n| || td|j  |S | |S Nzapi mode request: %szapi mode result: %s)r   r   r^   ri   r   _requestr   r   r   r   r   r7   rf   r   r{   rG   r   r   r>   result_segmentsr   r   r   r   r   !  s    
zReplayApiClient._requestc              	      s   |    |  rmtd|  t| |4 I d H  t |||I d H }W d   I d H  n1 I d H s4w   Y  |r^g }| 2 z3 d H W }|t	| qA6 t
|j|}| || n| || td|j  |S | |S r   )r   r   r^   rk   r   _async_requestasync_segmentsr   r   r   r   r7   rf   r   r   r   r   r   r   ;  s(   (
zReplayApiClient._async_requestr   	file_path
upload_urlupload_sizec          	         s   t |tjr&| }| }||tj tdddt	
|dii d}n
tddd|ii d}|  r[t| | t j||||d}W d    n1 sNw   Y  | || |S | |S NPOSTrL   rJ   zutf-8)rm   r=   rI   r7   r   r   )r   ioIOBasetellr   seekr[   SEEK_SETr   base64	b64encodedecoder   ri   r   upload_filerf   r   	r{   r   r   r   r   offsetcontentr   r>   r   r   r   r   W  s,   
zReplayApiClient.upload_filec          	   	      s   t |tjr'| }| }||tj tdddt	
|dii d}n
tddd|ii d}|  rit| |4 I d H  t j||||dI d H }W d   I d H  n1 I d H s\w   Y  | || |S | |S r   )r   r   r   r   r   r   r[   r   r   r   r   r   r   rk   r   async_upload_filerf   r   r   r   r   r   r   x  s.   (
z!ReplayApiClient.async_upload_filer@   c                   s|   |    | jd|i |d}|  r6t| | t j||d}W d    n1 s)w   Y  | || |S | |jd S Nr]   )r@   request_dictr   r   r   )	r   _build_requestr   ri   r   download_filerf   r   r   r{   r@   r   r   r>   r   r   r   r     s   zReplayApiClient.download_filec             	      s   |    | jd|i |d}|  rDt| |4 I d H  t j||dI d H }W d   I d H  n1 I d H s7w   Y  | || |S | |jd S r   )	r   r   r   rk   r   async_download_filerf   r   r   r  r   r   r   r    s   (z#ReplayApiClient.async_download_file)NFNNNNNF)r   N)NF).ro   rp   rq   rr   r   r   r   boolgoogleauthr   Credentialsr   r   r   r   r   r   r   r   r   r   r   r   r   r	   re   rJ   rf   r~   r   r   r   r   r   r   r   r   r   r}   r   r   r   r   r  __classcell__r   r   r   r   rc     s    	
 


	
0
!:"'")7rr   r   r   
contextlibr'   rM   r   r   r[   r   typingr   r   r   r   r   r   google.authr  rL   r	   _api_clientr
   r   r   _commonr   typesr   r   r   r   r   r  r/   r3   r6   r$   r<   r?   rA   rC   rK   rV   r^   ra   contextmanagerri   asynccontextmanagerrk   rl   ru   r~   r   rc   r   r   r   r   <module>   sP    	"	