From 9198625280d15688e3d392bd30a611cc92c83313 Mon Sep 17 00:00:00 2001 From: Tue Herlau <tuhe@dtu.dk> Date: Mon, 13 Sep 2021 15:32:36 +0200 Subject: [PATCH] Snipper compatibility work with 02465 --- .gitignore | 138 ++++++++++ setup.py | 2 +- src/snipper/__init__.py | 2 + .../__pycache__/__init__.cpython-38.pyc | Bin 167 -> 221 bytes .../__pycache__/block_parsing.cpython-38.pyc | Bin 3161 -> 3482 bytes src/snipper/__pycache__/fix_bf.cpython-38.pyc | Bin 2198 -> 2505 bytes .../__pycache__/fix_cite.cpython-38.pyc | Bin 2536 -> 2505 bytes src/snipper/__pycache__/fix_i.cpython-38.pyc | Bin 2820 -> 2820 bytes src/snipper/__pycache__/fix_s.cpython-38.pyc | Bin 1384 -> 1571 bytes .../__pycache__/load_citations.cpython-38.pyc | Bin 4979 -> 2652 bytes .../__pycache__/snip_dir.cpython-38.pyc | Bin 2103 -> 2057 bytes .../__pycache__/snipper_main.cpython-38.pyc | Bin 2644 -> 3025 bytes src/snipper/block_parsing.py | 30 ++- src/snipper/fix_bf.py | 63 +++-- src/snipper/fix_cite.py | 2 +- src/snipper/fix_i.py | 18 +- src/snipper/fix_s.py | 25 +- src/snipper/load_citations.py | 237 +++++++++--------- src/snipper/snip_dir.py | 42 +++- src/snipper/snipper_main.py | 17 +- 20 files changed, 384 insertions(+), 192 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5391d87 --- /dev/null +++ b/.gitignore @@ -0,0 +1,138 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ \ No newline at end of file diff --git a/setup.py b/setup.py index ad71618..a7fc926 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ with open("README.md", "r", encoding="utf-8") as fh: setuptools.setup( name="codesnipper", - version="0.1.0", + version="0.1.1", author="Tue Herlau", author_email="tuhe@dtu.dk", description="A lightweight framework for censoring student solutions files and extracting code + output", diff --git a/src/snipper/__init__.py b/src/snipper/__init__.py index f102a9c..4e820bd 100644 --- a/src/snipper/__init__.py +++ b/src/snipper/__init__.py @@ -1 +1,3 @@ __version__ = "0.0.1" +from snipper.snip_dir import snip_dir + diff --git a/src/snipper/__pycache__/__init__.cpython-38.pyc b/src/snipper/__pycache__/__init__.cpython-38.pyc index f52a70bcdae56e64584b49d2330bcdd216e21e6d..eae9fb89b94899b9aab163c73358f43efa116212 100644 GIT binary patch delta 157 zcmZ3^c$cw0l$V!_fq{WR;)P|R0|NuYV-N=!GchnQfFz1V7#J8*7@`<b7*m*X7;~AT zm>3ySn1dNKS*lnK^bGV2UxKu0GT!1S&dV%_PsuFu(`1g~j*l-(Eh^5;&x?<b5&+2* hq!#IcXpo8`UXbxC8H$)07#NC}Cq{U&7lTAt7y;OaAb|h? delta 102 zcmcc1xSTN}l$V!_fq{YH>Sx15aRvs4#~=<eW@KPsaA06yDCS^bU`SzzVn|^OX3%7+ rVl~h+&@=SYWW2>4A77SQRGgWg7azZpp@@lrfuV?LVviT=XOKAnc8C*1 diff --git a/src/snipper/__pycache__/block_parsing.cpython-38.pyc b/src/snipper/__pycache__/block_parsing.cpython-38.pyc index 5f0fa38e06964f4ccf08c26117b7b787eb3b0791..f863b8116bd2e1ce5093ddf2a92c11e93ae21392 100644 GIT binary patch delta 1887 zcmca9F-w{+l$V!_fq{Wxe};9UFW*Ey87>zF28I-dD25cli6)BjTq)cw3{k8pLMgl{ zd@YPoY$^OH0xb+t>?u6K44T3lbA*}d89@d>F%ts=0}BHKgEIpILvafO149i%3Zo=L zEn^8o4P!H73R5;ykx30>3bQ0ghDDM=oFRo(9K>b=vC|oA8S`x5YFUa3P}Qb0)-a|p zrLea$fmGKprm#yg)YmYiKsAdq)H2pEq;N<w)G&e#<pe1UX3*sFyTzK6lb@XZ66Dw- z5OIsOAiuc8@E4;3gk|*d|NsC0Z?UFj78RG=V#!G?E?LP~#LU3JpvhDuz`($8i#aJL zyNH{CfdNABfW)|xa_aMwv*WY!GxNkjeg=s$Fmf>RFe)(eFd8rx$uKZ5B!hwl8bS>G z3=9lx3=9k)ql<Z%7#KPjQy5YhL0;-)$YiKxDq*N$=wNJSieai{u4QRwOapnDxrL*a zwT3x`A)BMfEQKMMp@y}Fp#~I;^(-k2AkEE;wQMzPDJ+r<DJ<E{MHwB8vl&uYAtJLG z<}&9obuiYl*Ra=efGnuts9~;QNnsObNMY|~iD9bctmUfVOkv1oDq7RQNKnm{62=sc z1xz3()I+Ra$k@!t$WX$Z!U=MF6Jrf?4QDpf1jZt#8io{x8fK6aLCPgTJT3&Uh6|!U zoe30UHJo54fjuP7P|IDyQp4TBn8MY|RLfJtlfo^@uz+<T10zETTMbV$V+~IVk4-&8 z4NovA1;H#~O5wF(s9``hs)i|r&xWC$p`9^}37mpCYI$pTA<n5`0R?ppQ;MJsLk&}k zkPQP^hEtNEh6^eq43-fAo5~FK01L<i>5L!~>On59;RFdld;nGe_F+1sI72O84POmY z3bzf&%}mXVHB2cyHVidvHB2d@AQ}{5HB2dDAS;3yKryQ+?)MUuV3I+}6qag0sRfj= zgh7d{4xF(TFr+XpWUQThgH^kJ0doq=LdIIA6xI~B7KR!o7lvjKj~$s;!ji&);DhBk zYnZaxi>gvMYnW0vAuiD5@+%T$U|;}ek|L0GzZk7ioC0zi$SJ`fr-(2xFr+gm)-c5K z)H2pEE?`*5Fp;T{B^Z)PG#PKP7MB!d7Ob4y#iq=tJ$W6Qb3JauKzSvdp@tz=1YTe; zWU~~p)G$KK)MSLXN($sY1rULn9gCD17#Q?G&H`mHHU=gJ9tI5C>RA~W7{G1^sRUc6 zR?C>eP{WwbRwM=TLJGq|#yq|n#s!QE85S@tWJqC5V}d$>=@+AIh$izb*5ZPk%#vHI zIr-(OMMd%;r{HprKFB?w@B+E#7K5fVYY~VCE?OWuRY4^QOG;*P$z&mRGf8!j22hE^ zz{JI9#K_0Y$0)?a!N|chIhI|88zft#0<uteau2(nfEI`;1S0rAgv8`i>;-b5XoCb5 zNVz5x!bVNjBF)JW95#%Blc#bR*Xx4xfa35LOJY&FQIQzPDSX8xiA5#xC5h?riACwf zw^;HLb5k|hi+DkjtOZ4xc_p`4KqcNSPS=X$)Pj=C{JbJiv385OAin@y;%V|1fr7aR z6c6CivxpsJ69<UU1`);#3=C16lifI#O$<SNX%GR9O;C6hfr?SEk)Tj5b^_%BMjmDs zMm{DUehx+!mdOh_7xJcn0t%EG85oP~C;M|XFe**Hz$GV|0TKsSYv6(yR2UaIO=jlq zVU(Xdfm?ymZt_NMaaIQg28M#kXSrqVKrBrrNO*zroF=26CdV!I`1q9k<oI~7w~GWp o?gOPyu&avfL0pitiX0{@^QZ}d!k&edi-UucgOkIBgN2I&0Gw!IvH$=8 delta 1542 zcmbOweN%!jl$V!_fq{WR;*4qHU!IA4GF&zc3=Am@Q4A^k6HOGw1yZ<Ecv={vSW|dY z_*xjE*iyKH88ihqmIyP|Gl4Whu>b=D0~-Sa12Y2yL$LxA149R63PTEGE0ZKcCqoKT z3UdoXEmI~#EprJ&4MPWGGgAyxElVwHJ7XGS3QG!W3r8(m4ND3`Hb;?N3PUhM31baI z4T~g0Gb1BI4I6}A!<xbXGOwAjmc52Og{@waA%!iQxu~XtaW+E=SV)p#Hp5)zJf;rD zT8<iyT27E<HJmjpHLNKd;tVOAy(}?IwOqB_HC!nS*-S+TIv5G6c~Qcc!nJ@2<OGQI z3mHL<Dq&8k=LY$siLr*IhAW$C0%K8F4MPe;4GYMPAmx%E9yfwl!woSYok^UbhM|TF z>?E*{#2IRNN?2-mIv7)UdYNi@Yj{(5B^eg5E@WV2s9~z%ZDy?DP2sa)sNoG}K-f`V z!<@ozgJx6>bBcfsLpwt|V;WP6V2V%+M=f6sAH+E|te{}8VNMaYVW?qF5wT$a%Wz3D z)Nn&(M8Ps*U{hJZ9$*D|ARQbXAP3iQf%sq#xN(6MfPI+GD9%vJU&CL+oWg4Zax-%? zV+}Ld&FnSIDdIK^pcs<`St|juBA5Xb%bJpYFPSC_a*NcnFfcF#gOZL90|Us5jFKRd zNs=Lj8O&mlWDsWnSyIE00up6SVS~8?%x43uVn<TN0b&O;Xma}9Vol2|DlWOjnv|2D zoL$7oz`$^ewIIK^#PB7E{qq0+|MmYNB1X4ZauSP6intjV7&IA+K#3a6h7dd;oh(`T znR(J6r-JhhqYk6Ue<nt@|5cJ;<Kv49axzQwY;y9G6LX5~^gybULDoR?2{?nWGB7X* zgN#T6`*s1t<ln3Y&b3S>j5SQnj44dnOhsNPEGaCRjKK^g%qgrXY%L5mObb|2*cURo zFf=nZGuATIFa<Mca`^pXQ~>*^NDSn-$@AHzH9@R&h8l)gzFNi_#sv&13=0`2G8M7} zGiWmYVzkv{yu}K3q~_$)Y|4z9li#yBEB<1%)?_UL#X=D%2j5~XE-A_^xW$r^nOssN z$H2fa*_*>mToL4EP$)1kaWU#J@i1~QNibF^PX5cL$WtW4z`#%>3nIiOpXAUJPy;bV zKm;F%5T4A=Ss({;8^paJ<(f<gD>Ye*R3}g6v|)6ge2LSzUK6B86yztC#G-VgA_)+a zuec<!s3g85F+D!9D82X=OI~7bswP_zFG!NLpeQr1q(}<H=5(z{PAw?O%+D+02l1H; z@(VNtia_CB1S+M#svyzJ4zh>?M5u!ZeFg@GD9+%?tz1eLx?rtIIoXit*9OUhd=EAg z<e*|VP^>cYFmW)mF!C|+aC0!SF!3-=zRk6eHwqM1;1ZIt$a-=ocLSrsWG)^#(KwJe zB<XN4@-TvMk=<llo*qW!$)|V}WUWA!GNn{N>;xsmBCwsHVmWOxJFl!Ih^5H{2}MxK z(q#10WWU88AD@z+93Kx3j3PmhTR~ngvIep2K!nZYBwjTEkYOyWTpS!+98Mf8TpR!r CdN~RJ diff --git a/src/snipper/__pycache__/fix_bf.cpython-38.pyc b/src/snipper/__pycache__/fix_bf.cpython-38.pyc index 50edfabfa447d901387da5638cca83d0bdb560f9..08110df11cf8ba047f40b6a36f84bec56cdd98a5 100644 GIT binary patch delta 1296 zcmbOxcv6@zl$V!_fq{WxSGslL8Lo+ZGW7ur3=Am@DU3M`Q6QQrhcTBaiir`#X3k;G zWr<<|vsrSOb6KNUbJ?QU7#UJnQ`lM<qS#Y-QaDmLTNtA_Qg~CiQn*_fqc~F-gBdjW zUV<#~(`3BGnx34WTdc`=i!C!RB{i=^lj#<BQciwyc6@O`PG-q1ZY~HfD?c-D<0MZe zQBDR122G}0OnL^l7?W2r-eSs3DdL>`fys?gZn8OZoCa8)@fK@wNl|8jCQ}i}JGU5f zig*|p7>YoWMSLI@|Kz>Q9()1}3=Fr}5(^4a^HPeKCkwOqGYU>lX0Z_iD+Fr+slLUU zmRS*>#y)u~i={oI7^48A7^4^?7ZVpF7h{nM0|SFwGAqbKPz=({#=yYf%)r1<{DFai zp@gA^A%#(rp_#Fkb@D7$|9Z9>rUgt38EV-}7;D&@8B<uYS&KSq*g<MiShJbHY^D_E zRwhY?TJ{=7uv*3%=As2DZ0U?OY$6P`9C;o!EJf?m8EQFF7;D+`tV$Sb7@HYW7_(W5 zj?}Q$Fp4vzGv+a+Gt{uAu-CB7W=P?f%PbD!an`V_&SpsA0&&xs#2IQiYB*}x(wKr7 zG`anX7(s!<4kCmn_p=3vYBCowgLon!0u)@DoJBH|f3nHgvt*~H7TjVh&df>8D=Fdy zg(OpQ@-3#+)LTqBMv$Neg#<XfZ*j##;xVl>PX`n%N|R&QCF@xjSs2-v)EN2xv#}KE zF)%PBGeN@;M1h<E562z`28MKoTBa1nT4r!~GNmy0GS#xwu%s|#GZo1dHl?tnu(mMN zu%xg_GAv+R$lwAF?;55WmK1hL26Kj5rV=PSjj@I$g+r2|zJ?`*Q<5QtYYtNlYYKM_ zV<zKt=03(4ureElTDB7A8kT0pT80|t8a8u=TINEI8W5W)jX9V>lLs1FLZB4Mc#F9t zF+CX+d?2TTFeuzu7#J9W!Tx1nV8~>sVThHAVX9@UWh!B)VQj8vOkv1oDPpN%tYMnW zRLBy{pvef10ZqmtP=ISPLz8dzEygm85Vc9kOfE^z&n>X?2HC*Dz`(%9z{bGCz{F4` z1xm0<MtU|m`N@en#ddlK#kcs1OA?Dp;!6_K>*EuP(u;4gf}`dZOJY&FA(%AMWGYez zMYslt&;<F9r3mDeTdbKSskz1As44;_c}?~r8JL<|Y{{i1`K2Yd81rs1CV>qqzQvT1 zhwgATh}&Ek7~C0(#Xup&$im3N#KXwJ$iyhd$iryB$ic|PTx1Kfm&wgdlhI9+>lSBP zX<l+ketu5zExzKs%z}c{BE6i{^u*-KBBsf99MS=x;08Mq>@aY)gt!xA4w4%XX_CVx dH$SB`C)ExVYsH}4&cVpT$ipbW%%RF90RSi=6siCK delta 1053 zcmX>pJWY@<l$V!_fq{YH&Joi@C(em{GWAvr3=Am@DU3M`Q6QQrhcTBaiYb>likT6_ zXU<{CWsPEGWJqC2VQpcEVoTvnVNc;`VT@u=VGL%_<a!A*&QFu+7HfKPes1wC-lUxT z<m~u@qWt94;$lt4TWpzmDXDoS$xI-HP|U}`z`)ADz`)F~@w5?>C<g-rgC^50COv~& zjL9n*Z!u-26md)zVs>McogB#=rva8{yv15vQj}Ss$yCJ2z`$^eF{g-|fq|h2Bw54@ zV)0GB&+Ng+50Yd{EGS6LODSTRY|7%#C@{H|#YPOQ5Ud5H`W9<iW<`7&+vMvkmi0_x zi~`JJjAD#jEL@CSj77=}3=D24E@o$7U;tre1_p*=7f_fnrZ8nP)-t7Vv@@hJrZA_l zv~bokmoU^Yq_CDSW--+;*D$59^)jWf_cF(@)UwpF*0R>J)v(ksr7%h|)Uc&72Qz4L z`rTs8D`M1TU|>iFg$Fcv7(j8v#=yWJ4YKVM0|NutTt-QTX2x2!$^NYV_3SlF3z!x% z)N+(C)^Id4rm$qQ7IoBcfXq%|&1M3#nNpZrnIsu%IcgZeY8g8iiWa1>r8CyBi!ju3 z=2?|6)-X0RrZ8r+6m6?vt6>ypNN3DrN@u8HOJT2JpUsfMF_&2!#N({tn9Y#F1>&VM zi8Iu4s@JfjaI-Q<GSsk}GcYsQFw}6?u%|HvGidVo6)}P$1LXW7p~+5c0rf>Hp!j7j zVgZQ@g9uO@X>t{TymyPcxFoTtBtEsGq$u$gXKG#wl*yb}R04|f#FFA$Y}w_BMd`&w zJfOH`N>0ATl$v^rDaU9f<1Lo#)YJk*BDlo~Nq=djc}AeXlVV_~XJBCDVN_vMVdP-s zV3c6wVdP+BVdP=5ViI7ik_4rKBqKeWoc!d(oMJmYxb`AJkgFMsv_KToE#{KM^ddtL zo6%2`xd@aFZgHlS<|UWp=jRmPVlPN6D#=XD(PRhvs>lH3O_0_i!$c5M7UXiq_*-nr zr6u{LB@hSegJi&okqzPukgj4-I%QzwVB`}}U@S5R+vujrQDh7<fv-3(v!EcgNG~Tf zJu$hmhzVo@^W->AX<KmUf)XxR55xkHQ4ki`77m--{FKt1R69@%f$ia76kz0G=FkEF DTO{4T diff --git a/src/snipper/__pycache__/fix_cite.cpython-38.pyc b/src/snipper/__pycache__/fix_cite.cpython-38.pyc index 8182783048657d4e03b7fdc09bc39298fccc3065..41ff88198ed4802e312744218929d4693baa9cdc 100644 GIT binary patch delta 229 zcmaDMd{US<l$V!_fq{V`_O)f=%Z<Fdne{{%7#K<zY8Yx5Qy5d2QkZ*LYME=8gBdhg z{Hj=Dic-@;iewlV7&IA+<QW(kCX2A>bFhF+U=(25?8}nH$b5^DYw{jeC&sAB|5-P& z-D1hg&&->=jjfDFm4Sib7E4h{MM;tNW(#&>Mn<K{IUL#snhXpKZkmj@II>ey3sUn^ ziZ$7abQu^JikLuz9!M8!K~ZL2Ns$3az<Bae4tZr05YrSyn1Kj$5MjZ<z!1fhT2!PB L;#o~*=X?kNbw4#5 delta 260 zcmX>p{6d&Fl$V!_fq{Wx^&!*5=Nox<Gy5npFff!b)G*XArZA>3r7-uh)H0Varm!qv zs$pKp*v!btP{SO|pvmf2#S&ALnif(d!@$6Bi;+u{xkw(wVl61j%qzLYl9ivCH~Aa0 zJ{KFvd`1CAKE}<uELn`KMT!gz43lTEIx*gwe3x|-YmqXDKb5VFM;)Y}rKqH$q)2bG zIJ+?;qsnA&4sAUh1_lN<O~zXs*{P`osd*{InrvWAMNA9~3`GVY0_5r<BM{4U@-hy2 hWit@d97I@v2ul!Q#lXN2#gtl9qzB^JOn$-f5CH3rJIeq7 diff --git a/src/snipper/__pycache__/fix_i.cpython-38.pyc b/src/snipper/__pycache__/fix_i.cpython-38.pyc index b538f528512b367e6f1e99eaf64f3f4e0c4363b5..1f1675e90766d6fb6d166d74c20670272061e74b 100644 GIT binary patch delta 931 zcmZn>YZ2oM<>lpKU|?W)>0_0+hj${M3}eJZZ5=~~6viC3D7I9#EcO(ZY^EZY6p#o< z6lWd>n8g*vnZlaF*1{0Qox&K*pvgWlMU~|iQ(no&&J;#Ieg*~xHU<WUU<L+;Vy4Nz z8Pn=JN;tAOQ#evMQ@B#NdzovwYPc3~rSPOPE@Wh6sNt$%PvNj(0FjamwcIJZDSRyq zwLCQ}HS8(;k_;&ftxS>(DXi&?;tVbfu`;#1HQWohYk0wWxfk%H@T9P%Gl6)8>uPvv zxN8`inQHk!dRZAH8A=#xSSGVD3(D}-GSo2CaMUoQGo>*FGiVC<6)`d}Fx+B{FXEVN z$SlFa%D}*|Igt4yqZ}wq++P0w|NlQ&$uCCEA`S)yh9Z#9inu2yur5`-#hsZKpORk^ zpPQeOdW)qzzbK_h24oz2N`47QY$ZdH=436lSVqRl9c;3!j2et=Op{l!8M3i6FfeHH zPJYN{S6`lbi?z5Qu{`e<TWUo?YH~@D6v!HBkP7}HMUZja#U+VFCGn{hB}Iw1I8*ad zpiJh(qLN!I8L5dWw^&LNGjobSA%2S$qK+lMv?T2oWAQDf#JnN}kdfLTLIp&qf(T78 zVFDtxK(=ru<>V)4$ETI%@qr=@q>zD8gOP)gi;;&>h>3?$fRTrhgNcKYLv8YJc0F;B zWkr@CXENPlE=f!;vIQB%I@y84Rs&@AN~T*(dIq-`%Zfle2m!IkrZ}}EIX}0+E@1Lf z4s}MZ$qpPMlOJ+e8-v2UNDyQsW04NXG<yaHhLwy(Rv<Rm6tDqYHaVHa5EFtX`*X&# zfg^@v@)k~GHn29`$!|Fg0^tq>yX+QY;w{FcTa3v?oFLyaXO|V<V$Lruxy6`vi!l}A zJZF$SU@KUQO7r3~c|ZZ72Fe_ae2iQ+lk>O~dBZ`@<0<k0Db<@ihsz}P7E^xlEtb5* z+|*m_<<K}Z1lhq}0Of)7Kx_be0!)Cd;jqcgPbtkwwF9NXVgUvQ1`b9JMjlW=GjcI< IF>x>h0Daxt8~^|S delta 916 zcmZn>YZ2oM<>lpKU|?Xlc-k~^A^$`^8Ag+d+B&=}DXc9FQEVxU!3>&g6FXElZcJh1 z6J%guU}Iol2xeelC{~-S%#>EYCWSGDA%~-utA;C!Glesosi*-g!d1(i#{p(>*K*fz zXYr(Pq;REhr||SL*YecxEZ|MyO=n!l$jDH`Q^TIZVZ#6-B^hdYQ}|N&TNrBjYFKL6 zQv@U#QW#p9BpFgz(;3AXTo__yYWZt;7x2~agZ1*tEZ|S!O<_xC0&xp3)$rBu)-W_P z)e3+#Phys|5vXOTVW{D#VMu36V+v-_6!a@%WME*p#TZ}2&cMJ>#im!Bk(!fpi;?RW zv!0$_6_cJ`5erBGQ(npDK<1B(a-0kd3~n#~|Ns9Vtn(KmCs=0@KLZ0p5!d7d)}^XZ z+?jdtDfuPwx%nxnw^+*ai&BbY7#J9$*i-ULKw>Kyiqt1-vBfenPwrroWo6P}WMiMa zip`J>6q=d>lOM9#N#z&cV#!O)O^sqNPpv3OO)iOIFMu#6E3!+~3l=GYOyn*uNh~Uf zPpv2^N{r%6%}aqYnG=gjZn0#fCZ^nCDM`%CDPjeAf)%Xp7E69<N!l&O;v#*J5lrQ& zx0n+1iWEQ|&;$`GAVL*HsKW^jkbcgjoc!eM__WeIO;9it>wr=UqXr`fBNrnNqYx7h zn8n4!!6?AU!^pwJ!N{RE`4YRHILP)QQw9bGO{QDSC5h=pmLP*!CW~{}YJlum$#jcJ z&)^ngSrLc_As{x|6sMLX=jRsKMNF>YP-o<vyoAHw7-V@7DD`PF7HNS@vSwglSjkvq z24aIv0Bh#5$;m8+=#HAK#u?8BisB;n$=#gBY+!BLlaFv31i~E$cGWG$#9NF>w-}R) zI6$GpoLyFYi#flv<Q8MvEyh%c)9gX^fURIHD$R?}1esf`1`Z59MlR3Eu3U<|K_K6< w7rB6x>P#-?GBGIv2|)}1yAe!)P2sS~%}*)KNwou|#bS`X9E=={Jd8Zd08Aj#uK)l5 diff --git a/src/snipper/__pycache__/fix_s.cpython-38.pyc b/src/snipper/__pycache__/fix_s.cpython-38.pyc index 82d5e8e8b679eff28ef31891521b5b451b77d499..9ee4629819d4fb80d652bde8b91cbd64e3ec86af 100644 GIT binary patch delta 1197 zcmaFCwU~!5l$V!_fq{X6<+o*`8v8^(8OE-O+A7%$DJ(gxxolBvj0`EPDQqnaQS2$~ zDI6^fQ5-3pQJkq<DO}l1MQy3<shkVA7cw+6M)9QbEZ|+p;KC5A5yKS47sa0{kiwnH z*UZGokSdVEvp_JFe<5QtBbdhvq6=eEn1UHJ`6jMY)6`_V#g$f?lM`QDQj}Sc%m{K3 z6tgohFt9Q(FgP<XFcjBJd@ojSQOi`rl)@y*uz)#*IfZ2*Q?W$}OAS*Bt0Y4+BZ#(P z$YZDhvDhRTBpDX4)-Ww(WMn85%4Dczu3=oj26m-f3{x#jEi1%VHLNZS&5X5dHEcD^ zH7qs^g%LH(!3>(5RniJUsU@XFc?!jOnFYlPX+`<Dlj9iq75R!w5{pXWOA^!L6N}P| zqd2ltQwvHG(~I41u_oo@CudL2VRVryVq;)nSjnKte2YoX;1*-@EykQ84h9B>B96&t z7+o1fCkrv@)Uy{cF)%RPV#&!YE-7LLF`3g-ONv-PEVjggg4Dc}TdbKSskz0P?6+8R zGV@Z4qu9W96c>S_?iO2qX-Pq8Nf9WdZZRe2N3j)yRY9!+*~bGij5R&AB)%Brq+$_J z;4*PA@-Ye2GYYYaFtIQSF!Hf-F&2q3Ffb&8Tme!6!XWp8tO1ArAqED95{4R3STUC{ z)-X3SrZ8r+6ls+(Wic;csbO5mSgcjTw15@FVq~achK6-l3^=T7m{J(BIg8?Im=>_7 zFr_drWU6IKsb{HSn$0kmDV?!~Rh*%gHHCEnM-A&j##*)#&KkxPW^o3v;as3dOkqf2 zYh{vT5N9Z1tYLv#J|l&_hDDqqj|oJkaELRca5gjb3)HgLurJ`QVFN{dID;ueAVUyC z1Vf=w3PUi1CYN6kD2@GMjQLg1s9(jTtZ<8w>*e47|Nq}&jIUzWE2zB1Sgy$f4vkyP zIjMQKnDUEnu@oehWZYuSEKbQRy2YBCoswBpBnS#w_M+5+oW$hRTP#`mnR&NZ@(WV) zZgC_f7N_PV=BD0aEicL}N!8>i5&|jaf<#w5$Pmu7%<!Dlc#yeK?8*6gC8>Fkc#LAo z$+^XxUs`gDF%3N)*@_d(QsaviK^X!Zk&GNn5{z6-0*oAtJd6U2Tucs(MOu@CS%S4B z7#J9;xNPA-Q|K0Va(+%uYH~?teqJ#+<rT?-Ts8Rui*)@h5l}KONG;NX(($>8nR(!( z2o8!OEs#>CV#8Y;@$n$9#mC>`DlW*$EP*6AVNhBFhX`Z#Eyl82tOZ4xc_l?kAYo8C rLiY)WO>TZlX-=vgC^CvAq!}0(c)*_EVd9YH5MbfqU<P}Lk&h7oFQ6$d delta 954 zcmZ3?^MZ>nl$V!_fq{Wx^&!*5b1W12WEkrvYOBPvq_DOyM6sr@rLea!M6soCM6suG zq;O_46;-9Orm`>KT*%PO7{!&!wSapeg9}5fMhsIFPZVz|UkX<$PcsuELn>bi_X7S@ z-i3_Kj9?xQh%O9BVG3r@<ej)ntv;C%WG@u6F)%Q&FfcGUGcYg|hcPfPlrWSqHZ#^T zmN3;Yq%bx!xiG|v)iTvE)-a_oNis+>EMTr-TFA)AP$-niP|IAyxPS%h4yhQXT9#VY z6y_9`7KR#D7lvlW8s-`n8-_x&8s=aIP1Y)Dg`m`u(xSY{lNqHZpJ#NIxy724lb@Wu zl0lRC7L%UAEym<qj5$Rh2NkhR)?spG<egl^q*KpY#KgeBaEm1;v$&*)8N_5uEGS6L zOS#3GS(2JttjTtZH77GKwfGhr*u3H*4zQy9(vpJGk|L1jZZRe2Lk(tNU?>8G`z_Y= z)ROpOR*<*(Kw-he!N|ub!o<QTz$n64B+S6TkPNbnVX`T+Nc}2sz|=4_GuASfFlI3= zV6I_Y$XF~_!nlA1#A0NqVP3!r4v0EPK-4g$Fl2KUxur1HFwJI|%aqPo!z#{D%bLQp zfUSmgA!99D340A=3bQx^*gOtUpr$aSu(UEsGKe#jaMrLiGp4X+vlKO?u+>Dch%@9d z)v$;&q_B%Kq;NDd^$XOp*RU_(s$m1gML2^gLm)#CLj*&iS_(rjgC?h66_c{UEk>?i zjQTJC{{R2K2o&eH7~`v$^$IF)F_vp`gS|M}fkm<&<o#PLS^1fHw^;HEQuA(cBqbK7 z<|XE)-eS&4&AY`~UX)pqs>xBr4+>W<NVvwQWEMqnre)@&#up@(WZYs;&d)1J&4Yz^ zPR=dn{L+$JjA`iM&Q_dQmKt9y019{^P{0c_axn5Raxn@paxe-oaxpqE7O7AE$P%n2 z!oa{##bpZzngX}Dlk;<OQj<$E^Ye<q$)ZS-fq@}vavrNRJJ>@->XTQq%0&o*q8aQj z#_U^+Ww%%hiZb&`iey2;kOT&2ffECVO>TZlX-=vgD42@H7#J9MK(1oq;O5|A;o)HB J0lSQk5da>N-%<bo diff --git a/src/snipper/__pycache__/load_citations.cpython-38.pyc b/src/snipper/__pycache__/load_citations.cpython-38.pyc index e79c0857a12b2136f7aa6dcb235a3dc9c4293688..d56371f0185a8d8fca7bfd94be7ecc44f1d2f380 100644 GIT binary patch delta 1403 zcmeyYc1MISl$V!_fq{X6)x$cmN_HZj3}etlZJm0C6qX#eT=pn-MursD6t)(ID2^2N z6pj{#D9#j~6s{ER7RD&96vki%P2QIv?S7h!x7Z4DO4Bp*K&+(9q>|JMO~zX+<%vak z$&4T+P|U}`z`)7Cz~Iclz)&o}$iPs-kj1!wsfJ-8W3fyLa|&Y(gE&KdGb1BICPOeo z2}=z_3R5#vKVL0l4dVjVg$%V!;S8n>feb+m5e%6Owahh4E)20JYFTPn7O*X30MqO# z%nKQdoKje7ShCrQoN8DWaHOy<WUOTcv)C3g*0R;G)Uc+oi!;=)wK7RE)UtzRIBHlI zGNo{eGt|~|fCac}I2JP1a@MfaaMW;u6>`;Zr7+ZRE#OGuUdRX*;jZDT;ab26;)4uK zVE~Kr)NrTpWHS}LO5v^Hnaz;GH<!7VH&393djZ!%h7^8rh8iAmhFabl-Wu*2o)m#O z%r(q4>^2OAPBqNI44Q)VepNEg`K3823VHb@3Tc^nDGHDvRY=RsNwreA#aL9u8IzY< zo|BlAnp4H<kX)3Sc8jsPiVe)FeF+NjD(33y=$Fh43=FpzYkx7u-r`6tEKMxQ%+IT0 zO)b<@(D=ou`HN9Ollc~BUS@JC*r+IuqQvr?M8%}koLg*prMXF|MVj2VnDUEnu@oeh zWZYs)t;j4cDK27}Je|pri!X{jv9to@q{+{jECl!&7#O11^1ueIWGGUdtk3Mt#{r6G z9Z=*m^Dy&F-Y6tLc{MX9qx$Bp%-l?jRg(|0N;6hXzRN1lST*@Ct5N_f$h|D3C21C# zjJG&a^OEyZGV{`3{`>#`|1E|pmYC9_oFaAx28Js3n3B|rlBBdMb{qZTg2X(#UyOED zEDAPBc2%r4`bl;QFTu(t=d+2`Yk~}AEyzjC%qvm>u{l7F&P&Wq)s!w0U|?V<5(E)K zAc6_x3vN)D$3qfy5jY6h0uqagQ;Uj(LDD=0AWnR7Nl|KIZWLcyeo<~>NqlNvNl|8M zaghwj2DY-qoYK_dTTGexw<fc&ONc~qmltK0q=Hpd7Ab(NQkiVPZeA}AQqEqKT9A{N zoT@1r#h#Rz1ae*!PeCOp8^srwROX~c2}5}qCAm5ANr}nXsd*_;B2YoF*WjYOFj0^z zi;AQ`7O<owmLx{;fyj7>drMMNZm|@lrlb|$Vg)(9vd9wbxBSwQg3^+Bu#rWekSj6* z8Nggxlyi$Q^A=-4kvxdclxY;joRU#;iz&0TNEPHAFrfyL<4R90iHD?EeNg-dP0r(& zn4H96!^~FXIe8(+@p@1Z0FK9BjL}7)5~zrcfq_Aju?Q3znjE(ni*K<Omn0UIfJ5pQ zb4f)>kt@h(#;jW`$(bdow>XPZ(^894^O951ZRZ6?UP)?2JV;?K$N?gt1jxw3$iv9N z$j8XTs3gF|$0)-j!&npqvX-d`lwpdzKx}SEf-sx>T}UGw9Q7QaLM$^cy|{=4<V|%D o;Rzx@dXX$g_@BcjH$SB`C)EyQY%!?F<6z`q<N-lu4s{MY0Cf3&WB>pF literal 4979 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 VHTys<ULHms77ld|4=#QVcL0osoqqrT diff --git a/src/snipper/__pycache__/snip_dir.cpython-38.pyc b/src/snipper/__pycache__/snip_dir.cpython-38.pyc index a8205b9d82839835b55f286b4d28b2c5c8467e71..4ce3da3636250429478c87ecb3bafc063b86f0dc 100644 GIT binary patch delta 1356 zcmdlk&?%rD%FD~ez`(#@o@AZqF2KO>7{o!w91IK$4h#$o#eNgDZ3G!o7;`wHI8xYC zSX0<q7^65R7O2*9BB>W+U|`^8U|?VdX~|(?V5nhCVaR4Gk||+Wz_^g1ma&8>g)xPx zhOwEMk)eheEN4{0oWhX8kj{|8+{;|cT*CquwM%EHWvO9FVM%8+XQ*W<VaZ}$z*fV! zkg+(fgk=Fch{ebN60KjrQNys1u@=l(zyXq|WvpQW8`1|-uz(XJpTa86P|F17bJQ>` zWQ4N0Y8Yx57cv!XDB(_FYi4X>tYIzMSHiP^7i12|0+>}bjJ2F8>@^ITjI~@POeq{S zTq*3546_+h>N#sTXEV%YX=Vf|hq-bBV-X9IF+2<SAQmw)l<+SQNa0!tQY}~_RKwWJ zxIj3Cdm&>pV=Z?&LoH7Yw+ln8Q!OvpsUl!fv<BoHriF~14DAeQj43=Rye%9xEG`Vq zjJ16AH9QN%YIsY;YxtTOc^J}|Kt@ksEHp{stL3lZabbw<i(#r2s1*boB~c@=kZ}TI zaYKn@jX*Qw0;v>!5Wfh)2g?`jn!s4tP$M{jv8W-Pp;jo9p;ov=x<(+4v4*XNsfN8q zsD`nIxrQS}a85mYjqr4)KE_&+8j%#fY?cX3MJy#uH6pVaQiN&*W;4uX28B!we~pMa zLoGkpSdgQFVwh@0p^oCH5naewD_SEsfvFhcV;PXh1g0X75|#zBAT}dIo($9jqA9}S z3=0`2Fcpb_LO2#8J%OoEq=rA3K~u!9iZi-6FSDQ^wJ5gAJ}+M(CAGLDGcU0uGe1uu zC9_DOJh51zxF9t-Gc7YUMWHxfp|m(NFI^!oKd(47uQ(N1z13uWW+`!At@!wY%H+i4 zjMVsettxi?{L+$w(vry@%qncRSdtQpQzzFmtMgT{DCpWLq|cfO0y`(~WM0W=Jvo`h zl#4Syy(lpyRj;6OvLdUg$1P5fmiU6il8jqiMX712MX7nosl~T=ax#-a4v5c4O-!j` zvQzlQ7^5k7i=!kpw;(MuC-oM4ZgvWYbBnd0C^N5Qawn^f9(zh=QC?zh>Mf4q#N1S{ zGEUcu<kSL?cW<#3XOxy?=G<Z{$}K5MO}#bwA*&+et;x)6)+$9z3=9mn*fNX3df19m zbMwnmHN|dm73Y^0C8x%xWES0;oXsZ1cx!SSo4jX{00RR<ksyc=1!-i?FD<#nlu>?* zDW^D!D=`^lV`5TH>Mh2cTa3B481rs1rrlzLh!+Wgbg*TYCl;j_PiA7*tuFzU8C)EU z9E?0n9E^NS9E>bXT#P)7TueNSJd7NS0!%!Ne2g4SER0-?TudyC98407d|+8FCLu-^ zMh-?XMj=KCP8Jp(Mm<IrCN^#sMiy2+MkWya%fiC+hmDnsQHT*_8V@5IBOfCVlMo{x zQxT{v)8r8K^Yily2?_Dj<SLQ|c}W@Mz{$tiH3if_Tu_l#Bo1OZO#aQTrXa(>z#srN S4CG`EW(GzuWB`+l3_k&QHdxRA delta 1399 zcmeAa*e;+Q%FD~ez`($ucg!R)k&l7lF^GeVSr`}?92giFirpq^+i<d{u%@uJFh+4q ztWd3ILsBQnz`(%Gz`(!^Qd-5tz)-`S!jR2WBv!(Z!jQs{&XB^`%UsJ`!vYpnN@u8L zDPhcFTEJYxxR9~fqJ(h)3y8(Y02O6g$XM(L7G+w<2o+_mVOq#o%LG=zTEkGkkg*n` zoE4<CmJuw$R>M%kxR9x+ql7($shP2fv4*v1S_#JjPLLXqK`@JI7;8alSyGtiFx9e` zaHX)+u&1y}GR$U3VXI-A%`lgx8D=rqkwte9rhrw}Gt_dFa4g`i;Q(34$WX$wfH#F5 z>{`AO{u;(+#svZ?919tn8EZMy8EUy|I9(WGooczk&J+ZbLN(kVy$cyT8QK}r7*jY? zxLP=BSX>yI8EbiJxE2W4aF>YG@H8{>Fr<OQVFF{JND6l?Zw;3VLw)R?7^YgjT7Ixm zqBVRA87D9nCzOcQ@HI0o5KrL&^SdT67AAmIK&*tSD_T^;m&XMbmjLNp$XF{-!#{zs zC?TC8g*Sz74pXgQCPS@IIzz2+CPS@A3V*F=3V*FwiDV65jbIv6jaW@RQ;leiFv#~c z%qaqM*lR?lGxagnir0vzaA&hjU@8(S;i?gz&5$Bk!#A5@E;A@NYj|tK%^7NWL5>3X zAvP$6sa68&1=bpgg^aZlHT)Bpij}}llLCoMU@8hLVO$^$Vly)2$$(`<Ya}dEgv1#Z zGEQJBQUb?}1SseyFcm7*@CGwz3j1j?-(pTIt+>UOl$lhLT5*dbIX^cyF)yWf@-k)> zVNIr6EJ=yQsZpG%70EfJ#hLkelP@r<3m367FfdfHDCpWLq|cfO0w*W4vaDn@oxGmK zv_93fA~ClhCsm=iq%<WpuS6j^KP6R9AtWQSSRpMlCsiS{SRt{rBtJK?Br`cNC#O;& zJvA@2D6u3pMIo&yKUbk7BNeQ$SRpeH%*o6vE-5NaF3B&_P01`u1u-f$nWFgeQp@9u zQqxk4QuC5ii=+5J7R7TV=ND8KWu|A8giL<NVrm>En3<QHQ<{<*UyxXm5fAduElv;# z=HKE%7*NGzr|^q0MpI^THmlC$1*|dxQEWxIB}J*Jw^$2`GV@BJCLd*0WQ>~poYmUn z7JEu&QC?zhY7r9y1H&!0%wmw=Zm|`m=H{2BYDz|N73Y^0C8x%xWEMqnq@)&?fLOP< z@=Hq!O2O<R5e5c^sL6?J^88WE`K2XMOc~|ikd2x=lTF$<iY+lYIkli9iZu<alO;1R zE&moP$P>jyLSQ?y%M**zi;Dyq7#NBK7#J8PpJdamuK|@fY#fYyOdO0XOgxNSj6957 zOgxMr$j8XR#KOqM$i>XU$i&F>pN&}pEXx5>$0Wqa!pOlW#wf%n!OFtI!zjnd!l=f` z#>vIV0*3-1eT+<hSy-6<u(5J63W3aJ;$dWC<YVMv5@O_&WGXUcU|`T>@$>Tw(c~-= s2RTj-?9(oGO>PAcmlH&oPCm@8CI<3|0LTnR4n_`E21W)(1_p*d08Rd8CjbBd diff --git a/src/snipper/__pycache__/snipper_main.cpython-38.pyc b/src/snipper/__pycache__/snipper_main.cpython-38.pyc index fd90def87e043144655478d490c81d7f34538bfe..44240208f1eec24853d05c9805203b70e188365e 100644 GIT binary patch delta 1307 zcmca2a#376l$V!_fq{XcAlW+6i=TnvF^GeVIT;uj92giFiYH9eE>RRp;Ys0bVT=+= z5l-Pt;csD#5>63F5o}?I5=mhUX3!MbxMMR@J=jF3A<_&C4BQM149*}kx|kRkYB*9D zvYCo_G8t+)QW$HwN*HPwQkYVhQ&@VLCouJE)N<EwFJN5AP|H)pvw#UoGpDdFWUS>a zVX5J5W^`eQwTfY?<*Vhd;a|X-!nTkxg*}_4D6fRAhG8~C3P*hn-)x2y&bchjjEoF5 z{0rDqxKg+mGS%?b@YygFx>O03aMbYDaMZA;@bog*@`f|yS+FpaaAtEAonmCD6<}nj zk}6@V5di5fVN2nyVQ6MzWT+8nVhm?6Wk_MD6{r)4V2EVMV~Sv?VJyB@!#shpsHlc1 zg&~_0#7eJcs1>YXN&~r5t5&E+Z~<2dcNWhA-Wnk=%~!*)kZ}QX3LnVbk_-!(7BVt2 z6uznvOktN~SiqjbpCYi33B<Eus9~JISQJviU&C9&01}a8ND=I1W@IQ4Ko@~HqC~KU zw}iVsi)VpQ4MPpvLZ%v~6d|w%;Tql);S`Y+(RAi!rdr+_)(MP7i%LXlcx$*o{1Q=6 zz{W7w^41F1isZ4Ru-6Kgh=IhwYMF`zO2lhKn!y1*fvHHKh6U_f5Q|}f#6pHz(HhYO ztSMp(8EeHr{ufUXPmyS0s1b2tXlAUHC}F9Q0LPnH3{$OGtz?b(0<Id#G)9omComTN zC=mx)1&YN9Ohr~8UW%k71Kc{R8r}t5DN-QSDXa^4Yj_tj)=GgQBak78A%dZX6Y7|x z63H5=8cwZdrdla*vXV}b0VS(`0dS&{ssS5;q)~YC6V@e+QIk8_rZ7fLmScBfl%AZ( z9>=IZ`2f2|0B>4mMSOC8L1j^9dPd1D*7Bmvl2lFUA{_<>hFhFPrFrpbnK`M&w|GFz z{L+&6l+2>yTb#+IB~S_8;{2S_lFa<P_?*n*l3SBKIb@}7aTTSer52^;C4+S4WG1KP z6{p5$q$Z|JF5+-!yft|jhbCJBDD$vSe#xQ4C^DIcQ@37$k&97;iHnhoS%6W5u_%;* zfgza*qzH;ZY*tt<Q($0VNMT$6&Q&c8HH@I#1d4}+j46!b3^fem48aVVEPh35AX6Bj zCV(iIDZ!w;D#5_Okj_xU5Gzp2Sf2tihG8LtIKxDyLY80#O~xuFWd%*fTdc(;MVSSf zOhpC^3=Bp7AVLaGfbxEkA&3hykcEMPfsKKQp-K@YT=i^n@{<#DitY4lK%tbJpIcz3 z$yB5d3S_S0f}G5foJ_yG)M8DhB43bE-XH?a4krc%hC+}XARjO=7J>Mhj3JtwA$}0( wrzu)w1JWqSz`zhSIf>JmF>3NM&SW-FNESIw=HgOgRGDnZrNqj}@S7_T0KPXf;s5{u delta 895 zcmca8enmt(l$V!_fq{WR;*4pc0v`jzV-N=!b1*P4I503U6n9M2E|C;S;Ys0bVT=+= z5lrDr;csD#5>8<ZX3!MccwjSAJtvYzDFy}xZUzPhXOP}FCI*HYjueJ$rXrq9hFXpk z##+u2h8l(xrWEEBmR{xwO#K42Ts2$^7#A|sa@TM#V1m-jDXa?_Yk5joYIvF%T^M4m zVwh@qYx!#U7O<wUEo4k#&t@sgD`Bf)n9Y#FQD4J5n<0gBE=w~bBSQ_}0`?TH6z+vg zH9R%EHVlO>RYD~kH9R#OHS8%oz09>d;S6~eEDR-_*<3}Z7#V8$85ydiO4w@nLAp!W zQg~|^nwc0GYWSNN!x>B&QW$Fa>-ZxWA{p|SA{c5Ii?7u%Phc#{NN1=Os9{P2IgVee zR<K530apok7S96S8o|k3EYhA2Y6Mc)B^eg5r|_o;EMx-lY#3@7ComRymGIZ_)G&ZV zBpFf!dzl#-N(9hFAeNK}*6>Vz$0A<OlOmiVk|LVU+{{$VQ^Puev1mq#NDWU7Cx~An z3JRqd=31Uwp<3ZQmK63{p%O8W7+5V+5nG9Pjc_wK)Fv<$vDL7oFl2LrSquv#7BbX| z)QBu#O%YqjSSy;&P%D-qo+8o0P$TTZ(9BpXUcyo%UJs50u^6UW(OQWbu?1W;5^0PJ z85tQSFc!Wm5wGD%k(6YBTcA|Kvw$l_3M8Mxx`4NaXCY&)Bq%Hc8G;xh7{CcYIz<MQ z0HDz?StAKjjZjk~6wIJ0>*schvFH{{X~|?&w&{$wChujN!WcO@h~0@%YVuU}I7WlX zU)VhyS<8zuOHwtZigXwl7@|0fO7r5=GILUkqj*5f{L+&6l+2>yD9+^45~u`kaehu| zNoIatd`@O@Nz~*X4q2WkuA<bm)S}e9<kaHHhdJCCqb756YO=+Ek~Z69D^4XwuF0{S zx|%|aT#O=20*oSzMZOFS44RA~nj9g15U43qWXr(7P$bB}z;J8wH7;kyTa%@@lNo&{ QH*>2oDokF*t;F~T0Ax<wy8r+H diff --git a/src/snipper/block_parsing.py b/src/snipper/block_parsing.py index cfad9c4..23d4271 100644 --- a/src/snipper/block_parsing.py +++ b/src/snipper/block_parsing.py @@ -20,31 +20,41 @@ def block_iterate(lines, tag): yield contents +def block_join(contents): + blk = contents['block'] + if len(blk) == 1: + blk = [blk[0] + contents['post1'] + " " + contents['post2']] + elif len(blk) > 1: + blk = [blk[0] + contents['post1']] + blk[1:-1] + [blk[-1] + contents['post2']] + return contents['first'] + blk + contents['last'] + def block_split(lines, tag): stag = tag[:2] # Start of any next tag. - def join(contents): - return contents['first'] + [contents['block'][0] + contents['post1']] + contents['block'][1:-1] \ - + [contents['block'][-1] + contents['post2']] + contents['last'] + contents = {} i, j = f2(lines, tag) def get_tag_args(line): # line = line.strip() k = line.find(" ") - tag_args = ((line[:k + 1] if k >= 0 else line)[len(tag):] ).strip() + tag_args = ((line[:k + 1] if k >= 0 else line)[len(tag):] ).strip().split(";") + tag_args = [t.strip() for t in tag_args] + # if len(tag_args) == 0: + # return {'': ''} # No name. + tag_args = [t for t in tag_args if len(t) > 0] + tag_args = dict([t.split("=") if "=" in t else (t.lower().strip(), True) for t in tag_args]) - if len(tag_args) == 0: - return {'': ''} # No name. + if '' not in tag_args: + tag_args[''] = '' - tag_args = dict([t.split("=") for t in tag_args.split(";")]) return tag_args if i is None: return None else: - print( lines[i] ) + # print( lines[i] ) start_tag_args = get_tag_args(lines[i][j:]) START_TAG = f"{tag}={start_tag_args['']}" if start_tag_args[''] != '' else tag @@ -62,7 +72,7 @@ def block_split(lines, tag): l2 = lines[:i] + [lines[i][:j2], lines[i][j2:]] + lines[i2+1:] c2 = block_split(l2, tag=tag) c2['block'].pop() - c2['joined'] = join(c2) + c2['joined'] = block_join(c2) return c2 else: contents['first'] = lines[:i] @@ -81,7 +91,7 @@ def block_split(lines, tag): contents['arg2'], contents['post2'] = argpost(lines[i2], j2) blk = [lines[i][:j]] + lines[i+1:i2] + [lines[i2][:j2]] contents['block'] = blk - contents['joined'] = join(contents) + contents['joined'] = block_join(contents) contents['start_tag_args'] = start_tag_args contents['name'] = start_tag_args[''] return contents diff --git a/src/snipper/fix_bf.py b/src/snipper/fix_bf.py index 3a128bc..c4d5254 100644 --- a/src/snipper/fix_bf.py +++ b/src/snipper/fix_bf.py @@ -1,6 +1,7 @@ import functools -from snipper.legacy import gcoms, block_process +from snipper.legacy import gcoms from snipper.block_parsing import indent +from snipper.block_parsing import block_split, block_join def fix_f(lines, debug): @@ -29,39 +30,53 @@ def fix_f(lines, debug): comments = [id + c for c in comments] if len(comments) > 0: lines2 += comments[0].split("\n") - # lines2 += [id+"#!b"] f = [id + l.strip() for l in funrem.splitlines()] f[0] = f[0] + "#!b" - - # lines2 += (id+funrem.strip()).split("\n") errm = l_head if len(l_head) > 0 else "Implement function body" f[-1] = f[-1] + f' #!b {errm}' lines2 += f - # lines2 += [f'{id}#!b {errm}'] - else: lines2.append(l) i += 1 return lines2 +# stats = {'n': 0} +def _block_fun(lines, start_extra, end_extra, keep=False, silent=False): + id = indent(lines[0]) + lines = lines[1:] if len(lines[0].strip()) == 0 else lines + lines = lines[:-1] if len(lines[-1].strip()) == 0 else lines + cc = len(lines) + ee = end_extra.strip() + if len(ee) >= 2 and ee[0] == '"': + ee = ee[1:-1] + start_extra = start_extra.strip() + if keep: + l2 = ['GARBAGE'] * cc + else: + if silent: + l2 = [] + cc = 0 + else: + l2 = ([id + start_extra] if len(start_extra) > 0 else []) + [id + f"# TODO: {cc} lines missing.", + id + f'raise NotImplementedError("{ee}")'] + + # stats['n'] += cc + return l2, cc + + def fix_b2(lines, keep=False): - stats = {'n': 0} - def block_fun(lines, start_extra, end_extra, art, stats=None, **kwargs): - id = indent(lines[0]) - lines = lines[1:] if len(lines[0].strip()) == 0 else lines - lines = lines[:-1] if len(lines[-1].strip()) == 0 else lines - cc = len(lines) - ee = end_extra.strip() - if len(ee) >= 2 and ee[0] == '"': - ee = ee[1:-1] - start_extra = start_extra.strip() - if keep: - l2 = ['GARBAGE'] * cc - else: - l2 = ([id+start_extra] if len(start_extra) > 0 else []) + [id + f"# TODO: {cc} lines missing.", id+f'raise NotImplementedError("{ee}")'] + cutout = [] + n = 0 + while True: + b = block_split(lines, tag="#!b") + if b == None: + break + args = {k:v for k, v in b['start_tag_args'].items() if len(k) > 0} + cutout += b['block'] + b['block'], dn = _block_fun(b['block'], start_extra=b['arg1'], end_extra=b['arg2'], **args, keep=keep) + lines = block_join(b) + n += dn - stats['n'] += cc - return l2, cc - lines2, _, _, cutout = block_process(lines, tag="#!b", block_fun=functools.partial(block_fun, stats=stats)) - return lines2, stats['n'], cutout \ No newline at end of file + # lines2, _, _, cutout = block_process(lines, tag="#!b", block_fun=functools.partial(block_fun, stats=stats)) + return lines, n, cutout \ No newline at end of file diff --git a/src/snipper/fix_cite.py b/src/snipper/fix_cite.py index c4cfb1c..4b49641 100644 --- a/src/snipper/fix_cite.py +++ b/src/snipper/fix_cite.py @@ -19,7 +19,7 @@ def fix_aux_special(lines, aux, command='\\nref', output='\cite[%s]{my_bibtex_en def fix_aux(lines, aux, strict=True): l2 = fix_single_reference(lines, aux=aux, cmd="\\ref", strict=True) - print("\n".join(l2)) + # print("\n".join(l2)) return l2 def fix_bibtex(lines, bibtex): diff --git a/src/snipper/fix_i.py b/src/snipper/fix_i.py index 0d17a39..28b5bfb 100644 --- a/src/snipper/fix_i.py +++ b/src/snipper/fix_i.py @@ -2,6 +2,11 @@ import functools import textwrap from snipper.legacy import block_process from snipper.block_parsing import full_strip +import os +if os.name == 'nt': + import wexpect as we +else: + import pexpect as we def run_i(lines, file, output): @@ -14,11 +19,6 @@ def run_i(lines, file, output): lines = textwrap.dedent(s).strip().splitlines() if extra['python'] is None: - import os - if os.name == 'nt': - import wexpect as we - else: - import pexpect as we an = we.spawn("python", encoding="utf-8", timeout=20) an.expect([">>>"]) extra['python'] = an @@ -34,8 +34,6 @@ def run_i(lines, file, output): lines = l2 alines = [] - - # indented = False in_dot_mode = False if len(lines[-1]) > 0 and (lines[-1].startswith(" ") or lines[-1].startswith("\t")): lines += [""] @@ -57,14 +55,8 @@ def run_i(lines, file, output): if 'help(s.find)' in word: pass if dotmode: - # alines.append("..." + word) alines.append(">>>" + analyzer.before.rstrip() if not in_dot_mode else "..." + analyzer.before.rstrip()) in_dot_mode = True - # if i < len(lines) - 1 and not lines[i + 1].startswith(" "): - # analyzer.sendline("\n") # going out of indentation mode . - # analyzer.expect_exact([">>>", "..."]) - # alines.append("..." + analyzer.after.rstrip()) - # pass else: alines.append( ("..." if in_dot_mode else ">>>") + analyzer.before.rstrip()) in_dot_mode = False diff --git a/src/snipper/fix_s.py b/src/snipper/fix_s.py index c740280..5a97096 100644 --- a/src/snipper/fix_s.py +++ b/src/snipper/fix_s.py @@ -1,26 +1,47 @@ from collections import defaultdict import os from snipper.block_parsing import block_iterate +from snipper.snipper_main import full_strip def get_s(lines): """ Return snips from 'lines' """ blocks = defaultdict(list) for c in block_iterate(lines, "#!s"): + # c['start_tag_args'] + if not c['start_tag_args'].get('keeptags', False): + c['block'] = full_strip(c['block']) + else: + # In this case the #! tags are kept in. + pass + # print("keepting tags.") blocks[c['name']].append(c) output = {} for name, co in blocks.items(): - output[name] = [l for c in co for l in c['block']] + slines = [l for c in co for l in c['block']] + # full_strip("") + # c['block']['args'] + # slines = slines[ 23] + # co. + output[name] = slines return output +# def _s_block_process(): +# +# pass + def save_s(lines, output_dir, file_path): # save file snips to disk content = get_s(lines) - if not os.path.isdir(output_dir): + # Only make output dir if needed. + if len(content) > 0 and not os.path.isdir(output_dir): os.mkdir(output_dir) + for name, ll in content.items(): if file_path is not None: + file_path = file_path.replace("\\", "/") ll = [f"# {file_path}"] + ll out = "\n".join(ll) + with open(output_dir + "/" + os.path.basename(file_path)[:-3] + ("_" + name if len(name) > 0 else name) + ".py", 'w') as f: f.write(out) diff --git a/src/snipper/load_citations.py b/src/snipper/load_citations.py index 786c02b..0512cd1 100644 --- a/src/snipper/load_citations.py +++ b/src/snipper/load_citations.py @@ -1,18 +1,17 @@ import os import io -# from coursebox.core.info_paths import get_paths from pybtex import plugin from pybtex.database.input import bibtex +from warnings import warn ### Newstyle loading. - def get_aux(auxfile): # paths = get_paths() # auxfile = os.path.join(paths['02450public'], auxfile) if not os.path.exists(auxfile): - print(auxfile) - from warnings import warn - warn("Could not find file") + # print(auxfile) + + warn("Could not find bibtex file: "+ auxfile) return {} with open(auxfile, 'r') as f: @@ -104,17 +103,7 @@ def get_bibtex(bibfile): 'filename': url, } - # newref = {} - # ls = lambda x: x if isinstance(x, list) else [x] - # if 'tex_command' in gi: - # for cmd, aux, display in zip( ls(gi['tex_command']), ls(gi['tex_aux'] ), ls( gi['tex_display'] ) ): - # ax = parse_aux(aux, bibtex=gi['bibtex']) - # for k in ax: - # ax[k]['pyref'] = display%(ax[k]['nicelabel'],) - # newref[cmd] = ax - - return refs#, newref - + return refs def find_tex_cite(s, start=0, key="\\cite"): @@ -132,112 +121,112 @@ def find_tex_cite(s, start=0, key="\\cite"): return (i, j), reference, txt ### Oldstyle loading -def get_references(bibfile, gi): - """ - all references. - """ - if not os.path.exists(bibfile): - return None - - pybtex_style = plugin.find_plugin('pybtex.style.formatting', 'alpha')() - pybtex_html_backend = plugin.find_plugin('pybtex.backends', 'html')() - pybtex_plain_backend = plugin.find_plugin('pybtex.backends', 'plaintext')() - pybtex_parser = bibtex.Parser() - - with open(bibfile, 'r', encoding='utf8') as f: - data = pybtex_parser.parse_stream(f) - - data_formatted = pybtex_style.format_entries(data.entries.values()) - refs = {} - - if 'auxfile' in gi: - all_references = parse_aux(gi['auxfile'], bibtex=gi['bibtex']) - else: - all_references = {} - - for entry in data_formatted: - output = io.StringIO() - output_plain = io.StringIO() - pybtex_plain_backend.output = output_plain.write - pybtex_html_backend.output = output.write - pybtex_html_backend.write_entry(entry.key, entry.label, entry.text.render(pybtex_html_backend)) - - pybtex_plain_backend.write_entry(entry.key, entry.label, entry.text.render(pybtex_plain_backend)) - - html = output.getvalue() - plain = output_plain.getvalue() - - entry.text.parts[-2].__str__() - url = "" - for i,p in enumerate(entry.text.parts): - if "\\url" in p.__str__(): - url = entry.text.parts[i+1] - break - url = url.__str__() - i1 = html.find("\\textbf") - i2 = html.find("</span>", i1) - dht = html[i1:i2] - dht = dht[dht.find(">")+1:] - html = html[:i1] + " <b>"+dht+"</b> " + html[i2+7:] - - plain = plain.replace("\\textbf ", "") - iu = plain.find("URL") - if iu > 0: - plain = plain[:iu] - - refs[entry.key] = {'html': html, - 'plain': plain, - 'label': entry.label, - 'filename': url, - 'references': all_references} - - newref = {} - ls = lambda x: x if isinstance(x, list) else [x] - if 'tex_command' in gi: - for cmd, aux, display in zip( ls(gi['tex_command']), ls(gi['tex_aux'] ), ls( gi['tex_display'] ) ): - ax = parse_aux(aux, bibtex=gi['bibtex']) - for k in ax: - ax[k]['pyref'] = display%(ax[k]['nicelabel'],) - newref[cmd] = ax - - return refs, newref - - -def parse_aux(auxfile, bibtex=None): - # paths = get_paths() - paths = {} - auxfile = os.path.join(paths['02450public'], auxfile) - if not os.path.exists(auxfile): - print(auxfile) - from warnings import warn - warn("Could not find file") - return {} - - with open(auxfile, 'r') as f: - items = f.readlines() - entries = {} - for e in items: - e = e.strip() - if e.startswith("\\newlabel") and "@cref" in e: - # print(e) - i0 = e.find("{") - i1 = e.find("@cref}") - key = e[i0+1:i1] - - j0 = e.find("{{[", i0)+3 - j1 = e.find("}", j0) - - val = e[j0:j1] - - label = val[:val.find("]")] - number = val[val.rfind("]")+1:] - - if label == "equation": - nlabel = f"eq. ({number})" - else: - nlabel = label.capitalize() + " " + number - - coderef = "\\cite[%s]{%s}"%(nlabel, bibtex) if bibtex is not None else None - entries[key] = {'pyref': coderef, 'nicelabel': nlabel, 'rawlabel': label, 'number': number} - return entries +# def get_references(bibfile, gi): +# """ +# all references. +# """ +# if not os.path.exists(bibfile): +# return None +# +# pybtex_style = plugin.find_plugin('pybtex.style.formatting', 'alpha')() +# pybtex_html_backend = plugin.find_plugin('pybtex.backends', 'html')() +# pybtex_plain_backend = plugin.find_plugin('pybtex.backends', 'plaintext')() +# pybtex_parser = bibtex.Parser() +# +# with open(bibfile, 'r', encoding='utf8') as f: +# data = pybtex_parser.parse_stream(f) +# +# data_formatted = pybtex_style.format_entries(data.entries.values()) +# refs = {} +# +# if 'auxfile' in gi: +# all_references = parse_aux(gi['auxfile'], bibtex=gi['bibtex']) +# else: +# all_references = {} +# +# for entry in data_formatted: +# output = io.StringIO() +# output_plain = io.StringIO() +# pybtex_plain_backend.output = output_plain.write +# pybtex_html_backend.output = output.write +# pybtex_html_backend.write_entry(entry.key, entry.label, entry.text.render(pybtex_html_backend)) +# +# pybtex_plain_backend.write_entry(entry.key, entry.label, entry.text.render(pybtex_plain_backend)) +# +# html = output.getvalue() +# plain = output_plain.getvalue() +# +# entry.text.parts[-2].__str__() +# url = "" +# for i,p in enumerate(entry.text.parts): +# if "\\url" in p.__str__(): +# url = entry.text.parts[i+1] +# break +# url = url.__str__() +# i1 = html.find("\\textbf") +# i2 = html.find("</span>", i1) +# dht = html[i1:i2] +# dht = dht[dht.find(">")+1:] +# html = html[:i1] + " <b>"+dht+"</b> " + html[i2+7:] +# +# plain = plain.replace("\\textbf ", "") +# iu = plain.find("URL") +# if iu > 0: +# plain = plain[:iu] +# +# refs[entry.key] = {'html': html, +# 'plain': plain, +# 'label': entry.label, +# 'filename': url, +# 'references': all_references} +# +# newref = {} +# ls = lambda x: x if isinstance(x, list) else [x] +# if 'tex_command' in gi: +# for cmd, aux, display in zip( ls(gi['tex_command']), ls(gi['tex_aux'] ), ls( gi['tex_display'] ) ): +# ax = parse_aux(aux, bibtex=gi['bibtex']) +# for k in ax: +# ax[k]['pyref'] = display%(ax[k]['nicelabel'],) +# newref[cmd] = ax +# +# return refs, newref +# +# +# def parse_aux(auxfile, bibtex=None): +# # paths = get_paths() +# paths = {} +# auxfile = os.path.join(paths['02450public'], auxfile) +# if not os.path.exists(auxfile): +# print(auxfile) +# from warnings import warn +# warn("Could not find file") +# return {} +# +# with open(auxfile, 'r') as f: +# items = f.readlines() +# entries = {} +# for e in items: +# e = e.strip() +# if e.startswith("\\newlabel") and "@cref" in e: +# # print(e) +# i0 = e.find("{") +# i1 = e.find("@cref}") +# key = e[i0+1:i1] +# +# j0 = e.find("{{[", i0)+3 +# j1 = e.find("}", j0) +# +# val = e[j0:j1] +# +# label = val[:val.find("]")] +# number = val[val.rfind("]")+1:] +# +# if label == "equation": +# nlabel = f"eq. ({number})" +# else: +# nlabel = label.capitalize() + " " + number +# +# coderef = "\\cite[%s]{%s}"%(nlabel, bibtex) if bibtex is not None else None +# entries[key] = {'pyref': coderef, 'nicelabel': nlabel, 'rawlabel': label, 'number': number} +# return entries diff --git a/src/snipper/snip_dir.py b/src/snipper/snip_dir.py index 328e93b..f264c59 100644 --- a/src/snipper/snip_dir.py +++ b/src/snipper/snip_dir.py @@ -3,13 +3,21 @@ from snipper.snipper_main import censor_file from pathlib import Path import time import fnmatch - +import tempfile def snip_dir(source_dir, # Sources - dest_dir, # Will write to this directory + dest_dir=None, # Will write to this directory output_dir=None, # Where snippets are going to be stored references=None, # Reference database - exclude=None, clean_destination_dir=True): + exclude=None, clean_destination_dir=True, + run_files=True, # Run #!o tags and #!i tags + cut_files=True, # censor files. + license_head=None, + ): + + if dest_dir == None: + dest_dir = tempfile.mkdtemp() + print("[snipper]", "no destination dir was specified so using nonsense destination:", dest_dir) if references == None: references = dict(aux=None, bibtex=None, commands=[]) @@ -17,14 +25,16 @@ def snip_dir(source_dir, # Sources if exclude == None: exclude = [] + exclude += ["*__pycache__*"] # Just...no. if not os.path.exists(dest_dir): os.makedirs(dest_dir) - if not os.path.exists(output_dir): - os.makedirs(output_dir) - output_dir = os.path.abspath(output_dir) source_dir = os.path.abspath(source_dir) dest_dir = os.path.abspath(dest_dir) + if output_dir == None: + output_dir = os.path.dirname(source_dir) + "/output" + + output_dir = os.path.abspath(output_dir) if os.path.samefile( source_dir, dest_dir): raise Exception("Source and destination is the same") @@ -33,15 +43,14 @@ def snip_dir(source_dir, # Sources os.makedirs(dest_dir) out = dest_dir - hw = {'base': source_dir, - 'exclusion': exclude} + hw = {'base': source_dir} print(f"[snipper] Synchronizing directories: {hw['base']} -> {out}") if os.path.exists(dest_dir): shutil.rmtree(dest_dir) shutil.copytree(source_dir, dest_dir) - time.sleep(0.2) + time.sleep(0.1) ls = list(Path(dest_dir).glob('**/*.*')) acceptable = [] @@ -50,6 +59,10 @@ def snip_dir(source_dir, # Sources m = [fnmatch.fnmatch(split, ex) for ex in exclude] acceptable.append( (l, not any(m) )) + # for f,ac in acceptable: + # if not ac: + # print(f) + # print(acceptable) # now we have acceptable files in list. # run_out_dirs = ["./output"] @@ -58,7 +71,7 @@ def snip_dir(source_dir, # Sources # edirs = {os.path.normpath(os.path.dirname(f_) if not os.path.isdir(f_) else f_) for f_ in edirs} # edirs.remove(os.path.normpath(out)) for f, accept in acceptable: - if os.path.isdir(f) or not str(f).endswith(".py"): # We only touch .py files. + if os.path.isdir(f) or not str(f).endswith(".py") or str(f).endswith("_grade.py"): # We only touch .py files. continue # f_dir = os.path.normpath(f if os.path.isdir(f) else os.path.dirname(f)) if accept: @@ -70,15 +83,18 @@ def snip_dir(source_dir, # Sources # if "assignments" in str(f) and "_grade.py" in str(f): # continue - info = {'new_references': [], 'code_copyright': 'Example student code. This file is automatically generated from the files in the instructor-directory'} + # info = {'new_references': [], 'code_copyright': 'Example student code. This file is automatically generated from the files in the instructor-directory'} # paths = {} solution_list = [] kwargs = {} - cut_files = True - run_files = True + # cut_files = True + # copyright() + + # run_files = True nrem = censor_file(f, run_files=run_files, run_out_dirs=output_dir, cut_files=cut_files, solution_list=solution_list, base_path=dest_dir, references=references, + license_head=license_head, **kwargs) if nrem > 0: print(f"{nrem}> {f}") diff --git a/src/snipper/snipper_main.py b/src/snipper/snipper_main.py index 4b9e7da..b2f5803 100644 --- a/src/snipper/snipper_main.py +++ b/src/snipper/snipper_main.py @@ -33,7 +33,8 @@ def censor_file(file, run_files=True, run_out_dirs=None, cut_files=True, solutio censor_files=True, base_path=None, strict=True, - references=None): + references=None, + license_head=None): if references == None: references = {} @@ -55,7 +56,7 @@ def censor_file(file, run_files=True, run_out_dirs=None, cut_files=True, solutio print("Error in file, cite/reference tag not found!>", file) raise e - if run_files or cut_files: + if (run_files or cut_files) and run_out_dirs is not None: ofiles = [] for rod in [run_out_dirs]: ofiles.append(os.path.join(rod, os.path.basename(file).split(".")[0]) ) @@ -96,12 +97,20 @@ def censor_file(file, run_files=True, run_out_dirs=None, cut_files=True, solutio # with open(sout, "w") as f: # f.write(sol) - if len(lines[-1])>0: + if len(lines) > 0 and len(lines[-1])>0: lines.append("") s2 = "\n".join(lines) + if license_head is not None: + s2 = fix_copyright(s2, license_head) + + with open(file, 'w', encoding='utf-8') as f: f.write(s2) return nB -# lines: 294, 399, 420, 270 + +def fix_copyright(s, license_head): + return "\n".join( ["# " + l.strip() for l in license_head.splitlines()] ) +"\n" + s + +# lines: 294, 399, 420, 116 \ No newline at end of file -- GitLab