From f20a5fc8a14527f81fc01165448566b6ed995157 Mon Sep 17 00:00:00 2001 From: Tue Herlau <tuhe@dtu.dk> Date: Sat, 28 Aug 2021 18:30:09 +0200 Subject: [PATCH] Changes --- .../__pycache__/homework1.cpython-38.pyc | Bin 1318 -> 1208 bytes .../__pycache__/unitgrade2.cpython-38.pyc | Bin 26380 -> 26946 bytes .../unitgrade_helpers2.cpython-38.pyc | Bin 6801 -> 6825 bytes unitgrade2/unitgrade2.py | 49 +++++++++++++----- unitgrade2/unitgrade_helpers2.py | 19 ++++--- 5 files changed, 45 insertions(+), 23 deletions(-) diff --git a/cs101courseware_example/__pycache__/homework1.cpython-38.pyc b/cs101courseware_example/__pycache__/homework1.cpython-38.pyc index 674ec1107c08d6922af8e6e3b30d52d30cb68107..0d3386b94e926f441ec02b6e5452a23dc1d8f02d 100644 GIT binary patch delta 264 zcmZ3+wS$v4l$V!_fq{YH8=G2U`$S$@#)OI5-cqSNDcspiMKP&d%?ykTsoWqkg)x{x zlV{?LW=74)GK^AeYzzzxMQoF87_%9<C$C`KF3Qcoz@W)^i!rANA_bD?nq0!9$tX1W zFVh=Ffyu9!o#l|^7#J9C@h0ULm*nTg=Va!kCKgFg_GXckR0K(I#K-3*X6D7mYx3S= z%`43<s4NnhT+0#|2(qR~2xK@+U0z~tYJ5DBtzbJq-nzwMlbfGXnv-hB$iTo*4ARBH V$iv9PD8R<S!NJMF!@<bL2mt9VI931v delta 415 zcmdnNxr~c9l$V!_fq{X+g-tDS-9%nl#*B&D-byLlDLgF<Q9P-<DZJTCMJcIV%?ykT zsXQPug)x{xlW*dLX2q3^ek&O?nQyV>R_0_Dm)v42N-ZwUDY?a%UBu47z)-|K*@Q8h zk!SJ(#_gg!3=9mKjJFtbpi&@t?#Ve!nhC-T3=GMPAU8lUh|R>nz~Iclz);M=z`#(# zP{Yv77|c+_1~G)WxHMOj@fK4~F|uI{3=ANb#21(5ii325j9_3a5}Q1Y=?$ac<Ys2) z0Enx=R)bXYCgm5G<mbibWagzN7RiA$34q+d$j2zg#Ky?O$iu|ND8N{x3R27wAD^3; znHL|g$#;u2uQa!yvPfdG7)xLT$Y(_$PZWuPOol1WOUzA;k4JJK*m7>LQ8u~xDWy57 fb|9Y?i!d-SaDXgh6ky}v;9%uo=iuRBWMc#X+MiKF diff --git a/unitgrade2/__pycache__/unitgrade2.cpython-38.pyc b/unitgrade2/__pycache__/unitgrade2.cpython-38.pyc index aa46009fef3a824583373629a6d857240757d712..a70e7b1190a2294f68b5e051feddd744b6c88a79 100644 GIT binary patch delta 8176 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 Omw-?<2Q!B-2NM8^H*+ii delta 7643 zcmX?fiLvJ#BVQ;lFBby?1H<ERwZzLM8~OZM7^5b~v6M4LO}@tBz$h|VoOLmy;N;z` za*UFb8?+<@MHv_v<QW(kikTP~7&sV<L??^0%1%~b>tK|ayppX&1SEHhwY(^^B(+F^ zfq_AjsYqh7BfAWv^5i&nZ$|OSg(AX}_p&QX2{JG+6iI;yX%L|VB9uXdD##vD83qOh z5Vx2OY!3$u2TPI6WOa_!wi*l!47XT|OAAtqia@$FS&Ae;`oQ8WiACwfx7f1FLG((- zA_0&LH;CW?5lWN!Ij6G8f|zoXS8>X+fixA#Og_u0%LX>Y2<$##t~rc)lQ(clsp*20 zLezs;Mj*lfL>NN-24ZVX-k2dWnT6Xl44bEnK}yU)j^>SzPtHj!E>2F($%&6I0y_&# z=zx@f9jL~@zyLBI>TMwwF1{kQ&Hdaxi~(S;fGrRP8OBjqnp#|vnV(mr3DOM;iCe5C znI$=?umEuYiEDufZ4d#r1Z*AHCZ);Qymf4jAQ^C^Y-ZwfXOy!6@!3J<Gbbh$-(pWJ zPAn=)tc+qw%SkMWnw-wBrDzZGIU6|4Z*e5&=N6Qfq^8{BNUbPHO)g1IDYDtTiQk8j z(RK2F0a0%^kYdgvxUoeZAPYRf7UU*Y6nTNT-XOvUM1ag*$qF{R$QLBw2O_|_{Xv1e zxmb{sF~S8T=n5jh#&cmaz9<kR4>q13#6q>BC<r754h%2>4iUS_SA;5{DKtSi9m={b zJOPq4G$t2{R0`RGJj9IbLQsm?%rDBq!~wEHld;Hma-oRGWPS0&98n;}j75G>0oKXF z63*=E3=9laL0pp)C446rNU%&^CozW&;@8OmlDXa>Ly96m0mSKAk(^opj$&|(bCwh( zCZ{GPCTB-+rR5jpCYHpfRwUmNh=)Z&d}3a4d1_HnB*<F+B8kZyQreE76duK1kXT%t zn3EI5R-BoWnpaW;N)fj>3i6AKGm~;sAz>X23X>QH28Jm1<ou$d)Z~&|jHyKlApcEn zm%1YaGPWolWHuAT|0!Up4rzyaaI!>XW^k$kg%mhuZt;N<YHnglYD#=bW^QUx2*{#D zkVS0eshQ~+CE$Eq<OC8901?3;!VW})f`~8>0SXeZ&x%q(+%ynj0V22=7=#!gnF*Z4 z!EtFhIa0=u(Q<RQ%oQd!keiFZiF|T}d;z1x<d^angh0_y6bJGRdl4wt6=hC7t)OEK za#m3;NEnjDi$LLbi!Hyjq@c8<C<_!XjKxJcP>Z4Vf~}00Y@}#|UaVz;6oQN^iU1XB zj2V*`Dhe}ZOzxJEoqS2L6_T=qC&wy%V1oqT<Y474_iB(eEG3l%skhkU<MUF><Ks1< z&H<%_qB2m}ae~W|l+5IkD5mV<TZ~DNFhHc|`pGIP=1QnhbBi0SD>t<yBR{369OSxs zki$fa85kH|gUWSCdCSDe#Z*)bcII)F*^E|`lU0wKMX_fVgSFq{$}BD}O#-uvEEyOW zRx%Y;fZWWKUV`q5s>umzb@kww0+mskjJMd+Q%e#{N{WhFLDq|d2!x}n7#J9s85tPB z1t1#(69Wf>CSwt(DAQ!V#TK7glA2pw1P&jz#Dap<ycA7HW{hIbP0dY8Eh@gn=m~KG z*kDl1++xj~9IGCu+yRPJNYcH<T9%konhH^fu)KTnJ@rs|L_rHS0xS(CK!z0wPY%)u z<LHH&HF<-E1f%felN#30;zB|*S6d7u$x_q}@)^kGw*)d0i{q0Mb8=Es;xqFyOX7?A zK}tYX;|9$f0n{iea-6KAC1;in(mer0fb1#)IsO($K~a7|YEelg*z8+u#i=DFsYONL zGyyWPXc8zc8Ji~0)Y4~c+I&)rjgfKs<O|vgjMFE7)D9782E`F5_|r0TQj6+9hC{MN zj?Oy0c_6L`C}pvfr({A*y~SOeS`uH7SecWbm;$R;=7ZEs_R!U4RGM6(ds-rjD<rkJ z#3w&7CAFw%2FMB)P&SX69ImIQ1g=$=f{b1Ul3@cGlv-3Y8zeFZL@b}YT<-zn^2r_g zrjF}C0w5ELW`bDjLBw*fw)o`4<c!oJP*VZwj3}O>)Pnq?5~vKsKyX1TWYA_0HUy-) zXagvuAyrBg2h=CUMIb*QIRYHLU;-S+OD118FqK1(7LY^O%TkMqL6z=|$y$bL@{J%D zP6rX-&;up#BCsbmg2a}9V`JLn4ntMOX_MC(F82bLH!MYFAfs5)GV@Z3IzbBaKyG9! z$_522TV76PUTX0z#+)eT0#M#A%(=ywiJnsPC(k!hX31w@V3?fmB{lhh(QC03kReRB zSkrRy6H9I}XXce?G8I)!erPPlST*^Faiv2PdzfpGlYg*l6g$Z3#GIU4%sHufMc^6- zR7PsDK%5|&SDKqzl$ji#oS#<=ihfWk%Zr-4(L{o=VDc#wS;hiz$-ruQ(G678-(pHB zDcTM42&m;y!~yahV_wl}kb|I&vm+o`kU$Yg1G;aNCd-&j2s#SV$61n5l$w~5nU@~L z76N7#tptg)LBzp^7J<_Q4=9nv7ndX!fm$8dvg+!||IA$KK@~>|V+}(*Lk&X~;{v9I z42%pV%ry)tOwCM14mAu}EGZ1xoDkLm))eN2jEo?aEDP8`DpMG07~)w<*t0kmaDw<H zTno4sg5<d+7=jrzS^V5?u@odF78Nmqe9Kb=@<h=okZ(beS~Qcvkb$A-4A=*y1u2Oo zskc~@bMlK*ix7=URgh|smx@k<SdbiPZNbk9Du@^+2V1;US_?9O1(a)}K$UhTs8JBb znv<GXmKw#9l3JV`H95{wA>lYkKf+*eP=oDeElSKwPlY({97qw!x?8NpIjN}yMaMt_ zXF<+~6plsUd<o7CU;>;aRx&U!te$+&(p2pbNF{p_TJ8WReQ*Sy2N|~#l=Q_9GB7ao zg9>v{lHg$E;^JWA;4V5iIm61E8%aM%t>85V28KN#wa|{mwaL$|3faJ_I42uKiZdRV zTxM;g2ny9(%(;mL;HLd8=G>xuO{QBMnR&$}iFwJXMMdB?$sKDE{{0}sSU{Z{Mk&Uk zyOaN02kV0hz$mu#)RNqy{3wphTu6Hy?3Y^{@$sO_G(KLFDT)PDK^D!L+-PGcaTsI{ z$O8<F0*pM2T#QBcK|XZee9Gn}qfab|4JzcSIBatBQ%ZAE?TU7SLWsKvWZ5m&;*!MV z?4tdktj!6s7_0`8?LnTq#gP`Dlb@WJQ(Po4`M;g0D#(MH>`^Sm*_j1J4?w1aLN$uJ zAh9SluOzJ~F*mhHc(SFvA>+x(+4h=DPZ=gpvo8+-IRP9bnyg@pqj*5IY*9M6o+}31 ze~URiwWO#W<T$n{rnDlkx*~7~0Tkm=Twt}}Kq$Hc4#olpQK`2e@AH9!k%Li)S%is) zk%fhaspvVw<oOOa*{ne><OancD=z~B1Iy&uj=uFEpGWZ|mlh$M{0NkSIn(0PbMliw zo&{Atx0uqCqj=L(OX7=C(^89yQj3bg&Vz&wD9AL~Zn1*Be2XPHKP5Ga6{Nj5iX*Kw zFB#N4ied$^if^%iD0rzdIo(N=kzsPJlQPo>hRKVZwCh1F$W(?X#uSDqrgnxj#uUaB zrWTGU<`m`>mN|?mtSM|QEKw|}tXXVX>?zDC>~ok>I8r!USfV&mxKg-V7@{~+cv5&< z7^1jR_)_>=7^1k_8CV#ic!C);1#WSNhNM=M1f>?2=9DCZ6C5bCK!L%)z`zP>&rGgy z){@W!g%l{8+~O=QO-@cNE>0~5)n$|SIZH``Ye;bO6_MpYYK13%bj}lqVs#A)@(+q) zadY(a(PWOAobMve6UC91n3+>rlv)gF+lq4+6lLa>xE2-V7Zr;$F)$Q^-NHP1kBfA@ zCKIIX{EdNuAsLjzpiX1}C2SCO2DSYbF))CNHiiX^HH@HQFom&}DTS$)xrV7|UJ26z zW>8_dfOR253iCpyT9y*FEcOK)phB^RA&aw?wS)^qr?8Z8r?A#Ar?5#dl<?HBHZw{v zG}kkUFo-jxu%~eJGBGlwaMrS=aMrTdu+^|<GZmGkaOE+jaM!Zdu%z&0vldOOVNKyJ z;jLk5W)x>g;S*;tX8;?{+RVtvkOC@o`Tas(f;$QzSA(-#5i<h=!%L8di$FPYCF3pT z)VvgMp&Z2$;8-6VT*alOrKJE0Kv$Qd!wd`zznBy>esL-krzYp;r4(yw@)dms#Spkc zM$}_W$;n0F5)DzTg39Y#0-%;?Jh;Cd4-R)oH45%^f>Q1+=HikfO%6y$DH7zm$rs&) zrEW3h`9!gn6sIN^M==!_N3laQNl`L5!>x4VR+R%q9ccK2fr*Ekg%JdW7`YhP7&Vw# z7+IJE7&#b47$+ZeQ>_QZ8wi6!p%|2fYZzD<vKUer%^8>&;u%tyYMD|PYnf9RYguZb zaazk-!@7V8RLP~VNHWy2f@6wNoS}v#1w^u@F^hpJJmwU(TDBDSTJ{>IqKp!j8nzmS zEM`#T)iA`f=4q9H`SmHBCG06IHS8%|5)36AASK|)hQu{@3J)l*Yd|$GCpgx4{lM`N z0`7HzBdm%K6eoqMnR=?3nhL7LFF|8bML!`O3UHGFT!n$k)1qIX$N|M|(Qi-*#udd8 zUXof|QXEv87sZ#JTH=ygoLrO%?k?YAEiTB(EGc4OWMC)))j>u7L7Kts9C!ppvBrb+ z!=nhKf(fMI_+&;eVRmryo0)MkBbV@GJugl<TTrZkx@Zhcd`zG?VPWKA<YSZo#Sat9 z<Y2EFM(4>FyiCp67#SEe*=`BN7ZjzIW#*R_gBr)qpkW_KqZU-D7jc0sg1Zb{3fOo{ zv4MsEgHuAjH!ox0<XZ1r^`O`VCu*?A!J+euQ2`u&;B;K{7v%JRpcKt$tI1o$4Kf?- zVQ{*ICuQ^&2RJyu;R_FwB1VwonZb!RimedbTW2a_o_xbci7|HaZy(EgUT|HBK5q8| z<N{FpK8htdu{iY>2iVVv#i>OsAjfcm2p$l@4<f*QL2xk#Ccvd0xQ+3Nfq_8?6wV+X z2O|#)AG?S=hX@Bx5lBXp@s{A^o4)%zzkuSO<rY(Bei5j2MT~!GLYn!IDh)Kk0g(r( zF9O>Fwhv@Dc)%fV@&iAoR8Zf)h9Qfgma&8}i>a2egt>;XnX#6!hG78<DDh^o)-YtT zEo2U6C<1kjHQ9^6<{^p$K}H6KDDEOi@ehvYub|)nmFS?sPZ0YHI7<8dd3Zs?rp2H< z%fQISIC+`BiYurQfF7PAc!NoZk%1u>6ilGvj)RehwMb|(e?SY%bx?0W$6AxU=myAA zNUN!O^8El~-kYExgSPI9Cd&s(GgeKu4m2_n16d>vBEUf-3Sxo6=N5Z;5vY4zR0*;N z<ZlK>9u^M9BFWA311lIAr6)@S>zjew9N_i?IIt^0w)Q|WFUa6qte`471yU`8Of8aR zWMJr;TpMg+0g^A$1X-sDB0v%lbs8WpSg|rA14Ap^dKMN&K8_;g%`b!H88tzDx?Aj! zo}ZB>W6>;-&0rsZ39xohuWZ(2!_aggZBU|S0ymC|Kx{~LIeBj=FXMvAr$e{YgEIlB zMXbpN?pj0%6ldfYA(tpcY9ME+FfuUQ;s+NSzTg2AKTu;#7i2tSbS8=mRHQ)UiooR; zc)*A~H7Bv4I5j1TsTdj>aA)4)k58WbFN~LQ>13YpTp@7b0PeQxflOsCl9=2bF3AeA zc+2FK;f;(cleHtX_(1_5#guJO1P<~Y;M7$fA;7qEa!15m^d{NS$sUo00f^QIcRZ*M z4hg)XkDzubFSv6ZpP84ET9H}|9Z*5aMOgCAp~)vBd(=VkP^1HLDJxRp1`@r+0%}Wx z<)FdcA0^6oeDcz$JQ+(+Sb}{DQd#s2lr|w{PEqA#{b(6hbw&n;vy%g&6HE|F!M4Cu zfub9f&>%?$9+==*x;Qx?T7EKfjIBOGGsvEm(BuyeGO!jf0ZuEbj0_A{C+Ek+%UOfm zW&<L?vS0$N#FUYN;pXHwF~;ofAltt&Oje8S&^8091nGv<{-ELOB9QCBE&&zmAhot2 zMedVt#;P#ho%}DhRb>H4bRmdX3?e|S<)XPD7C2DA1p=fKxGRo_@#*B_am(vL-oM3E zo}|fB<Nz`bZp1Ct%wo`J4alTh9Jz_vsVSL7#faFr#gbo;ns<w>ATv2TC-oLfN@;EZ zI9j05e2X<1)UCY5n1&vhpwX8Xp!~<fz%co3{G%jLC_-!pR~-l^u%%XH7MBzkxqw{e z3d$rbpd<#)aj-ye2g!MW<x&z$645O)XJlab%rx0B(Gq<u8JuImR)fNz2r=RU%6CNu zAY(z<qX--opeAz>INss0Py~)1Q1lhO0EMwVNC!9!K^`muSzLr%BMC7uKq?Dxv}-Xk zFif5NJ5ireYqEBdk;Z$F5#Uq-CctVWL2YSf=#&@(V-biy+22fb^Q<IAMyB@+llLYY zu?8|SFmO)(lI$oBj$a8-reQ1!067M1lK*6%6eVG1kTKxufsK!YgOP)&C}?wIiZGLo zFCznkpC)V3Jy17_4ct+KMlwhSocc7GA?2X&<O69I^%5YHK+P!zK0Zb+MlMDU#-b32 zrJx3dCZn6CYZ1s5kfsHwOHc%^!CCW4a|<eqz|9756oYFzVUR<?wQUI~1i(plFNk## zL|g(9paQfA6#GTSj12V*x7c$li}FkJQf{&27MJGUV#`g-$<Hq;0*x>hfo2hJvE?Ua zr6!jYf!ex7H6SBEb#ajZ$STmFa#03I4AfC90*y`=HG#O(Km=&qtEd3P0=1!{_)7CK zOF$*BUU4aC-tj5}Lp?*$8c@;332KQ1gGE6D3`KWAn!x?{ry$mIaB!AX7G&n7Lz2fE zknjf(0WKQ(KwUeK8IbNBxFHh754W$VG%qi;s0h>qC|Uv11ge`s)tocKElyCMv?M=2 zr?^N8<RxhkAp;_0LD_&S-WfEc>6w?7Uj(Y^ia<#XoOX(WK#D>bCpT(|O+K6vps&rt xB*M(W!okL+!Xd!JD8R%az{4aI!NbVIB*eqPA;QSRD8$4iAe7C)%puId1OPFp%3J^d diff --git a/unitgrade2/__pycache__/unitgrade_helpers2.cpython-38.pyc b/unitgrade2/__pycache__/unitgrade_helpers2.cpython-38.pyc index 85a4965da5d65114c8709bc88a2d0be4810d2f9e..5f1fcf25687cedd7203740db7a57b848a3ce5503 100644 GIT binary patch delta 1097 zcmbPey3&+4l$V!_fq{YH&wq`?V-tC08G|-z3o$aPPPSuIQgUZVQAkm2VMtL-<;hZL zW{y%!QA<%yQE6d}Qc7VAX3$jMT)=pYjnQPYIY$sPqyFYDZXHI(_Q~6Mav57EtMcAv z?3v8SSIyhaz`#(<#K6G7!C2%w`HYY~(=Cz7YQma~%##Cz_lZX_FfdF2Dd7OQgpr4l zkCBhDN_DcGh`B#Vt|**=fuTqOP6UBiG9V&?fq|hPq!Vg5h#!*712P7Rbr={J*cliY zoI$EYm?y8~+frY`*UV5WR>EJykR{N}=)y38F}5s*sa8COsaB#^GDWCXs)jLzA)B-4 zRgHLxusA~vV>WZqtHMJyVhaRoBo;E(O4mqa3DwG^h(P6K(wM{;YGq3}YGhLcQbc>1 z7#UI+Yb4@@!K6qgL#<p2V~SXgXs%eTJYzjWjckc{yhM$Big<~5ibOBd0?8Wbg^aZd zDU!8{H40f$wMr$@H40fW&5X6mFcz4WZDtf_0JG#kERfo4rU{J29VPNjj5SIrjM*#` z7>kybDAY*SD2p(pNQp4iC`mIkGv+a+FxD#9NP@)cYvgKVQl#gw)`-@K+c4B9*GR;R z)F^@7D+BS-Y=*f^wJIsHH4<4Ovl&w4Y9wbf%w?%nE#at9Ns+G+E|IQLX=aoFIYkvj zi!g{Y)ToLxG&3?XlyIcTg6JBd1&S#O2=m}()q@OUPG?%k$jDH5s6?qow3#u6xmK-K zsaCl}p+vbxshP2vu~rGpRtB?`Ym{mj;)QFJYZ&51N|+WfFJ!3Yt>In3nWDImu~wi& zp@eq<??Q$e5ebH7##;3n^%Ny3hFXmp^%{*7B@qS*hFVQ<x@D-<D&fdTQLPaWXGl>K zXQ<Jt(MVBmW)f#e(E#%_Q#8RmEr?&he$Y-4C{d|l$Pxhsd5WAk1DGca;z2x7qg<nu z##AGkqBDo7R=Y;KMktLbm_bu_@_fM=jB_Si2u<I-LxhEqF>Uf*QGG_O$!|q-8C54o zi)HYqGB7aQVkybYO)UZ?-N}!|Y7CP=Vw}aL$;qk3#i_-&*iws%@{5XZaik??=9Ctt z7T@A?EG|whD#^^xa|KCF&K8$t)S28VUMFyiy(GT4B(bRE7He^Geo^XV83}#H*2z8+ zdW^RwS4$W$PMf?&LY<Lm@-+!1RxTzjHl@kGB|I3FC%Z_x^4#Jm&C4t)Ni8lZYMDGi wawgv`u8`E?5}*9Ul+>c4h{<YF+KhISgQSf3nYqF^*o0Vw*cliZ7#aQn0BNup$^ZZW delta 1075 zcmZ2!I?<Fjl$V!_fq{XcE>tbCaw4xRqr*mRAx1{!$##rN0x2pfiYZDhj8O_HjKK_= zs+*e_kFhbDZuaB|VrDehJcnC{k+Ea)NuFHBw#nwaw;6jU3-eX$_AoFo6f-d}FmNyy z`7$stge3ETY=B~21_lOp1_lOakg88ilM@BD)VnjJ2&D+OFr)~V@MZBgGuMjMh&40R zikAq~Fk}ffGrBNLV2pK&VXBpgVXBp^l}Zt*m9Ak-VaVnz`cos3A}Y>M!<fxn^r!Gj zjrang8p(x>wK6r5S;DolDPmB0*)%3GhFZB2jvBcXffVsxCPs!7#u~|Zkrc+7ddYav zOom$d6vh;Z9I;&SS_MXi8o3gQc*z=t6v+~a6scaO1yVIK3mIz_Q>1H^Y811iYn5x1 zOJr&kvt*kYB^YW|YNSf!YE)8WL>Ow6r5TzTMZjV;QZ*_y@-?z4vU6B#L~A5$7;02% zB;!SEl)+ZZK^#{<n_(_ft!j#VjbxVSY=#tt8mZX~b6INDN;qm%Qxt22OJr(PLDrPW z)Tn`I5e9LF8Z~i-W=2Ma5{?vk5M3j*Kt4qYVj##o6tkGqnHDlKG8A4ZQK%7ZW{hF3 zRj*a9RVk4xQLIsJu4im!tW^ecRGL9-l^W$5hIo-0l^TY4(GsQw%nKQ6d24tVaHc3P zWULh^kt^X{z`Ky4Mnr<4nXy)*Mk7T<ilJ7sMx#bEMMZ=`f}vI`MKwjOg`rlvgd;`0 zMnIe)MMIpSM!QBcMYEYnoFPRE%+pHI2JzfdbRd2K`$0EFphT&LAxpHGQJf(~L7V~1 z69MrczNk^DQBGs35lzvX!&IwNqf;Z4#uUt;sXw_=cn0J2$wDI2C(q-vk*?BBElbQP zO)N=`FG?-QFDlWq$;nSn%qh0hn|y~)lTmmw8~;9o1O^6%<)Ea<0ZN~YJdAvde2i6g zxV7HqH+KMODhg*{U?`G+6G0%B3<CqhEs@~V!qU{dlFY=MkksN5pZvs>)S_h|JD`~& zee*IAc1Fh7$?HV*8MP<h6U}8*p6nx*p%4So&Qg+@n|h0*G%vHHB(=EY78k;h$%n;i zcp^cH*iws%@{5Wm7l_L;>Q3$xuM>@8FNrTMNh~V4#af)4UzA#u&cMJhSw=#iv3;_S zgdStm<Z1~6#)*^HNT@S23$abUBB8|0$1XDYw}c0y;$#;|SN5VtkQdq}PnDcG*<MP6 Y(Pnanlo2lrR~QGI5Gw;C10%yf0M0EI=l}o! diff --git a/unitgrade2/unitgrade2.py b/unitgrade2/unitgrade2.py index 95b071c..50a8c52 100644 --- a/unitgrade2/unitgrade2.py +++ b/unitgrade2/unitgrade2.py @@ -414,6 +414,8 @@ class ActiveProgress(): self.time_started = time.time() def terminate(self): + if not self._running: + raise Exception("Stopping a stopped progress bar. ") self._running = False self.thread.join() if hasattr(self, 'pbar') and self.pbar is not None: @@ -528,6 +530,8 @@ def giveupthefunc(): from collections import defaultdict class UTextResult(unittest.TextTestResult): + nL = 80 + show_progress_bar = True def __init__(self, stream, descriptions, verbosity): super().__init__(stream, descriptions, verbosity) self.successes = [] @@ -535,9 +539,24 @@ class UTextResult(unittest.TextTestResult): def printErrors(self) -> None: # if self.dots or self.showAll: # self.stream.writeln() + # if hasattr(self, 'cc'): + # self.cc.terminate() + # self.cc_terminate(success=False) self.printErrorList('ERROR', self.errors) self.printErrorList('FAIL', self.failures) + def addError(self, test, err): + super(unittest.TextTestResult, self).addFailure(test, err) + self.cc_terminate(success=False) + + def addFailure(self, test, err): + super(unittest.TextTestResult, self).addFailure(test, err) + self.cc_terminate(success=False) + # if self.showAll: + # self.stream.writeln("FAIL") + # elif self.dots: + # self.stream.write('F') + # self.stream.flush() def addSuccess(self, test: unittest.case.TestCase) -> None: # super().addSuccess(test) @@ -552,21 +571,22 @@ class UTextResult(unittest.TextTestResult): # (current, possible) = item.get_points(show_expected=show_expected, show_computed=show_computed,unmute=unmute, passall=passall, silent=silent) # q_[j] = {'w': item.weight, 'possible': possible, 'obtained': current, 'hidden': hidden, 'computed': str(item._computed_answer), 'title': item.title} # tsecs = np.round(time.time()-start, 2) - show_progress_bar = True - nL = 80 - if show_progress_bar: - tsecs = np.round( self.cc.terminate(), 2) + self.cc_terminate() + + + + def cc_terminate(self, success=True): + if self.show_progress_bar: + tsecs = np.round(self.cc.terminate(), 2) sys.stdout.flush() ss = self.item_title_print - print(self.item_title_print + ('.' * max(0, nL - 4 - len(ss))), end="") - # - # if not hidden: + print(self.item_title_print + ('.' * max(0, self.nL - 4 - len(ss))), end="") current = 1 possible = 1 - # tsecs = 2 - ss = "PASS" if current == possible else "*** FAILED" + # current == possible + ss = "PASS" if success else "FAILED" if tsecs >= 0.1: - ss += " ("+ str(tsecs) + " seconds)" + ss += " (" + str(tsecs) + " seconds)" print(ss) @@ -574,16 +594,19 @@ class UTextResult(unittest.TextTestResult): # super().startTest(test) self.testsRun += 1 # print("Starting the test...") - show_progress_bar = True + # show_progress_bar = True n = 1 j = 1 item_title = self.getDescription(test) item_title = item_title.split("\n")[0] + + # test.countTestCases() + self.item_title_print = "*** q%i.%i) %s" % (n + 1, j + 1, item_title) estimated_time = 10 nL = 80 # - if show_progress_bar: + if self.show_progress_bar: self.cc = ActiveProgress(t=estimated_time, title=self.item_title_print) else: print(self.item_title_print + ('.' * max(0, nL - 4 - len(self.item_title_print))), end="") @@ -625,7 +648,7 @@ class UTextTestRunner(unittest.TextTestRunner): super().__init__(*args, stream=stream, **kwargs) def _makeResult(self): - stream = self.stream # not you! + # stream = self.stream # not you! stream = sys.stdout stream = _WritelnDecorator(stream) return self.resultclass(stream, self.descriptions, self.verbosity) diff --git a/unitgrade2/unitgrade_helpers2.py b/unitgrade2/unitgrade_helpers2.py index 17004c3..c1961ea 100644 --- a/unitgrade2/unitgrade_helpers2.py +++ b/unitgrade2/unitgrade_helpers2.py @@ -44,7 +44,6 @@ parser.add_argument('--unmute', action="store_true", help='Show result of prin parser.add_argument('--passall', action="store_true", help='Automatically pass all tests. Useful when debugging.') - def evaluate_report_student(report, question=None, qitem=None, unmute=None, passall=None, ignore_missing_file=False, show_tol_err=False): args = parser.parse_args() if question is None and args.q is not None: @@ -141,6 +140,12 @@ class UnitgradeTextRunner(unittest.TextTestRunner): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) +class SequentialTestLoader(unittest.TestLoader): + def getTestCaseNames(self, testCaseClass): + test_names = super().getTestCaseNames(testCaseClass) + testcase_methods = list(testCaseClass.__dict__.keys()) + test_names.sort(key=testcase_methods.index) + return test_names def evaluate_report(report, question=None, qitem=None, passall=False, verbose=False, show_expected=False, show_computed=False,unmute=False, show_help_flag=True, silent=False, show_progress_bar=True, @@ -161,14 +166,7 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa nL = 80 t_start = time.time() score = {} - # Use the sequential test loader instead. See here: - class SequentialTestLoader(unittest.TestLoader): - def getTestCaseNames(self, testCaseClass): - test_names = super().getTestCaseNames(testCaseClass) - testcase_methods = list(testCaseClass.__dict__.keys()) - test_names.sort(key=testcase_methods.index) - return test_names loader = SequentialTestLoader() # loader = unittest.TestLoader() # loader.suiteClass = MySuite @@ -267,14 +265,15 @@ def evaluate_report(report, question=None, qitem=None, passall=False, verbose=Fa # ws, possible, obtained = upack(q_) possible = res.testsRun - obtained = possible - len(res.errors) + obtained = len(res.successes) + assert len(res.successes) + len(res.errors) + len(res.failures) == res.testsRun # possible = int(ws @ possible) # obtained = int(ws @ obtained) # obtained = int(myround(int((w * obtained) / possible ))) if possible > 0 else 0 - obtained = w * int(obtained * 1.0 / possible ) + obtained = int(w * obtained * 1.0 / possible ) if possible > 0 else 0 score[n] = {'w': w, 'possible': w, 'obtained': obtained, 'items': q_, 'title': qtitle} q.obtained = obtained q.possible = possible -- GitLab