ó
    UB/jÒ  ã            
       ó<  • S r SSKrSSKJs  Jr  SSKrSSKJ	r	  SSK
Jr  SSKrSSKJrJr  SSKJrJr  SSKJr  SSKJr  SS	KJr  SS
KJrJrJr  S\S\S\S\\\      S\4
S jr S\RB                  4S jr"S\RB                  4S jr#S\RB                  S\	4S jr$S r%g)a^  Tests for the two-flow extractor (no LLM, no real Camelot).

Covers the contract that matters for the parallel flows: the Camelot flow
tags every surviving grid with an is-table verdict but never drops on it
(only content-empty shells are dropped), the vision flow maps located
tables to per-page VisualTables, and the DualResult page-count helpers.
é    N)ÚPath)ÚList)ÚClassifierResultÚMockClassifier)ÚLocatedTableÚMockGridLocator©ÚCamelotCandidate)Úcamelot)Úvision)ÚCamelotTableÚ
DualResultÚVisualTableÚcidÚpageÚmarkdownÚcellsÚreturnc           	      ó   • [        U SXUSS9$ )NÚstreamg     ÀX@)Úcandidate_idÚflavorr   r   r   Úaccuracyr	   )r   r   r   r   s       Ú./home/mande/repo/quber/tests/test_dual_flow.pyÚ
_candidater      s   € ÜØ °ÈuÐ_cñð ó    Úmonkeypatchc                 óØ  ^^• [        SSSSS/SS//5      m[        SSS	S
//5      mU R                  [        SUU4S j5        [        [	        SSS95      n[
        R                  " [        R                  " [        S5      U5      5      n[        U5      nSoCU:H  oU(       Gd  [        R                  " SU4SX445      S[        R                  " 5       ;   d  [        R                  " [        5      (       a  [        R                  " [        5      OSS[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[!        [        R"                  " U5      5      eS =n=pTUS   oˆR$                  o3R&                  nSo•U	:H  oª(       d™  [        R                  " SU
4SXY45      [        R                  " U5      [        R                  " U5      [        R                  " U5      [        R                  " U	5      S.-  nSSU0-  n[!        [        R"                  " U5      5      eS =n=n=n=p©US   oˆR(                  nS oCULoU(       d„  [        R                  " SU4SX445      [        R                  " U5      [        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[!        [        R"                  " U5      5      eS =n=n=pTUS   oˆR(                  o3R*                  nSo•U	L oª(       d™  [        R                  " S U
4S!XY45      [        R                  " U5      [        R                  " U5      [        R                  " U5      [        R                  " U	5      S.-  nSSU0-  n[!        [        R"                  " U5      5      eS =n=n=n=p©g )"Nzstream-p1-0é   ú!| a | b |
| --- | --- |
| 1 | 2 |ÚaÚbÚ1Ú2zstream-p1-1z|  |
| --- |Ú Úrun_camelot_flavors_parallelc                 ó   >• TT/$ ©N© )ÚsourceÚrealÚshells    €€r   Ú<lambda>ÚFtest_camelot_flow_tags_verdict_and_never_drops_on_it.<locals>.<lambda>    s   ø€ ÐVZÐ\aÑUbr   Fzmock-reject)Úis_tableÚreasonúx.pdf©ú==©z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sÚlenÚout©Úpy0Úpy1Úpy3Úpy6úassert %(py8)sÚpy8r   )zS%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.candidate
}.candidate_id
} == %(py8)s)r9   r:   Úpy5r=   zassert %(py10)sÚpy10)úis not)z:%(py3)s
{%(py3)s = %(py1)s.classification
} is not %(py6)s©r9   r:   r;   ©Úis)zT%(py5)s
{%(py5)s = %(py3)s
{%(py3)s = %(py1)s.classification
}.is_table
} is %(py8)s)r   ÚsetattrÚcamelot_flowr   r   ÚasyncioÚrunÚrun_camelot_flowr   r5   Ú
@pytest_arÚ_call_reprcompareÚ@py_builtinsÚlocalsÚ_should_repr_global_nameÚ	_safereprÚAssertionErrorÚ_format_explanationÚ	candidater   Úclassificationr/   )r   Ú
classifierr6   Ú@py_assert2Ú@py_assert5Ú@py_assert4Ú@py_format7Ú@py_format9Ú@py_assert0Ú@py_assert7Ú@py_assert6Ú@py_format11r+   r,   s               @@r   Ú4test_camelot_flow_tags_verdict_and_never_drops_on_itr]      sh  ù€ Ü�m QÐ(MÐQTÐVYÐPZÐ]`ÐbeÐ\fÐOgÓh€DÜ�} a¨¸B¸4¸&ÓA€EØ×ÑœÐ&DÕFbÔcô  Ô 0¸%ÈÑ VÓW€JÜ
�+Š+”l×3Ò3´D¸³MÀ:ÓNÓ
O€Cäˆs‹8Ð�qÐ�q‰=×××Óˆ8×××××ÕŒ3×××ÑŒ3×××××Öˆs×××Ñˆs××Õˆ8××Ó�q××××××ÓØˆq‰6Ð9×ÑÐ9×(Ñ(Ð9¨MÐ9¨MÑ9×9×9×9Ò9Ð(×9×9Ô9ˆ6×9×9Ó9Ð×9×9Ó9Ð(×9×9Ó9¨M×9×9×9×9×9×9×9Øˆq‰6Ð,× Ñ Ð,¨Ð,¨Ð,×,×,×,Ò,Ð ×,×,Ô,ˆ6×,×,Ó,Ð ×,×,Ó,¨×,×,×,×,×,×,Õ,Øˆq‰6Ð2× Ñ Ð2×)Ñ)Ð2¨UÐ2¨UÐ2×2×2×2Ò2Ð)×2×2Ô2ˆ6×2×2Ó2Ð ×2×2Ó2Ð)×2×2Ó2¨U×2×2×2×2×2×2×2Ð2r   c                 óh  ^• [        SSSSS/SS//5      mU R                  [        SU4S	 j5        [        R                  " [        R
                  " [        S
5      S S95      n[        U5      nSo2U:H  oD(       Gd  [        R                  " SU4SX#45      S[        R                  " 5       ;   d  [        R                  " [        5      (       a  [        R                  " [        5      OSS[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n=pCUS   owR                   nS o2UL oD(       d„  [        R                  " SU4SX#45      [        R                  " U5      [        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[        [        R                  " U5      5      eS =n=n=pCg )Nzstream-p2-0é   r    r!   r"   r#   r$   r&   c                 ó
   >• T/$ r(   r)   )r*   r+   s    €r   r-   ÚFtest_camelot_flow_without_classifier_leaves_untagged.<locals>.<lambda>.   s	   ø€ ÐVZÑU[r   r1   )rS   r   r2   r4   r5   r6   r7   r<   r=   r   rB   )z6%(py3)s
{%(py3)s = %(py1)s.classification
} is %(py6)srA   )r   rD   rE   rF   rG   rH   r   r5   rI   rJ   rK   rL   rM   rN   rO   rP   rR   )	r   r6   rT   rU   rV   rW   rX   rY   r+   s	           @r   Ú4test_camelot_flow_without_classifier_leaves_untaggedrb   ,   sM  ø€ Ü�m QÐ(MÐQTÐVYÐPZÐ]`ÐbeÐ\fÐOgÓh€DØ×ÑœÐ&DÔF[Ô\Ü
�+Š+”l×3Ò3´D¸³MÈdÑSÓ
T€CÜˆs‹8Ð�qÐ�q‰=×××Óˆ8×××××ÕŒ3×××ÑŒ3×××××Öˆs×××Ñˆs××Õˆ8××Ó�q××××××ÓØˆq‰6Ð(× Ñ Ð( DÐ( DÐ(×(×(×(Ò(Ð ×(×(Ô(ˆ6×(×(Ó(Ð ×(×(Ó( D×(×(×(×(×(×(Ö(r   Útmp_pathc           	      óF  ^^• US-  mUS-  mTR                  S5        TR                  S5        U R                  [        SUU4S j5        [        SSSS	S
SS9/n[        R
                  " [        R                  " [        S5      [        U5      5      5      n[        U5      nSoTU:H  of(       Gd  [        R                  " SU4SXE45      S[        R                  " 5       ;   d  [        R                  " [        5      (       a  [        R                  " [        5      OSS[        R                  " 5       ;   d  [        R                  " U5      (       a  [        R                  " U5      OS[        R                  " U5      [        R                  " U5      S.-  nSSU0-  n[!        [        R"                  " U5      5      eS =n=peU V	s1 s H  o™R$                  iM     n
n	SS1oºU:H  oD(       do  [        R                  " SU4SX«45      [        R                  " U
5      [        R                  " U5      S.-  nSSU0-  n[!        [        R"                  " U5      5      eS =n
=pKS U 5       n['        U5      o»(       d¢  SS[        R                  " 5       ;   d  [        R                  " [&        5      (       a  [        R                  " [&        5      OS[        R                  " U5      [        R                  " U5      S.-  n[!        [        R"                  " U5      5      eS =pÛg s  sn	f )Nzpage-0001.pngzpage-0002.pngó   xÚrender_pagesc                 ó   >• TT/$ r(   r)   )r*   ÚdpiÚout_dirÚp1Úp2s      €€r   r-   ÚBtest_vision_flow_maps_located_to_per_page_tables.<locals>.<lambda>9   s   ø€ ÐSUÐWYÑRZr   r   Út)çš™™™™™¹?rn   gÍÌÌÌÌÌì?g      à?©r   r_   )r   r   T)ÚordinalÚtitleÚregionÚ	grid_rowsÚ	grid_colsÚ	tightenedr1   r_   r2   r4   r5   r6   r7   r<   r=   )z%(py1)s == %(py4)s)r9   Úpy4zassert %(py6)sr;   c              3   ód   #   • U  H&  oR                   S :H  =(       a    UR                  v •  M(     g7f)rm   N)rq   ru   )Ú.0Úvs     r   Ú	<genexpr>ÚCtest_vision_flow_maps_located_to_per_page_tables.<locals>.<genexpr>I   s"   é € Ð;²s°!�w‰w˜#‰~×- !§+¡+Ô-²sùs   ‚.0z,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}Úall)r8   Úpy2rv   )Úwrite_bytesrD   Úvision_flowr   rF   rG   Úrun_vision_flowr   r   r5   rI   rJ   rK   rL   rM   rN   rO   rP   r   r|   )r   rc   Úlocatedr6   rT   rU   rV   rW   rX   ry   rY   Ú@py_assert3Ú@py_format5Ú@py_assert1rj   rk   s                 @@r   Ú0test_vision_flow_maps_located_to_per_page_tablesr…   4   sæ  ù€ Ø	�OÑ	#€BØ	�OÑ	#€BØ‡N�N�4ÔØ‡N�N�4ÔØ×Ñœ ^Õ5ZÔ[ô 	ØØØ'ØØØñ	
ð	€Gô �+Š+”k×1Ò1´$°w³-ÄÐQXÓAYÓZÓ
[€Cäˆs‹8Ð�qÐ�q‰=×××Óˆ8×××××ÕŒ3×××ÑŒ3×××××Öˆs×××Ñˆs××Õˆ8××Ó�q××××××ÓÙÓ šC�q�FŒF™CÐ*Ð  Q¨ FÐ* FÑ*×*×*×*Ò*Ð ×*×*Ô*Ð ×*×*Ó* F×*×*×*×*×*×*Ó*Ù;±sÓ;Ð;Œ3Ð;Ó;Ð;Õ;×;×;×;×;×;Ñ;Œ3×;×;×;Ñ;Œ3×;×;Õ;Ð;×;×;Ó;Ð;×;×;×;×;×;Ó;ùò !s   ÇLc                  ód  • [        S[        SSSSSS9[        SSSSSS9[        SSSSSS9/[        [        SSS	/ 5      S
9/S9n U R                  o" 5       nSSS.o2U:H  oD(       dÏ  [
        R                  " SU4SX#45      S[        R                  " 5       ;   d  [
        R                  " U 5      (       a  [
        R                  " U 5      OS[
        R                  " U5      [
        R                  " U5      [
        R                  " U5      S.-  nSSU0-  n[        [
        R                  " U5      5      eS =n=n=pCU R                  o" 5       nSS0o2U:H  oD(       dÏ  [
        R                  " SU4SX#45      S[        R                  " 5       ;   d  [
        R                  " U 5      (       a  [
        R                  " U 5      OS[
        R                  " U5      [
        R                  " U5      [
        R                  " U5      S.-  nSSU0-  n[        [
        R                  " U5      5      eS =n=n=pCg )Nr1   r   r%   )r   r   r   r   T)r   rp   rq   rr   ru   r_   r!   Úm)rQ   )r*   Úvisualr   ro   r2   )zS%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.visual_count_by_page
}()
} == %(py7)sÚresult)r8   r}   rv   Úpy7zassert %(py9)sÚpy9)zT%(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.camelot_count_by_page
}()
} == %(py7)s)r   r   r   r   Úvisual_count_by_pagerI   rJ   rK   rL   rM   rN   rO   rP   Úcamelot_count_by_page)r‰   r„   r‚   r[   rU   Ú@py_format8Ú@py_format10s          r   Útest_dualresult_page_countsr�   L   sy  € ÜØä˜Q¨°¸LÐTXÑYÜ˜Q¨°¸LÐTXÑYÜ˜Q¨°¸LÐTXÑYð
ô
 ¬
°3¸¸3ÀÓ(CÑDÐEñ€Fð ×&Ñ&Ð8Ð&Ó(Ð8°°a©LÐ8¨LÑ8×8×8×8Ò8Ð(×8×8×8×8×8Õ8ˆ6×8×8×8Ñ8ˆ6×8×8Õ8Ð&×8×8Ó8Ð(×8×8Ó8¨L×8×8×8×8×8×8Õ8Ø×'Ñ'Ð3Ð'Ó)Ð3¨a°¨VÐ3¨VÑ3×3×3×3Ò3Ð)×3×3×3×3×3Õ3ˆ6×3×3×3Ñ3ˆ6×3×3Õ3Ð'×3×3Ó3Ð)×3×3Ó3¨V×3×3×3×3×3×3Ö3r   )&Ú__doc__ÚbuiltinsrK   Ú_pytest.assertion.rewriteÚ	assertionÚrewriterI   rF   Úpathlibr   Útypingr   ÚpytestÚquber.agents.classifierr   r   Úquber.agents.grid_locatorr   r   Ú%quber.core.extractors.camelot.acquirer
   Úquber.core.extractors.dualr   rE   r   r   Ú!quber.core.extractors.dual.modelsr   r   r   ÚstrÚintr   ÚMonkeyPatchr]   rb   r…   r�   r)   r   r   Ú<module>r¡      s¥   ðñ÷ „ ƒÝ Ý ã ç Dß CÝ BÝ >Ý <ß SÑ Sð�Cð ˜sð ¨cð ¸$¸tÀC¹y¹/ð ÐN^ô ð3Àf×FXÑFXô 3ð)Àf×FXÑFXô )ð<À&×BTÑBTð <Ð`dô <ó04r   