o
    r::j                     @  s  d dl m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 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mZ d dlmZmZmZmZmZmZmZm Z  d dl!m"Z"m#Z# erpd dl$m%Z% G dd	 d	ej&Z'e(d
did
digG dd de'Z)e(d
did
digG dd de'Z*e(d
did
digG dd dej&Z+e(d
did
digG dd dej&Z,G dd de'Z-ej.ej/dkddG dd de-Z0G dd de+Z1G dd de,Z2G d d! d!ej&Z3d5d$d%Z4ej.ej/dkd&dG d'd( d(e'Z5ej.ej/dkd&dG d)d* d*e'Z6ej.ej/dkd+dG d,d- d-e'Z7G d.d/ d/e'Z8G d0d1 d1ej&Z9G d2d3 d3e'Z:e;d4krYe<  dS dS )6    )annotationsN)TYPE_CHECKINGAny)
ModelProto	NodeProtoTensorProtocheckerhelperparsershape_inference)_ALLOWED_EXTERNAL_DATA_KEYSExternalDataInfo convert_model_from_external_dataconvert_model_to_external_dataload_external_data_for_modelload_external_data_for_tensorsave_external_dataset_external_data)
from_arrayto_array)Sequencec                   @  s`   e Zd ZU dZdZded< dddZdd	d
ZdddZ	ddddZ	ddddZ
dddZdS )TestLoadExternalDataBasezBase class for testing external data related behaviors.

    Subclasses should be parameterized with a serialization format.
    protobufstrserialization_formatreturnNonec                 C  b   t  | _| jj| _tdddtj	d | _
tdddtj	d | _|  | _d S N         i      )tempfileTemporaryDirectory_temp_dir_objnametemp_dirnparangereshapeastypefloat32initializer_valueattribute_valuecreate_test_modelmodel_filenameself r3   c/home/nk/hobo-godmode/plappi-mvp/.venv/lib/python3.10/site-packages/onnx/test/test_external_data.pysetUp5   
   

  zTestLoadExternalDataBase.setUpc                 C     | j   d S Nr%   cleanupr1   r3   r3   r4   tearDown<      z!TestLoadExternalDataBase.tearDownc                 C     t j| jtt d S Nz.onnxospathjoinr'   r   uuiduuid4r1   r3   r3   r4   get_temp_model_filename?      z0TestLoadExternalDataBase.get_temp_model_filename value	list[Any]tensor_namelocationr   c                 C  s   t t|}||_|p| d}t||d ttj| j	|d}|
|j W d    n1 s3w   Y  |d tjj|_|S )N.binrK   wbraw_data)r   r(   arrayr&   r   openr@   rA   rB   r'   writerO   
ClearFieldonnxr   EXTERNALdata_location)r2   rH   rJ   rK   tensortensor_filename	data_filer3   r3   r4   create_external_data_tensorB   s   

z4TestLoadExternalDataBase.create_external_data_tensorc                 C  s   t jjdg dg| | jdd}| | jd|g}tdt jj| jj	g}tj
|gd|g |d}t|}tj| jd}t ||| j |S )	NConstantvaluesr.   inputsoutputsrH   input_value
test_graphr^   r_   initializer
model.onnx)rT   r	   	make_noderZ   r.   r-   make_tensor_value_infor   FLOATshape
make_graph
make_modelr@   rA   rB   r'   
save_modelr   )r2   rK   constant_nodeinitializersr^   graphmodelr0   r3   r3   r4   r/   P   s<   
z*TestLoadExternalDataBase.create_test_modelc                 C  s$   | j dkr
| d t| j d S )Nr   zDcheck_model supports protobuf only as binary when provided as a path)r   skipTestr   check_modelr0   r1   r3   r3   r4   test_check_modelv   s
   
z)TestLoadExternalDataBase.test_check_modelNr   r   )r   r   rG   rH   rI   rJ   r   rK   r   r   r   )rK   r   r   r   )__name__
__module____qualname____doc__r   __annotations__r5   r;   rE   rZ   r/   rr   r3   r3   r3   r4   r   -   s   
 


&r   r   r   	textprotoc                   @  s*   e Zd Zd
ddZd
ddZd
ddZd	S )TestLoadExternalDatar   r   c                 C  \   t | j| j}|jjd }tjt	|| j
 |jjd jd j}tjt	|| j d S Nr   rT   
load_modelr0   r   rn   rc   r(   testingassert_allcloser   r-   node	attributetr.   r2   ro   initializer_tensorattribute_tensorr3   r3   r4   test_load_external_data   s
   z,TestLoadExternalData.test_load_external_datac                 C  sl   t j| j| jdd}t|| j |jjd }tj	
t|| j |jjd jd j}tj	
t|| j d S )NFload_external_datar   )rT   r   r0   r   r   r'   rn   rc   r(   r   r   r   r-   r   r   r   r.   r   r3   r3   r4   !test_load_external_data_for_model   s   
z6TestLoadExternalData.test_load_external_data_for_modelc                 C     t | j| j}tj| jd}t| tj|d}t 	||| j t || j}|j
jd }tjt|| j |j
jd jd j}tjt|| j d S N	save_copyrd   r   rT   r   r0   r   r@   rA   rB   r'   mkdirrk   rn   rc   r(   r   r   r   r-   r   r   r   r.   r2   ro   r'   new_model_filename	new_modelr   r   r3   r3   r4   test_save_external_data      
z,TestLoadExternalData.test_save_external_dataNrs   )rv   rw   rx   r   r   r   r3   r3   r3   r4   r|   ~   s    

r|   c                   @  sF   e Zd ZdddZddd	Zdd
dZeje	ddddZ
dS )TestLoadExternalDataSingleFiletensors_datalist[tuple[list[Any], Any]]r   list[TensorProto]c           	      C  s   d}g }t tj| j|dX}|D ]L\}}tt|}| }|d dkr:|	dd|d    |d |d  }|	|j
 t|||| | d ||_|d tjj|_|| qW d    |S 1 sjw   Y  |S )Ntensors.binab   r       rK   offsetlengthrO   )rQ   r@   rA   rB   r'   r   r(   rP   tellrR   rO   r   r&   rS   rT   r   rU   rV   append)	r2   r   rX   tensorsrY   rH   rJ   rW   r   r3   r3   r4   create_external_data_tensors   s2   



z;TestLoadExternalDataSingleFile.create_external_data_tensorsr   c                 C  r}   r~   r   r   r3   r3   r4   #test_load_external_single_file_data   s
   zBTestLoadExternalDataSingleFile.test_load_external_single_file_datac                 C  r   r   r   r   r3   r3   r4   #test_save_external_single_file_data   r   zBTestLoadExternalDataSingleFile.test_save_external_single_file_data)TFuse_absolute_pathboolc           	      C  s   t | j| j}tj| jd}t| tj| jd}t| |r,tj|d}nd}tj| jd}t| tj|d}ddd}|||d | 	t j
j t ||| j W d    d S 1 shw   Y  d S )Nr   invalid_external_datar   z$../invalid_external_data/tensors.binexternal_datard   ro   r   rK   r   c                 S  s&   | j jD ]}|drt|| qd S )NrO   )rn   rc   HasFieldr   )ro   rK   rW   r3   r3   r4   'convert_model_to_external_data_no_check   s
   

zTestLoadExternalDataSingleFile.test_save_external_invalid_single_file_data_and_check.<locals>.convert_model_to_external_data_no_checkrM   )ro   r   rK   r   )rT   r   r0   r   r@   rA   rB   r'   r   assertRaisesr   ValidationErrorrk   )	r2   r   ro   	model_dirtraversal_external_data_dir traversal_external_data_locationexternal_data_dirnew_model_filepathr   r3   r3   r4   5test_save_external_invalid_single_file_data_and_check   s.   



"zTTestLoadExternalDataSingleFile.test_save_external_invalid_single_file_data_and_checkNr   r   r   r   rs   )r   r   r   r   )rv   rw   rx   r   r   r   parameterizedexpand	itertoolsproductr   r3   r3   r3   r4   r      s    


	r   c                   @  s   e Zd ZU dZded< d.ddZdd	 Zd/ddZd0ddZe	
edkdd.ddZd.ddZd.ddZd.ddZd.ddZd.ddZd.dd Zd.d!d"Zd.d#d$Zd.d%d&Zd.d'd(Zd.d)d*Zd.d+d,Zd-S )1 TestSaveAllTensorsAsExternalDatar   r   r   r   r   c                 C  r   r   )r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   create_test_model_protoro   r1   r3   r3   r4   r5     r6   z&TestSaveAllTensorsAsExternalData.setUpc                 C  r=   r>   r?   r1   r3   r3   r4   rE     rF   z8TestSaveAllTensorsAsExternalData.get_temp_model_filenamer   r   r   c                 C  s4   g }|D ]\}}t t|}||_|| q|S r8   )r   r(   rP   r&   r   )r2   r   r   rH   rJ   rW   r3   r3   r4   create_data_tensors!  s   z4TestSaveAllTensorsAsExternalData.create_data_tensorsr   c                 C  sr   |  | jdf| jdfg}tjjdg dg|d d}tdtjj| jj	g}tj
|gd|g |d gd	}t|S )
Nr.   r`   r[   r\   r   r]   ra      rb   )r   r.   r-   rT   r	   re   rf   r   rg   rh   ri   rj   )r2   r   rl   r^   rn   r3   r3   r4   r   ,  s(   
z8TestSaveAllTensorsAsExternalData.create_test_model_proto:check_model supports protobuf only when provided as a pathc                 C     t | j d S r8   r   rq   ro   r1   r3   r3   r4   rr   G     z1TestSaveAllTensorsAsExternalData.test_check_modelc                 C  sV   |   }t| jdd t| j|| j t|| j}|jjd }| 	|
d d S )N   size_thresholdr   rV   )rE   r   ro   rT   rk   r   r   rn   rc   assertFalser   r2   model_file_pathro   r   r3   r3   r4   7test_convert_model_to_external_data_with_size_thresholdN  s   zXTestSaveAllTensorsAsExternalData.test_convert_model_to_external_data_with_size_thresholdc                 C  sj   |   }t| jdd t| j|| j t|| j}|jjd }| 	|
d tjt|| j d S )Nr   r   rV   )rE   r   ro   rT   rk   r   r   rn   rc   
assertTruer   r(   r   r   r   r-   r   r3   r3   r4   :test_convert_model_to_external_data_without_size_thresholdX  s   z[TestSaveAllTensorsAsExternalData.test_convert_model_to_external_data_without_size_thresholdc                 C  s  |   }tt }t| jdd|d t| j|| j | 	t
jt
j| j| t|| j}t| |   }t||| j t|| j}|jjd }| t|j | |jtj tjt|| j |jjd j d j!}| t|j | |jtj tjt|| j" d S )Nr   T)r   all_tensors_to_one_filerK   )#rE   r   rC   rD   r   ro   rT   rk   r   r   r@   rA   isfilerB   r'   r   r   rn   rc   r   lenr   assertEqualrV   r   DEFAULTr(   r   r   r   r-   r   r   r   r.   )r2   r   external_data_filero   r   r   r3   r3   r4   ?test_convert_model_to_external_data_from_one_file_with_locationb  s.   z`TestSaveAllTensorsAsExternalData.test_convert_model_to_external_data_from_one_file_with_locationc                 C  s^   |   }t| jddd t| j|| j | tj	| | tj	tj
| j| d S )Nr   T)r   r   rE   r   ro   rT   rk   r   r   r@   rA   r   rB   r'   r2   r   r3   r3   r4   Rtest_convert_model_to_external_data_from_one_file_without_location_uses_model_name  s   "zsTestSaveAllTensorsAsExternalData.test_convert_model_to_external_data_from_one_file_without_location_uses_model_namec                 C  s~   |   }t| jdddd t| j|| j | tj	| | tj	tj
| jd | tj	tj
| jd d S )Nr   Fr   r   convert_attributer`   r.   )rE   r   ro   rT   rk   r   r   r@   rA   r   rB   r'   r   r   r3   r3   r4   Itest_convert_model_to_external_data_one_file_per_tensor_without_attribute     "zjTestSaveAllTensorsAsExternalData.test_convert_model_to_external_data_one_file_per_tensor_without_attributec                 C  s~   |   }t| jdddd t| j|| j | tj	| | tj	tj
| jd | tj	tj
| jd d S )Nr   FTr   r`   r.   r   r   r3   r3   r4   Ftest_convert_model_to_external_data_one_file_per_tensor_with_attribute  r   zgTestSaveAllTensorsAsExternalData.test_convert_model_to_external_data_one_file_per_tensor_with_attributec                 C  s   |   }t| jdddd t| j|| j | tj	tj
| jd | tj	tj
| jd t|| j}|jjd }| |d |jjd jd j}| |d d S )Nr   F)r   r   r   r`   r.   rV   )rE   r   ro   rT   rk   r   r   r@   rA   r   rB   r'   r   r   rn   rc   r   r   r   r   r2   r   ro   r   r   r3   r3   r4   Etest_convert_model_to_external_data_does_not_convert_attribute_values  s   zfTestSaveAllTensorsAsExternalData.test_convert_model_to_external_data_does_not_convert_attribute_valuesc                 C  s   |   }t| jddd t| j|| j t|| j}|jjd }t	j
t|| j | |d |jjd jd j}t	j
t|| j | |d d S )Nr   Tr   r   rV   )rE   r   ro   rT   rk   r   r   rn   rc   r(   r   r   r   r-   r   r   r   r   r   r.   r   r3   r3   r4   =test_convert_model_to_external_data_converts_attribute_values  s   z^TestSaveAllTensorsAsExternalData.test_convert_model_to_external_data_converts_attribute_valuesc                 C  s   |   }tj| j|| jdd | tj| t	|| j}|j
jd }| |d |j
jd jd j}| |d d S )NF)save_as_external_datar   rV   )rE   rT   rk   ro   r   r   r@   rA   r   r   rn   rc   r   r   r   r   r   r   r3   r3   r4   Etest_save_model_does_not_convert_to_external_data_and_saves_the_model  s   zfTestSaveAllTensorsAsExternalData.test_save_model_does_not_convert_to_external_data_and_saves_the_modelc              
   C  s   |   }tj| j|| jddd ddd t|| j}|jjd }| |	d t
jt|| j |jjd jd j}| |	d t
jt|| j d S )NTr   Fr   r   rK   r   r   rV   rE   rT   rk   ro   r   r   rn   rc   r   r   r(   r   r   r   r-   r   r   r   r   r.   r   r3   r3   r4   0test_save_model_does_convert_and_saves_the_model  s$   zQTestSaveAllTensorsAsExternalData.test_save_model_does_convert_and_saves_the_modelc              	   C  s   |   }tj| j|| jdd ddd tj|| jdd}tj||| jdd ddd t|| j}|jjd }| |	d t
jt|| j |jjd jd j}| |	d t
jt|| j d S )NTr   F)r   rK   r   r   r   rV   r   r   r3   r3   r4   -test_save_model_without_loading_external_data  s:   

zNTestSaveAllTensorsAsExternalData.test_save_model_without_loading_external_datac                 C  s   |   }| jjjd j}tj| j|| jddd | t	j
| tj|| jdd}|jjd }d|_t|| j | |j| d S )Nr   T)r   r   Fr   s   dummpy_raw_data)rE   ro   rn   rc   rO   rT   rk   r   r   r@   rA   r   r   r   r'   r   )r2   r   original_raw_dataro   r   r3   r3   r4   6test_save_model_with_existing_raw_data_should_override&  s"   zWTestSaveAllTensorsAsExternalData.test_save_model_with_existing_raw_data_should_overrideNrs   r   r   r   )rv   rw   rx   r   rz   r5   rE   r   r   unittestskipIfrr   r   r   r   r   r   r   r   r   r   r   r   r   r3   r3   r3   r4   r     s.   
 















#r   c                   @  s|   e Zd ZU dZded< dddZedd	 Zdd
dZdddZ	e
edkddddZdddZdddZdddZdS )TestExternalDataToArrayr   r   r   r   r   c                 C  sT   t  | _| jj| _tj| jd| _t	j
dddt	j| _d| _|  | _d S )Nrd   
   <   d   )   i,  )r#   r$   r%   r&   r'   r@   rA   rB   _model_file_pathr(   randomrandr+   r,   
large_data
small_datar/   ro   r1   r3   r3   r4   r5   E  s   

zTestExternalDataToArray.setUpc                 C  s   | j S r8   )r   r1   r3   r3   r4   r   M  s   z'TestExternalDataToArray.model_file_pathc                 C  r7   r8   r9   r1   r3   r3   r4   r;   Q  r<   z TestExternalDataToArray.tearDownr   c           	      C  s   t dtj| jj}t jdtj| jjtj	| jdd}t
| jt
j}t jdtj|jtj	|dd}t dtj| j}tj jdddgdgd}tj jd	dgdgtjd
}t j||gd|g|g||gd}t j|ddS )NXT)r&   	data_typedimsvalsrawShapeCReshapeY)r^   r_   Cast)r^   r_   toz
test-model)rc   zonnx-example)producer_name)r	   rf   r   rg   r   rh   make_tensorrT   numpy_helpertobytes_little_endianr(   rP   r   int64INT64re   ri   rj   )	r2   r   
input_init
shape_data
shape_initr   r*   cast	graph_defr3   r3   r4   r/   T  sB   
z)TestExternalDataToArray.create_test_modelr   c                 C  r   r8   r   r1   r3   r3   r4   rr   z  r   z(TestExternalDataToArray.test_check_modelc                 C  sJ   t j| j| j| jdddd t j| j| jdd}| jtjtj	|dd d S )NTFr   r   r   r   r   )strict_mode)
rT   rk   ro   r   r   loadr   r   InferenceErrorinfer_shapes)r2   model_without_external_datar3   r3   r4   .test_reshape_inference_with_external_data_fail  s"   

zFTestExternalDataToArray.test_reshape_inference_with_external_data_failc                 C  sX   t j| j| j| jdddd t j| j| jdd}t|jjd | j	}t
j|| j d S )NTFr   r
  r   )rT   rk   ro   r   r   r  r   rn   rc   r'   r(   r   r   r   )r2   ro   loaded_large_datar3   r3   r4    test_to_array_with_external_data  s   	
z8TestExternalDataToArray.test_to_array_with_external_datac              
   C  s8  t j| j| j| jddd ddd t j| j| jdd}|jjd }| |	d t
jt|| j| j |jjd }| |	d  t
jt|| j t j|| j| jddd ddd t j| j| jdd}|jjd }| |	d t
jt|| j| j |jjd }| |	d t
jt|| j| j d S )	NTFr   r   r   r   rV   r   )rT   rk   ro   r   r   r  rn   rc   r   r   r(   r   r   r   r'   r   r   )r2   model_without_loading_externallarge_input_tensorsmall_shape_tensorr3   r3   r4   1test_save_model_with_external_data_multiple_times  sX   


zITestExternalDataToArray.test_save_model_with_external_data_multiple_timesNrs   r   )rv   rw   rx   r   rz   r5   propertyr   r;   r/   r   r   rr   r  r  r  r3   r3   r3   r4   r   <  s   
 



&

r   c                   @  s<   e Zd ZdZ	ddd
dZdddZdddZdddZdS )3TestNotAllowToLoadExternalDataOutsideModelDirectoryEssential test to check that onnx (validate) C++ code will not allow to load external_data outside the model
    directory.
    rG   rH   rI   rJ   r   rK   r   r   c                 C  sF   t t|}||_|p| d}t||d |d tjj|_	|S )NrL   rM   rO   )
r   r(   rP   r&   r   rS   rT   r   rU   rV   )r2   rH   rJ   rK   rW   rX   r3   r3   r4   rZ     s   

zOTestNotAllowToLoadExternalDataOutsideModelDirectory.create_external_data_tensorr   c                 C  L   |  d| _| tjj t| j W d   dS 1 sw   Y  dS )MWe only test the model validation as onnxruntime uses this to load the model.z../../file.binNr/   r0   r   rT   r   r   rq   r1   r3   r3   r4   rr        "zDTestNotAllowToLoadExternalDataOutsideModelDirectory.test_check_modelc                 C  r  )More relative path test.z../test/../file.binNr  r1   r3   r3   r4   test_check_model_relative  r  zMTestNotAllowToLoadExternalDataOutsideModelDirectory.test_check_model_relativec                 C  r  )JONNX checker disallows using absolute path as location in external tensor.z
//file.binNr  r1   r3   r3   r4   test_check_model_absolute  r  zMTestNotAllowToLoadExternalDataOutsideModelDirectory.test_check_model_absoluteNrt   ru   rs   )rv   rw   rx   ry   rZ   rr   r  r!  r3   r3   r3   r4   r    s    

r  ntzSkip Windows test)reasonc                   @  .   e Zd ZdZdddZdddZddd	Zd
S )<TestNotAllowToLoadExternalDataOutsideModelDirectoryOnWindowsr  r   r   c                 C  r  )r  z..\..\file.binNr  r1   r3   r3   r4   rr     r  zMTestNotAllowToLoadExternalDataOutsideModelDirectoryOnWindows.test_check_modelc                 C  r  )r  z..\test\..\file.binNr  r1   r3   r3   r4   r    r  zVTestNotAllowToLoadExternalDataOutsideModelDirectoryOnWindows.test_check_model_relativec                 C  r  )r   zC:/file.binNr  r1   r3   r3   r4   r!    r  zVTestNotAllowToLoadExternalDataOutsideModelDirectoryOnWindows.test_check_model_absoluteNrs   )rv   rw   rx   ry   rr   r  r!  r3   r3   r3   r4   r%    s
    

r%  c                      s   e Zd Zd fddZ  ZS )(TestSaveAllTensorsAsExternalDataWithPathr   pathlib.Pathc                   s   t t  S r8   )pathlibPathsuperrE   r1   	__class__r3   r4   rE   !  s   z@TestSaveAllTensorsAsExternalDataWithPath.get_temp_model_filenamer   r'  )rv   rw   rx   rE   __classcell__r3   r3   r+  r4   r&     s    r&  c                   @  s   e Zd ZedddZdS )TestExternalDataToArrayWithPathr   r'  c                 C  s   t | jS r8   )r(  r)  r   r1   r3   r3   r4   r   &  s   z/TestExternalDataToArrayWithPath.model_file_pathNr-  )rv   rw   rx   r  r   r3   r3   r3   r4   r/  %  s    r/  c                   @  sR   e Zd ZdddZdddZdd	d
ZdddZdddZdddZdddZ	dS )TestFunctionsAndSubGraphsr   r   c                 C  sD   t  | _| jj}tj|d| _t	d
tj}t|d| _d S )Nrd   r   rW   )r#   r$   r%   r&   r@   rA   rB   r   r(   r)   r+   r,   r   _tensor)r2   r'   rP   r3   r3   r4   r5   ,  s
   
zTestFunctionsAndSubGraphs.setUpc                 C  r7   r8   r9   r1   r3   r3   r4   r;   3  r<   z"TestFunctionsAndSubGraphs.tearDownrW   r   c                 C     |  |jtj d S r8   )r   rV   r   r   r2   rW   r3   r3   r4   _check_is_internal6     z,TestFunctionsAndSubGraphs._check_is_internalc                 C  r2  r8   )r   rV   r   rU   r3  r3   r3   r4   _check_is_external9  r5  z,TestFunctionsAndSubGraphs._check_is_externalro   r   nodesSequence[NodeProto]c                 C  sl   |D ]}|  |jd |jd j}|| j | | qt|ddd |D ]}|jd j}| | q&dS )a  Check that the tensors in the model are externalized.

        The tensors in the specified sequence of Constant nodes are set to self._tensor,
        an internal tensor. The model is then converted to external data format.
        The tensors are then checked to ensure that they are externalized.

        Arguments:
            model: The model to check.
            nodes: A sequence of Constant nodes.

        r[   r   Tr   N)	r   op_typer   r   CopyFromr1  r4  r   r6  )r2   ro   r7  r   rW   r3   r3   r4   _check<  s   z TestFunctionsAndSubGraphs._checkc                 C  s,   d}t |}| ||jd jd g d S )Na|  
           <ir_version: 7,  opset_import: ["": 15, "local": 1]>
           agraph (float[N] X) => (float[N] Y)
            {
              Y = local.add(X)
            }

            <opset_import: ["" : 15],  domain: "local">
            add (float[N] X) => (float[N] Y) {
              C = Constant <value = float[1] {1.0}> ()
              Y = Add (X, C)
           }
        r   )r
   parse_modelr;  	functionsr   )r2   
model_textro   r3   r3   r4   test_functionT  s   
z'TestFunctionsAndSubGraphs.test_functionc                 C  s:   d}t |}|jjd }dd |jD }| || d S )Na2  
           <ir_version: 7,  opset_import: ["": 15, "local": 1]>
           agraph (bool flag, float[N] X) => (float[N] Y)
            {
              Y = if (flag) <
                then_branch = g1 () => (float[N] Y_then) {
                    B = Constant <value = float[1] {0.0}> ()
                    Y_then = Add (X, C)
                },
                else_branch = g2 () => (float[N] Y_else) {
                    C = Constant <value = float[1] {1.0}> ()
                    Y_else = Add (X, C)
                }
              >
            }
        r   c                 S  s   g | ]}|j jd  qS )r   )gr   ).0attrr3   r3   r4   
<listcomp>x  s    z;TestFunctionsAndSubGraphs.test_subgraph.<locals>.<listcomp>)r
   r<  rn   r   r   r;  )r2   r>  ro   if_nodeconstant_nodesr3   r3   r4   test_subgraphe  s
   
z'TestFunctionsAndSubGraphs.test_subgraphNrs   )rW   r   r   r   )ro   r   r7  r8  r   r   )
rv   rw   rx   r5   r;   r4  r6  r;  r?  rF  r3   r3   r3   r4   r0  +  s    





r0  r   tuple[ModelProto, np.ndarray]c                  C  s8   t d} tjdtjd}| jjt|dd | |fS )zPCreate a simple model with a large initializer suitable for external data tests.z
        <ir_version: 7, opset_import: ["": 17]>
        agraph (float[100, 100] input) => (float[100, 100] output) {
            output = Identity(input)
        }
        )r   r   dtypeweightr&   )	r
   r<  r(   onesr,   rn   rc   r   r   )ro   rP   r3   r3   r4   _make_external_data_test_model|  s   rM  z/Symlinks require elevated privileges on Windowsc                   @     e Zd ZdZdddZdS )%TestSaveExternalDataSymlinkProtectionzSTest that save_external_data rejects symlinks to prevent arbitrary file overwrites.r   r   c           	   	   C  s>  t j| jd}t|d}|d W d   n1 sw   Y  t \}}t j| jd}d}tj||dd|dd	 t j| j|}t 	| t 
|| tj|d
d}| |jjd _| tj tj||dd|dd	 W d   n1 s{w   Y  t|}| | d W d   dS 1 sw   Y  dS )z4Saving external data must refuse to follow symlinks.zsensitive.txtwSENSITIVE DATANrd   data.binTr   r   r   rK   r   Fr   r   )r@   rA   rB   r'   rQ   rR   rM  rT   rk   removesymlinkr  tobytesrn   rc   rO   r   r   r   r   read)	r2   sensitive_filefro   rP   
model_pathext_dataext_data_pathloaded_modelr3   r3   r4    test_save_rejects_symlink_target  sB   



"zFTestSaveExternalDataSymlinkProtection.test_save_rejects_symlink_targetNrs   )rv   rw   rx   ry   r^  r3   r3   r3   r4   rO    s    rO  c                   @  r$  )%TestLoadExternalDataSymlinkProtectionzQTest that loading external data rejects symlinks to prevent arbitrary file reads.r   r   c                 C  s   t  \}}tj| jd}d}tj||dd|dd tj| jd}t|d}|d W d	   n1 s7w   Y  tj| j|}t	| t
|| | tj t| W d	   d	S 1 sfw   Y  d	S )
zLLoading a model whose external data is a symlink must raise ValidationError.rd   rR  Tr   rS  
target.txtrP  rQ  N)rM  r@   rA   rB   r'   rT   rk   rQ   rR   rT  rU  r   r   r   r  )r2   ro   _rZ  r[  target_filerY  r\  r3   r3   r4   'test_load_rejects_symlink_external_data  s*   


"zMTestLoadExternalDataSymlinkProtection.test_load_rejects_symlink_external_datac           	      C  s   t  \}}tj| jd}d}tj||dd|dd tj| jd}t|d}|d W d	   n1 s7w   Y  tj| j|}t	| t
|| tj|d
d}| tj t|| j W d	   d	S 1 snw   Y  d	S )zAload_external_data_for_model must reject symlinked external data.rd   rR  Tr   rS  r`  rP  rQ  NFr   )rM  r@   rA   rB   r'   rT   rk   rQ   rR   rT  rU  r  r   r   r   r   )	r2   ro   ra  rZ  r[  rb  rY  r\  r]  r3   r3   r4   1test_load_external_data_for_model_rejects_symlink  s,   


"zWTestLoadExternalDataSymlinkProtection.test_load_external_data_for_model_rejects_symlinkc           
      C  s  t j| jd}t | t j|d}t|d}|d W d   n1 s)w   Y  t j| jd}t | t j|d}t | t \}}t j|d}tj	||d	d	d
dd t
| t || tj|dd}	| tj t|	| W d   dS 1 sw   Y  dS )zIA symlink in the parent directory must be caught by realpath containment.	sensitivez
secret.binrN   sx  SENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATASENSITIVE DATANr   subdirrd   Tzsubdir/secret.binr   rS  Fr   )r@   rA   rB   r'   makedirsrQ   rR   rM  rT   rk   shutilrmtreerU  r  r   r   r   r   )
r2   sensitive_dirsecret_filerY  r   subdir_pathro   ra  rZ  r]  r3   r3   r4   *test_load_rejects_parent_directory_symlink  s4   





"zPTestLoadExternalDataSymlinkProtection.test_load_rejects_parent_directory_symlinkNrs   )rv   rw   rx   ry   rc  rd  rm  r3   r3   r3   r4   r_    s
    

r_  z'Hardlinks behave differently on Windowsc                   @  rN  )&TestLoadExternalDataHardlinkProtectionzFTest that loading external data rejects files with multiple hardlinks.r   r   c                 C  s   t  \}}tj| jd}d}tj||dd|dd tj| j|}tj| jd}t|| | t	j
 t| W d   dS 1 sGw   Y  dS )zVLoading a model whose external data has multiple hardlinks must raise ValidationError.rd   rR  Tr   rS  zhardlink_data.binN)rM  r@   rA   rB   r'   rT   rk   linkr   r   r   r  )r2   ro   ra  rZ  r[  r\  hardlink_pathr3   r3   r4   *test_load_rejects_hardlinked_external_data   s"   

"zQTestLoadExternalDataHardlinkProtection.test_load_rejects_hardlinked_external_dataNrs   )rv   rw   rx   ry   rq  r3   r3   r3   r4   rn    s    rn  c                   @  rN  )*TestSaveExternalDataAbsolutePathValidationz4Test that save_external_data rejects absolute paths.r   r   c                 C  sf   t jdt jd}t|dd}t|dd | tj t|| j	 W d   dS 1 s,w   Y  dS )z;Absolute paths must be rejected as external data locations.)r   rH  rJ  rK  z/etc/passwdrM   N)
r(   rL  r,   r   r   r   r   r   r   r'   )r2   rP   rW   r3   r3   r4   test_save_rejects_absolute_path<  s   "zJTestSaveExternalDataAbsolutePathValidation.test_save_rejects_absolute_pathNrs   )rv   rw   rx   ry   rs  r3   r3   r3   r4   rr  9  s    rr  c                   @  s   e Zd ZdZe	d!d"d	d
Zd#ddZd#ddZd#ddZd#ddZ	d#ddZ
d#ddZd#ddZd#ddZd#ddZd#ddZd S )$TestExternalDataInfoSecuritya  Tests for ExternalDataInfo hardening against attribute injection and bounds.

    Covers all attack vectors from the security advisory: unknown key injection,
    dunder attribute injection, negative offset/length bypass, and validates
    that legitimate keys still work correctly.
    test_tensorentriesdict[str, str]rJ   r   r   r   c                 C  sV   t  }||_t j|_|jdg t j|_|  D ]\}}|j	
 }||_||_q|S )z@Create a TensorProto with given external_data key-value entries.   )r   r&   rg   r   r   extendrU   rV   itemsr   addkeyrH   )rv  rJ   rW   r|  rH   entryr3   r3   r4   _make_tensor_with_external_dataM  s   
z<TestExternalDataInfoSecurity._make_tensor_with_external_datar   c                 C  st   |  ddddd}t|}| |jd | |jd | |jt | |jd | |jt | |jd dS )	zCAll valid external_data keys must be accepted and correctly parsed.weights.bin161024zsha256:abc123)rK   r   r   checksum   r   N)	r~  r   r   rK   r   assertIsInstanceintr   r  r2   rW   infor3   r3   r4   !test_valid_external_data_accepted^  s   z>TestExternalDataInfoSecurity.test_valid_external_data_acceptedc                 C  s   |  ddd}tjdd}td t|}W d   n1 s"w   Y  | t|dd	 | |jd | 	t
d
d |D d dS )zJUnknown external_data keys must not be set as object attributes (CWE-915).r  
evil_value)rK   malicious_attrTrecordalwaysNr  z;Unknown key 'malicious_attr' should not become an attributec                 s      | ]
}d t |jv V  qdS )r  Nr   messagerA  rP  r3   r3   r4   	<genexpr>      zITestExternalDataInfoSecurity.test_unknown_key_rejected.<locals>.<genexpr>z3Expected warning about unknown key 'malicious_attr')r~  warningscatch_warningssimplefilterr   r   hasattrr   rK   r   any)r2   rW   caughtr  r3   r3   r4   test_unknown_key_rejectedp  s    

z6TestExternalDataInfoSecurity.test_unknown_key_rejectedc                 C  s   |  ddi}|j }d|_d|_t}tjdd}td t|}W d   n1 s.w   Y  | 	|| | 
t|jd	 | 
|jd | td
d |D d dS )zDunder keys like '__class__' must not be injected via external_data (CWE-915).

        Without the whitelist, setattr(self, '__class__', ...) would corrupt
        the object type, enabling type confusion attacks.
        rK   r  r,  zbuiltins.dictTr  r  Nr   c                 s  r  )r,  Nr  r  r3   r3   r4   r    r  zHTestExternalDataInfoSecurity.test_dunder_key_rejected.<locals>.<genexpr>z-Expected warning about dunder key '__class__')r~  r   r{  r|  rH   r   r  r  r  r  r   typerv   rK   r   r  )r2   rW   dunder_entryoriginal_classr  r  r3   r3   r4   test_dunder_key_rejected  s    


z5TestExternalDataInfoSecurity.test_dunder_key_rejectedc                 C  \   |  ddd}| t}t| W d   n1 sw   Y  | dt|j  dS )zBNegative offset must raise ValueError to prevent seek(-1) attacks.r  z-1rK   r   Nnon-negativer~  r   
ValueErrorr   assertInr   	exceptionlowerr2   rW   ctxr3   r3   r4   test_negative_offset_rejected     
z:TestExternalDataInfoSecurity.test_negative_offset_rejectedc                 C  r  )zCNegative length must raise ValueError to prevent underflow attacks.r  z-100rK   r   Nr  r  r  r3   r3   r4   test_negative_length_rejected  r  z:TestExternalDataInfoSecurity.test_negative_length_rejectedc                 C  sH   |  dddd}t|}| |jd | |jd | |jd dS )zNZero values for offset/length should be accepted (edge case for bounds check).r  0r   r   N)r~  r   r   rK   r   r   r  r3   r3   r4   $test_zero_offset_and_length_accepted  s   
zATestExternalDataInfoSecurity.test_zero_offset_and_length_acceptedc                 C  s   |  ddddd}tjdd}td t|}W d	   n1 s$w   Y  | t|d
 | t|d | |jd dd |D }| t	|dd | 
d
|d  | 
d|d  | 
d|d  d	S )z>Multiple unknown keys in a single tensor must all be rejected.r  abc)rK   evil_oneevil_two__dict__Tr  r  Nr  r  c                 S  s(   g | ]}d t |j v rt |jqS )zunknown external data key)r   r  r  r  r3   r3   r4   rC    s
    zXTestExternalDataInfoSecurity.test_multiple_unknown_keys_all_rejected.<locals>.<listcomp>r   z.Expected 1 aggregated warning for unknown keysr   r  )r~  r  r  r  r   r   r  r   rK   r   r  )r2   rW   r  r  unknown_key_warningsr3   r3   r4   'test_multiple_unknown_keys_all_rejected  s2   

zDTestExternalDataInfoSecurity.test_multiple_unknown_keys_all_rejectedc                 C  s$   |  tt | tth d dS )z>The whitelist must be a frozenset to prevent runtime mutation.>   r   r   basepathr  rK   N)r  r   	frozensetr   r1   r3   r3   r4   $test_allowed_keys_constant_is_frozen  s
   
zATestExternalDataInfoSecurity.test_allowed_keys_constant_is_frozenc                 C  H   |  ddd}| t t| W d   dS 1 sw   Y  dS )zFNon-numeric offset string must raise ValueError from int() conversion.r  abcr  Nr~  r   r  r   r3  r3   r3   r4   test_non_numeric_offset_raises     
"z;TestExternalDataInfoSecurity.test_non_numeric_offset_raisesc                 C  r  )zFNon-numeric length string must raise ValueError from int() conversion.r  not_a_numberr  Nr  r3  r3   r3   r4   test_non_numeric_length_raises  r  z;TestExternalDataInfoSecurity.test_non_numeric_length_raisesN)ru  )rv  rw  rJ   r   r   r   rs   )rv   rw   rx   ry   staticmethodr~  r  r  r  r  r  r  r  r  r  r  r3   r3   r3   r4   rt  E  s    




	
	


rt  c                   @  r$  )&TestLoadExternalDataFileSizeValidationzQTests for defense-in-depth file-size validation in load_external_data_for_tensor.r   r   c                 C  s   t jdt jd}t|dd}t|dd tj| jd}t	|d}|
|j W d   n1 s2w   Y  tj|}t|d|d	 d
 |d | td t|| j W d   dS 1 scw   Y  dS )z.Offset beyond file size must raise ValueError.rx  rH  rJ  rK  rR  rM   rN   Nr   r  rO   zoffset.*exceeds file sizer(   rL  r,   r   r   r@   rA   rB   r'   rQ   rR   rO   getsizerS   assertRaisesRegexr  r   r2   rP   rW   	data_pathrY  	file_sizer3   r3   r4   $test_offset_exceeds_file_size_raises     
"zKTestLoadExternalDataFileSizeValidation.test_offset_exceeds_file_size_raisesc                 C  s   t jdt jd}t|dd}t|dd tj| jd}t	|d}|
|j W d   n1 s2w   Y  tj|}t|d|d	 d
 |d | td t|| j W d   dS 1 scw   Y  dS )z;Length that overflows available data must raise ValueError.r  rH  rJ  rK  rR  rM   rN   Ni  r  rO   zlength.*exceeds available datar  r  r3   r3   r4   )test_length_exceeds_available_data_raises	  r  zPTestLoadExternalDataFileSizeValidation.test_length_exceeds_available_data_raisesc                 C  s   t jg dt jd}t|dd}|j}tj| jd}t	|d}|
| W d   n1 s0w   Y  t|ddt|d	 |d
 t|| j | |j| dS )z;Valid offset+length within file size should load correctly.)g      ?g       @g      @g      @rH  rJ  rK  rR  rN   Nr   r   rO   )r(   rP   r,   r   rO   r@   rA   rB   r'   rQ   rR   r   r   rS   r   r   )r2   rP   rW   r   r  rY  r3   r3   r4   +test_valid_offset_and_length_load_correctly  s   
zRTestLoadExternalDataFileSizeValidation.test_valid_offset_and_length_load_correctlyNrs   )rv   rw   rx   ry   r  r  r  r3   r3   r3   r4   r    s
    

r  __main__)r   rG  )=
__future__r   r   r@   r(  rh  r#   r   rC   r  typingr   r   numpyr(   r   rT   r   r   r   r   r	   r
   r   onnx.external_data_helperr   r   r   r   r   r   r   r   onnx.numpy_helperr   r   collections.abcr   TestCaser   parameterized_classr|   r   r   r   r  r   r&   r%  r&  r/  r0  rM  rO  r_  rn  rr  rt  r  rv   mainr3   r3   r3   r4   <module>   s   $(	
Q$`  * %

Q
,
_ 0
8