From 0dec08c204ab8826a6ac1e4b4a45b0de71ccfaba Mon Sep 17 00:00:00 2001 From: Eneko Martin-Martinez Date: Sat, 29 Jun 2024 13:52:41 +0200 Subject: [PATCH] Add support to GET SUBSCRIPTS with cellrange names --- pysd/py_backend/external.py | 40 +++++- tests/data/input.xlsx | Bin 18028 -> 15430 bytes .../pytest_types/external/pytest_external.py | 115 +++++++++++++++++- 3 files changed, 150 insertions(+), 5 deletions(-) diff --git a/pysd/py_backend/external.py b/pysd/py_backend/external.py index 26ce7df8..35e4ffae 100644 --- a/pysd/py_backend/external.py +++ b/pysd/py_backend/external.py @@ -1067,9 +1067,45 @@ def get_subscripts_cell(self, row_first, col_first, lastcell): return data - def get_subscripts_name(self, name): + def get_subscripts_name(self, cellname): """Get subscripts from cell range name definition""" - raise NotImplementedError + excel = load_workbook(self.file, read_only=True, data_only=True) + global_cellranges = excel.defined_names + local_cellranges = None + # need to lower the sheetnames as Vensim has no case sensitivity + for sheet in excel.sheetnames: + if sheet.lower() == self.sheet.lower(): + local_cellranges = excel[sheet].defined_names + break + + if local_cellranges is None: + # Error if it is not able to get the localSheetId + raise ValueError( + self.py_name + "\n" + "The sheet doesn't exist...\n" + + self._file_sheet + ) + try: + # Search for local and global names + cellrange = local_cellranges.get(cellname)\ + or global_cellranges.get(cellname) + sheet, cells = next(cellrange.destinations) + + assert sheet.lower() == self.sheet.lower() + self.sheet = sheet # case insensitivity in sheet name + + # Get the cells where the cellrange is defined + first_cell, last_cell = cells.replace("$", '').split(":") + except (AttributeError, AssertionError): + # key error if the cellrange doesn't exist in the file or sheet + raise AttributeError( + self.py_name + "\n" + f"The cellrange name '{cellname}'\n" + "Doesn't exist in:\n" + self._file_sheet + ) + else: + return self.get_subscripts_cell( + *self._split_excel_cell(first_cell), last_cell) @staticmethod def _not_nan(value): diff --git a/tests/data/input.xlsx b/tests/data/input.xlsx index 0b3b8179f09529f0a519b15fbf03c82445619a7e..82c45985f0ce44d6f6a9c4d46507571097d204b6 100644 GIT binary patch literal 15430 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 literal 18028 zcmeIaRa_m*wmpmoTe!QsOK_Lq4#9%Ey9FmW1b24=1a}SY!QCxbaQFX8_C0rJ=j8mp zx9{bie&}YgdXDbuu32N&s5zH{G&lqr2owl32nYxV z8z*BMCtVeHJ7dRp3~ts|M7a=PRM{Y4!1MpR{U3e;BMHMcT}((~HwpKMF%7B)*@&v> zeqw~f7@sb|m)(Tv@RrW8V13p?-HS_?JRPT1-b^>Sz`sB+CIEcbOytPi1iS!cK z1!aKF2nY05T?b<;M@EJp`~Q0B|6$ksrRim{vhv+b@IfaMkHG^sGb_Jphn7}&BM%0MuQ%Ds!cow8Nb6lc2PNIxJHMi# za7YxlFWcxrcA2@FxlVZ_7gu94N33(>R=)F)4Rx%2@g5;l}uma#Ye995CIb1E+)j z;e^Gje{>RCElfISNDz>8WDpQU;FEE)Vsy22ur#o>wfsS6`RdlTd7Mbk-jh$SFo>^E zAundp*fq%66kA%}s#;gjX3&Tsa7Le!|y_% zzHEo3aKwr2`bHc6WSl%k(y_wB>1PmdjoUZk_1h3{7W|Q7dV-8oGh_5pOCbHnTJ$RK z(u20+14}>T=YnjI^?~h~!ZnXb)slS&OVWF;)I1=TP6T1jV@6NIQ&Ei_7wC}3?ytcb z(II`S;dtwDDnfx*b}l(S?WQ6u@|EQ^W-y2~T0ZVI>6BnGMQ8ITAr7+s_3aob!ee#& zlYp{T{KOmhpb_~zV(8DjYMw|Z0cOV^(+UvezOhj>i0#q1HMM>Ty;LcqVgA~~nd>j= zbp_3^fcj}=y>!P+%+Rb(d)PtMuo7-px?I%g+Oxn=`2MHP1R^}i`R(k%C$#$9R-u+lnN=r&wAj2v&A!*#b|dIa>@jUi&| zg!ayEpfp!-udj$t>AJnECz{fo*h}eSbbOfDaX(S0e@cWJo_3KQRKCW;Iaktn$v5xG zyf67k$7G@0;W>osGbuqwRF608$I#oxDtvh0dSLY}3{?Kf-;w_Q{6QPW=RtxExDHTW9Rj;!}Ws*Q|U-D9L= zk>wvjG9Uq#PkxK#9d&CjcQ8`IHSh;-b|hVl^Pd*ubg*_+`nVpp7?NWv<6&+;6P=ul zfVsP}T{OL8r~NV~>gQ0XU8&OaIl|wl0e5GISoZ+>&bN>(b{|sZv$k~|Am>sr5ba=H zBY<&Hl!u#{CSwf;X0VK#ZG3q)$01feX2g0u&r(CV;LRxaxP-_NS-nI+K;bLIb~C>q zZQTci{*Upw7;<{)6<&u{`rrt)9+Bp9m)*QE+*F1-sQ^8_mYIcvP9b^%$Ng2qPcw>* z9}%p(+KBPa^Q9Fk(yCXUFJQR90=jiJq+zLMbx`5851=TQCE+^5|2+yp3q|~K!kvi>| zW`ux~4j%CU5@0eQVfmJXG`&l_9Bx^`F@GstEz_R@pmB4cNL1DCg>?AYJ&|$|f&75{ zBSOf$%t{uKW?C&Nmw66C118GgXK688c`vR>8{}Cog3j#|e6Nf0__l;>KAN}G*71Ir zBA!%YfliH>aWgv@Wz%~4Xk9LHnPGLvWp;y_j{~CKL9%Fp_MiL#HJ{=t7AU`$Hae+ED+F*1~Guc>3iV7i30)+3LG^53NC&f zI{y`DfC8rjz;pj^Z>{mN7Trupfj5DxLT0+dE+`!IF*PuOR$4b8T?8*kS}duOT5IiH z1(D!FD_FJ=tO2VJZ2k>PKF;(HAmNb{v2TP1u=keHBFo8q#&ihk(}}6y70;SQdxC5~ zTt3^}zvE42#oC zsW^PN!J{g>=Y?^e-IqF9jn`awGTz66Qvf(Ww%TJ*I^}w>*vBFSJW|YtqqmNWJ~;2Y zaC{jceCW}(jCKOt(@}$#2|FQ;=z876`Gedx0(YNAA|=-$35E; zcLyxJAelsEPOf#tyFvA6dMsp?Ilo?styW~@B=14tU7_hGdGQ*OG20a6p-J$Z%Ooc4 zDJqyKxpKg~o3GnAiNSM@>N_kmaUFlwu8P?e3GOLkgPhv12Lh?kn4ODBZbl58!__lO z;=!+mw5RxpEKfJABljsX2?ie6t;cev{e!I1Q-sapEsUU$rXM?~lZGKL z{Jr?no4=U<>g)4?Bp_1#@OJ&Ow8Such&S!jlRI;HocMOsy2Dqq9yw1e5vSiC$s||^)ZF>ky z9Q^wAkfEz){Z8DE-LTvx9xuz=$J6um&Df1=zpc;X)$!7iK46$UMh<&q|b(9-1u)YzZMZRzi(DaC;aeP_{vR_b~RO&vW7+3r|8f~ z$3);0W{?gRkAUofk^AVZyx(8;Q+JJ~+|p+(8AnsQU=COZNghBmoS>1*fXTu15vOi1 zM)-^@3YY5X!Sht>?r{Y+70^*8{v+%@rDgc79|mYCvth#M9|0Kw=OdE>3WZvoToC2i=@R)mVeyb$B|12D@G?471YxVI;ZOS zL8aYy+w4n)c{ygqV5$3$)xbNmzbMwucD4D8KFs9QEz4NTq5^Qu7;&v0AIu$@7Rlh& z(5bP;!U+qa$;R%pYcs`RoEhcRDR6bNCbvb%msFjyW^`&Bzv&wPP;ypQU4R(1N06>Zh?h)|giMIVC>t-(s(i<@ot>10YUGa<637`63?cD>Od@C` z8tjwOV$hN1Ayiv-`fCk->ls-W;iiAP^3h5;z18?bk9k~y>p@E@%npC<-x5 zEHP`oU`c$vYfECG(Au?pG>ice#wHN~3K4QF5jKkmY`&B^ZoOp`_GRQFL<-Tr85Zhq zm8)(QG(XMx?p%!?!L$F{8TI-t$1kMEFMmcpd=}VzM*IWt|Lbqox63%JKg-dgG$qBVcGT_HI zKRNP!*S=(8wy~@JsMjy(BWnn;ynIQey0OAYk{DR0tydLYt{s~{E2Vs7*_q^`rgNKF zmBWZ#B3mxbs0SlASf>bY25W(Egb*ppdX!Z>$E!afkEl-o@gPsZ$hd%TsfWEXlaPu~6Wwu>3 zQ%QsWzWOd<`kVKTyqhA<`>M{o`Iy9&D}=+G1dLYP-e;Q0^;TYo_UM=O2mvJij;qQO zrOvUBoiX1n*N7aR|H!K>Z}NmufxPNR{U3Ri?JnO)t&msrB(sE?GlBS{1Il*dw|BX? z5~kduG6`z-QzF#N)vZ|?yS*xgYnI*=WE$^VVOxWFQl6h;VihM_)>D&-Q>-odZG3vf zWd`{68(-p>9wXeod)*Z8Y)h75)~ev3lGA&A{#^Wb{JNSP#;kydnc zQ=Cc4=?j(eC=9_M-3S`FZcnX4aC9+bfkZlV^|f(ZQy|eqzq-0w_8!kK-F|V&X8AQ*;Ko~+Z|!vj zoWW4_euBB}am^pD@yTPl+g^MbPW){Z2^=L^zY%QTpG5@+7abk%A79^3 zW%+d6J2`5~RS>*1Kis-K&js%sTpncY92`G)pS;*0M%^G1X4%Lk2~-p<9X@y+RXl8_ zO?fomLUjOX^EE&XIK5zp04Rz~M*pBqk;C;(?XQj^hcY4$1{2XxdHPd&?3@4{k#Qt; zGQbbcVy{II6{#@AS;PzvVoR>DYscR$Iyrm%?$zGb+J5W#-pl^wsA}mWdcUI?JLhu* z?Hy}tJDFL?J*G5Hbx>}Og&BSb!kBH_%M1T9W;g{t^+tx(d3nKNxx5rFMpZwU3!0tOO5Dg}H7 zSG;XW>ALC7Jq5q+nt2rjJlURgz$$BBX@%<2tJuaK%jloT0{@GA|H$rD2zSEzt^_}@ z98vX?cXXf-##Mc6P#KUuaWr4$p6Z&wu3?6EA1O~c@ z!vAp_4qQ{WNiz-+^A&5xCy$>G9^LNk$DX6GkBe za+a_rV|C>xMaLI839sD%eN@ZWzp&b3|V4tFA!|ALn3N@Kjgy4+={wDsvnve0C9hDv{j0mb)=x^T77o^F* zB7xN^5>I6;-MM-0mvF=r1K1i4R+z(Z=1!J0dQL32f2rRWv zhp5a3cVaf?kR`N;60Q=^iEz6v@j~eHoZ&LSjxk>!usAs{4TZeDFQgiw3MIzt6GD7j zz_@ugdDw{@SEM#~Tio>eDO5Ch#sj6(RvtcR;rMgY01>^SJi{lss&4|09vI{v^`4rLdn9R5-6!IS=Zw zHImH~UzJ>7-f2qhU)y~i*isj*)|TX|yIkRMIQTAX(}hFWhx0AXr)=$_C4k-N6~EbB zqKZ*EidjObQwziXjqUIRkCbq{HF>0EPW~I{OPjOnQO}b{3O0}!q8tFZwZV7TK7WfZ zLqICk9GU*Ag?%(X|@Hk**Oq$FOt{7 zG+x#WWm>Ri)e_@SFVZ80iyy@ok5U@e?|j&*jh+5LWRp+wD$4ZZoSWHHg|1VzraPuK zJ}X&G+_&K~+Xec#1DWRZ7n+DheF7J5>vdKdpA0f)u9|bx`P+obee6X3B*yw?ntj6O z7px8Cd|X2NOJPDlQ->3C1>3P*YM5KG^t}!mp`*}(!7A=vaFCZ9avarLc|Ad~FBJZ< zd(H9+{qLD5(B-M`j?%r9Cco@%OKPLztz>$(I@rYdMyU@~IqwO5s#8%sS%=X0#`=iq zePzMKkZ72>U0IWvbe3(s@bD5&i9YRMx!J}l;Eay@ouPU#B1()uN94S8$p@s(hQ#E; zDkyYSN6gvNH+%eqigCDVU*H#tO&RK?WW z>N2BzT0!Oku^sf3R!ff_rglvt+`Xvd(usOlc^F&cIAJWcaCW?N_H2O{;CtK6=u>iZ zcKLYUz@;m<+i*C1aD8Y}x0WG%bffTCy;wFIXD65=o+H$mJ)S$BGoGiXXh-EnTo#;A zxML%gh#NNJpjfPErocp1OXWm$Nu`d42de{Z(d0@#4Cu9J5>}|Okv0MTrG|Du_1%^5 zVQJ;wutO`W5HKsDW^O{ZWHu}1Ql!DS&}O1m{c1GbC@R%`FcU?&d?l$7BTN8s*A9%a z`%a6~5sNlRz_SFz=RiH?B7un%dt?D+R?;Q7Q2G|qqz<0@{1g9J{1GB~eekB`Pz=1b zgR|D=xoKUsyOKJbB)LW&IwUI~fIc9@-;v=~W{MBj93A2fe!#O2+)NN=K@81mjpON? z0y*}ka0Q`O81x>ZA|h?L4FCB8^baNm=pRJZ(LQvfCh3?-hsTPe=k=wp=`GOl&sTX!(Ld-U=`9=U&@3M2eo>@H>CdlhPnW8mtsc)2XDBQ9Bm#Kn zG3@^a2WQ0*u2)*@K_i~N1dHLDOC>xi)<&Vw#gB9)DedzK+yPBv;+SI9F&Z+xQS`kYlae1XpJ48~G*LxH44!q}oD@RGSmCW$@1BD;F+DvGlUuyPHixkzp7*;z;?D zadooj&$)CUyA=fDDZ6r@C$rIZv1NH9H{zS=HB*go*QbCl}Ju&fx0JAlNctX zBK|@Ie()eiZnxD;w5nLctxeUpSK1RGD{VM*@n(spEmqdGp^EamYCxM?U*5bT>Cz#7 zq6j^^`oZ1xkil*%@4ctibGNDGGuiit&+HG>JCDbEc#<7g=p;p1ebN?Z2wR-LGOR4nv&FVIGqmT6wtBK$WDAy(*qi4k2RZc#Ew&$GRB#`yJQG14>U4?1k z>bhS;A1WxPy-zynhkiRD@7WXX&5ixC=cHuGyU|XIlKp9qQjtI0zk1(@XyT}^EEq(%cIG4f8;@|;|X$x%byfWp-nfW#~2b(&+cKD8RzMSD3ExlGViOo z=eQ@1=M#)ahkBl9Pfl|DnB&vQLluPSQuFDL!fKhD9 zmKuBOgJa_k0k)QI8)ctXFFF2MF;$u7n-$BsmpTtB3f&olx$?}8G_Sd1UBp8J4<6dr z&eF4#=jGuViqEiGXz;KASPaNu|2M=;Ip0eOq_d3U<#ZIeVW9${AjADdI`fc{iKMbj z|N5s1(tYy1yYo}+$29YI1RTx_&j=-$WV;aWJKScY+)#4Yp0gEQN zY)mGk6C;X71>@GV0nZUo{gr0KK4`@Q5Hvg!LUzm=OH?620viwE`4Ggq%mrJMuHPUR zkSQ|2uWdpS`iype6Ds5K` zUGgpX)8vm72nYCh-~k?tGfc&Zc{KOMh1iklBj<@i!;(2U!Z9Ybs6B)1GPOKonEmbwK41fW~EyM8E7QZwjJX&sTE z<-D?YM1%$VMvr+@lAljMD8KCyQJ$!1_1q*KDvVnd>_D^Xl9YMoH1(Fq+2G=m%S&>+ zba2>TZZckc4msfR2RDlzWE5Sm4#GBD=HJ50cwV$DzzUpK+-Ku2UcLGH{O!l0&OWE( zeZ$X19bDaA5uJ#A;=2`V0zvv8%2P|9sBL=n>WWbGo)H~At-|H6jGwq<<1dH>R9x-W zHa9;pODJ(&VD!XZ4!t(8dbl=LT+h;9F*+IX>>m2s_4wh)bV@t!Uh~by&Y`J2m)nq5 z?b=n-k@wNeq}F4Jv)7`}Bf0E*i?4G54W58jDqi!Gme+)>UoHr{Vgi!`KLo}HMg*n@ z`Ul1aN2zLn&3HJ$q748%s6efq5Ul}rXU4(BjBqsPk)hcG2 z;}b6Ya>=zkR$t2aw^{d6f?D-(S4c>(94 zuY#%H!by|ov9rPrlfTb_gTtkxcU4ZoCTnq)R7-QNeh1!7!jmLcyHFc)>=Ue?y}}7l z4}Czd>z}3uX;J}kC+8c6n7N-g=pJSuKQA zlpUlUxAPwC&gIH@OQiJ%o5YM)U&y!fqNoXd2Mk!Tm^qO;5CFN`gnta%vK5HB#DHVF2v7?64~x;S|C;OnYccv~*han} zXZ0g&V@j1)tkw9+#$FBWs3_?nJ?;t|x-fx@(f&QwJttYnKC;L4nlbF0jGw8^6Z7MJ zk?Uhk6eo9!G;Bpf5tmi8HNeSN{EA$Gb8ZUU!^Cz_Xb70Tq*|C9daR3F&`~b~Ehel_ zpQm`&r|FYz@lQ*Z^3jK_aWfD;NMPg7w*Aj!!7Mn zTXss0U`n+_M+#!~=Y*&ya^1AC4sW&fSC*{4KrV2%I(pu}O0jtomXzKoYjBo`9=Yby zO%yOO?CXtj(s)r#w)%osX3YBqmF7iTYTHp6~{5Hqgg>kOx7_n68vQ^RwU&(EZ8yfkbWe4{?%;3ZKr zW{XXA!;MeKagvJt0bs~SBAhOkjjsYLd_|Ye>wdDc zohdC74(L!xgtwjYPDI=%zFo5M_SI$s&2x7M_xma)R`(u+aeOveJvMLe*WNxc0oz4{ z1zeLxW+d93MDB)3aV9hnenVSm<$Sa7Xio*<{F=bK@4>ojEgfzVg0$C3cbrWxD8?sw z0x|g-UtE4D;;4f0sMXmJ%dW<<3hmm_!|2RBu@>1V(O+E;Qbw8|w1M1m-D}WPPwgBs z*_5J+r~g7=bIUq?YYt}Va8^I8NPosR-`Qu9TfqEX)}{30#*G`gt)u5#FSzQbX^vn0 z@*ff$=mABlREYT|Sn6w?FL^pYB{*htd3g*ycyqpW5t6%bAD=-!waW;lrg9E|^^7q0 zP~pPS_p(C09@Q%($6;0XE-JgCk;ImEFjVSBc5uq=jG^pEeGiU>f+zOddMm%0!{dYw*R+iXSTvRY}t}7*~{DLH5TfX>7L2y9ZWfTlq?LOfI z<>)-==N+;%D=AGEK=_;IwxXh&OmB}1r?bhnWREw=a9y#9y6p<*eCZMM$z)TBK9-zR zY@YHG@e#6uF)`QUf^Wb-)Rym1;l3YtP7`@OzF^ykLIQ`ZrBKjq| zNV72d@$dsylQC!uls;pT#@_1q8z{W@Vj(8|4oHyldH<+}(mzD~mk`9eQ z41skPu1$;RMqPU!QCHyugxX@M#}uOhrQem5Wz}cq+#_;EcprV^g`8fm9E_kdIn|cA8E5^ zIEWZC`QAUD?q39V@cCTs-F53$H`UQd+q@!IRz9AI(tUY)!d%tucs@NiUcThzN*|@MrUmIIzQi!!(8*a+Le#OUtGe&Pd+6MtvW5=Fg&3M*Y`tsI0F^P z=wTA>i4{cNb16O^9stwPB0A`Dt~}~m!c*^qY~}5+TxcddYa;uYQXyUixojBWg5}D+ zUXnU|dTN&`vl4gF6xtFx9%FgTAXNr(v&)+Oc2j8~veNh)APgn6kh61AxuZ%X0>89H zBxGlfk7ZM)GW7BosUjd`id@7&k6ekNR>UA=xXYO6!{Yhqs&z$ovE>Y(rxB?>@IIKl zLq6^F4Vy72epliWWoE~34>#Ioaq#JULs8C1Ch8GJeQ|F{_d)s_ckmUCPzNmh7QzF; zyPnsv(hhr*P2pIqF?=rbkqW$yi!!kTJ>C=u#9}e70g{-WQ42hxd?I)X)y&HcF!fze zCM1oJ+ZL(ulp*)VU-7G2BU0K3F`fJ?!;Ket>*wo6Ls@yaFFqwKwqPkcMf734Z{T-S zAJ=Cc-ffzAOQM&6|6Qt#cHpb(Rk|Liacqg@EVV-tG_CQ?S-f?nsja=g8wOP<@>>2K zj_8WiJIkPH zj@luxJuR?_t{bjLkrXZcdG&*!Vc{`X{6o;6wM8>ZHLZ^0)8^A&BZ8xetF@uVZAbQw zg;rBOx(*Szf;vJ$MroZr#B--n8Sjev)xg{k(ph?#WiEdK3QLZ&?y8PDGq*1fB_>lk z{1wJuEmJNu`>w99ge+28J^h9#PR{o-TJpmZI~bIOpBg1{`o=f!YwLt zO3t*YtU2`)9AxaB8?|<%NRm|Ho+jVP>gVZ0?>!Y)jU*_lg()n3853MZXDmfs1YtBC z(+@feDe4nW>JthFNjaM0_B*gl*68SNJJ;)CZ9Bn2i$Xyrc=5Z2=tZ?Dtr6w0UsJ?A z;#fbWfGQX;vJyo(DK9kJyIVM$m$ZrH)00Lx)kHE)GWla}(D95WK4|ncrvy*4$Tt}@ z;X1G$L?R+vijhz@`cY6QkN5D{+|^k?H_(u>S>B=UVRg^BK{b(1YhmUpH@aX;X4>4k z>L+4jRtJm5b8E-R4M8!-B)^aEq1UDNNdT}-;N@D=zV$`o*W5}Kq$NzVM{?pBaAWBt zH4j?BQp}Vi^xIG_w|g$>UBfRUTfpmTBaDn{1Lxl5K+acJXQX}gG1NCaz~Nw&*)OdU zJ!a?5byIK1Y_2tIk}LirDR;PnOK!4JW*2*C`N)JkEg_ctLTYEuAp>u63HWuJ{0ax* z%#b6L`8U(TUYdhxr?~xKo^3$sxyW=iO@Ymm9KA!iB|{Se%8a{I>&CQKICv)$ebxwz ztVXL`cUVo0;!-Uu9W=cB^y^z|XK_xxvvNv-fs7GNXF<9{sf^qEq2<;YlUJ^OydHKw zoJC4|3c|KYq*V8lxC8O8^}?6qG$NtbTDd6cU%aWUUad&Y)5qiJcOa<*DCHp6mj=3E zsSQ6>Y9Bb$Ag=4hC~6~29o~a#>yL}Mm{;`AF&uC0(2oWphlk7Pj$qbp+;6sPFL>IY zAQNRg)D2~8Si4vRn$+=8LA1%`jenoz4%GRqbpr5Mshq&$J#8ZeAS}+(OY);Tn2 zL0ga;d*^8sze`h%6=lEHPqXo_A+V*xv^-efB9p&$n7#8@jQ^2>3|dr_=|oW zo!qUA9e;$o`Ks2oX-r7Z{N}(E99Ih>Vri0Wi&PTT#X`xWd@tuOWNJ_T5pgkc4<|e# z(4raFlio1xH789;yT>TH97@^Xtn70%ot+6$$jVI&jf)hwhlbxqnM>$ZA<;FfAP6-g zE2eHvHWvvX-_J9fAPW|Ack)=4k`p_(8^+GQZ8m_lk+LSMBTA+JMB8nq$U{mkvG>4A zLjAT;M1AN{SCEWd{$XgiuB>f`3BoDyQ4ykzplQgF#5+#Hc2`_QT6v?rO zHr^$&*+vryNlOo5aqF_%uJ-n{Wnva=)Lh%Hc_s`tN$QmYzaTdk>Skx%UBfw83w6xm zu*~8ENhcFiIrI}U3Ku?4tDN1fVJ*UY2p&I!CjmN(A=YQyGUU%R_D+Dw*Rr&q7h@65 zBiFUaHEzfv%^7nuUO!^XyrbQ*8`GQA%TmvbVqWBSt*w8vJ$fCY|_>+ki~h)14M zX~G4hQ4~8V?SvRbc$T12C68o`z21|q(lzm}>0^Cdcta7vP%z~!pjn?1gHwn^EX(z8A4~1XTbX?KDc-FQ z(E%zmL5RteJ+EMlvkZ)y3T%)WB1Yu-VQGZr5G^=k;iO(V1g?8*b^IZ*CU+5a zUm|0UQT-NeJmzi!b;?DKhTiCH7(Gal-wI}KOig5czrTQMw4AhFhqUo+8rqhJRa0ftUsXXrCJ4l#{^CGdcd=vv zjS15c=dZzWc9%$kme#&#vRe;;ed zJeGo)m|3!LJILh~8#$r#1?G*Va;m8N-l>lP4&@W4Y|)@^EWy!ACUTVTx?|_G!I6(L z0!?Nc)Yzg*^4@vgw>98v`1k1|oRiVSXJGFYgaH9T`n3n^+u8lM0|Ot~|7_`MvbLK{ zNNp9hFP+<6p8$cdstJ<7$=po0O@rp-F>;C#l^Q-zHGt;niiaW^(QdLjSfYM+^!9Fn z71iS+5vCf-x-m9xebW;ODLPcD$uk8){w%7d)E8^mXy`*M6U=Kp|FpeB%=={hYv@41 zhlR{pK6D5vCvbXy<67O8;LK$!J%odD;wB z6Q`%UdrtJt)?bl0V^Wq-OI?y>%hvajDuO|^3+K&+M1?X_ryqZ>C%5&cuP$_NQKy2q zN(!}mO>t+~cO(V0-y5YY<(rHqZ(sm=+>!cr-@#tRWQ7Tg9sq!>KxY%|Y~?k=n0JQZ z8z85LeCTH!9V;Ny{)JjALIGjhu{KzX4k0{^!#Jb~UC*15Af=u_ReYvkRz_?T6HBvIFEo z{_3VLu^Oti4%^NsM5bb$3+P{9S4Zl-PI6TuRosx%3{s%UlU?4u>{uIht#0ZY zNd`ko5E_r&g3U0bM^uIi9OkymK8{9nKOV03MSph_VeX!RCqEY8^xe#?nflYc=nJs3 z{^jDJVDv!l{qrwR{Hsg<>-dM?p-_*K%|5hmVJIe2g;D4jkqyG`*XIl90 zD8FaH{f+X1_eYeUIdQ+E{GJx^Hwqi+A5nfLN&JrT`wHXVD2%`&vj3^&{`I;1TyOjx z<#($P_T;{NJL&-_8F?!oQj)@c&}|Ka{K>4GHv}9|iY_Age(4 Ka})mY>Hh&3mM0zn diff --git a/tests/pytest_types/external/pytest_external.py b/tests/pytest_types/external/pytest_external.py index 60aa4af8..e5296531 100644 --- a/tests/pytest_types/external/pytest_external.py +++ b/tests/pytest_types/external/pytest_external.py @@ -1883,7 +1883,7 @@ def test_subscript_d2(self, _root): sheet = "No monotonous" firstcell = "H10" lastcell = "" - prefix = 'j' + prefix = "j" expected = ['j3', 'j2', 'j1', 'j6', 'j4', 'j8', 'j-1', 'j3', 'j2'] data = pysd.external.ExtSubscript(file_name=file_name, @@ -1895,6 +1895,73 @@ def test_subscript_d2(self, _root): assert data.subscript == expected + def test_subscript_name_h(self, _root): + """ + ExtSubscript test for horizontal subscripts + """ + import pysd + + file_name = "data/input.xlsx" + sheet = "Horizontal missing" + firstcell = "time_missing" + lastcell = "B7" + prefix = "l" + expected = ['l0', 'l1', 'l2', 'l3', + 'l5', 'l6', 'l7', 'l8'] + + data = pysd.external.ExtSubscript(file_name=file_name, + sheet=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + assert data.subscript == expected + + def test_subscript_name_v(self, _root): + """ + ExtSubscript test for vertical subscripts + """ + import pysd + + file_name = "data/input.xlsx" + sheet = "Horizontal" + firstcell = "vertical_index" + lastcell = "" + prefix = "p" + expected = ['pA', 'pB', 'pC'] + + data = pysd.external.ExtSubscript(file_name=file_name, + sheet=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + assert data.subscript == expected + + def test_subscript_name_d(self, _root): + """ + ExtSubscript test for diagonal subscripts + """ + import pysd + + file_name = "data/input.xlsx" + sheet = "Horizontal missing" + firstcell = "d_names" + lastcell = None + prefix = "" + expected = ['X', 'A', '0', 'B', '0', 'C', '1'] + + data = pysd.external.ExtSubscript(file_name=file_name, + sheet=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + assert data.subscript == expected + class TestWarningsErrors(): """ @@ -2008,7 +2075,7 @@ def test_non_existent_cellrange_name_pyxl(self, _root): final_coords=coords, py_name=py_name) - error_message = "The cellrange name '.*'\nDoesn't exist in" + error_message = "The cellrange name 'non_exixtent'\nDoesn't exist in" with pytest.raises(AttributeError, match=error_message): data.initialize() @@ -2032,7 +2099,7 @@ def test_non_existent_cellrange_name_in_sheet_pyxl(self, _root): final_coords=coords, py_name=py_name) - error_message = "The cellrange name '.*'\nDoesn't exist in" + error_message = "The cellrange name 'constant'\nDoesn't exist in" with pytest.raises(AttributeError, match=error_message): data.initialize() @@ -3231,6 +3298,48 @@ def text_openpyxl_str(self, _root): assert np.isnan(data.data) + def test_subscript_name_non_existent_sheet(self, _root): + """ + ExtSubscript test for diagonal subscripts + """ + import pysd + + file_name = "data/input.xlsx" + sheet = "No exit" + firstcell = "d_names" + lastcell = None + prefix = "" + + error_message = r"The sheet doesn't exist\.\.\." + with pytest.raises(ValueError, match=error_message): + pysd.external.ExtSubscript(file_name=file_name, + sheet=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + + def test_subscript_name_non_existent_cellrange_name(self, _root): + """ + Test for non-existent cellrange name with openpyxl + """ + import pysd + + file_name = "data/input.xlsx" + sheet = "Horizontal" + firstcell = "fake-cell" + lastcell = None + prefix = "" + + error_message = "The cellrange name 'fake-cell'\nDoesn't exist in" + with pytest.raises(AttributeError, match=error_message): + pysd.external.ExtSubscript(file_name=file_name, + sheet=sheet, + root=_root, + firstcell=firstcell, + lastcell=lastcell, + prefix=prefix) + class DownwardCompatibility(): """