o
    SDi-j                     @   sd  d dl Z d dlmZ d dlmZmZ d dlmZmZ d dlm	Z	 d dl
mZmZmZmZm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mZ d dlmZm Z m!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, d dl-m.Z.m/Z/ d dl0m1Z1m2Z2 d dl3m4Z4m5Z5 d dl6m7Z7m8Z8m9Z9 d dl:m;Z; erd dl<m=Z= ededef dZ>ededZ?edeedZ@ededZAdZBeCZDeCZEeFZGe	dPi edddG dd  d ZHe	dPi ed!diG d"d# d#ee?e@f ZIdd$d%e?d&e/d'ee@df d(eIe?e@f fd)d*ZJG d+d, d,ejKjZLd%e?d(e?fd-d.ZMd/eAd(eAfd0d1ZNG d2d3 d3ee?e@f ZOd4ePejKj fd5d6ZQd/ed7ed8eeRe df d9eeCdf d:d;d&e/fd<d=ZSd>eCd?e9d@efdAdBZT	dQdCdDd4ee dEeCdFeUeC dGeeCdf dHeVd(ePejKj fdIdJZWd4ee dKe1d(eejKjdf fdLdMZXd/ed(eVfdNdOZYdS )R    N)defaultdict)CallableSequence)copydeepcopy)	dataclass)TYPE_CHECKINGAnyGenericUnioncast)	APIRouter)APIRoute)	BaseModel)	BaseRoute)TypeVarassert_never)DATACLASS_SLOTSSentinellenient_issubclass)CadwynErrorRouteAlreadyExistsError/RouteByPathConverterDoesNotApplyToAnythingError8RouteRequestBySchemaConverterDoesNotApplyToAnythingError9RouteResponseBySchemaConverterDoesNotApplyToAnythingErrorRouterGenerationErrorRouterPathParamsModifiedError) _add_request_and_response_paramsgenerate_versioned_models)VersionVersionBundle)EndpointVersionType)_AlterRequestByPathInstruction_AlterResponseByPathInstruction)EndpointDidntExistInstructionEndpointExistedInstructionEndpointHadInstruction)VersionChange)	Dependant_Call.)bound_R_WR)r+   default_RouteT_CADWYN_DELETED_ROUTET)frozeneqc                   @   s"   e Zd ZU eed< ee ed< dS )_EndpointInfoendpoint_pathendpoint_methodsN)__name__
__module____qualname__str__annotations__	frozenset r<   r<   P/var/www/Datamplify/venv/lib/python3.10/site-packages/cadwyn/route_generation.pyr3   >   s   
 r3   r1   c                   @   s.   e Zd ZU eeef ed< eeef ed< dS )GeneratedRouters	endpointswebhooksN)r6   r7   r8   dictr"   r,   r:   r-   r<   r<   r<   r=   r>   D   s   
 r>   )r@   routerversionsr@   returnc                C   s$   |d u r
t tt }t| || S N)r   r-   r   _EndpointTransformer	transform)rB   rC   r@   r<   r<   r=   generate_versioned_routersJ   s   rH   c                   @   s   e Zd ZdedefddZdS )VersionedAPIRouterendpointrD   c                 C   sR   t | j|}|d u rtd|j dt|jv r!td|j d|jt |S )NzRoute not found on endpoint: "zE". Are you sure it's a route and decorators are in the correct order?zThe route "z1" was already deleted. You can't delete it again.)_get_route_from_funcroutesLookupErrorr6   _DELETED_ROUTE_TAGtagsr   append)selfrJ   router<   r<   r=   only_exists_in_older_versionsV   s   
z0VersionedAPIRouter.only_exists_in_older_versionsN)r6   r7   r8   r*   rS   r<   r<   r<   r=   rI   U   s    rI   c                 C   s   t | } dd | jD | _| S )Nc                 S   s   g | ]}t |qS r<   )
copy_route.0rr<   r<   r=   
<listcomp>e       zcopy_router.<locals>.<listcomp>)r   rL   )rB   r<   r<   r=   copy_routerc   s   rZ   rR   c                 C   s6   t | ts	t| S t| }t| j|_t| j|_|S rE   )
isinstancer   r   r   	dependantdependencies)rR   	new_router<   r<   r=   rT   i   s   
rT   c                
       s   e Zd Zdedededdf fddZdeeef fdd	Zd
e	de	de
fddZde	deeeeee f f dee deeef fddZd
e	deeeeeee f f ee ee f fddZdeee ee f de
fddZ  ZS )rF   parent_routerrC   r@   rD   Nc                    s<   t    || _|| _|| _t|| _dd |jD | _d S )Nc                 S   s$   g | ]}t |trt|jv r|qS r<   )r[   r   rN   rO   rV   rR   r<   r<   r=   rX   ~   s    
z1_EndpointTransformer.__init__.<locals>.<listcomp>)	super__init__r_   rC   parent_webhooks_routerr   schema_generatorsrL   routes_that_never_existed)rQ   r_   rC   r@   	__class__r<   r=   rb   w   s   

z_EndpointTransformer.__init__c              	   C   s  t | j}t | j}i }i }| jD ]>}| jt|j j| | jt|j j| | 	|| j| |||j< |||j< t |}t |}| 
|j|j | q| jr`tdtjj d| j t| jjD ]V\}}t|tspqft| t|j}t| D ]<}	|	j| }
tt|
}
|
jd urt|
rt|
jjdr|
jjj}n|
jj}nd }t|
|||
jd ur|
jj nd || j qqf| D ]}dd |jD |_q| D ]}dd |jD |_qt!||S )Nz.Every route you mark with @VersionedAPIRouter.z must be restored in one of the older versions. Otherwise you just need to delete it altogether. The following routes have been marked with that decorator but were never restored: __cadwyn_original_model__c                 S   (   g | ]}t |tjjrt|jv s|qS r<   r[   fastapiroutingr   rN   rO   r`   r<   r<   r=   rX          
z2_EndpointTransformer.transform.<locals>.<listcomp>c                 S   ri   r<   rj   r`   r<   r<   r=   rX      rm   )"rZ   r_   rc   rC   rd   r9   valueannotation_transformermigrate_router_to_version!_attach_routes_to_data_converters!_apply_endpoint_changes_to_routerrL   re   r   rI   rS   r6   	enumerater[   r   r   r   r\   listvaluesr   
body_field_route_has_a_simple_body_schemahasattrtype_rh   _add_data_migrations_to_routealiasr>   )rQ   rB   webhook_routerrouterswebhook_routersversionroute_index
head_routecopy_of_dependantolder_routerolder_routetemplate_older_body_modelr<   r<   r=   rG      sh   












z_EndpointTransformer.transformrB   head_routerr   c                 C   s(  |  |\}}}|jD ]}g |j |j D ]}|D ]
}	| ||||	 qq|j D ]*}
|
D ]%}|js8q2t|j	| }|rWt
d|j d|jj ddd |D  dq2q.|j D ]2}
|
D ]-}|jshqbt|j	| }|rtd|j d|jj dd	d |D  d
|j d|jj 
qbq^qd S )Nz"Request by body schema converter ".z9" failed to find routes with the following body schemas: c                 S      g | ]}|j qS r<   r6   rV   mr<   r<   r=   rX          zJ_EndpointTransformer._attach_routes_to_data_converters.<locals>.<listcomp>zV. This means that you are trying to apply this converter to non-existing endpoint(s). z&Response by response model converter "z<" failed to find routes with the following response models: c                 S   r   r<   r   r   r<   r<   r=   rX      r   z. This means that you are trying to apply this converter to non-existing endpoint(s). If this is intentional and this converter really does not apply to any endpoints, then pass check_usage=False argument to )?_extract_all_routes_identifiers_for_route_to_converter_matchingchanges#alter_response_by_path_instructionsru   "alter_request_by_path_instructions _attach_routes_by_path_converter$alter_request_by_schema_instructionscheck_usagesetschemasr   r6   transformer%alter_response_by_schema_instructionsr   )rQ   rB   r   r   path_to_route_methods_mappinghead_response_modelshead_request_bodiesversion_changeby_path_convertersby_path_converterby_schema_convertersby_schema_convertermissing_modelsr<   r<   r=   rq      sj   
z6_EndpointTransformer._attach_routes_to_data_convertersr   r   r   c           	   	   C   s   t  }|jD ]8}|||j v r9||j | D ]!}|j| }t|tr-|jt| | q|j	t| | qq|
| q|rWt|j d|j d|jj dt| dd S )Nz "r   z4" failed to find routes with the following methods: a
  . This means that you are trying to apply this converter to non-existing endpoint(s). Please, check whether the path and methods are correct. (hint: path must include all path variables and have a name that was used in the version that this VersionChange resides in))r   methodspathrL   r[   r$   $_route_to_response_migration_mappingidrP   #_route_to_request_migration_mappingaddr   	repr_namer6   r   rt   )	rQ   r   r   r   r   missing_methodsmethodr   rR   r<   r<   r=   r      s*   


z5_EndpointTransformer._attach_routes_by_path_converterc                 C   s   t  }t  }tdd }t|jD ]F\}}t|trW|jd ur+t|jtr+|	|j t
|rG|jd urG|jjj}|d urGt|trG|	| |jD ]}||j | 	| qJqdd |D }	dd |D }
||	|
fS )Nc                   S   s   t tS rE   )r   r   r<   r<   r<   r=   <lambda>"  s    zf_EndpointTransformer._extract_all_routes_identifiers_for_route_to_converter_matching.<locals>.<lambda>c                 S      h | ]}|j qS r<   rh   )rV   modelr<   r<   r=   	<setcomp>0  r   zg_EndpointTransformer._extract_all_routes_identifiers_for_route_to_converter_matching.<locals>.<setcomp>c                 S   s   h | ]}t |d |qS r   )getattr)rV   bodyr<   r<   r=   r   1  s    )r   r   rs   rL   r[   r   response_modelr   r   r   rw   rv   
field_info
annotationr   r   )rQ   rB   response_modelsrequest_bodiesr   indexrR   r   r   r   r   r<   r<   r=   r     s"   	




zT_EndpointTransformer._extract_all_routes_identifiers_for_route_to_converter_matchingrL   c                 C   s  |j D ]e}|jD ]^}t||j|j|jdd}t }|j }t|t	rlt||j|j|jdd}|rYt }	|D ]}
|	|
j
O }	q8tdt|	 d|j d|j ddd	 |D  |D ]}||j
O }|jt q[d
}nt|tr4|rt }	|D ]}|	|j
O }	qytdt|	 d|j d|j ddd	 |D  t||j|j|jdd}zt| W n. ty } z"tdt|j d|j d|j dt|j ddd	 |jD  
|d }~ww |D ]S}
||
j
O }|
jt t| j|
j|
j
|
jjdd}t|dkr| j|d  qt|dkr0|}tdt|
j
 d|
j d|j dt| ddd	 |D  
qd}nt|trO|D ]}||j
O }t|j|| q<d}nt| || }|rht|jt||j|jdq	qd S )NF
is_deletedTz
Endpoint " z" you tried to delete in "z" was already deleted in a newer version. If you really have two routes with the same paths and methods, please, use "endpoint(..., func_name=...)" to distinguish between them. Function names of endpoints that were already deleted: c                 S      g | ]}|j jqS r<   rJ   r6   rU   r<   r<   r=   rX   X  rY   zJ_EndpointTransformer._apply_endpoint_changes_to_router.<locals>.<listcomp>z}Endpoint "{endpoint_methods} {endpoint_path}" you tried to delete in "{version_change_name}" doesn't exist in a newer versionz" you tried to restore in "z" already existed in a newer version. If you really have two routes with the same paths and methods, please, use "endpoint(..., func_name=...)" to distinguish between them. Function names of endpoints that already existed: c                 S   r   r<   r   rU   r<   r<   r=   rX   k  rY   z" has z applicable routes that could be restored. If you really have two routes with the same paths and methods, please, use "endpoint(..., func_name=...)" to distinguish between them. Function names of endpoints that can be restored: c                 S   r   r<   r   rU   r<   r<   r=   rX   |  rY      r   a.   applicable routes with the same function name and path that could be restored. This can cause problems during version generation. Specifically, Cadwyn won't be able to warn you when you deleted a route and never restored it. Please, make sure that functions for all these routes have different names: c                 S   s"   g | ]}|j j d |j j qS )r   )rJ   r7   r6   rU   r<   r<   r=   rX     s   " z}Endpoint "{endpoint_methods} {endpoint_path}" you tried to restore in "{version_change_name}" wasn't among the deleted routeszjEndpoint "{endpoint_methods} {endpoint_path}" you tried to change in "{version_change_name}" doesn't exist)r5   r4   version_change_name)r   alter_endpoint_instructions_get_routesr4   r5   endpoint_func_namer   r   r[   r%   r   r   rt   r6   rO   rP   rN   r&   "_validate_no_repetitions_in_routesr   lenrL   removere   r   rJ   r'   _apply_endpoint_had_instructionr   format)rQ   rL   r   r   instructionoriginal_routes#methods_to_which_we_applied_changes)methods_we_should_have_applied_changes_todeleted_routesmethod_uniondeleted_routeoriginal_routeerrere   method_diffr<   r<   r=   rr   6  s   




z6_EndpointTransformer._apply_endpoint_changes_to_router)r6   r7   r8   r,   r    r-   rb   r>   rG   r   r   rq   rA   
_RoutePath_RouteMethodr   _RouteIdtyper(   r   r$   r#   r   tupler	   r   rt   r   r   rr   __classcell__r<   r<   rf   r=   rF   v   s.    H/

(
rF   rL   c                 C   sB   i }| D ]}t |jt|j}||v rt||| |||< qd S rE   )r3   r   r;   r   r   )rL   	route_maprR   
route_infor<   r<   r=   r     s   
r   r   template_body_fieldtemplate_body_field_name dependant_for_request_migrationsr)   c              
   C   s~   | j jr| j js!td| j jd| j jdt| j d| j d	|j||| ||| j j| j j| j jd| j	| _	| j	| j _
d S )Nz#route.dependant.request_param_name=z&, route.dependant.response_param_name=z for route r   z9 which should not be possible. Please, contact my author.)request_param_namebackground_tasks_param_nameresponse_param_name)r\   r   r   r   rt   r   r   
_versionedr   rJ   call)rR   r   r   r   r   rC   r<   r<   r=   rz     s*   	
rz   r   r   r   c                 C   s   |j jD ]c}t|j |}|turgt|||kr,td| dt|j d|j d|  d	|dkradd |jj	D }t
td	|}||kratd
t|j d|j d|  dt| dt| dt||| qd S )NzExpected attribute "z" of endpoint "r   z" to be different in "zl", but it was the same. It means that your version change has no effect on the attribute and can be removed.r   c                 S   r   r<   )r{   )rV   pr<   r<   r=   r     r   z2_apply_endpoint_had_instruction.<locals>.<setcomp>z{(.*?)}zWhen altering the path of "z" in "z2", you have tried to change its path params from "z" to "a[  ". It is not allowed to change the path params of a route because the endpoint was created to handle the old path params. In fact, there is no need to change them because the change of path params is not a breaking change. If you really need to change the path params, you should create a new route with the new path params and delete the old one.)
attributes__dataclass_fields__r   r   r   rt   r   r   r\   path_paramsr   refindallr   setattr)r   r   r   	attr_nameattroriginal_path_paramsnew_path_paramsr<   r<   r=   r     s:   	r   Fr   r4   r5   r   r   c                   s"    d fdd| D S )N/c                    s`   g | ],}t |tjjr.|jd kr.t|jr. du s%|j	j
 kr.t|jv kr|qS )r   N)r[   rk   rl   r   r   rstripr   r   issubsetrJ   r6   rN   rO   r`   r   r5   r4   r   r<   r=   rX     s    z_get_routes.<locals>.<listcomp>)r   )rL   r4   r5   r   r   r<   r   r=   r     s   
r   rJ   c                 C   s.   | D ]}t |tjjr|j|kr|  S qd S rE   )r[   rk   rl   r   rJ   )rL   rJ   rR   r<   r<   r=   rK     s
   rK   c                 C   s   t | jjdkS )Nr   )r   r\   body_params)rR   r<   r<   r=   rw     s   rw   r<   rE   )Zr   collectionsr   collections.abcr   r   r   r   dataclassesr   typingr   r	   r
   r   r   fastapi.paramsrk   fastapi.routingfastapi.security.basefastapi.utilsr   r   pydanticr   starlette.routingr   typing_extensionsr   r   cadwyn._utilsr   r   r   cadwyn.exceptionsr   r   r   r   r   r   r   cadwyn.schema_generationr   r   cadwyn.structurer   r    cadwyn.structure.commonr!   r"   cadwyn.structure.datar#   r$   cadwyn.structure.endpointsr%   r&   r'   cadwyn.structure.versionsr(   fastapi.dependencies.modelsr)   r*   r,   r-   r/   rN   r9   r   r   intr   r3   r>   rH   rl   rI   rZ   rT   rF   rt   r   r   rz   r   r   boolr   rK   rw   r<   r<   r<   r=   <module>   s    $		


  =



$




