Ë
    ­mâiG  ã                   óF  — d Z ddlZddlmZ ddlmZmZmZmZ ddl	m
Z
 e
 G d„ d«      «       Ze
 G d„ d	«      «       Z G d
„ d«      Zedk(  rV ee«      j                   j                   j                   Z e ee«      «      Zej)                  «       Zej-                  e«       yy)za
Model-Schema Analyzer - Analyzes SQLAlchemy models and Pydantic schemas to detect coverage gaps
é    N)ÚPath)ÚDictÚListÚSetÚTuple)Ú	dataclassc                   óD   — e Zd ZU dZeed<   eed<   eed<   eed<   eed<   y)Ú
ModelFieldz(Represents a field in a SQLAlchemy modelÚnameÚtypeÚnullableÚfileÚlineN©Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚstrÚ__annotations__ÚboolÚint© ó    ú@/home/factor_ks/STREAMA2026/tests/utils/model_schema_analyzer.pyr
   r
   
   s   … á2Ø
ƒIØ
ƒIØƒNØ
ƒIØ
„Ir   r
   c                   óD   — e Zd ZU dZeed<   eed<   eed<   eed<   eed<   y)ÚSchemaFieldz'Represents a field in a Pydantic schemar   r   Úrequiredr   r   Nr   r   r   r   r   r      s   … á1Ø
ƒIØ
ƒIØƒNØ
ƒIØ
„Ir   r   c                   ó¸   — e Zd ZdZdefd„Zdeeee   f   fd„Z	de
deeeee   f      fd„Zdeeee   f   fd„Zd	e
deeeee   f      fd
„Zdefd„Zdefd„Zy)ÚModelSchemaAnalyzerz7Analyzes model-schema coverage to detect missing fieldsÚproject_dirc                 óü   — t        |«      | _        | j                  dz  dz  dz  | _        | j                  dz  dz  dz  | _        g d¢g d¢g d¢dd	gd
dgg d¢g d¢g d¢g d¢g d¢dœ
| _        h d£| _        h d£| _        y )NÚbackendÚappÚmodelsÚschemas)ÚUserResponseÚ
UserCreateÚ
UserUpdateÚUserListResponseÚ	UserLoginÚUserProfileUpdateÚUserRoleUpdate)ÚStreamResponseÚStreamCreateÚStreamUpdateÚStreamManualCreate)ÚCommentResponseÚCommentCreateÚCommentUpdateÚTagResponseÚ	TagCreateÚChatMessageResponseÚChatMessageCreate)ÚWatchHistoryResponseÚWatchHistoryCreateÚWatchHistoryUpdate)ÚTwitchOAuthResponseÚTwitchOAuthRequestÚTwitchUserInfo)ÚSiteSettingResponseÚSiteSettingUpdateÚSiteSettingBaseÚSiteSettingsResponseÚSiteSettingsUpdateBulk)ÚPermissionResponseÚPermissionCreateÚPermissionUpdate)ÚRoleResponseÚ
RoleCreateÚ
RoleUpdate)
ÚUserÚStreamÚCommentÚTagÚChatMessageÚWatchHistoryÚTwitchOAuthÚSiteSettingÚ
PermissionÚRole>   ÚChapterÚSessionÚ	StreamTagÚActivityLogÚProcessingJobÚRolePermission>   ÚidÚbadgesÚemotesÚtag_idÚdetailsÚuser_idÚ	parent_idÚ	stream_idÚ
created_atÚ
ip_addressÚ
updated_atÚ
user_agentÚaccess_tokenÚpassword_hashÚrefresh_tokenÚstream_metadata)r   r!   Ú
models_dirÚschemas_dirÚmodel_schema_mappingÚmodels_without_schemasÚfields_to_ignore)Úselfr!   s     r   Ú__init__zModelSchemaAnalyzer.__init__!   s•   € Ü Ó,ˆÔØ×*Ñ*¨YÑ6¸Ñ>ÀÑIˆŒØ×+Ñ+¨iÑ7¸%Ñ?À)ÑKˆÔò
 IÚ^ÚLØ! ;Ð/Ø1Ð3FÐGÚ`ÚZò MÚXÚ@ñ%
ˆÔ!ò'
ˆÔ#ò!
ˆÕr   Úreturnc                 óî   — i }| j                   j                  «       s|S | j                   j                  d«      D ]8  }|j                  dk(  rŒ| j	                  |«      }|D ]  \  }}|sŒ	|sŒ|||<   Œ Œ: |S )z/Analyze SQLAlchemy models to extract all fieldsú*.pyú__init__.py)rj   ÚexistsÚglobr   Ú_extract_model_fields)ro   Úmodels_infoÚ
model_fileÚ
model_dataÚ
model_nameÚfieldss         r   Úanalyze_modelsz"ModelSchemaAnalyzer.analyze_modelsY   s…   € àˆà�‰×%Ñ%Ô'ØÐàŸ/™/×.Ñ.¨vÓ6ò 	5ˆJØ�‰ -Ò/Øà×3Ñ3°JÓ?ˆJØ&0ò 5Ñ"�
˜FÚ¢&Ø.4�K 
Ò+ñ5ð	5ð Ðr   ry   c                 ó  — 	 t        |dd¬«      5 }|j                  «       }ddd«       g }d}t        j                  |«      D �]  }|j	                  d«      }|j                  «       }|j                  «       }	||	d j                  d«      }
g }d}d}|
D ]r  }|j                  «       rOt        |«      t        |j                  «       «      z
  }|€|}||k(  r|j                  |«       d	|v sŒWd
}ŒZ||k  sŒ` n|j                  |«       Œt |sŒÉdj                  |«      }g }d}t        j                  ||«      D ]û  }|j	                  d«      }|j	                  d«      }|d||j                  |j	                  d«      «      z    j                  d«      dz   }|dvsŒbt        j                  d|«      }t        j                  d|«      }|r|j	                  d«      nd}|r|j	                  d«      dk(  nd
}|j                  t!        |||t#        |j%                  | j&                  «      «      |¬«      «       Œý |s�Œö|j                  ||f«       �Œ |S # 1 sw Y   �Œ2xY w# t(        $ r}t+        d|› d|› �«       g cY d}~S d}~ww xY w)z/Extract model name and fields from a model fileÚrúutf-8©ÚencodingNzclass\s+(\w+)\s*\(\s*Base\s*\):é   ú
FÚ__tablename__Tz(\w+)\s*=\s*Column\(([^)]+)\)é   r   )r…   Ú__table_args__Ú__mapper_args__z?(String|Integer|Text|Boolean|DateTime|UUID|ForeignKey)\(?\d*\)?znullable\s*=\s*(True|False)ÚUnknownÚTrue©r   r   r   r   r   úError analyzing ú: )ÚopenÚreadÚreÚfinditerÚgroupÚstartÚendÚsplitÚstripÚlenÚlstripÚappendÚjoinÚindexÚcountÚsearchr
   r   Úrelative_tor!   Ú	ExceptionÚprint)ro   ry   ÚfÚcontentÚmodels_dataÚclass_patternÚclass_matchÚ
class_nameÚclass_startÚ	class_endÚlinesÚclass_contentÚindent_levelÚhas_tablenamer   Úline_indentÚclass_content_strr|   Úcolumn_patternÚ	col_matchÚ
field_nameÚcolumn_argsÚline_numÚ
type_matchÚnullable_matchÚ
field_typer   Úes                               r   rw   z)ModelSchemaAnalyzer._extract_model_fieldsk   s£  € ðL	Ü�j #°Ô8ð #¸AØŸ&™&›(�÷#ð ˆKð ?ˆMä!Ÿ{™{¨=¸'ÓBó ==�Ø(×.Ñ.¨qÓ1�
Ø)×/Ñ/Ó1�Ø'ŸO™OÓ-�	ð   	 
Ð+×1Ñ1°$Ó7�Ø "�Ø#�Ø %�à!ò 3�DØ—z‘z”|Ü&)¨$£i´#°d·k±k³mÓ2DÑ&D˜Ø'Ð/à+6˜LØ&¨,Ò6à)×0Ñ0°Ô6Ø.°$Ò6Ø04¡Ø(¨<Ó7á!ð &×,Ñ,¨TÕ2ð!3ñ& %Øà$(§I¡I¨mÓ$<Ð!ð �Ø!A�Ü!#§¡¨^Ð=NÓ!Oò �IØ!*§¡°Ó!3�JØ"+§/¡/°!Ó"4�KØ&Ð'a¨Ð6G×6MÑ6MÈiÏoÉoÐ^_ÓN`Ó6aÑ(aÐb×hÑhÐimÓnÐqrÑr�Hð "Ð)_Ò_ä%'§Y¡YÐ/qÐs~Ó%˜
Ü)+¯©Ð3QÐS^Ó)_˜á<F Z×%5Ñ%5°aÔ%8ÈI˜
ÙHV >×#7Ñ#7¸Ó#:¸fÒ#DÐ\`˜àŸ™¤jØ!+Ø!+Ø%-Ü!$ Z×%;Ñ%;¸D×<LÑ<LÓ%MÓ!NØ!)ô'õ ðó, Ø×&Ñ&¨
°FÐ';Ö<ð{==ð~ Ð÷O#ñ #ûôR ò 	ÜÐ$ Z L°°1°#Ð6Ô7Ø�Iûð	úsN   ‚I �I¡C	I Ã+I Ã4B$I ÆBI È9I ÉIÉI É	JÉ'I?É9JÉ?Jc                 óî   — i }| j                   j                  «       s|S | j                   j                  d«      D ]8  }|j                  dk(  rŒ| j	                  |«      }|D ]  \  }}|sŒ	|sŒ|||<   Œ Œ: |S )z.Analyze Pydantic schemas to extract all fieldsrs   rt   )rk   ru   rv   r   Ú_extract_schema_fields)ro   Úschemas_infoÚschema_fileÚschema_dataÚschema_namer|   s         r   Úanalyze_schemasz#ModelSchemaAnalyzer.analyze_schemas»   s‹   € àˆà×Ñ×&Ñ&Ô(ØÐà×+Ñ+×0Ñ0°Ó8ò 	7ˆKØ×Ñ =Ò0Øà×5Ñ5°kÓBˆKØ'2ò 7Ñ#�˜VÚ¢6Ø06�L Ò-ñ7ð	7ð Ðr   r»   c                 óø  — 	 t        |dd¬«      5 }|j                  «       }ddd«       g }d}t        j                  |«      D �]ý  }|j	                  d«      }|j                  «       }|j                  «       }	||	d j                  d«      }
g }d}|
D ]k  }|j                  «       rHt        |«      t        |j                  «       «      z
  }|€|}||k(  r|j                  |«       ŒS||k  sŒY n|j                  |«       Œm dj                  |«      }g }d}|j                  d«      D �]  }|j                  «       }|r"|j                  d	«      s|j                  d
«      rŒ9t        j                  ||«      }|sŒR|j	                  d«      }|j	                  d«      }|d||j                  |«      z    j!                  d«      dz   }d|v xs
 d|v xs d|v }d|v xr d|v}| xr | }|dvsŒÄ|j                  t#        |||t%        |j'                  | j(                  «      «      |¬«      «       �Œ |j                  ||f«       �Œ  |S # 1 sw Y   �Œ'xY w# t*        $ r}t-        d|› d|› �«       g cY d}~S d}~ww xY w)z1Extract schema name and fields from a schema filer   r€   r�   Nz!class\s+(\w+)\(.*?BaseModel.*?\):rƒ   r„   zC(\w+)\s*:\s*([^\s=]+)(?:\s*=\s*(?:Field\([^)]*\)|.*?))?(?:\s*#.*)?$ú#ú@r†   ÚOptionalú|ÚNoneú=zField()Úmodel_configÚConfig©r   r   r   r   r   rŒ   r�   )rŽ   r�   r�   r‘   r’   r“   r”   r•   r–   r—   r˜   r™   rš   Ú
startswithÚmatchr›   rœ   r   r   rž   r!   rŸ   r    )ro   r»   r¡   r¢   Úschemas_datar¤   r¥   r½   r§   r¨   r©   rª   r«   r   r­   r®   r|   Úfield_patternÚfield_matchr±   r¶   r³   Úis_optionalÚhas_defaultÚis_requiredr·   s                             r   r¹   z*ModelSchemaAnalyzer._extract_schema_fieldsÍ   s®  € ðJ	Ü�k 3°Ô9ð #¸QØŸ&™&›(�÷#ð ˆLð AˆMä!Ÿ{™{¨=¸'ÓBó ;;�Ø)×/Ñ/°Ó2�Ø)×/Ñ/Ó1�Ø'ŸO™OÓ-�	ð   	 
Ð+×1Ñ1°$Ó7�Ø "�Ø#�à!ò 3�DØ—z‘z”|Ü&)¨$£i´#°d·k±k³mÓ2DÑ&D˜Ø'Ð/à+6˜LØ&¨,Ò6à)×0Ñ0°Õ6Ø(¨<Ó7á!ð &×,Ñ,¨TÕ2ð3ð  %)§I¡I¨mÓ$<Ð!ð �à f�à-×3Ñ3°DÓ9ó �DØŸ:™:›<�DÙ 4§?¡?°3Ô#7¸4¿?¹?È3Ô;OØ ä"$§(¡(¨=¸$Ó"?�KÚ"Ø%0×%6Ñ%6°qÓ%9˜
Ø%0×%6Ñ%6°qÓ%9˜
Ø#*Ð+W¨KÐ:K×:QÑ:QÐRVÓ:WÑ,WÐ#X×#^Ñ#^Ð_cÓ#dÐghÑ#h˜ð '1°JÐ&>Ò&kÀ#ÈÐBSÒ&kÐW]ÐakÐWk˜Ø&)¨T kÒ&J°hÀdÐ6J˜Ø*5 oÒ&I¸k¸/˜ð &Ð-GÒGØ"ŸM™M¬+Ø%/Ø%/Ø)4Ü%(¨×)@Ñ)@À×AQÑAQÓ)RÓ%SØ%-ô+ö ð%ð4 ×#Ñ# [°&Ð$9Ö:ðw;;ðz  Ð÷K#ñ #ûôN ò 	ÜÐ$ [ M°°A°3Ð7Ô8Ø�Iûð	úsI   ‚I �I¡C	I Ã+BI Å8A1I Ç*AI ÉIÉI É	I9ÉI4É.I9É4I9c                 ó  — | j                  «       }| j                  «       }t        |«      ddi i di dœ}|j                  «       D ]  \  }}|dxx   t        |«      z  cc<   Œ |j                  «       D �]ä  \  }}|| j                  v rŒ| j
                  j                  |g «      }t        «       }i }	|D ];  }
|
|v sŒ||
   D ],  }|j                  |j                  «       ||	|j                  <   Œ. Œ= |D �ch c]  }|j                  ’Œ }}||z
  }|| j                  z
  }||z
  }t        |«      t        |«      z
  }|dxx   |z  cc<   |r\|D �cg c]J  }|j                  |v r:|j                  |j                  |j                  |j                  |j                  dœ‘ŒL c}|d   |<   |rt|D ��cg c]`  }|	j                  «       D ]K  }|j                  |k(  r:|j                  |j                  |j                   |j                  |j                  dœ‘ŒM Œb c}}|d	   |<   t        |«      |t        |«      |rt#        |t        |«      z  d
z  d«      nd|dœ|d   |<   �Œç |d   dkD  rt#        |d   |d   z  d
z  d«      |d<   |S c c}w c c}w c c}}w )z?Compare model fields with schema fields to detect coverage gapsr   g        )Útotal_modelsÚtotal_model_fieldsÚcovered_fieldsÚmissing_from_schemasÚextra_in_schemasÚcoverage_percentageÚmodel_detailsrÓ   rÔ   r‹   rÕ   rÈ   rÖ   éd   rƒ   g      Y@)Útotal_fieldsrÔ   Úmissing_fieldsr×   Úrelated_schemasrØ   r×   )r}   r¾   r—   Úitemsrm   rl   ÚgetÚsetÚaddr   rn   r   r   r   r   Úvaluesr   Úround)ro   rx   rº   Úcoverage_reportr{   r|   Úmodel_fieldsrÜ   Úschema_fields_setÚschema_fields_dictr½   ÚfieldÚmodel_field_namesrÛ   Úextra_fieldsÚcovered_countr±   s                    r   Úcompare_model_schema_coveragez1ModelSchemaAnalyzer.compare_model_schema_coverage  s  € à×)Ñ)Ó+ˆØ×+Ñ+Ó-ˆô   Ó,Ø"#ØØ$&Ø "Ø#&Øñ
ˆð #.×"3Ñ"3Ó"5ò 	AÑˆJ˜ØÐ0Ó1´S¸³[Ñ@Ô1ð	Að )4×(9Ñ(9Ó(;ó >	Ñ$ˆJ˜à˜T×8Ñ8Ñ8Øð #×7Ñ7×;Ñ;¸JÈÓKˆOô !$£ÐØ!#ÐØ.ò ?�Ø ,Ò.Ø!-¨kÑ!:ò ?˜Ø)×-Ñ-¨e¯j©jÔ9Ø9>Ð*¨5¯:©:Ò6ñ?ð?ð :FÖ F° §£Ð FÐÐ FØ.Ð1BÑBˆNð ,¨d×.CÑ.CÑCˆNð -Ð/@Ñ@ˆLô  Ð 1Ó2´S¸Ó5HÑHˆMØÐ,Ó-°Ñ>Ó-áð ".ö	Gð °·±¸~Ñ1Mð !&§
¡
Ø %§
¡
Ø$)§N¡NØ %§
¡
Ø %§
¡
óò	G�Ð 6Ñ7¸
ÑCñ ð '3÷	Cð #Ð@R×@YÑ@YÓ@[ò	Cð 8=Ð_d×_iÑ_iÐmwÒ_wð !&§
¡
Ø %§
¡
Ø$)§N¡NØ %§
¡
Ø %§
¡
óð	Cðó	C�Ð 2Ñ3°JÑ?ô !$ LÓ 1Ø"/Ü"% nÓ"5Ù\h¤u¨]¼SÀÓ=NÑ-NÐQTÑ-TÐVWÔ'XÐnsØ#2ñ<ˆO˜OÑ,¨ZÓ8ðq>	ðB Ð/Ñ0°1Ò4Ü5:ØÐ 0Ñ1°OÐDXÑ4YÑYÐ\_Ñ_Ðabó6ˆOÐ1Ñ2ð Ðùòi !Gùò	Gùó	Cs   Ã4I?ÅAJÆ+A%J	rã   c                 ór  — t        d«       t        d«       t        d«       t        d|d   › �«       t        d|d   › �«       t        d|d   › �«       t        d	|d
   › d�«       |d   rpt        d«       |d   j                  «       D ]O  \  }}t        d|› �«       |D ]7  }t        d|d   › d|d   › d|d   › d�«       t        d|d   › d|d   › �«       Œ9 ŒQ |d   rpt        d«       |d   j                  «       D ]O  \  }}t        d|› �«       |D ]7  }t        d|d   › d|d   › d|d   › d�«       t        d|d   › d|d   › �«       Œ9 ŒQ |d   s|d   st        d«       t        d«       |d    j                  «       D ]&  \  }}t        d!|› d|d   › d"|d#   › d$|d
   › d%�	«       Œ( t        d«       y&)'z6Print a human-readable report of model-schema coveragez<============================================================zModel-Schema Coverage Reportz
Total Models: rÒ   zTotal Model Fields: rÓ   zCovered Fields: rÔ   z
Coverage: r×   ú%rÕ   z
Missing from Schemas:z

  Model: z    - r   r�   r   z (nullable=r   ú)z      Defined in: r   ú:r   rÖ   z!
Extra in Schemas (not in model):z (required=r   u,   
âœ“ All model fields are covered in schemasz
Model Details:rØ   z  ú/rÚ   z (z%)N)r    rÝ   )ro   rã   r{   r|   rç   r^   s         r   Úprint_reportz ModelSchemaAnalyzer.print_reportw  sG  € äˆhŒÜÐ,Ô-ÜˆhŒäÐ  °Ñ!@Ð AÐBÔCÜÐ$ _Ð5IÑ%JÐ$KÐLÔMÜÐ  Ð1AÑ!BÐ CÐDÔEÜ�
˜?Ð+@ÑAÐBÀ!ÐDÔEàÐ1Ò2ÜÐ+Ô,Ø&5Ð6LÑ&M×&SÑ&SÓ&Uò PÑ"�
˜FÜ˜ J <Ð0Ô1Ø#ò P�EÜ˜F 5¨¡= /°°E¸&±M°?À+ÈeÐT^ÑN_ÐM`Ð`aÐbÔcÜÐ.¨u°V©}¨o¸Q¸uÀV¹}¸oÐNÕOñPðPð Ð-Ò.ÜÐ6Ô7Ø&5Ð6HÑ&I×&OÑ&OÓ&Qò PÑ"�
˜FÜ˜ J <Ð0Ô1Ø#ò P�EÜ˜F 5¨¡= /°°E¸&±M°?À+ÈeÐT^ÑN_ÐM`Ð`aÐbÔcÜÐ.¨u°V©}¨o¸Q¸uÀV¹}¸oÐNÕOñPðPð Ð5Ò6¸ÐOaÒ?bÜÐAÔBäÐ Ô!Ø#2°?Ñ#C×#IÑ#IÓ#Kò 	@ÑˆJ˜Ü�B�z�l " WÐ-=Ñ%>Ð$?¸qÀÈÑAXÐ@YÐY[Ð\cÐdyÑ\zÐ[{Ð{}Ð~Õð	@ô 	ˆh�r   N)r   r   r   r   r   rp   r   r   r
   r}   r   r   rw   r   r¾   r¹   rë   rñ   r   r   r   r    r       sº   „ ÙAð6
 Có 6
ðp  S¨$¨zÑ*:Ð%:Ñ ;ó ð$N°ð N¸¸eÀCÈÈjÑIYÐDYÑ>ZÑ9[ó Nð`  c¨4°Ñ+<Ð&<Ñ!=ó ð$L°$ð L¸4ÀÀcÈ4ÐP[ÑK\ÐF\Ñ@]Ñ;^ó Lð\Z¨tó Zðx"¨Dô "r   r    Ú__main__)r   r�   Úpathlibr   Útypingr   r   r   r   Údataclassesr   r
   r   r    r   Ú__file__Úparentr!   r   Úanalyzerrë   rã   rñ   r   r   r   ú<module>rù      s¯   ðñó 
Ý ß )Ó )Ý !ð ÷ð ó ðð ÷ð ó ð÷{ñ {ð| ˆzÒá�x“.×'Ñ'×.Ñ.×5Ñ5€KÙ"¡3 {Ó#3Ó4€Hà×<Ñ<Ó>€OØ×Ñ˜/Õ*ð r   