From d873243b87387951b1a1fbc8fa0ae8bc1535bc69 Mon Sep 17 00:00:00 2001 From: Carl Date: Mon, 2 Nov 2026 14:19:00 -0500 Subject: [PATCH] Preserve spreadsheet error values --- src/types/cell.rs | 5 +++++ tests/data/error-cells.xls | Bin 0 -> 5632 bytes tests/data/error-cells.xlsx | Bin 0 -> 4892 bytes tests/test_error_cells.py | 19 +++++++++++++++++++ 4 files changed, 24 insertions(+) create mode 100644 tests/data/error-cells.xls create mode 100644 tests/data/error-cells.xlsx create mode 100644 tests/test_error_cells.py diff --git a/src/types/cell.rs b/src/types/cell.rs index 871ff93..cc91e45 100644 --- a/src/types/cell.rs +++ b/src/types/cell.rs @@ -114,6 +114,11 @@ where .map(|s| CellValue::String(s.to_owned())) .unwrap_or(CellValue::Empty), ) + } else if value.is_error() { + value + .get_error() + .map(|error| CellValue::String(error.to_string())) + .unwrap_or(CellValue::Empty) } else if value.is_bool() { value .get_bool() diff --git a/tests/data/error-cells.xls b/tests/data/error-cells.xls new file mode 100644 index 0000000000000000000000000000000000000000..34d5f8f7db181a477955116c138bb41c9813126a GIT binary patch literal 5632 zcmeHLO=wd=5dJpJZ)uY>riv9ys9H5Gh#|gLc=IYOM@YrpnSkgg_+Bg$xGpr1ND+)>78H0w3=B zpOXV0_&b3!$QBFv)H>1u9YfB@7>39VZc!7(W*t>R`6=Zal;2U$r^-iEb5;2e5-6MF zSk7eA``H)R(=lJ4+M?tJ54FuZ)$Bz#UeL$AcukU>)&NGG)4AEd)6nbhz#_PAv+;&K+o`$SK|ak!lGk0D(Q$;aa{Ke^LsJu(ld74c zMo2o{Ap?MmOVWakqhe4?1QIE&Ee4cd79VU;xkq`DyMz0)f1=wH4$iC36}9#=&OW6# znVog=F3P1(hadHpK4x}PUK+1lNG`q2ETE77F4K%5&pZarpt*TN=y9f28t!H}5#B4W zo(1)%K-kCAjMUCKDVZ1ozUq8gH&t0?9`a=AE#}FB{U%QqT()|0fbw=vmh&;~$#P&0 zm{mn8LcE2BeF;2}PB9|PBf-*=MZh9p5wHkY1S|p;0gHe|;LjrBBA;_eVGIS94$gDsTc?c(m>M#YORZ4td!hIqWpoEKn9^~~ nw9>r6hwpv8WAZS zB>hHR|K}_J``x?FIqR-TC0000!pwijWRH;u>B@z8Jj2E153tfRMg zKV2T*b5_oV6zBopngc|rk4SEc?NnxHFgHAR&9_o;AtjX|e# zYn*nxW@_!fRPfKaRkDZvbzV#Wfb^d#SUI`Ef9fzChg5qjKoVvSb#*G^@(Or9%NQ zWEw3o(ISu)@njK)PC#~9Zd~M|@Es<~J6U-0RXRcCD+<=N5TmV-a0Q8vQD*xGkZ(8- zge{_prQypWc$}Nh55!OmCICpJK-0OY+$$3GZ(8=-07;HM`{YRh(6{OvO$a<n`0R@#gxT$8&g`b48~58Ty(n>y3F$RJ+4xpHI8@SU*3hkvxlz zLO!VtHuq#{2mH-Ws!0YL2`&JT!36-2quKGY=XbY-JHUU>fT_{oGyh8-aZ?FDsOIy zc^`e@v)l@OmT>50F~dJM)zZknxU4V4PAV@zQ(U#*0W8!ot2aUby2bnl$jQ3rpG4rR zdr=HcnJgRA^0Q5Ss+(K57lN?Qy{>F+;co`El^fO5F>*3zu3KkUF*Cu(Of9_ponlTqW?yfPVr` zvnncof)ZbdNKzuxV8p`@^>#Nqa&XpN*nxI=^}tK4VQ4(UnI3ytrzNW^^Q(P(fjmK7 zK4R4R18TN1wx~2pS8L+fe`zP(HUk)CtTpk_b7A7e^WKV4FQT>st+4LO=e=d4?mGxh zu8Yct1>01%3QDUxK4g^j>v9v!00U=_sdwX8NoG8!j}mBS7+MzOP4*4Gh(9O2?Crsx zLX6WS2`jl~#^4YGMBk2SX!}*kH-s;D#f_W9Od)ydwQ2Fw`h&hHKVj*aue$h_+%ixA z@yYa;7w3Hp$rb{|ru}&u_u|u=_Z#J)yiq)$U z36aaEhk+j_it>&?_Y{~c3kF^Cas@qpgJ4!okWRtCBtpQ zZOr}*uTW_Wb+>gsKiPm1Bl-H0aH$BmXUZ$FA7LKNW6?i|L5V@M^L-d63(C%zaz#%4vk%DzA85D(z< zM;7iieU;7~Zxm(ox9OaSFkV!0G=6(lDL6YV%*Sn|?>gMyr&krv^FchjVHmVr)pjYzjug@a}_iwx<*s?a}AQ;k{fQyEcWhu}(ZtH$iOPpS>YT|w^ zWxTdsmFq48MxIESZ`KVHLKGWa)ju^PwAFKpseP?^=L};U0!i9P#W6H^<}iqyp-es2 z*a`)7lNDdnDzsraG-u9Bh-Ib3HUTH@#5i@IZ1;H4u87ZIH~FXNJ8XU!8#~+V)Tz$j zlS*Rfdv=(|@+CJk1=+0_=Iv{qVw2dbEllBHU(OCzYP5JgeE_CdwzjyLgBM(-gL!!8 zu7#j+FBWf1o}We}bjx`&*~ENxEN*qK2wv}4#p6lizPXM;##RD@(IRteNaYI#RAx^0`hs&DU#wL>8dWXacCS2y}xV7jl# zJQ}WH3N^Kem-xU1ZHf+;Zh{EF#?K7NRy0j_-*2X8RQj-boF;pAS{zKHGnqLJaQS zLr@bBdS|=PCl6AfZLCoprQ*#BVg=LW6WSLQ+ zH7}{GI-Va>9IjQQ@mFEqdn!ns5s_uIG;^S^aJI3D$WS>w@))xZ+I7Fw{>%S9- zr<3bLH(NN|-Hrd(@+*s&#yL4X5g_Sp2ktByo2)c|J64$HRon$>7j|xh2{$Cv7uzpA zzWI#Q%tdQ&y4bT1CvluB9xLaV7kXbIjxEV4Ax)7uE;Z;zZgr{#VqjFwzo2NcWBfFZ z;_JY1c8PT>vyOIlg*(Md2+*uU&36OLF%dvcQVJZ1sl$8t_}v)8C^z>E>8-#y*TRZC z(c}bmZjk=dViv*yukT5deng+e^fvfVCS1OSFc>>R#ZR9EUo6MX0_7IOga0woo<>$* z%hh+>v^CoJ*n6R67mfsJB!1uE*eeCycyp;y{+ie>7cH95Kk8kv0HOPz9D zYJvjEGYDT?PDCTzr}o1|LxNb`b@<-sJgW-;m&oj5ld?hky8rS2tJ;zq4f8w7pVvWe7K#7>Ao{&wZtmXp zaJQeie&OC+_?!UA1?9(UFXK~0TvQLW6)kda61H6PziTN@y0tQR825EYl1<#>Rhc2T zf0^d~JNnEfI-7~JGBTtMi&Tp({M5k%)pnM#d2s+1-jkhyU6(W35kAgo)?M_3?H4J> z-8-?X;dUD?9PprnY`sBAOU`zFcWCH8Tqvr4&;WjA8<=lGh#Gueuk;q3h>g0Wsb3SzMEp9Y@k#l@6cvR(aZD<(1 zW26qCQ8{-K@?uNbck^t#_QOse?%ccT$#i^zC`)&8%CA3)8@JA~7iwW`MnB+zb{eAr z#8VMmTt?mmr-g5#WuFp1pND3bgOaV%{rfU?UlDp-FE|{JoHe`^C9r3Qb)3ayQL=a5 zeWFz7r+o>>Y@7iHkVnzGi)8wA)%NPXI;XUG4K5xIF&GzKVNLVVTi7PKjf;7kfuFq< ziu$O=M!{u?z!tngoQTo$9DHNshaNJmoXb+rafiK@Q~Y5Zxgk#hu_z_iaLKZozR_K% zPLiJTjzp@w=C=y)K{85dJrs05+FHG>}MLqo@AvYC~>)$^tf(R;ZV}Sn)9bq7Z)|Z)IXbQ!dqYL z=AChUCw7TEyb{IO8PoGB(8PX6lT7=Y;NQmdPnv%jR(-5Aaj*dBX%*QzKt#Jl5l6$+ zfR~R1=ZKArtfvy#$o~{0M#BAmZPv|zy#ZLZErq9JPQwwq(nH)q>!HtkfCA&XaK4dM z0WCY~@)g5S+}80ob|i7!&GH{0)>&Ut^D?9^72O{#ApFEGYQ^@i3ACDSl|Zd|)F^4! zG`egXZgt*S8PZ6~dnrT{ej~}*h}6<8u($tXd8kr#=C=>%rQc*jsR+uFoB#=&i|!>bn{gy>q3rNIXByKgV`54w>9(ylMx;n0ca*M zFe$M9cP9gFGrz7tG{679uW=Q9wTbW>3jhRSbpI3me=UWp@T;fnKk$#}&;QGr`>KGe zRn~t61hL}(67a7z*HtN3Q~!UZU`(Kk0rYSDDFm)UuSV`aP%Y43ar`RqY9#yv6hl`Z z=x_ehVXuO(difu4D)BGy|M2;%a;`ekA32ZF(fME8N?RQV-4p=;2++3-I)?ZEY<>a$ E1L+W8#sB~S literal 0 HcmV?d00001 diff --git a/tests/test_error_cells.py b/tests/test_error_cells.py new file mode 100644 index 0000000..644811b --- /dev/null +++ b/tests/test_error_cells.py @@ -0,0 +1,19 @@ +from pathlib import Path + +import pytest +from python_calamine import CalamineWorkbook + +DATA = Path(__file__).parent / "data" +COMMON_ERRORS = ["#NULL!", "#DIV/0!", "#VALUE!", "#REF!", "#NAME?", "#NUM!", "#N/A"] + + +@pytest.mark.parametrize( + ("filename", "errors"), + [("error-cells.xlsx", COMMON_ERRORS), ("error-cells.xls", [*COMMON_ERRORS, "#DATA!"])], +) +def test_error_cells_keep_codes_in_both_sheet_apis(filename, errors): + with CalamineWorkbook.from_path(DATA / filename) as workbook: + sheet = workbook.get_sheet_by_name("Errors") + expected = [errors + ["", "#N/A"]] + assert list(sheet.iter_rows()) == expected + assert sheet.to_python() == expected