From 33699b460f2abdf5afef38ec8df86e0950cd72c2 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 1 Feb 2026 20:11:06 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20optimize=20memory=20usage=20in=20fi?= =?UTF-8?q?le=20loading?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced inefficient `read().decode()` with `io.TextIOWrapper` for MGF and mzTab loading. This avoids loading the entire file into memory as bytes and then as a string, significantly reducing memory footprint for large datasets. Added regression test `tests/test_streaming_io.py`. Updated `.gitignore` to exclude `__pycache__`. Co-authored-by: erayfirat <59361860+erayfirat@users.noreply.github.com> --- .gitignore | 3 +- .jules/bolt.md | 4 ++ __pycache__/data_loading.cpython-312.pyc | Bin 0 -> 2115 bytes __pycache__/processing.cpython-312.pyc | Bin 0 -> 4213 bytes app.py | 5 +- tests/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 119 bytes .../conftest.cpython-312-pytest-9.0.2.pyc | Bin 0 -> 2099 bytes ...m_spectra_ref.cpython-312-pytest-9.0.2.pyc | Bin 0 -> 15572 bytes ...t_integration.cpython-312-pytest-9.0.2.pyc | Bin 0 -> 10094 bytes ...test_load_mgf.cpython-312-pytest-9.0.2.pyc | Bin 0 -> 18187 bytes ...st_load_mztab.cpython-312-pytest-9.0.2.pyc | Bin 0 -> 13133 bytes ...ms_to_spectra.cpython-312-pytest-9.0.2.pyc | Bin 0 -> 15331 bytes ..._streaming_io.cpython-312-pytest-9.0.2.pyc | Bin 0 -> 2971 bytes tests/test_streaming_io.py | 58 ++++++++++++++++++ 14 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 __pycache__/data_loading.cpython-312.pyc create mode 100644 __pycache__/processing.cpython-312.pyc create mode 100644 tests/__pycache__/__init__.cpython-312.pyc create mode 100644 tests/__pycache__/conftest.cpython-312-pytest-9.0.2.pyc create mode 100644 tests/__pycache__/test_extract_index_from_spectra_ref.cpython-312-pytest-9.0.2.pyc create mode 100644 tests/__pycache__/test_integration.cpython-312-pytest-9.0.2.pyc create mode 100644 tests/__pycache__/test_load_mgf.cpython-312-pytest-9.0.2.pyc create mode 100644 tests/__pycache__/test_load_mztab.cpython-312-pytest-9.0.2.pyc create mode 100644 tests/__pycache__/test_map_psms_to_spectra.cpython-312-pytest-9.0.2.pyc create mode 100644 tests/__pycache__/test_streaming_io.cpython-312-pytest-9.0.2.pyc create mode 100644 tests/test_streaming_io.py diff --git a/.gitignore b/.gitignore index 5a2dce5..5f73537 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .gitignore /venv -/.pytest_cache \ No newline at end of file +/.pytest_cache +__pycache__/ diff --git a/.jules/bolt.md b/.jules/bolt.md index 8780446..24dc78f 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -1,3 +1,7 @@ ## 2024-05-23 - [Regex Pre-compilation in Loops] **Learning:** Pre-compiling regular expressions (`re.compile`) at the module level provides a significant performance boost (measured ~1.8x speedup) when the regex is used inside a tight loop or a pandas `apply` function, compared to compiling it repeatedly or implicitly inside the loop. Vectorized string operations in Pandas are usually faster, but in complex logic cases (multiple prioritized regex groups + fallback logic), a simple pre-compiled regex with `apply` can sometimes be cleaner and sufficiently fast, or even faster if the vectorized approach requires multiple passes or expensive intermediate structures. **Action:** Always check for regex usage in loops or `apply` calls. If found, refactor to use module-level pre-compiled patterns. When considering vectorization, benchmark against the optimized loop version, as the overhead of complex vectorization might outweigh the benefits for moderate dataset sizes. + +## 2025-01-29 - [Streaming File Decoding with TextIOWrapper] +**Learning:** `streamlit.UploadedFile` is a binary stream (`io.BytesIO` subclass). Reading it fully with `.read().decode()` to create a string for `io.StringIO` doubles memory usage (bytes + string) and is O(N) in allocation. Wrapping the binary stream directly with `io.TextIOWrapper` allows streaming decoding, which is compatible with `pyteomics` parsers (MGF and mzTab) and significantly reduces memory footprint for large files. +**Action:** When handling `streamlit.UploadedFile` (or any binary stream) for text-based parsers, prefer `io.TextIOWrapper(file, encoding='utf-8')` over `io.StringIO(file.read().decode('utf-8'))`. Ensure the downstream parser accepts a file-like object (and `use_index=False` for MGF if needed). diff --git a/__pycache__/data_loading.cpython-312.pyc b/__pycache__/data_loading.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d1e1885f26ff2470dadcdee10c94e47d7927277 GIT binary patch literal 2115 zcmbtV-ES0C6u)=Ac6Z8x&{7K)bKR|hvCUQ=Af{H60xg6rXsDR5iko5QZkcswcD*xe z+09lP<3pR66rQ>m5{oZj>I41@zWM^$nAC}hB>3Xnl46KFdCu$yrHVdyCv!i}J#)^v z_x#RpevHR;0&V^K&+M59A@_07ZLkj8=4BXGiA6HRqLx&oj+BucIU_qtMxiK^i)u!L zQ7J~8XeR2!GBJ>=T(LARahdB}$xHjd3ch*8ihQAD`a1hsVJP(SR0ldy(1}-NBUbxd zKW_RaE0#>lcITK=vMNQ+@+HCEnLW+kv-vz1DgC7BT1D>l)L_ZVrtt8SQl5Ebp7VuS zWER@W+o*cz^obdRp`vYZ*SGU_&h+h)%LMl-MIRKL+PmgOBc=b2(HU}}q;1a+l;d{J z59BGgdd83f*_q1+s#EjLi$Nb6&R(qK^IQa);C@B8IlAR&c-u0(n;(L7mCTU^>i6~w z(iY9mv<~a@_s!WMURRrL9>uAtu2cd4b-wP(Z@=~{ipezd!9#jf{aq~y!0LSn?y@adk7k~*Cw zN%9);=)6S9c|zeq*=6}WnWu(sQaGf}prrvjVWJTcoI&2V0m63u60;z!kbYCx0FHUv zzr?r@0JBR7Ex=Jq4~WLj_yyw9~u;JB0dps}> z7RK?~vK<0Qm8(G%=UFH`fsBHmd*48}NLm9VzH4#%m)MS#q2-|~qqp|{6dS*N2WY5qemFTaw5@g5j#q^`(llfy0WBqFC&7%qVhlF}`Eb)jfrevbzVn1OArPA!V})YYFQhE)4A1jn|*2>C9g)h-2wg<&#e;2FRTZ`XzGmMcE{ z#4Os787P_mSs87&|5h7iE7c2OVtX|B8_1Q46~_h2_V~vY?&hFCI+ULkJU_;`pGyIe zBc=km>^T5wgjt}TMv4!lvK7R79t^3CR2ewkL+WKr;9n}x+qgrn7Yqci!0WvX-6DB7 zNcx^z8C@Q|@=;SyEFSxRP5J4&WkIuKK*>*f}pOt}tpbfV!Ac@gjB%x^Ibi3Fl#)(aH8-@-1-? zWC#=QZRlDurSyR$Q{|CPX!0&e+$a6N64ug&>F!3dMPOJPS@UllyWM~5@BaLG%0>j$To9P?rhd2!#{snWT3?Bdh literal 0 HcmV?d00001 diff --git a/__pycache__/processing.cpython-312.pyc b/__pycache__/processing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a9d28eadaf75df9319a0bce3a090cfb057344f0 GIT binary patch literal 4213 zcmb7HZ)_9E6`x)ITmRq01_wf5bA<%c5DEu(Gz7$-goINGflxrmo_);0d7y7Ah*4}kW z30z0=%-fmw-n^Oj=DnZ)91Qvpvh<*$Iaiv%=^1WKSY)F@?+ z^r!b#QFqoe>Y)&gL@Lc%N*bf!d_dK{M!l=@xNIJu;1)fie;tSj9*asj z1?EHNXh86aF41kS`9w#0ePb7k0-4v&r`&=cG=wJTcwq9jZy3u-QBkDa7?+iWLPq3L zGUkRyj&o-u@tTOceMjV+%1b$gOBHfSRgwt>EaG()^Y9IVN?uH=xRB+foFIWVj?W2P zme1$OBB)Y0RjxDfT*2JyDoDs!niK_2&Wo5g^>+K766=TJ4#W8)Nl^`FpOjP$=0u(> z^O?zwuz`4e|JDn__v4z9AD0fn+-}a+*ni#IG3znxOpiK=*e$+7tG#8 z8Y)r~lxi-KE=|^6X&SQJF-2(z;hyj6$Iv8oO`z*e=x z<`_Y$72YWA{ogY+PL62}ji3oC?wb6IkAv1<^E{U;WJN3`SGZpgbE=e*M9ihIoaL_a zSdt40hsBhL#az;itt_u9-9A&%Av~t^m=sZ~a9b4>$9uRDE1Vi~umG`C7dvITcBQ0> zIf%$1IVbj5)RjFCrbACjbUdX=M|>Z58G*#9{-cTEL#I#opBggUipb;S zxZxVZav^W9iJ>1K?>}|yh|S=F!z9P!G$vPx$&*)zHjevu^9~6A9eMk4b>}CHjrAv! zFrzp@t|(D^I(!0-iXr_V@>6~WT@h8Ii18LDD&fcrHwvy>3T)B?o93x<;GJUsUp;|u z{p{_1xAx6knLbd7wA|e{yKnBwodcyndnMR>`~0o*b4}BizT*PuXIhp#ZMvszj(_6e zDq;2}Q+1;Ny9|~f!&A4?aOah5LP#aaA+1Kzr}?TvPV-e!X=`Q0h+9Lnm%AAgt z3d}>V#glGn%v+S;6MR3V1%HYr)`69Q-r88Rw$0Q6jR3DqkC{Vxj*tZhYf+KME6#S;>YZm3SDepBDkML*Vq4-F4KhEcED4>pu z66TUJ#-fs!0W;Vbg6A$zaH^yN41rW_=E<%%AqMW+I8+ucF9U+PoDpANSIlz4b6W|d zI8PA8MJO`lgOgK@;swaXL>X8Tp*|6lNvkD1ZfjoX?&DSdDCV;wNZT}bO;X2AxFo>x zY6WVgbPu@-6B(JJWP|!S74b@eRLL$2E0LV7Tw*q_P8f7vFueAe z@J8S@d}sJfLF~s^#)b>?xiQgjWW=1|00d$%y5~9h=*{L7)TPe2_cN2c~J>fHi3ab zNk-7*v}ZhdUR6b$GrabN7!k|I#1#nzFqxf|h|+ul!b`EX2DFb4!pbiADJ|d>KqxJU3H@BVp?w{0x~<*Po+GqnkbZ#> zdyK9k2GW0m4cMp9XYALNdTMnHoG3TB!X#4JR^zf$x z^H&zGEXF>coH;pjZFY3NY4+m%f#UH}^zc7-zW0T)`2OeGlbwC#XurO*@BX2WN9LOD zoS8d2fAW)2eNAU+XCGnhuQDhUB>?Cb7mG)$0TkX_9H_8sXQp&^%M#nAvt18I%IwZ1 zc8|{PSz`C=?Eb~EGJCXm3?$pP{Wg3ryl`?pT;|?i;(B$i_YWr@QH!T_?r`yF$-hB& zwpByO8@@TEGi^&uyUw)FZ(rP7V%p10-#6a1x7uc|mNxFtV?S7m?bc(v7cTy3ycFAA zj-4%g&sAN>)$*(v?H{JfO~ZQciG?d4PtLdh=Jb=;w%PUtT5sM}>OE2Xpwu*6ztOo5 z%Hhu9U}a6~-3zl9ih~~xExQqWgu3ad_(L<}OKUsywH;siJ1QHvn}ahWA03A+VEF}u z*k(T8GljZ2HN~~=ztH-*QV(;p)cfUANj_s|iYoG7b*KMmr zH_VOd(XEx%@0B+1(OciEL|W&L>5-0SVW!Q!j2PBa90YV4h!#)0d_G2@HAkqIe~`-sz+UI$R)+NZ)(-4<{_%&cgS0aqHav-hASV+EgT^8tO8BqHD|idY z7;bo1Pzx|A%$T4=O#W<+UZ%J9XZ8Rd zfH?xzlpD}h9TY`9qaBoU*@r0K-%#Wm)TyJ+st>X2Z{pjNwPO4oID^M9D5Ep|OADI~$8H<>KEC6317*_xQ literal 0 HcmV?d00001 diff --git a/tests/__pycache__/conftest.cpython-312-pytest-9.0.2.pyc b/tests/__pycache__/conftest.cpython-312-pytest-9.0.2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9240e9b7ade39c8e8f49f9078ad0125293948a40 GIT binary patch literal 2099 zcmd5-&2Jk;6o0e3v3LDZJ0Z9MQfJ!&iF0s1gcI5zgoMPG)PNK&^~GA->vkircQw2D zu$77+Dgolau{q`%Eh34L`U4#lC;(-17GuS->7Zvqeoty^t78Hce4Es`b zE!ELXyQ!;pKK@8;7)`x+{$^cswI$zOv8irTtEM}SUavT|UUR8dH19R&1g?4leYW;_ zZb`H4C0BP`XQ^hj8q6x%Z7&lng7}J!+tC!F*@sRRyF+*pgH*PgUF#*+yV5#k3G!00 zygm|(+4)kd2GQK$(bP0YYgxNiWp#PAw6eTW1$M}&MD9&THa*H zogsYo8T2!b!|dPbB}-kYbeVk&q5LEc(D?V0cmOU#@OFSXeHz?^5|5+lXGpc_x^%j2%Df>~wef zb}zGW_{ncd`n&r_;uB@|nEaZ_{v4-TF4&~&j7Yh0Y!Z>sw=v1zoyWN}I zIQ)zWx_xx>iIP9QJ|yVeQzidc$)8hJ4Qhj0fCH9yJUd70!~sO=1nJDN!Vqv^F@?oP zt?o1$IxSMRNP+P4cGw0%P7Ll3=7bNW*Kn5oBKHSV;_Y5?zAMf9_vd98UiU@+4;-0< zQI4++2_3MUL(q*&EEjsoLRTtqmW3%#uI?C3*JwFj>I1ut0S2SjDt4P!KMe~ebq%Xk zr1~B;T-{R!E-xPX68JHLS2XIyeA5#Qi{c+7cyU%Tn?}{Yit&cA@9t2Y*HFrC7MGl| zn7Fc(5g)B$@_VLL-)ZXa(?y(R>N>~Ror#2y=Kv4koAfid`V3}%C-HCdU+4c41oCcQ v1R;CItTPz|IrOg${A&@vL}mg%T4$*New<$*3xjnQBI^ibk^32gMK1F{IvTmR literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_extract_index_from_spectra_ref.cpython-312-pytest-9.0.2.pyc b/tests/__pycache__/test_extract_index_from_spectra_ref.cpython-312-pytest-9.0.2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..781adb3192426ba9d11c472ae5af8291b84fe5ed GIT binary patch literal 15572 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 DD28QM literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_load_mztab.cpython-312-pytest-9.0.2.pyc b/tests/__pycache__/test_load_mztab.cpython-312-pytest-9.0.2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..56c7a4e742797316877ae5d2022c3eb1ce04ad2f GIT binary patch literal 13133 zcmeHN&2JP(7VnFMe5FxY?rlaPUggu%vNKtfQ!`5+rm7QzPh;wT!mUF|SV&j;0Q zz>^tmw93I~BZXTg5>k@W#zK48+e-T<>}Bk+<*1ct51UJF5v;NjhtdHt&Dz50C9@BOO!Z<&lP!FBu3zbjq=?jM*Cm*O#Z-v;JWiAY4Yq;Z)&W2N|H zOqNQ@ctYkS>Ua`LVwP4)ji*>%+|oG15IE{<0?r2 zO%fHTHk-_AZsw9{JHLjy&y8Pt<<&{ABdk&lXdHfbFQ>3-M>HkX<=Yh_dM|f(xFGDtOU5 z8rIk^dwkM zp#eQoLgS3kfpzulVI4U|$dSaYL=D!fk#M$&^$6*17kR<6o)Eg?`FokD*X2gMp*TB* zTriIfl_bH+)VlKiX=o=|Puf3*TG%Btf+x}H$tjtnP-iN3+p}h(KeDyx6>W(TtZSbg z8n71nFK?frd5p3KRg7;PxxgCIw-jy-q>E(giK5I>+JR>?2!O!9KR4MqnQyov67;i5@-ntCsY8+I=g|=3gg0 zWLsVLRwKRP)kuq)#M4`i6s(5YNRsWFs{z&!__8Rw`T163$L4B0KC3aS=6h>TV@Q_6 zcn^ZVoO9XC*+!{qnYmK!k};8+Dq7~?y-S8|o7Bl2I9Q#1K5y$Ecuejj%Nowx2Qg

kl zj^}MGIqqtKp&x^j6>Fwcwqb~I))3v{wRWr) zZs-Nx&aqez9P~#kVH>V!w|llCwaoB3tHdDHczz!)-PVv`fiT;#e!YJ zs(3C4G`oFqpMko5P^GPXE$zAH+nm*F^(oWzi<>aLsI~<4o$zIR z2D0yh6-tvnY=(pnsk;Cc!`^}1kRJf65qPsJ1Zm=q2TCMq+6TKr4nR%_HrC^H#RuDo zdV+y%gtqwpV%IeOA@93Zf$gj)oQ?=k92^O|M34tyCeY{+rNOgP!-KjT?a_`<{SiG1 zKqw7MM)V|*L}*JAk8Do-)!FczbZ9`25}|QM_1=d~>&W?lnW!GvRvmPF>S${Kv2u#Q|{4P74CR!N3zsjD8mOKsRTd`K&1 z*0T+?543{#^b^8Df+xwM*^sSB8#?KRtr;D*X3$!2YsL!oKH6GvYo-Tv0&5BBM9qvY z`nQgp|9>LeZp9ezO_S|pM?LM$%zyu{(fKySnlsbu&CJgK$C-hh=v}oV7})u+$H+|> zc5yOy)v$_0ARiVDJ0{6ZR?3c9b_Q#ebC*u17%n<|)uc8A$f=RR;lW`&$S+lhnYuVr zDj9TEzi{zPO2CK|kL**SXdlYYr7paF;nLaDuct;*CA&ap%I}Q4d!kq-=Jk`qIz_+7 zf_@fCGdMuelb-(`{rtRqFLv_eyj&aJ7#KRq(Ha0a7S~hU_@wwkrnsfa;1$L9lAH88 z1y%QWxGv`@1E8Caaa@CLaTRvLiV;vz{7crlJI0gGQVcW#XhZj65|j-Fjt5oj zxT_5GC&cCn&}UaDE>cJgJfh;oMYzfQV{jlgjqj5CE)r*(%y2xmDlU4M7}Y;;i##Oj zh&UlG3N#|(>Hu>He~K|GQ6C~M3hIwIq6%gU;`Tr?q9=hQ^gvxl*7xe`$OUmx(u<2A zmWAjv>3RR~Aw8&|-MkJ6VgeG}bbk z=<~IAUNh)~Q7V#3$#gEyTJN5DGs-!o$}^UwbKkNNC&auJI-%P3s3xME5`6>2=@}po za1s0OcM<5Z3#-Od8(!N_bZVg2vNg|HtOd{>XJ;|i%5$i40GQQK1#?1B1&$CfiBLu4 zuM1T$6l754FR-dV0jl^QVDlIOW^&aPfQ-#!1e}=QySqnwjDR1X)}F(6L)5FcT)}W3 zUc8fd<~>*&ddS!AgSY8c1=_f^|4=(#^GUYDb$_6}dQ;0rG~}IhcWhUgrK&T#-gZ?; z=tZc@{womJu2NzwbXFrn=g0MI8xGMsBi_vy7_6v3!?2rypZxy9=S-XDps*zOU2C0# zvKQE1_5urH#>$MtUR;+=gP3%%_Wnb@w>Ee@5fu-vaWp~C!MNyoAf2zK4wPT6Aigi~ z5v+&uR|&s{4Tx9O8iCt)kNd0Yd_LuB1@?JXq2THTjA&;p6Zoz|;mV9*;fGs=0zHb; zile4yk-UlIEhN7IGB2^$9&-Q`zt&&`H;HZB#`#FP6H6tYz0;dXye!|@n@$Yh>C=(j zl}rrW-L5AFxH@X)Gp;7SE@Qhv?(PErv}}-n#f3hSn%8L2f$z!uEH~-pu>%}etr}%w z*!&B&Sh2!3oZKz~UjVXCui#@teh$Ps`&;ZW?vZm3roF`H;1qoq@({q=cs}$)T$bg( b<7nE_wr{1K-%3yaOF1LU19v2(tb+dlsGJ_9 literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_map_psms_to_spectra.cpython-312-pytest-9.0.2.pyc b/tests/__pycache__/test_map_psms_to_spectra.cpython-312-pytest-9.0.2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9086857be7222f975ce98e47e73b972315d428f0 GIT binary patch literal 15331 zcmeHOU2GKB6`tAO*&loT{{zNe5=dA|{DXmjiHVbtq>T!tfh3jFX0q%Z+iUiZJLAAE z>o%?OK-5-EpTYwVJlY~kU8$=2=trc!?Ao|SqgJidN>%!VplT(add|Hwvtu*fT_<*$ zKt{V~&b@Qy&YiQf=bZ1HJAZ6w2nw*>{OwPY|7sV6zhlGPJO*?B6<|IVh(N@YFfOva zEA39WL?P`N_lo?8Z`=<@Tq!9X7!QboOL$cv?hgdwx#{BLj0f{#%=;NOPRB&OH672% zIW?`yT2@wbNJ9gR&-m^9@0ANEqaRH3;P6N)>rhY|Iq@b+%)?!%@*I2wxVxBB<*<4 zgzKj9qmmA-!IYbBG`Y(Drop}^sNJ^ln<^3}r}<3IoFlcL(PAF0>>oZOBa#l%S@(?E ztIw#SEozr^m`OzvX3%LH)k)T4-d_zluPH~mu6qigomoHWCOeA$q{v#527ffZ*+%Lx z`zrgQWR7I+exk^0e5_anek{oL>#OpeaZCuDh5nLL^Fd7ej_-{B>)_Z;oW{4b22lJ8;L< zH1mX^8S!z{OnztV$wDjI!RYz8noLB&3g?oU$$s67Hh6H}HOU^NXmRZHKlvkd_j!X6 z#tdeU$s8J+_vl_NsihR%pHp(_xT@+>x**3Xjpy}9GNUOOHL2x|4t9+p^BRLcwXPwV zBQ}}L36nWFrhCr3d}gT746cICWZoY7(MU2wl*^+qSzS_7^?&@|7B4_u?8^I~Ce@4j4qIHm@#7)*3DiripK-G}?3m>LVtMn`$?k(jExQ%Xkn zQAM3eX>jXqkVP_tWEjbj2aTWug=%b|qj*X#fAloP>(U+U;)NDtY;)j4F?HTW_rgIG zKD1^8xF~%Zk2Iv?T4G8eGSl{agYL=^J#aFv#b2TEv_jEq(cLH+9Lwc3_<=#^db6B} zr&6Gj98F}?xj0qyFdUZ8&m>b?GNbCgR2C#uy-QZ7vNI{dMCHj;_Ix}gXJBAGAgl2S z1xL^uUtqVE%w}GuG)whXc_K?;Ub1pImx^cN8XVC*Nf>fItb0@?HKF^BUq$zUtCz_H zeFCQ#!Z~m~9ke$N+Z%^?gJ0rVd*hg0Y|!2qwu>EB!*H>vZF}(406gvks2!D2*&zt& z&*k+-ra(N%{w0Mc@gK83a_Cz+H^eWk&d%Hfk10}_3~`+~bAbk&DqdvCloH?iD& z_^R*Ek(Q5+{QOEu>bn*Pa`no!csbIyD&c2^w|T>&WvTBMDsL@USnKeT)c4U5>#)h* z#-VsG2waO>;uZsA-HEjS>dJ>#t_^+o<7?C9NUS6c&%Ftx6p78fS&j^^O88kZI(TcD zwK%_o@|?9(5V4P(El2uG(y@i7fs`Ws3s09L$5ti$tQZ}Kp`4iZug134+G}1bU+BqBb4q1veS!g;<~$UKi*!)E!pY!?x`U z^cqNG-7~U>Zw@o6gm0S)^crh~DVq=UB37W+M4GoK&}*p~=(VyyukCY&Goc~|dhOdB z=yh0uUMK0=qCgKdV+4BnmRL78&SoGJJ)e(~Bn3DbWu6lH!Eg5KVcrP_ADUExzc@wM zL@@@YAtdN5D1su2Q8h)ieuid&_9BTQLI27;7=02sKwtum0Wti0KeqQH`4*CAkf8IX z14xbodB`KtSD{z$s(6w-cknWwZsD04j%TfS8(!j&<%0Gu?7DTf^!gjOUMrL8F>vs!?_#(k7+U~uFouqxzZ@A`mGHA-bnw

1}C@eh0MY>y;mBYsX;4K8o z;gPQ&zS}|+20(55@Ld(R{`(D+{B_|wC7gzz6&#a*RT%X)sLpW9DE0bj{h^h zi)=Z*YqIbily9~O-?i4ncMRE)b_3tFatAdd%+`~}?_lVzbDPm!mxb=Iz_B%HeAG+z zG(OkM&c|0T`PNuZp_jSsOH)cFn#o3ansp}4;jW_A<+IT%>!D0Gqg+m^kg3uNdkG!+9`vJy(hhtxEV= zF*)Mr6hq}AXHDSJK-R6iYo#ZMtW;4O&CzxQX)R-gY(6%c&rBIz}%-w5T zlapq4tkI10IBF)}9ouObVUnD{3RwnG6l52noEp{gIWWSykEijfV<(-%Aca)NPZium zzXv}qFDbH=BeT^GdB@WfP5FF)4x;=J5>_T0LGB=uVIM5DC(hBrZbg`M~>R*oEBmGHA-bnw22wF732Ep)*Dxe8Pz(fS{oSECT2RCk%Cd(tm$ZB7^rnE2C|trCu8Z9s&kU77}Yi- zuJx04(y>KGwX>#C<(la-G!xjQQGFydlkbFj&OsL0YE$twC7h@hzo4km9F%qxf-63v z+4mG0Wr>-(qTL_B6IYLgg};nIYuHuvu5=v9+d!ObV7FxhSs6;M%)8KE-3qRke+{qD zW!b?EvQE8D=5ZrCxN)HSu$9^l`8n4t%48c6l?oX!8g0t zRq(6WzjvAat1Qi&6g2dJY@0TgLYi&do68=pMVO*(5vI-NK``hpx{7XVSzWC~m@bCL z**TSEb;MJ5rsT`X-FS$%?itmp&0E^4S(~>cVG*X+X3L$H8d}R{Ysgs(W{JLd%k1;ZhX?@jGT9 zwq>2SRPQ?P4FV-c^a<%dT=V_tVo$MVnAFVzNE4NBHh|p00?3`)96)XdDz|9{UZm(L zj54ERtgnos@yX5@5tAC-$Cq;ioQ$-1>L2uXRVk0I8oK~%40q0Gg-#%=ONGKJylw#xCOAHwx*uyW^(*~Q^o?#2D3 z^An}1R4JY=hcopr(`3avEaLgg;iDTD@g5GVwj*b^g(W#y7+J+?{sDq0=bT-=g)7ayW(!8Pkk&1Nk!>~YBi9Ts8+piPVdSH)nGWNb zY1kydek3%LZ;N&EG+dMcYjen6dh9b;o3UHoNTzd)?}c3+2fEk~A;}FB=S$BKzmyZG(YT2|p`F2X8I2 z7U!2xp0jp(TN+?a=5#EqOEP=iM3(iSET^+%CZzx$mgS2x@f5y@BFpsK@T<^MNX{U6 z6A8L=`VNwJktC2z0ht%r&>at^6ZQ`B!EhXSk5n>WpP>lL^lq8IaMRDq1LUq- a6ve;d4J`|;e-ZZo*F!~d@ScE_o&7&+8FRV- literal 0 HcmV?d00001 diff --git a/tests/__pycache__/test_streaming_io.cpython-312-pytest-9.0.2.pyc b/tests/__pycache__/test_streaming_io.cpython-312-pytest-9.0.2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..198395560b69dc4ac48754b5bfbf1cc4e611a9d3 GIT binary patch literal 2971 zcmc&$O>7&-6`uVgITR^XwkwO4n=F#X3E@a4<;1nysneA;!kT6d+z~p8`;Q~TvU~!UiK7AmXN1b zHK`>@R1=XTSxrJOyD1M>v6rr<+wz`jMn;p!R&F6%CCTMu@iN{1p3(OnzzQyc`H^Hz0@A;4FYi+k!UAX*_Ljh zs$$E~stqNthJAB{@d~HJ^c;V2YQ~BUg?$44!pS`fTsRVGUE&@2vMf{%eog6KTfQ#u z(^L;?iBVIw?VIxQq3$TA?4GV&13iz5h)JuE zU{@h-68haQZYWpLs+7-6vnyaSUYeYm)~9BsE9tqZxz|c#l^U@)t$TVgJzJVBU#L{Z ziiJX9q>#RN`NB^pOJk!a)4&)h=xz3BGqDNRqb=6bBv`NHtoyHc1Uz7^OI|4Vr( z#C1jt$G6FiuSG1W2vL}*nbh=HsBwq8WG&tGV68gt_$F=WEJ`AsEd_Pg*8PC%^F+7Y zfDv1FyqfD+VA{}~1-%w9=FGd~WqrQRg`Hz@Jy`V#WlK&?_ngHguCKtH`E)2dL6{tG zaKff$!t5Nm!KY@fP_tGel#0|0RY+YsR9%Phu*YPKP+q!TH{DQii63(=nJyz?qUB9K z5vq*13tnFv+5WH<>65J^CI$dkUO61^#gs zwQUVttv&`F@){y3A=-Ff}f?CB3zz8E;RdFBu9 z#^g5&>V0K5fpGR=YH%kt_{YPWSKd9oef>cy|5+;2;%y$??%z7LeR(H0d}nbdcjlwa zgH&lZ)v?+9&coa=2zL=Gye9t(AzYTf>4$m$l0E&HWx(4%Co<#1%E!an_?hGZED`V; zVaY51cPxo(em{yV3+JEsnyRgeD(~oPfF~X7=qmG0-8Z{<(m|^Tg`Q&7)SikAi3nHP zNV6X$@_3s49nP*iH-WviIdgt^1q#Lqd|Vt6rQhXyflY9w?s-r```EluBY4V&WOo)E z%j961o~>NQj9jk+01!M|DH~H0*t9GH1qu__eFsF?HsN+LS(h;4l^HRqwPX-~(eVjP zv~OfEE1=}(#b07@r?Vi#l!$VJ*$wV^1Y1icT_l*?s2LtqufYSO&9Y3_dXm?!KZBA5 zT%!a7l5otpNjWCIje{CD7TsXpbPa38C|AA@@HaYI{GMSGD`*%sQsWLB&C}EhXV0E% zD+CJx^^DG`?9&#@8)U_F>jX}&i~)S-rY1_bh%a2chzodPT*LxbO1Lm`?i}{(u8Sia z#-pN#D8*fbuVY0#48I~U!8o1_w2Eme%Adj$1%*nDc~oR)3yD*)V_~vwkxx^RUi4d{ z5vfSUeH&_JktCs9vqL-q5xfKdPUsOK|F)2;jvH9{1Qid2FdMxfVlbrQwL*u4K!MN$ z`ZLe47xuv(eMSh6v|vj-KK6mzcb^V!2eqCDdv+5V0dHDP1vu-C;ce{xVDZ1eTMG3Z zdHdR1*EUby?>(`he9?dS_VM2z-?X-0*jm2dpWjG)6+;=o+t1z|+BP4gUh2Zz!23g6 zL)$;udge}gCwKb8tDmNRyaztOOG*n{dNg_-lU zhS3@2jGDOb_({>{v;g4AQt GD*pzcjoO$1 literal 0 HcmV?d00001 diff --git a/tests/test_streaming_io.py b/tests/test_streaming_io.py new file mode 100644 index 0000000..197ab34 --- /dev/null +++ b/tests/test_streaming_io.py @@ -0,0 +1,58 @@ + +import io +import unittest +from pyteomics import mgf, mztab +import pandas as pd + +class TestStreamingIO(unittest.TestCase): + def test_mgf_streaming(self): + # Create a mock MGF content as bytes + mgf_content = b"""BEGIN IONS +TITLE=Spectrum 1 +PEPMASS=1000.0 +CHARGE=2+ +100.0 1000.0 +200.0 500.0 +END IONS +""" + # Wrap in BytesIO to simulate Streamlit's UploadedFile + binary_stream = io.BytesIO(mgf_content) + + # Wrap in TextIOWrapper for streaming decoding + text_stream = io.TextIOWrapper(binary_stream, encoding='utf-8') + + # Verify pyteomics can read from it + with mgf.read(text_stream, use_index=False) as reader: + spectra = list(reader) + + self.assertEqual(len(spectra), 1) + self.assertEqual(spectra[0]['params']['title'], 'Spectrum 1') + + # Check if underlying stream is closed + # TextIOWrapper might define closed property + self.assertFalse(binary_stream.closed, "Binary stream should not be closed implicitly if possible, but strict ownership might vary") + + def test_mztab_streaming(self): + # Create a mock mzTab content as bytes + mztab_content = b"""MTD\tmzTab-version\t1.0.0 +MTD\tmzTab-mode\tSummary +MTD\tmzTab-type\tIdentification +PSH\tsequence\tPSM_ID\taccession\tunique\tdatabase\tdatabase_version\tsearch_engine\tsearch_engine_score[1]\tmodifications\tretention_time\tcharge\texp_mass_to_charge\tcalc_mass_to_charge\tspectra_ref\tpre\tpost\tstart\tend\topt_global_cv_MS:1002217_decoy_peptide\topt_global_cv_MS:1000889_peptidoform_sequence\topt_global_spec_evalue +PSM\tPEPTIDE\t1\tACC\t0\tDB\t1.0\tSE\t0.99\tnull\t100.0\t2\t1000.0\t1000.0\tindex=1\t-\t-\t1\t10\t0\tPEPTIDE\t0.01 +""" + # Wrap in BytesIO to simulate Streamlit's UploadedFile + binary_stream = io.BytesIO(mztab_content) + + # Wrap in TextIOWrapper for streaming decoding + text_stream = io.TextIOWrapper(binary_stream, encoding='utf-8') + + # Verify pyteomics can read from it + # pyteomics.mztab.MzTab reads the whole file, but it should accept a file-like object + tab = mztab.MzTab(text_stream) + psm_df = pd.DataFrame(tab['psm']) + + self.assertEqual(len(psm_df), 1) + self.assertEqual(psm_df.iloc[0]['sequence'], 'PEPTIDE') + +if __name__ == '__main__': + unittest.main()