From 382c0be70e9e9cbf5064a8ef0705699a910a855e Mon Sep 17 00:00:00 2001 From: Julian Smith Date: Wed, 18 Feb 2026 18:04:45 +0000 Subject: [PATCH 1/6] tests/: added reproducer for #4755. --- tests/resources/test_4755.pdf | Bin 0 -> 23033 bytes tests/test_annots.py | 44 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/resources/test_4755.pdf diff --git a/tests/resources/test_4755.pdf b/tests/resources/test_4755.pdf new file mode 100644 index 0000000000000000000000000000000000000000..61b4d386257da14c90e94d23b72a68fb415df890 GIT binary patch literal 23033 zcma&NQ*bU$@UR)%PEKswIxpm!>|xC651PC!SM3JFvytNnY&mJGBL3d{;vhYAZBUfV(LW5 zAZBCeVk%;4Y;R%;!_N=n?BZlExxSCJ1@9C6#7W z3~n3w{j;O{zpNC;2p$?$93qD(o=_b46e0=g91OAQuG{o1V%+cNZ1qL^_Q&?5 zsJ+I4U$)K+l8PNq8^+Yml5^|2Jt&8@Ni=4hlWoNI|{bzjdy6lUfs>)4VL+bJylCUPA&^ zB}4SKpe-O&0z?jOb_n#y{?#AWcJx4)m<*7Zn26+{LG)O+P#;^-6ZwdN9f1W%2>>J$ zLqfu@33ABbzYog=NdA#oB>q{L{d9zbbd-Z5;QI%MC_k9UFsQ)ez&iu%K&}Y>FlZo7 zBPQ`7+};EIZZG#`ra#Y62CZhm4zRGWjo;V^@opdk{i^~{0(ekukX(E<7Vs`$=K?hY zgzam95(A8;u%R4LPA)!PUQU0xT3m(n95C2F{h)Adklhd+fd;pPfBFf)L0SFf^82Wd z`b~h&H-mJ48?OXx5AX%Bpzci^z_f!1Yvqyckp3XS-8XXzh-<>Y1gx#glUR@r!9&-9Z3bcq{YwLJAh%IxA%KKzeh5MEbPMDk z1l$SNku9D@-ki?_`~#cWf!uC zd>I3r46w#ODsJ?$0Xfy6V3)uT?|;?6;$FH8=JR=Sw|}SQ(ceBeg>!&gaio$782Q43TxHzOZVLy?BSv2nXR))m>Rxn z2DfzV?C1L$R7^r?h3QHFu&xKSH&V^{)3gdZUf&l~qA+%|%XgeUUuKDao{#NdPY1yy z_dI?OFEaJ0;iTMjD|*^q>Fu9E@!~U)`YIVsy4s-+EKX4LJpWO8t^P};j|-l;vAR=* zE;rgqk!u(`7tMmem|;BDFr7_YC>Y$RnAb5DqY16A< z&+?Nz#7WYl@)Vgd$kybSB)?(ltaa7Y)uBA@o0+!c-KyTuqHAd_U!qYxad9^2Go`yn z@_4dQf?E|vipuAoW*D$U22`Bw#COm<9t@+(G{t$^G(7mL8b4-Q1CkWSA=HWd&vjd$ zkuS}q9P1{B+5H(FAJlXpK@d1Aeob#_cJ^`7*3+c6SuoRC@sxY-lxCFiB1R3w$_!YV zQ?89lyu)~k$3i)o%>%>NWf{Z1vfA}-P91JEEBvFEGhO!BgL0ox-3cEcm;Gke5bg6^ zPOKO6iRx>>N`L9=gyk|j?cgp9YH)w&kpOs6Nn}<`@?pVWM zb9h}DGT|h_H}V8iZi1U158;iCZZ;S9;{bc3qwJh;r(49M^oIDr4Ci|CDn_dZw$HRQJ+lcv+nykCH0OXPku&4U3F+%P?f(@6K$K;9d9V zh#sB*#Jo~obmwNGZ&QXv;tBVDRXAr!&E}`1bSqw{Vttv$#e0A~=3CRe*j6YGM1eNJ zzIXwNP1FoCGQ7$d*{_#u`3Oy(@Sj2YNANsoz>%R4jyQN*B&caanUbIm+B(Q_SK3> zxfRvgmA}}IDRILcpHS6FWHT9huAsRC{2g$m3lE7=`ov_WmvYz@PSxd!z62&0CM2r3 zO3%Pz<2X~4W-W$F%ARyAMD)_b_4;i8t#HxqEF$Dmw)Dwh`Vn|2EihN*iM? z-i@U*F`bW;z#({ZSs{h!o2}TDQ??lL|9-i(KXVm9nhclpe)Vz{o=BauP6l}CFA?a< z>%2fR{!{VE!6kiJ*V#H|3QBdW1Er?BB}=&pbKF62GRgL%&QFY7c09^wAl=GOgY$sa zfpDd*0WL?Yj}jhVCj8^U~Lf1Hu>FR1TQyPP`}{9xN968Pr>)YRus>ssu` zK#_oe<_qRit27~R6ojr+(x*6rIeFk9LuRp;9>ZlCL0gUE%E}o9ns>~dx@>&*Btcfs zSP}Y{A`=v@bluc>rwS>x;5h6Dvm*p^a_{E{?OlSp3qDS9ckZgn22^G_lH8heqb}h*{-(4Mk36;5@n4w@D4@K#Islg9X|kv?2?84 zsMJrjbBRD$0ljQ?)BXe(iTtuji#rfmqhLnbDZh@PGk%F1hbbmVR-s~|AfpA?%o-hq zI;#kQ{~7_d<&)Hox|c|_tlqJx(xD{F*fk4hua*GoYW&(leIuj8giRH>NovbOfjf(r z$EMR00Dru6O8(7z2uX>$>$JdNL5o8LMB1LogL~4sIb162(0#ih=l-cV9@zlAjNl23|$uanCOVM4n9W73F} za--4C$>~HJkeSuRSuA{T(%%j`_26yJ*=-Gg9mC>Iwq$s2{ku2fsvNU{kap#26JG*E zyOM6u{TakKG+aA6?-*bfx40Vg8bABc_>%XzXZ9-fo`U6KTF>hfyTq$G( z(5-P!cj`X@)mKCj%8E0gHtw|duV31>SWgcFmPm%vB6v=u!cS~E7h~q?jX&uetK4BI zIwEKVl$?xP3L>2R43?@t{@Q%6zY| ztYOtyw=Vb0pnR}!5yVa%8q~BJ7c5<2t2h_pP zIHAlAJDZ?%C||p1p_&>?J!JOd<7m48x|;CYuK&C{?S6b5{CMlbG~m%waQP%qv3+&M zewqnfgztTOs446`$#P{sR#T_MqV$p*TEy74f=TCO1fElPch=ZREKHIq$^g;$Q@8aS zi}dLo^U+>RhGnY1)@$chUnZ3CH{&@j8wqwCk`%oK7lqd4)P!pK^85NAf^|BQ8=jg# zHKgnTPtB`$ACER7V#YYNa3A(PXckYd?CDwK z1Ppl8Zz%_L;30`g>9OfM_46`w0-9R90%qsENmM3_M3x=Pj#@+gn?(n7!rvr4-BwfLRi0Inxr~q>2+P^_F z5RqtP4mrIP+I{XviPr&p`%Zee$f9L0y{UBNo>X9NzwZN0;{-nYWGbbZIz5$;?%r4D zjB`$u7{=BTkha?pzysY`*4KQ@?g*~d9@|uL-rr*^cuG(RDfiQ6_^flql+~ygNAdm1 zck~*pAJ8V;D6!kqT zQ&-&qD)VT{Oa!ha=ciKV1U$~h$uth7y$IeZtH6_t4zw_lvCN3H7Tw&D)PEFQ=ge$5 zCI=B_5k2mnz?$ohu)#c)6HXL3FFIQ|5aVnI5$`p+FfddDlcXfl zut#T=R=sT-{qyO2dAWA~r57Vx1eIAtp!nm<`4#IR%M(-{&2QYS&HEjplXB4CDbQQ_ z5dXoht7GOUvT-fyk3juOwtuqW!qUq(8y?}7p6OeG{Am}Thj2XrJC3NZ#;in}k%Lr% zAr@P}Dome2$|gh@0h4lwD50U7XHweVJsFAH>SU#p?$J6kg>ovBeeMa2jBDIV=iBgh zhrFzY;m*tHBko}E$Ci5}(c~-Amt5O*O|lsqM;Nrnd#@|1GgPc7w-d{`+CRfHl%wdo zS?Xp?F;gn;JgBIF6=UsLu@LfL#klO}L7O_}mWy*Gz>J20=>l^>$}ug&Kd2Ua^kKd*!n61C#lF0GHZ+;5VWy zBH1jw|lrd4nop z>rj*COFywx*~U#~0pHYg3I^d!zr6~~#|p{7RNSRkw}Z8%q+BNNo{02_%`ZsZD5orHS%r%)ZGfVQ)g zVzph!%~;4i9@gH|w*)`GyIHjPyJ5k8*2<AGy}j!nF(S z98cer!asc>M%boALQUJzG?BxWX8V9r5zJD9gH62T)i*}-)z)K|H-6*={M zd@Hh!422oX4IeEhf$u6wg_j|e0BoyX@!vR%V?5LJsRkFOx*C`HPGtV|8s251Ir(Srtj7E`U#nY zEt1Yz{)~Dn5Kkz-xLPad`FOvvAv?wfJ(hKos|@pH*tDO0UIr7>)8nyK4v#M@(UM8L zRo7non+l%uqn?visOQnHUGHYBk^0u1v_DbNcz3VSXRl@s0KOXMfBImq-RI)XE?tRU zVh@{;flKUg_v$S;++S2=y2!aPdZpD%-8l<@=Dxcv#YIa*?z+F+|{F1`>O|`E+BT|+{9T!h!mZv$W^j3rxu40wD3mJP)Q-Q(3 z(1H=dsl8uKaZ>TGnsb>^G{xW-z3<~8Js3yF0ee-iFTcHRJ9KdEu1IR^UpWR@>WNGd z&Ci^EfGMeV4GT(uMshSq|ATK*t8ro0ZOUY0ETP<3BC;zw_X+UiLzbxx^=O6Y1!&4y zwW&97=E4tbS|wCC|3nvV{Kj9A857e|i`-yH3?-qmL7fZaX*7*uj&S3;vPsl6M(m6m)Qu)N}FZ*tR`=&|?|z z!1|PJGcf!X?>h>m4CWS3$Z8QjefH7C``m@|=c0Khybv z7j@un3Er8$c0#r(1{>Tz%bMmG`{|xB!-%$HEE{tf3P>ZyO9r%N#9(P6nSKlNw<`Rq znb_Zaf=fgdG)|-~`3^Fjbr0borN-+Wlh2~n*(D=>Lk0+J^)Yj;l7h7Z{B{|}1!Aw* zQ5^`Aq&%*a!$YsR@HB%OMT)r|LKqM3D`ct2YSY$e3OVj;(<9LKSIJan-ymP-2Ll#K zd(5#a19QYXO)TVCk_=b2Xi0`bx&V*xLbTdl++2U=RH~V=`0o_h2%ZE%->5C~Ae5$% z!MfxQAIZ`ynF}9`@P#{WoyMW);q`T?Fa-6`8ZC`uWZQ}*&(6B9I4O? zDR^jC@Dr+t=K~bY{vEbk?PWuc&p)>ly)GBN>%ydtreh{2pzq<4-k4d`Guk52OPli# zh#%H>d*%kEyCv3P%bC^H5f`pFkqX3+bac{MO?r$rJ_DSK7MckQ2bc(5Ft^o$(Nr^q zSGiXcaRS#&)Vk^HH&#(>mXg_((SaT7ItmLb%vD?RZvl#e%R^=j@O4NHkE! zq#-5YQd^W$z4gb@Q2$0u0H6YB_w0CXyd!uWanlMXMILN8<&$#!eO3zjO;zY@T2#7~ z<7nH$i%m|#S}aU##DM80#)4w9bxAEzUz28I#&NwGMhU_?{J-|8?1WEtSEzizfg23? z5KK3vJ#>A1q~1@mmpAq#VR_$AANusqpX+Gc-ZG&IME>^udzSgzNS z8yW4XBQMC3`(50+0#&WGO>P0B)=7oq(y|smJprWxRAI7vX5b-cH$Og;0nJ>ZWEZ{E zYA2C4L6o3ArY7{wA*iPEVJ!>!bCbb^VxvUFwEDy+oVOg(QrxUo9M2jVGmR9u?D-KsFD7RsvJJZ8D&jm1Q&; zFK7ZVARl+ERp76nla)!)FFEc_^m!PfF&Omuh+07!%*a9Wl=^dz)2XBMB!3}s%{M$b zRJw|{$#6UO%K%fZ3789rLs;915RZA9s#lH=KCdw!T7SKIlRCL^{hT%VMTI2xYjlcp zK~-2~j4|spq<@ttiA&z_>O0w7f4}uCS-7B3(QTsH5ISJ|2?eL05Vv@d3l;v_7(aP3 zrt2%<7(#Ru)8R=hG{o;jXa3D*vfE6D4;Fc%dPLWLsqo%R z^e+6!J}eY@RKr+;uy2(9H32J7gT` zj?;AL0v6S+22%m~RqVIDu_=!WQ0ZH-ttC^$-ny8Ck9D>|=;<47{CVs7zN1?Zm#!Iw zGW*Lq$3Hga;-v5y&+)p(51%6j&Be**pkcF3)NBVg1hIvAhpuLdTNl`PhbfhJJzQ5m z{f)YH%ba=I0pQF6j3QiTG@>QxRWMD(Lg<5y&TkQSOklZ=uxzQA{cWoWDWd41YAlC( zm_HxsIuW_Rj%b4$ZZwWzw>=Fh0ow|HB2n{DME_kqTN~7y_qC zJxJxTq2GSvpgcFDji7n%i!JP*EAf3RgQA$=pZtZKS(XXK`7y(U6Qu&}lxPa#=(VplS7P z@2#t|Y6(ugGY^m>+AsN;H&&ifPLW&HWHD`zXPdbsUr=g1y0HR)U8L8k8ZXJ1Z}*`| z3p^u5O+1kk*5m32S3Taf85U_MBw%wzfuW3?>&1U`XCUIsV)0#Cjm?F2hUD?;H08>VU%v6K$IdN_hk7~HCqlNTTIgJ(+ZtOFdwlGY|Ai$tq-KUDe&on(waTeS%8e$(;(_a% z)NdEcJ<&dippj))mm$OXtn*`hu@9XV@^Qa2Te$bMo%^VTTVJD~Q{UQ;9L#>OMRATx zfzsOZp$kd6GiL0&+=p5`mdy=znkBuLWtt=S9jKvIz)rmLdQ|Zc2HcHxVQL^tW)CUK zfaaL_z}w-!mkC?CTpKG1<}5C>2CY;7CFQw8!S_WPb$DY7D;mDKDM@?^BXF`50WGRP zW5{SGSOkeZwH<>;xvt3ph{%?u166QXzdF+?01|8KI;~WOz)Q{R3GQoVI#x+w)|SY0A0RqYkt!`B#&9TPWHpU4JT8LhARrL@18!4vmuX z8kpTCQ5$nW+NZ{6Yf?gnpIb~S7AcO})a@Y7S1S>*To<6f248R0TjZ6u9rPFtP$~Id z|4D+o2{Gz^-|c$CwEx*M=-WB-z}rd@tuX%Qp*XZx6|R8x&5nI?b%r_+y%1Z!S&Sf8RfJR68iyH7XJKlj;CbJj@V=87wdNH&Cxvv@-a zjb3>|Wo`MDc{xo}+60#AcHoZh5~vS)sumWxAnodPWF`P7sbrvqpj9M0`>~d`4RdpL11a{`^5vC>Jibe~OUYqOd}JyscggOSHv~UP<2hwcaT;hOK*Ny=j&qK3t!xtFHxu}W& zE^TF6<+Le`T{^D`TU`nBt+cr+$wX1IVAq!Ky&}d_-~ta$_uxJCs(52xC<+|Ap?l=e zc(-M_-O`+cmRe0vB~7n&M}T<>RMy9X*taZ}+3JC>l~320VfCQVd?WW;QWnJx9%TN`n@jX927$IvyX(m~;pmQ5&(w!AvubbTskBCNV z;cpJzDPl}m^kp%wMU=9`#dmweJ}gM8rWgXWSY^q*L^>$%j!rTM! z{q$Dj=Fw1P*Jcq0H1ThBz8t>wQ7qnRY7v|nFx3yneY8<2-nL^j`I{12=4OH>oSd7c zjjV=hGISH(XF6ZIQlT)wFk_^_d#L#iMS4cY9L0r)cx;vx=WO*@$p0m$Za3}3p-^M9 zX7r@M9cfOZdX#L%PUI$JOaE`{XS z-I=djD^mOBxM59p&?oRaZhKGfxLzLbZhAk)P^L~PWO|}#*_@bOT3&+QE-%e*jj`HUI-OtUFVa}c*B@r<5z^$msSq?>wKd!~?Enf8w#pJA^d+)0m!?dxcf@wcBA`}XD{WlI4#?iT& z?Dc_@z>%HhaXWQMT+$&2y_`-dz9Wc6|I-m`9Oh#ak9$21FLzV||{OW_7!wFv0pjtW1mly`RYrCEh>4zvh0~4&DrR#%QvYc;r#=AUU_6 zy*Rwxo6u3KJeEc28a+|rYa120cjE$slu;P}W)^C=rQa~)kc7(9$)ru!lZx)mO6#$&myl}AIufFux7EZoz(Rg>zG;XN#i3#F3AZAYW*-{o z^%(>13u5UXSX{G&*KT#k_Vu!Ts2awUh(2Iku7yW_YgY<8!{^Zl3nuYybAV5cob^(U zL?EwP_BK?Ze&gGl3r%4o5d0RBnB+m|6`K@Ugh5ytBbj#}(|kjO(np4(V@2$lHI#Bh zoT-|YDQI`>^X(g+B^NIU0A_FxACH{?oeJQ2j+)cEmBQ09LZ5DMR9c;A^R*i4rbAAI z$3w^Kf$W_o>wtbagmb00MTMMJn0Snk50*a7h%-WLiwm;0;4s>*GO}?C@j1#Cjf#`J zOjQf}tCgVPn`EZD!F$5MR>VFoQ4?&^H*2KqC$1IXaX(x*leh4>Yg?aobz1!km$WkB z^o=*ox45S`TZaDGB0xqVcDG{fkE5A8=_daD#QC(Qvz|&&(U%T~W=R+eIA* zJKN9m*i3n#sdkU3^fmpqNolej6@yHLJStjA;1@AnE-F;J-Gl#|ny>8Ip=)0)#0fEP zz6&~t&ovEGVZr6j>*i8tuTghaD5ARXnGg#Z7Vtny-I^kvWM9Zk%%fogO9{Mw#+W=w zUbG8VmtFlYd$^Xpr%M=!DPHyL@?g38WLT(It>)6qr2oIoTwr~`zt9lWn{e|)sl~Y| zcqllpc*b1{w)4i+1ovt?n$mJujP@YCH!~x+H|JJ(gtT*tf5` z0aELFVlMZYz2SMDBP2C5Wf7TR>M%?Bs}ZHq=q_>Fkh#{o8>sNYGBY6?*Z-v~|KA;Dc217}r6?2r|8SJmAXSpK8cQXi zdnCmDsHEhD(35woRHzn(ppXcmgB3s}6f?^SWx*>J(G`oODL{y2BhgBv6f0pQ&P4fM zbKP&ft$W%U)f!)YSendVeD?H^`R%QUDsCek1;qA#C=Ex&;cX2Qv#`~sKmeFA(R&(X^`TE zLPQ&KB7#MF5aXW0YZ&ZHfYHAZP>Ixf>^tyF88{diL<8~><1Zc0*3V^ z*{?(d`5xOij|&33Ut0lEpgQkc`bPhzK}PxJ!GZ`gR^VrJVMMt>Xea7H?pMVlq0&K; z1Mx4=1#k^^e=`nyXaK=oz&jIhf6?PYoR?<-Ga3N^u4j;A#J&!GN`4Y|`gnnW5+c1u z_DxmPAR(f8&cE|@AI8GZq#9GfA|e(SQpm_3hJKI zAQ!+swoYUFft`?`LkhVd;XgW;m5f3?_zD>zj2|`~7-hk|eF^~);IKUnt zgI|Nd34w4|36Mj7@B06`6H=l%hz>gX!w%v_Kz!%qSctWMZ=h1di9!Ic5s4fM0*}|t z^{FF>*mW4q?+yUEe(~uwwgh$t7bU*jhkip@Ss4X^^pv!K;x`o|20;UK@$rh!Dv7{K9QvJT$ixL|T$fj@ng zKRm|(CakaIUG)tiJ2glJ7=_0JB-tZJGQ% z?xE_ruH5L4(lidDa9nocOc=%=!K0vSdx+fXN_FHn3lB27l~kcPU*S4YuY|RvRxGHq zj}Lt##u@V+*z0BZO5$YMo+xZ>R&6hOdkJrq7rn<=)k0sBhj547sUt->V5w|Uf)=bP zHKe2Q*;_{G*?y`%!A4F>o10h}qFp<+kJ}%M@v^eiMZX#yAsx4DpJN`{yHNUlHnl}~ zPX2vqm@-(g>+h&TQ~uUO&hyZ?nI%dcXfbkquYyfkKfejz+cPa#TU`b%A&y!j=I@Ec z29fs|7y{;wk`t0~Ik{K(Qur?{eQfC&>44NC3YbjqI{e(6w757%B;L82>TYMI6acKZ zH?zOKX`;S+7ERBg4_tcgUbJ4=z?&-P0DLs}7)feaH(er~1HR^FDkyVwys>Hl2^#J~ zd#MB#XR7+%;Xz^iI*voQ(==oVt+RteALdcPyB;0>*@+^z%&8}vL&-(a9S-(P>Kb@N zG8x56c-Wns*Wvydn9_V@m*{uVsv}k52GvDT+q4G`Vp+3NHq`;8NgBHZ)nn$;DZ zmOMOa+m@|zjq5@wUuwirGQ8-Wp`1{betPc0>zj2)<4E+>He1o|%=~_1lLPEaT8Z`q zJ+xIGomF}kHuFZGQ(_Vn-kIm$Jad+_l+u2t>O9Rl;%Vn*6m}m_RzF9pg~x*m3(Gf6 zBHx1_<-Lv1(vLvZ#8Fx*P@1*C?howEASi3Ar8@D_MvWUYxMMzI_PiN+YVUG+wb_4t zMJh&C$TEZN(cr8yO@c@>FJoU@(VkbuH=bbp5>j)M8F=j%&M`>50X%y#BA#Y-qv)CU z&q=pMQEv$6VQOq^el_<7e{7sH)kajiicxOxD*}q+Cab832V==(4KA!}TyYCsXSU<| zdMR9dF)}u^#BJFfI@lZ(a|{pI`e@(}TykUUT3Cf_gCyPmW;N`xb^fMuMDhFz$c=wp#Fkz!@6!?gC%m9szMCm`&9HBxD(Vvg(=jb6H*bCyN18~hSj)nwyRf<2n z+oGOMAM>2G3?UXU$?b z=g31()}Zk)5VMo6@vuAO3GgB@xlLdPpx7~G+4z(xTq~B54+%xJiRjaY8Z!~UgDer* zv9X-_s~<1vIsgtlM%PH{^u`FgyfMRcFTGPv5()24LZ9>0Hb~CtWvLQRN8CZT6k+*+ zc3dNAaaM!z{3G?Yl|$P-4gqa+{iIbi0ihccMBY#dp>u6A&XHM8S7#?~mwQt5iGA}{ zBojRmy5WF@ywTa|~GA0AEK*pp4r`s%5WL*M8ljW+% zlyLM@#`KtuOIh0aWs?+IM^$6~0%oHM`!bA&f9%S){dr%Wb(99iK_Pv>@@kI zd)26|r3TJL_sXzCSQSwX3apZK6jOX z2PDyB;Q7Ecw!{d3VmzoRU$?|mFRcn&d95#k+5Vi*Tb8ZRPME!-XES}%Q|oJKlJ6{1 zy~Um>0$E)=MeKcXU7KmHYzTfDAI|tA0`nqxmbFTjx}dn&sJ|C`(3F4IUkofgYKRD2l zeH^378UWdNSgvB=10U%+?drTCh&@pLP_hRrqf0B{f@5dW+o3tkg;^Hcel6&Adplx8 z^T78izB4%caN&Yg(v7jybLuf8ELKDA^!(IOh7%{QSzklBJ)Pd~r+YCbH{%|{9SwNe zdlJVcM5n1@_CD?fM#EO(Mwjzpzr66|HtcFUsb&krn@Ar-sZkXREfKCQeWzDM!`!>C ziKdr0MjnT-%Q1NN9`xpaghj7Qasq@t8S~*QdHs0E+SCh&QAH zU{_cr?LW$~e=NCS-BJ*DJqKqe*_b>wuUY`%^m-AEjIY!(*l2T)eu$GdEmzt+>{wL9 zh>0KYHw+5)QorccM9j>oV#3zj$$9kIgNHVzD;emYnz% zetGGK-2KVIaF4C5Sh^s$LrPkE9bzP+o1i=(?xr;?ON}!z&pai$ld-wAMWe_9FM-j{ zIzAe99GE}ua!IrQH>b}LmdGG?x+mwn3!z$7VQBTS;Ems{T~{IowKmFs5&jA>S?@PF z@kVQ9H$*wEuHKwir*V!+{5eCew_lP!#cNF1fz1C$4y6dy@G&~rWH#x;=rn6srztqW zMCY6Su9tNVa!S(WEp*w-lhvWAB#nZuc{;)&)-}qRyyAA)THrWimI@|Vubnj2ci38* zxQT)AL=NRgbX3Ur>*BpP`p(yHDNS!F{FT8cvOr#5n7=&ht*}I4Z>ZLFxn2K3*x})Q zR)t3FbABC-8Sa5fG_9wr#+G1%OVN>%f3__CXEmaA;hMr#qS@1&_Zx^p3AV`buQV4c z2PT~e{f*O$mbh6H+wY4RTh@E(?<&byi&vOB%wizZoR(2rZeSqVI)*h}^TwYOYS_hE zvp7UMtsYgS5#FbgDx=0$b6!vHmn~vItUZV(GGy2V+=TXaN=_4gG3?5XuCMbc3h*4d z9g9_0ya;kC&h_zna)-MLH}fk?Ildk8Xyf_|4A>mImqvYhm3mEugu9%wn6f^e>a!Wz zeGY~p?&60R8@b!qo^_bcDpfR~l195eIktFyqnPX#$Vf>JePsE(xZ}-5=xDOrspGTq zKox@W4QSQH@7w2EA~L*5@U96_CsL_F_Y}N`Y(RlpzOvAM_Z+UMGH({r?i2JsD^xLi zZglW-^6L*OoSp}S6}*EGdRr$vUJZJ*oTO;wUYo~7jm{v7okO){AnHaJWlp($3IJP+ zb53f_g$3er_uv+8x!3*Ot#tHnPU)$`PbST1<8FnHHf1R%1eOs~omByxeB0|HE}9iH#ym}1>{6;0 zR&vJik-PfA!5LUio}xi?&ecEjzk6#dGW&t3X3ux&ZBgw^Nxg+Z%$2iczKY0Yjcmn- z3(dw|WICyrW8{}le*0%G^Q*TNyQ&CuPl)&&F$fcfsK#aKXVTKDg4`(j?klBMN%*d= z9@4Y0kWBUe$^0J-eN4pGEz{$&amxNDFB1V6VeS8UX}Za0Oy0uo8&^{M?v00r6!~P; z6*cy?$EB_`$+y6whilGE<>dS)^dXL3k(N~Bu zR>JGO5BfwZ(d}HfzgzV7+721J0qU?=~>#t+)ULoMKhGir1qoZ0DhD zdSkiG?%$uLy&FnS8_!P1SADmpUSuLjk0;RI4`kJa`4goXyDC;=lT~X!;W8uUNqA|l4Y0yyiim46P(-*sCHi%q8}=C3a)`YBRmuciLknSFQ( z9h&A0ICmP4?9tKeC2;0c6X_U$^J(@;S@f-^V^RT#(Ne8r2B3(@mm zAm8~~)oFBG3xIhiNKPFv()_Fs2wSNb-IJ#$y)XPIBLHxR`U1nbAwQeBm}BYQx+7 z>;Cql`OOz+vHW(^4+T$+`C8J14q?;ZJD_ttI)m`{Y>ri&o$$ZzZzVIgyURu49|ck%ckZ82p1QaL zN??4pj3<9kKTDAyFaNhzt~;oyZ(GxmrXV69T|fndG)RJk06}{1U3wECNa$5cL_mrH z(m|Ru6#)T569j3Zp$XEY_bL!N@}l>5%e?EGx$n(8f8^}5_sm**ueH9jzsa8Sg=Iym z2z<3KExpoWv{JWyrBvc1LJasx=)(`h820LRzUvR)qWM4RF5PFd^1T5KXUDT%KALO0cRLUJw!4)J_TTqn;{mZ-R(E`+zTs@*<_9B{eK)c0 z(MHkumbdtRuOiv{E=M1jfyCEZ^HO|2#fW*t)$d(+Rz-S|bav6jtRD~4R^ToZUXSu= zKOv>i`;f!JrGbEyz`W?!9bk&!l2vAAAy%h`;M{Q;%Mzu>C!oD2XAkXoG{UySpWY>X z`GRT`AC%;{zhG#XbG-GP78-{l+zzYd>c~>*o$ z>&8T^2PmB^Wd<_P4c~x!(}!LE^!&$+-~qK5xlBJVmtefG6=;9gBsWJo=JMJ|nsKM} ziu22d2xnS?a)6ZDX5k8lLRu`>MAr_Z1x3h|6_mf$r*LR71VoWPMiSw`kB z`nj=F7lz7o@}QGsFHCjs$w@2CO1A3>ucX7`ozb+0mi|JDXsDvZv(UKjkis^$7n*NI0y4XAzV!E+4ht2b{>`2*70OECF%xN%H-(WJjqEy z59|=kl|N;2z&a9DQAx17*t(p*7-s-;TC_8VVkO>vjp%-C;W88<7WML|a2y)s!T_k0 zp3r@&$pOY~O{ApdZRW3qX9?sYw7Vq69+d9E{3VhIoR?)UrHDNWZc1C>NURRNt^>mW}!Tv8E4s<=s$a7#BEL?S4X%Fsr8p zQE8*%N{oMWXY?oIpxziB9?2)5nMK2QwQJdgcV)t}gi=XtRoZkR>&ae#8AqZsQF$Xi zYn)ZKEjfBX?VevP@yn8q$p@Ea{nsrszO0oye;kxTu7+LFke{4*`(E(&2mO+fm$Q|J ztz+LFi_gVf3X$Io{Qm6cAm(YenwJ}?=loOV(<-|Ui6dAe{z!?NVp9uuYbTx_?4hR}zgCB9&oP?*cKID?u zQ@DEPOEMER;I7W}T(W8aT_58I_D%Mai9sBa-LK2oaC4i54mH>bn-K}8v!G<%az0r67U>`01D|=N_K;m znyadF=WX*L9w=&_S;_#|s1<5E!2Qb*nM@b8yo=KQ@!EE!(e5Oyfm7vYcPpk?E0J|C zd69wAk+A2@kZfFUP(8KA-AowKSL;Q;7H51@K)Rx;+(p7+GXd zQ?bwgMg!lcOSuYdOmy^c0?Og&XVSa!ynmM8i<=m}vC6PhGY2oJD=o6p!rMn@(A60R zp?lU-PZUm7gz?-O4~eG~&p`eLtf-+63YLaH=N$ zZ>MU!Fvwr0W&go(nX7>YdIor@VbRFm2M{i{^g9y7t`I$Ga2Blx`@PQ_j6P`1k zKiyyb!S6e=M{-3bKF4vbW&G6FLQ8+b^|L_W+}h{NI*etS${q$ozp=6X`WBD66oNx9 z!#`76x?;GgY{ALey-`ni4pl_%3htehI8>bT2aU&Nr zq^75uV6ERhnlc<}+THH=?zqCsUtkTxaK;ozLaWi6-vG1`DVHJ-tb$m5T@3e zgv;l;R$g2YneB+42&`c?(3xm4+N+3&Ifk&SDI73 zcy*Sc=Je4Urpv50j|s#In^Kj~i#`LbXxlqinT3 zy_X#3#&J|w;L;Py{9%hrSBp|pSz6v5b&H=tx=)Y{p7;pP1lN%Z&gB#CV)bv&Jm^iB z)2Ei<3ywq5EPMKtz?a+ngr_n21^8InAh*GuMMVW9On48c6NQh}MZ%&h^PVeNG)M(+ z>=ZETbYO7E*x?5 z)bktS;sZK6-ZMPD(>(?Fu~V%52gpeL0W#vi|5)$q-yuW)7i7jt^~)MjHg!*UqfqeO z$@0kn8nH2M+1bS(JCCJP>v;fUX|G2cv#{}*jiZ==Wi=_akd3;j4KbHbpSqx}02dK6 zjjF}#d;PWZL+96!6LuLdxVbs~29i3|?5_{)3)oJsw(D8(c%M0(^>pi%I~=P8ajrPD zhaMSTP*OT{c!s-pY;N;zs&*akHHHBF=#=!qHk9=5QBZwp3B1&@koZ!5LjSZlVqMON zSD%Yv;>`3>}7fOl_D; z^brv<R7kstmWRD!4He>RNiX zaOu@Io@=EZ`b`n#+DfauPl#U)JS6k^#$p8)*Eg<18N)esTBdoUu&t`L#Jdi#MAxZ} za<{ivzWjAP+#->zI`dL;h|g(pR-}k=du~M%f{F+kT3_XFBzG9UkSe_;r{-jCN6vnE zciB^wui|>zBin;!IANCMF+@hwIx}QOD|4oX3K7bE`auzeC#tM?A9)>k1mIU>u`MO+oGaK4#%q?H*tG~aBgXTrQn5~ zf}JtM@(fh#;p9TsqjEnm5i{ybJ9d|mTGzJyz(maGAhjHpckB$2T8hUA_Sqdf-JI)* zhlsTC#jZ<8EunosRV-dlI4HaSBjL+dO8k3I-;61iMx_6I;pRlZBP~&+=T_U-*v6)I zi?J5rlPL)D)V6sEckU-?fqYT$A20*`8)g`YB6$EgTMx7%+QXF>BuVVm1!!A4+GBWO zzuWqL?)CtAYftNYXh$TH;g=<%LLCDw81yd&G^{;6oPEuHbpd%nyrLi&OiUaM<`soP z#l?V72@8O(JqGRNVM{bi^rztKsifyg6yN*xpzmSrhEe+6|J&C;1_5#^db|$S_b^2N za=ajbtu-$QNxT5s9%x%Vdrva}QTNY+`23f|9}M`HvfsZ7`vFiWG;v~o&F8P_@Pgnl zF-Zu77YYN5NdmzZfZv{twQTO%+j;`@ylgywt@>9;e*gR${pI^_B7F?BzL^6Tgj9P( zya9&F07Kv)goK=uoL(_ODkV2NH?#yr6u86TvZJ0n2}?`EW=CP8P_M&svAFEQ3Xr*g z5??AENkIL@ncuPeyUBlq^)Kzh-+B3OVI>Cl|1ppNWBuQu|DA(h%l&8IQ5pbE;@Yk6 z{clqM|DRJp6lerOf#SrP_uQ2&t1^{A_=y|&G0yK$&jKqTTz9L@wA@V`_3yKoW3DkXjMcoUvPa!2YaF z>O0qF9G**sNsgW-4xT5b0Ig(`KR*+8m35>I#a$_+u;pVBT1?4LYf1fZP+?Ghutvy+ zqREQFv*bFP4e(M;OloYZi-{9_ZK_IK$ojz+`#>3!_<%g!v%%KB;_xEBE9RvaMH#cR zGx-okwSuPJR(IiT5QBnxgf?Yf^#+!f-!JpK*aHD&ZTB%-HAFHl44Y}{L>5D4!dv!Y z(I<`UN%eBrwq2S0l?=9*P#-vfM6G_@n8lI);n&mvQ;X0U+-cn$W71;o@8bXi`$iXfm8> zQZh6J9ck{8b(TCUuBMb7%+E_h`zE{DPFyr?t&u3IDW9LpjhFzST}bW@9Lwg!aTh!X zw@bnf^D7i~eE~Wy;^sBAq?D8`L*RgA(+}G>B5eGu(1#R|0Jgz52RCY0Na`xgSsx9P zb!eMAS-XeP8-7$na4lDccPKn}QTOGQd@>@%@(LzfXGpzju$w7InDY~wy}@>U)tC<$ zVp6)!QtY*rq8MpL!VxQNu`iA2KpOgn^K;IMYPv^5GD{Gu@|m-Fmd9R~LnTzR%O5Z1 z2bweEDY`PRDR+N6yI8Q}k>H%it?*&*$yAIu;z{937CoCaRB+I~$K#$G%y|D-Cu?^0(QM?RU4`n-I zv=CVe>^T}$nuO3$mJ8Im>0^oi)$!mlY4*Zxj$pB*jnC6!4=7i$rU5~SuH=Y&E>#Sq z(DSy8P-olTES6gd(XBQ*)h39H*~uNxlxjul4i^|Ccbwn5e!O6w*Kzf z=ZZt(Wou>RInQv3)8ergCq8eo+zlGir;-kvXkD z7y5h%&PFRE13=*)_tPVV%kg}5ZLC_}@lyNs`yRpEs>cHfPD*;gvA6i{z}ESe+q#@yF#9wHU=t1pLf?dZ9!~Yojzq)ep&LV} z@Ui4TfpeaMCKMdi$!yB}Nri1z+~HqT&$kcklzI2vPbg}-N$q}((fEBj0L;Sa#SS#~ z5%1Avn^&56*AsdJoc27gA?B-2ZNxac&P7xR`vbAAZkSnGd4AiYuPfOGDsp2c*U3Kz zSB1IRThfbBcT2Sy-uj zf`$`BNH)8R?lixvu0-k1dS3{mt*N2&A-mz4L9UK%Vjc9PG}9rRUzpKKQ`Jt})DO6S zPvkUI<%bqsz^sj_P$+R`(q9mh{DX)9-h7)_6|hW35J5;M4e|r K1uaDe+W!JJk0Gc4 literal 0 HcmV?d00001 diff --git a/tests/test_annots.py b/tests/test_annots.py index b6df366f2..122968291 100644 --- a/tests/test_annots.py +++ b/tests/test_annots.py @@ -3,6 +3,7 @@ Test PDF annotation insertions. """ +import copy import os import platform @@ -674,3 +675,46 @@ def test_4447(): path_out = os.path.normpath(f'{__file__}/../../tests/test_4447.pdf') document.save(path_out) + + +def test_4755(): + print() + path = os.path.normpath(f'{__file__}/../../tests/resources/test_4755.pdf') + path_out = os.path.normpath(f'{__file__}/../../tests/test_4755_out.pdf') + + with pymupdf.open(path) as document: + for page_i, page in enumerate(document): + print(f'{page_i=}') + caret = page.add_caret_annot((50,50)) + + colours = [ + (0, 0, 1), + (0, 1, 0), + (1, 0, 0), + ] + for annot_i, annot in enumerate(page.annots()): + print(f'{annot_i=}') + #if annot_i != 2: + # continue + before_rect = copy.deepcopy(annot.rect) + + def draw_rectangle(rect, c, w): + drect = page.add_freetext_annot(rect, str(annot_i), text_color=c) + drect.set_border(width=w) + drect.update() + + colour = colours[annot_i] + print(f'{colour=}') + draw_rectangle(annot.rect, colour, .3) + + print(f'before: {annot.rect}=') + annot.set_rect(annot.rect) + print(f' after: {annot.rect}=') + + print(f'difference: {annot.rect-before_rect=}') + + draw_rectangle(annot.rect, (0, 1, 0), .3) + print() + document.save(path_out) + print(f' {path=}.') + print(f'{path_out=}.') From 7f9e2439364922db6f45d335b1c12c7ed81c43d9 Mon Sep 17 00:00:00 2001 From: Julian Smith Date: Fri, 20 Feb 2026 16:00:00 +0000 Subject: [PATCH 2/6] src/extra.i: fix compiler warning for use before set of last_char. --- src/extra.i | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/extra.i b/src/extra.i index 8f4e79c63..cd3fce901 100644 --- a/src/extra.i +++ b/src/extra.i @@ -3424,6 +3424,7 @@ int _as_blocks(fz_stext_block *block, fz_rect tp_rect, PyObject *lines, int bloc PyObject *text = NULL; fz_rect blockrect; mupdf::FzBuffer res; + int last_char; while (block) { switch (block->type) @@ -3438,7 +3439,7 @@ int _as_blocks(fz_stext_block *block, fz_rect tp_rect, PyObject *lines, int bloc case FZ_STEXT_BLOCK_TEXT: blockrect = fz_empty_rect; res = mupdf::fz_new_buffer(1024); - int last_char; + last_char = 10; for (fz_stext_line* line = block->u.t.first_line; line; line = line->next) { fz_rect linerect = fz_empty_rect; From 6c522f1c96b1bc2e3ac36578dc4e5f5c52e74f75 Mon Sep 17 00:00:00 2001 From: Julian Smith Date: Fri, 20 Feb 2026 16:00:48 +0000 Subject: [PATCH 3/6] tests/test_pixmap.py:test_3493(): fix failure caused by out of date venv. We need to delete any existing test_3493_venv, because things go wrong if python version changes. --- tests/test_pixmap.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/test_pixmap.py b/tests/test_pixmap.py index 54128e523..bfbf3c565 100644 --- a/tests/test_pixmap.py +++ b/tests/test_pixmap.py @@ -11,6 +11,7 @@ import os import platform import re +import shutil import subprocess import sys import tempfile @@ -284,6 +285,10 @@ def test_3493(): import subprocess root = os.path.abspath(f'{__file__}/../..') + + venv = f'{root}/tests/resources/test_3493_venv' + shutil.rmtree(venv, ignore_errors=1) + in_path = f'{root}/tests/resources/test_3493.epub' def run(command, check=1, stdout=None): @@ -319,7 +324,7 @@ def run_code(code, code_path, *, check=True, venv=None, venv_args='', pythonpath , f'{root}/tests/resources/test_3493_gi.py', check=0, - venv=f'{root}/tests/resources/test_3493_venv', + venv=venv, venv_args='--system-site-packages', stdout=subprocess.PIPE, ) From db93f183ce55f407b153cc06423caadb67ad1534 Mon Sep 17 00:00:00 2001 From: Julian Smith Date: Fri, 20 Feb 2026 16:01:48 +0000 Subject: [PATCH 4/6] pipcl.py: fix wheel name with Py_GIL_DISABLED, e.g. with python-3.14t. We need to set abi tag to cp314t or similar. Also fail if py_limited_api and Py_GIL_DISABLED are both set - this is not supported by current python. --- pipcl.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pipcl.py b/pipcl.py index bca1ad1b3..9f3c93538 100644 --- a/pipcl.py +++ b/pipcl.py @@ -914,10 +914,19 @@ def tag_abi(self): ''' ABI tag. ''' + Py_GIL_DISABLED = sysconfig.get_config_var('Py_GIL_DISABLED') if self.tag_abi_: return self.tag_abi_ elif self.py_limited_api: + assert Py_GIL_DISABLED != 1, \ + f'py_limited_api and Py_GIL_DISABLED are not supported together as of 2026-02-20, e.g. see PEP 803 and PEP 809.' return 'abi3' + elif Py_GIL_DISABLED == 1: + ret = '' + ret += 'cp' + ret += ''.join(platform.python_version().split('.')[:2]) + ret += 't' + return ret else: return 'none' From ee268f7a849fb1b95a97ce387c9d90654883bdd9 Mon Sep 17 00:00:00 2001 From: Julian Smith Date: Fri, 20 Feb 2026 16:03:44 +0000 Subject: [PATCH 5/6] tests/test_4767.py: update to cope with free threaded python. We need to strip out `The global interpreter lock (GIL) has been enabled ...` message. --- tests/test_4767.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tests/test_4767.py b/tests/test_4767.py index 433df6ddc..e8a88fe51 100644 --- a/tests/test_4767.py +++ b/tests/test_4767.py @@ -4,6 +4,7 @@ import pymupdf import subprocess import sys +import sysconfig def test_4767(): @@ -66,36 +67,51 @@ def get_paths(): paths.append(path) return paths + def get_stdout(cp): + ''' + Strips free-threading warning. + ''' + stdout = cp.stdout + if sysconfig.get_config_var('Py_GIL_DISABLED') == 1: + line0, stdout = stdout.split('\n', 1) + assert 'The global interpreter lock (GIL) has been enabled to load module \'pymupdf._extra\',' in line0 + return stdout + cp = run(f'cd {testdir}/one/two && {sys.executable} -m pymupdf embed-extract {path} -name evil_entry') - print(cp.stdout) assert cp.returncode - assert cp.stdout == 'refusing to write stored name outside current directory: ../../test.txt\n' + stdout = get_stdout(cp) + print(f'{stdout=}') + assert stdout == 'refusing to write stored name outside current directory: ../../test.txt\n' assert not get_paths() cp = run(f'cd {testdir}/one/two && {sys.executable} -m pymupdf embed-extract {path} -name evil_entry -unsafe') assert cp.returncode == 0 - assert cp.stdout == "saved entry 'evil_entry' as '../../test.txt'\n" + stdout = get_stdout(cp) + assert stdout == "saved entry 'evil_entry' as '../../test.txt'\n" paths = get_paths() print(f'{paths=}') assert paths == [f'{testdir}/test.txt'] cp = run(f'cd {testdir}/one/two && {sys.executable} -m pymupdf embed-extract {path} -name evil_entry2') assert not cp.returncode - assert cp.stdout == "saved entry 'evil_entry2' as 'test2.txt'\n" + stdout = get_stdout(cp) + assert stdout == "saved entry 'evil_entry2' as 'test2.txt'\n" paths = get_paths() print(f'{paths=}') assert paths == [f'{testdir}/test.txt', f'{testdir}/one/two/test2.txt'] cp = run(f'cd {testdir}/one/two && {sys.executable} -m pymupdf embed-extract {path} -name evil_entry2') assert cp.returncode - assert cp.stdout == "refusing to overwrite existing file with stored name: test2.txt\n" + stdout = get_stdout(cp) + assert stdout == "refusing to overwrite existing file with stored name: test2.txt\n" paths = get_paths() print(f'{paths=}') assert paths == [f'{testdir}/test.txt', f'{testdir}/one/two/test2.txt'] cp = run(f'cd {testdir}/one/two && {sys.executable} -m pymupdf embed-extract {path} -name evil_entry2 -unsafe') assert not cp.returncode - assert cp.stdout == "saved entry 'evil_entry2' as 'test2.txt'\n" + stdout = get_stdout(cp) + assert stdout == "saved entry 'evil_entry2' as 'test2.txt'\n" paths = get_paths() print(f'{paths=}') assert paths == [f'{testdir}/test.txt', f'{testdir}/one/two/test2.txt'] From d0f4d6de0e0494745f8db8aa98d51123f6d78821 Mon Sep 17 00:00:00 2001 From: Julian Smith Date: Fri, 20 Feb 2026 16:04:58 +0000 Subject: [PATCH 6/6] tests/test_general.py: test_4392(): cope with free threaded python. Return codes from python are slightly different because of extra warning. --- tests/test_general.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/test_general.py b/tests/test_general.py index 7449010c0..96d070f1b 100644 --- a/tests/test_general.py +++ b/tests/test_general.py @@ -2004,7 +2004,7 @@ def test_4392(): print('test_4392(): not running on Pyodide - cannot run child processes.') return - print() + print('', flush=1) path = os.path.normpath(f'{__file__}/../../tests/test_4392.py') with open(path, 'w') as f: f.write('import pymupdf\n') @@ -2024,15 +2024,22 @@ def test_4392(): e3 = subprocess.run(command, shell=1, check=0).returncode print(f'{e3=}') - print(f'{e1=} {e2=} {e3=}') + print(f'{e1=} {e2=} {e3=}', flush=1) - print(f'{pymupdf.swig_version=}') - print(f'{pymupdf.swig_version_tuple=}') + print(f'{pymupdf.swig_version=}', flush=1) + print(f'{pymupdf.swig_version_tuple=}', flush=1) assert e1 == 5 if pymupdf.swig_version_tuple >= (4, 4): - assert e2 == 5 - assert e3 == 0 + if sysconfig.get_config_var('Py_GIL_DISABLED') == 1: + assert e2 == 4 + else: + assert e2 == 5 + if sysconfig.get_config_var('Py_GIL_DISABLED') == 1: + # GIL warning results in failure because of -Werror. + assert e3 == 1 + else: + assert e3 == 0 else: # We get SEGV's etc with older swig. if platform.system() == 'Windows':