o
    Yi[                     @   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   Y/home/kim/smarthome/.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,   Znormalized_obj_1Z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   )r.   r   r   r   _redact_version_numbers]      r1   language_labelc                 C   r/   )z;Removed because replay requests are used for all languages.z
gl-python/z{LANGUAGE_LABEL}/r0   )r3   r   r   r   _redact_language_labelb   r2   r4   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   r4   r1   )r5   Zredacted_headersheader_nameheader_valuer   r   r   _redact_request_headersg   s$   



r9   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}r0   )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}/r0   )r=   r;   r   r   r   _redact_project_location_path   s   r>   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   r>   r   r   r&   _redact_request_body	enumerate)r?   keyr)   ir   r   r   r@      s:   





r@   http_requestc                 C   s6   t | j| _t| j| _t| jtst| j d S d S N)r9   r5   r<   r:   r   databytesr@   )rD   r   r   r   redact_http_request   s
   rH   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   

rS   messagec                 C   s    t dtjddt d|  d S )NzDEBUG (testZPYTEST_CURRENT_TEST)z:
    )printosenvirongetrS   )rT   r   r   r   _debug_print   s   
rZ   c                 C   s   |  dd |  dd dS )z*Remove headers that are not deterministic.DateNzServer-Timing)pop)r5   r   r   r   pop_undeterministic_headers   s   r]   clientReplayApiClientc              
   c   s:    zd V  W d S  t jy } z| || |d }~ww rE   r	   APIError_record_interactionr^   rD   er   r   r   _record_on_api_error      re   c              
   C  s:   zd V  W d S  t jy } z| || |d }~ww rE   r`   rc   r   r   r   _async_record_on_api_error   rf   rg   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:   r5   body_segmentsN)	__name__
__module____qualname____doc__r   __annotations__r$   r&   objectr   r   r   r   rh      s   
 rh   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_coder5   rj   Nbyte_segmentssdk_response_segments_ReplayResponse__contextr   c                 C   s   t | j d S rE   )r]   r5   )selfrv   r   r   r   model_post_init  s   zReplayResponse.model_post_init)rk   rl   rm   rn   rs   intro   r$   r   r&   rp   rt   r   rG   r   rx   r   r   r   r   rq     s   
 rq   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)rk   rl   rm   rn   rh   ro   rq   r   r   r   r   rz     s   
 rz   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)rk   rl   rm   rn   r   ro   r&   rz   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 )Dr_   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   ZGOOGLE_GENAI_REPLAYS_DIRECTORY)
super__init__r   rW   rX   rY   replay_session_mode
_replay_id_private)rw   r   r~   r   r   r   r   r   r   r   r   	__class__r   r   r      s"   
zReplayApiClient.__init__r   c                 C   s   || _ |   d S rE   )r   _initialize_replay_session)rw   r~   r   r   r   initialize_replay_session@  s   z)ReplayApiClient.initialize_replay_sessionc                 C   s   |  | j| jS rE   )"_generate_file_path_from_replay_idr   r   rw   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   rW   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 rE   )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   )rZ   r   _replay_index_sdk_response_indexr   rW   r=   r   r   
ValueErroropenr}   Zmodel_validatejsonloadsreadr   r   )rw   replay_file_pathZ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   extendrW   r=   join)rw   r   r~   Z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   )Zexclude_unsetindent)
r   r   r   rW   makedirsr=   dirnamer   writeZmodel_dump_json)rw   r   r   r   r   r   closey  s   
zReplayApiClient.closerD   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)ri   r:   r5   rj   c                 S   s   g | ]
}|d d d qS )Nd   s   ...r   )r   segr   r   r   r#     s    z7ReplayApiClient._record_interaction.<locals>.<listcomp>)r5   rj   rt   rs   ru   )r5   rj   rs   ru   )r5   rj   rt   ru   z Unsupported http_response type: No replay session found.)r{   r|   )r   rH   rh   ri   r:   r5   rF   r   r   rq   r$   r&   segmentsrt   rs   r	   ra   r|   Z_to_replay_recordcoderG   r   r   typer   r   appendrz   )rw   rD   r   r{   r|   r   r   r   rb     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: )rZ   r:   r{   r5   ri   copydeepcopyrF   r   rG   r@   rj   r-   )rw   rD   r   Zrequest_data_copyZactual_request_bodyZ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>)r5   response_streambyte_streamz{}rI   )rH   r   r   r   r   r   r   r	   ra   Zraise_for_responser|   r   r5   rj   rt   r   )rw   rD   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   Zsdk_http_responser5   T)exclude_nonezresponse_model: r   )r   r   r?   zraw_body length: z
raw_body: rI   zSDK response mismatch:
Actual: r   z(Expected SDK response mismatch:
Actual: )r   r   r   r   r   r   r   r&   getattrr]   r|   ru   r   Z
model_dumprZ   r   r$   r   r   r   r   r   r   )rw   r   r   Zsdk_response_responser5   actualexpectedZ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   rZ   re   r   _requestr   r   r   r   r   r5   rb   r   rw   rD   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   rZ   rg   r   _async_requestZasync_segmentsr   r   r   r   r5   rb   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POSTrI   rG   zutf-8)ri   r:   rF   r5   r   r   )r   ioIOBasetellr   seekrW   SEEK_SETr   base64	b64encodedecoder   re   r   upload_filerb   r   	rw   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   rW   r   r   r   r   r   r   rg   r   async_upload_filerb   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 NrY   )r=   Zrequest_dictr   r   r   )	r   _build_requestr   re   r   download_filerb   r   r   rw   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   rg   r   async_download_filerb   r   r   r   r   r   r   r     s   (z#ReplayApiClient.async_download_file)NFNNNNNF)r   N)NF).rk   rl   rm   rn   r   r   r   boolgoogleauthr   Credentialsr   r   r   r   r   r   r   r   r   r   r   r   r   r	   ra   rG   rb   rz   r   r   r   r   r   r   r   r   r   ry   r   r   r   r   r   __classcell__r   r   r   r   r_     s    	
 


	
0
!:"'")7rn   r   r   
contextlibr'   rJ   r   r   rW   r   typingr   r   r   r   r   r   Zgoogle.authr   rI   r	   Z_api_clientr
   r   r   _commonr   typesr   r   r   r   r   r   r-   r1   r4   r$   r9   r<   r>   r@   rH   rS   rZ   r]   contextmanagerre   asynccontextmanagerrg   rh   rq   rz   r}   r_   r   r   r   r   <module>   sP    	"	