From 971af254abdcdd06c49850031510da7cbd141e45 Mon Sep 17 00:00:00 2001 From: Tue Herlau <tuhe@dtu.dk> Date: Sun, 5 Sep 2021 15:02:48 +0200 Subject: [PATCH] Refactor dir snip --- dist/codesnipper-0.0.2-py3-none-any.whl | Bin 0 -> 14584 bytes dist/codesnipper-0.0.2.tar.gz | Bin 0 -> 13342 bytes docs/build_docs.py | 8 +- .../load_references.cpython-38.pyc | Bin examples/block_processor.py | 63 +++++++ {example => examples}/citations.py | 0 examples/cs101_instructor/homework1.py | 20 +++ {example => examples}/exercise1.py | 0 {example => examples}/latex/br.pdf | Bin {example => examples}/latex/index.aux | 0 {example => examples}/latex/index.bbl | 0 {example => examples}/latex/index.blg | 0 {example => examples}/latex/index.log | 0 {example => examples}/latex/index.out | 0 {example => examples}/latex/index.pdf | Bin {example => examples}/latex/index.synctex.gz | Bin {example => examples}/latex/index.tex | 0 {example => examples}/latex/library.bib | 0 {example => examples}/load_references.py | 2 +- {example => examples}/output/citations.py | 0 .../output/load_references_a.py | 2 +- .../output/load_references_b.py | 0 examples/process_cs101.py | 25 +++ src/codesnipper.egg-info/PKG-INFO | 158 +++++++++++++++++- src/codesnipper.egg-info/SOURCES.txt | 5 +- src/codesnipper.egg-info/requires.txt | 4 +- .../__pycache__/citations.cpython-38.pyc | Bin 5040 -> 0 bytes src/snipper/__pycache__/fix_s.cpython-38.pyc | Bin 3629 -> 3728 bytes src/snipper/block_parsing.py | 78 +++++++++ src/snipper/fix_bf.py | 0 src/snipper/fix_cite.py | 65 +++---- src/snipper/fix_s.py | 105 +----------- .../{citations.py => load_citations.py} | 0 src/snipper/snip_dir.py | 10 +- src/snipper/snipper_main.py | 1 - 35 files changed, 399 insertions(+), 147 deletions(-) create mode 100644 dist/codesnipper-0.0.2-py3-none-any.whl create mode 100644 dist/codesnipper-0.0.2.tar.gz rename {example => examples}/__pycache__/load_references.cpython-38.pyc (100%) create mode 100644 examples/block_processor.py rename {example => examples}/citations.py (100%) create mode 100644 examples/cs101_instructor/homework1.py rename {example => examples}/exercise1.py (100%) rename {example => examples}/latex/br.pdf (100%) rename {example => examples}/latex/index.aux (100%) rename {example => examples}/latex/index.bbl (100%) rename {example => examples}/latex/index.blg (100%) rename {example => examples}/latex/index.log (100%) rename {example => examples}/latex/index.out (100%) rename {example => examples}/latex/index.pdf (100%) rename {example => examples}/latex/index.synctex.gz (100%) rename {example => examples}/latex/index.tex (100%) rename {example => examples}/latex/library.bib (100%) rename {example => examples}/load_references.py (93%) rename {example => examples}/output/citations.py (100%) rename {example => examples}/output/load_references_a.py (71%) rename {example => examples}/output/load_references_b.py (100%) create mode 100644 examples/process_cs101.py delete mode 100644 src/snipper/__pycache__/citations.cpython-38.pyc create mode 100644 src/snipper/block_parsing.py create mode 100644 src/snipper/fix_bf.py rename src/snipper/{citations.py => load_citations.py} (100%) diff --git a/dist/codesnipper-0.0.2-py3-none-any.whl b/dist/codesnipper-0.0.2-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..a3de71167725d94f82ba94271db109d7a5baa198 GIT binary patch literal 14584 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 LW(J0XrXU^wg_8;? literal 0 HcmV?d00001 diff --git a/dist/codesnipper-0.0.2.tar.gz b/dist/codesnipper-0.0.2.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..128343f9db99e65419e5a8c62fb3bed6fa91d662 GIT binary patch literal 13342 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 literal 0 HcmV?d00001 diff --git a/docs/build_docs.py b/docs/build_docs.py index 02f7791..46e7a45 100644 --- a/docs/build_docs.py +++ b/docs/build_docs.py @@ -20,10 +20,8 @@ if __name__ == "__main__": from snipper.fix_s import save_s from snipper.snipper_main import censor_file - - # - # EX_BASE = "../examples" - # np = EX_BASE + "/new_project" + EX_BASE = "../examples" + np = EX_BASE + "/latex" # if os.path.isdir(np): # shutil.rmtree(np) @@ -40,7 +38,7 @@ if __name__ == "__main__": # my_nup(np + "/index.pdf") # my_nup(f"{np_basic1}/index.pdf") # - # # convert.pdf2png(np + "/index.pdf", "./index0.png") + convert.pdf2png(np + "/index.pdf", "./index.png", scale_to=600) # output = np +"/index_2up.pdf" # # data = {} diff --git a/example/__pycache__/load_references.cpython-38.pyc b/examples/__pycache__/load_references.cpython-38.pyc similarity index 100% rename from example/__pycache__/load_references.cpython-38.pyc rename to examples/__pycache__/load_references.cpython-38.pyc diff --git a/examples/block_processor.py b/examples/block_processor.py new file mode 100644 index 0000000..c8662f7 --- /dev/null +++ b/examples/block_processor.py @@ -0,0 +1,63 @@ +from snipper.fix_s import get_s #!s +from snipper.block_parsing import block_split +import textwrap +import numpy as np + +# Implement a sieve here. +def primes_sieve(limit): + limitn = limit+1 #!b + primes = range(2, limitn) + + for i in primes: + factors = list(range(i, limitn, i)) + for f in factors[1:]: + if f in primes: + primes.remove(f) + return primes #!b +#!s + +def obscure(blk, fun): + blok = block_split(blk, "#!b") + lines2 = blok['first'] + fun(blok['block']) + blok['last'] + s = '\n'.join(lines2) + print(s) + return s + +# driver program +if __name__ == '__main__': + with open(__file__, 'r') as f: + s = f.read().splitlines() + blk = get_s(s)[''] + + def cmnt(lines): + whitespace = " " * (len(lines[0]) - len(lines[0].lstrip())) + lines = textwrap.dedent("\n".join(lines)).splitlines() + lines = ["# " + l for l in lines] + return lines, whitespace + + def f1(lines): + lines, whitespace = cmnt(lines) + lines = [lines[i] for i in np.random.permutation(len(lines))] + lines = textwrap.indent("\n".join(lines), whitespace).splitlines() + return lines + + obscure(blk, f1) + + def f2(lines): + lines, whitespace = cmnt(lines) + kp = """#'"[](){},.+-012345679:=""" + l2 = [] + for line in lines: + line2 = [] + for w in line.split(' '): + if w in ['', 'return', 'if', 'else' '=', '#', "for", "in"]: + line2.append(w) + else: + w2 = "".join( [ (t if t in kp else '?') for t in w] ) + line2.append(w2) + l2.append(" ".join(line2)) + lines = l2 + lines = textwrap.indent("\n".join(lines), whitespace).splitlines() + return lines + + obscure(blk, f2) diff --git a/example/citations.py b/examples/citations.py similarity index 100% rename from example/citations.py rename to examples/citations.py diff --git a/examples/cs101_instructor/homework1.py b/examples/cs101_instructor/homework1.py new file mode 100644 index 0000000..49ed989 --- /dev/null +++ b/examples/cs101_instructor/homework1.py @@ -0,0 +1,20 @@ +def myfun(): #!s + """ + Simple aux references \ref{eq1} in \ref{sec1}. + Simple bibtex citations: \cite{bertsekasII} and \cite[Somewhere around the middle]{herlau} + + Example of custom command (reference notes) + > \nref{fig1} + + Other example of custom command (reference assignment) + > \aref2{sec1} + """ + print("See \\ref{sec1}") # Also works. + return 42 #!s + +def fun1(l1, l2): + s1 = sum(l1) #!s + s2 = sum(l2) + print("Hello worlds!") #!s + return s1 + s2 + diff --git a/example/exercise1.py b/examples/exercise1.py similarity index 100% rename from example/exercise1.py rename to examples/exercise1.py diff --git a/example/latex/br.pdf b/examples/latex/br.pdf similarity index 100% rename from example/latex/br.pdf rename to examples/latex/br.pdf diff --git a/example/latex/index.aux b/examples/latex/index.aux similarity index 100% rename from example/latex/index.aux rename to examples/latex/index.aux diff --git a/example/latex/index.bbl b/examples/latex/index.bbl similarity index 100% rename from example/latex/index.bbl rename to examples/latex/index.bbl diff --git a/example/latex/index.blg b/examples/latex/index.blg similarity index 100% rename from example/latex/index.blg rename to examples/latex/index.blg diff --git a/example/latex/index.log b/examples/latex/index.log similarity index 100% rename from example/latex/index.log rename to examples/latex/index.log diff --git a/example/latex/index.out b/examples/latex/index.out similarity index 100% rename from example/latex/index.out rename to examples/latex/index.out diff --git a/example/latex/index.pdf b/examples/latex/index.pdf similarity index 100% rename from example/latex/index.pdf rename to examples/latex/index.pdf diff --git a/example/latex/index.synctex.gz b/examples/latex/index.synctex.gz similarity index 100% rename from example/latex/index.synctex.gz rename to examples/latex/index.synctex.gz diff --git a/example/latex/index.tex b/examples/latex/index.tex similarity index 100% rename from example/latex/index.tex rename to examples/latex/index.tex diff --git a/example/latex/library.bib b/examples/latex/library.bib similarity index 100% rename from example/latex/library.bib rename to examples/latex/library.bib diff --git a/example/load_references.py b/examples/load_references.py similarity index 93% rename from example/load_references.py rename to examples/load_references.py index 9718dde..aad5a0f 100644 --- a/example/load_references.py +++ b/examples/load_references.py @@ -3,7 +3,7 @@ import os def reference_example(): # Load references and insert them. - from snipper.citations import get_bibtex, get_aux #!s=a + from snipper.load_citations import get_bibtex, get_aux #!s=a bibfile = "latex/library.bib" auxfile = 'latex/index.aux' bibtex = get_bibtex(bibfile) diff --git a/example/output/citations.py b/examples/output/citations.py similarity index 100% rename from example/output/citations.py rename to examples/output/citations.py diff --git a/example/output/load_references_a.py b/examples/output/load_references_a.py similarity index 71% rename from example/output/load_references_a.py rename to examples/output/load_references_a.py index 304c800..672cac2 100644 --- a/example/output/load_references_a.py +++ b/examples/output/load_references_a.py @@ -1,5 +1,5 @@ # load_references.py - from snipper.citations import get_bibtex, get_aux + from snipper.load_citations import get_bibtex, get_aux bibfile = "latex/library.bib" auxfile = 'latex/index.aux' bibtex = get_bibtex(bibfile) diff --git a/example/output/load_references_b.py b/examples/output/load_references_b.py similarity index 100% rename from example/output/load_references_b.py rename to examples/output/load_references_b.py diff --git a/examples/process_cs101.py b/examples/process_cs101.py new file mode 100644 index 0000000..0268b19 --- /dev/null +++ b/examples/process_cs101.py @@ -0,0 +1,25 @@ +def main(): + from snipper.snip_dir import snip_dir + from snipper.load_citations import get_aux, get_bibtex + bibfile = get_bibtex('latex/library.bib') + auxfile = get_aux('latex/index.aux') + + references = dict(bibtex=bibfile, + aux=auxfile, + commands=[ + dict(command='\\aref2', output="(Assignment 2, \\ref{%s})", aux=auxfile), + dict(command='\\href', output="\cite[\\ref{%s}]{herlau}", aux=auxfile), + ] + ) + + + output = snip_dir(source_dir="./cs101_instructorm", dest_dir="./cs101_students", output_dir="./cs101_output", + references=references, + ) + + a = 234 + + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/src/codesnipper.egg-info/PKG-INFO b/src/codesnipper.egg-info/PKG-INFO index 487bc49..070de1a 100644 --- a/src/codesnipper.egg-info/PKG-INFO +++ b/src/codesnipper.egg-info/PKG-INFO @@ -1,11 +1,11 @@ Metadata-Version: 2.1 Name: codesnipper -Version: 0.0.1 +Version: 0.0.2 Summary: A lightweight framework for censoring student solutions files and extracting code + output Home-page: https://lab.compute.dtu.dk/tuhe/snipper Author: Tue Herlau Author-email: tuhe@dtu.dk -License: UNKNOWN +License: MIT Project-URL: Bug Tracker, https://lab.compute.dtu.dk/tuhe/snipper/issues Platform: UNKNOWN Classifier: Programming Language :: Python :: 3 @@ -15,8 +15,158 @@ Requires-Python: >=3.8 Description-Content-Type: text/markdown License-File: LICENSE -# Snip -A lightweight framework for removing code from student solutions. Currently used at DTU. +# Snipper +A lightweight framework for removing code from student solutions. +## Installation +```console +pip install codesnipper +``` +## What it does +This project address the following three challenges for administering a python-based course + - You need to maintain a (working) version for debugging as well as a version handed out to students (with code missing) + - You ideally want to make references in source code to course material *"(see equation 2.1 in exercise 5)"* but these tend to go out of date + - You want to include code snippets and code output in lectures notes/exercises/beamer slides + - You want to automatically create student solutions +This framework address these problems and allow you to maintain a **single**, working project repository. + +The project is currently used in **02465** at DTU. An example of student code can be found at: + - https://gitlab.gbar.dtu.dk/02465material/02465students/blob/master/irlc/ex02/dp.py + +A set of lectures notes where all code examples/output are automatically generated from the working repository can be found a +- https://lab.compute.dtu.dk/tuhe/books (see **Sequential decision making**) + +## How it works +The basic functionality is quite simple. You start with your working script in your private repository and add special tags to the script. +In this case I have added the tags `#!b` (cut a block) and `#!f` (cut function scope). +```python +def myfun(): #!f The error I am going to raise + """ The function docstring will not be removed""" + print("This is a function") + return 42 + +def a_long_function(): + a = 234 + print("a line") + print("a line") #!b + print("a line") + print("a line") #!b Insert three missing print statements. + print("a line") + return a + +if __name__ == "__main__": + myfun() +``` +This will produce the following file: +```python +def myfun(): + """ The function docstring will not be removed""" + # TODO: 2 lines missing. + raise NotImplementedError("The error I am going to raise") + +def a_long_function(): + a = 234 + print("a line") + # TODO: 3 lines missing. + raise NotImplementedError("Insert three missing print statements.") + print("a line") + return a + +if __name__ == "__main__": + myfun() +``` +You can also use the framework to capture code snippets, outputs and interactive python output. +To do this, save the following in `foo.py` +```python +def myfun(): #!s This snippet will be saved to foo.py in the output directory. + print("Hello") #!s + +print("Do not capture me") +for i in range(4): #!o + print("Output", i) +print("Goodbuy world") #!o +print("don't capture me") + +# Interactive pythong example +print("Hello World") #!i #!i # this is a single-line cutout. +```` +These block-tags will create a file `foo.py` (in the output directory) containing +```python +def myfun(): + print("Hello") +``` +A file `foo.txt` containing the captured output +```txt +Output 0 +Output 1 +Output 2 +Output 3 +Goodbuy world +``` +and a typeset version of an interactive python session in `foo.pyi` (use `pycon` in minted; this gitlab server appears not to support `pycon`) +```pycon +>>> print("hello world") +Hello World" +``` +All these files can be directly imported into `LaTeX` using e.g. `minted`: You never need to mix `LaTeX` code and python again! + + +## References: +Bibliography references can be loaded from `references.bib`-files and in-document references from the `.aux` file. +For this example, we will insert references shown in the `examples/latex/index.tex`-document. To do so, we can use these tags: +```python +def myfun(): #!s + """ + To solve this exercise, look at \ref{eq1} in \ref{sec1}. + You can also look at \cite{bertsekasII} and \cite{herlau} + More specifically, look at \cite[Equation 117]{bertsekasII} and \cite[\ref{fig1}]{herlau} + + We can also write a special tag to reduce repetition: \nref{fig1} and \nref{sec1}. + """ + return 42 #!s + +``` +We can manually compile this example by first loading the aux-files and the bibliographies as follows: +```python +# load_references.py + from snipper.citations import get_bibtex, get_aux + bibfile = "latex/library.bib" + auxfile = 'latex/index.aux' + bibtex = get_bibtex(bibfile) + aux = get_aux(auxfile) +``` +Next, we load the python file containing the reference code and fix all references based on the aux and bibliography data. +```python +# load_references.py + file = "citations.py" + with open(file, 'r') as f: + lines = f.read().splitlines() + lines = fix_aux(lines, aux=aux) + lines = fix_aux_special(lines, aux=aux, command='\\nref', bibref='herlau') + lines = fix_bibtex(lines, bibtex=bibtex) + with open('output/citations.py', 'w') as f: + f.write("\n".join(lines)) +``` +The middle command is a convenience feature: It allows us to specify a special citation command `\nref{..}` which always compiles to `\cite[\ref{...}]{herlau}`. This is useful if e.g. `herlau` is the bibtex key for your lecture notes. The result is as follows: +```python +""" +References: + [Ber07] Dimitri P. Bertsekas. Dynamic Programming and Optimal Control, Vol. II. Athena Scientific, 3rd edition, 2007. ISBN 1886529302. + [Her21] Tue Herlau. Sequential decision making. (See 02465_Notes.pdf), 2021. +""" +def myfun(): #!s + """ + To solve this exercise, look at eq. (1) in Section 1. + You can also look at (Ber07) and (Her21) + More specifically, look at (Ber07, Equation 117) and (Her21, Figure 1) + + We can also write a special tag to reduce repetition: (Her21, Figure 1) and (Her21, Section 1). + """ + return 42 #!s +``` +Note this example uses the low-level api. Normally you would just pass the bibtex and aux-file to the main censor-file command. + +## Additional features: +- You can name tags using `#!s=bar` to get a `foo_bar.py` snippet. This is useful when you need to cut multiple sessions. This also works for the other tags. diff --git a/src/codesnipper.egg-info/SOURCES.txt b/src/codesnipper.egg-info/SOURCES.txt index 8b9ec96..0064f64 100644 --- a/src/codesnipper.egg-info/SOURCES.txt +++ b/src/codesnipper.egg-info/SOURCES.txt @@ -9,5 +9,8 @@ src/codesnipper.egg-info/dependency_links.txt src/codesnipper.egg-info/requires.txt src/codesnipper.egg-info/top_level.txt src/snipper/__init__.py +src/snipper/citations.py +src/snipper/fix_cite.py +src/snipper/fix_s.py src/snipper/snip_dir.py -src/snipper/snipper.py \ No newline at end of file +src/snipper/snipper_main.py \ No newline at end of file diff --git a/src/codesnipper.egg-info/requires.txt b/src/codesnipper.egg-info/requires.txt index 7f7afbf..4ba7d8f 100644 --- a/src/codesnipper.egg-info/requires.txt +++ b/src/codesnipper.egg-info/requires.txt @@ -1 +1,3 @@ -jinja2 +pexpect +wexpect +pybtex diff --git a/src/snipper/__pycache__/citations.cpython-38.pyc b/src/snipper/__pycache__/citations.cpython-38.pyc deleted file mode 100644 index 9a647f415713b55177e96ceff6c8c791938806ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5040 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 Q2=lOTsB?I5@pHHX0KU?#RsaA1 diff --git a/src/snipper/__pycache__/fix_s.cpython-38.pyc b/src/snipper/__pycache__/fix_s.cpython-38.pyc index a4e3cf8604fe8f78dcdcc41bf88f448690de8363..b161b2c89e36fa9e9f5a4b97990c7c3ba4833196 100644 GIT binary patch delta 583 zcmZ20GeMR&l$V!_fq{YH?go>@dmDL=Ffj=*O}@;u*^n!RA)Be_MhRmI*8-**h8mU> zhE^s?hJ}pHjEoE=%qiR*jLl3<j5RDZT-i($7>nE{_cPm?vefW&FsAVIGS%|d@TTxe zGAv+S$iT=@!&JlD%vi&l!e_%!!yC*{!;r#I!vZp|hB<|QG9!yHuYe6hJ3~8T8dHj3 ziqK?57EwiE8-^O@6cHPS8onBa8ZJqO8t!JM7^WKL6j88@*yL~)Yh7L&km=0Lj5W+) z)7fj7Q^ai;YS>fQBtiNmKx%^-QW%06G$l9hXSu{AcZ-p$O421WMIkT0L?JCRFGV3Y zu_QSoGcR4CBr$#RME0$WQIp*{R2dy6=W-Y`YENFsp(V>!B*4JHaErB|C^N65NEXEA zbgf8EEhx#%&zpRa!$T~JDbpy5Da+^<Q;ty-Q?gN!E=bX2eNI_Mm&v}I3hay=jAD#j z%$xH#wHX<sCePxEVKklmol8qHn1O+zm=6>UOdO1Sj3SIIi~@`zj72t+t++3-7HKgs zFihs>k!G}+tj#0CXgS$~M_Vh3E5Ed)ptK}DC9^1sGc7YGHNGIRBqNGFIX|x?HLs*d zpMilPiYX^2YVuqjImY<Odw8T7JtyDb31-xqtix;17&SSESD)L4fq|jO5kz=SUdAgY vW(8tef(Rav>lw?63_!Nu;k6RC<KW_8;!tMc<zVJv6kz0H<YVMwVPOOS*H($G delta 561 zcmbOryH<ubl$V!_fq{WR|Bi8D^hVwzOiV8rCtqgT%*j&2mCZDPu}E(6c4pgp#u}au z#uTnzrdr+_-V|<0h6PLu85kLAm}+>N8Ebe`cx)JIc!L>g7*ZH&SX!AR8ETkQcx@PJ z7;3muIK&xJ7@%T&HVo|y?Tl$mDf}q{EgZFcHGDM;H7t@0HLT4{F-$egDS|d2y+Sq& zU>Pn+h8pf>CLXYqFjz`tay^T+F1HQHa^_~n8fLKN>^00OqBaaQ>?v$u%f&!ygBem7 zf*CZ$H$P{DOj`&PzVlY2Q-8EqzS<}hZ|n*5wYi;cNRfPsNwvL2_0*e#|^qbQ~< zqgzZlMo~=3Mn$>|3=C0|dpKno?Iy3{RA6M<e34U|kuhxYU#=KN<H=FnT9W<@3=GA5 zpb%u@VB}*IVPs(xU=(32vYI@X`;z=EMy_9s`Y-?f|Np;;k%58X7Gr!BvtB{vEyi+9 z?jozn6L@48%_pzr(e}K>m0wy?P+Ah7l38?%Gc7YGHNGIRB;yu)a(-S(YF<f^KFBRh zIXSnO^Gi!^F{TxPEQJvKAd}gO6U$QLi=!ti@=7!MOt$3>X0)C>k=LH_*5r%4`rK9w z3=BmMAi`%dH=mq@1&C=5B6vW$8Ov_578GUXl}xthvl6%B;NoE7P-fxfVCG>IVB})t KW8`9CVFUop^@~{m diff --git a/src/snipper/block_parsing.py b/src/snipper/block_parsing.py new file mode 100644 index 0000000..0b1009c --- /dev/null +++ b/src/snipper/block_parsing.py @@ -0,0 +1,78 @@ +def f2(lines, tag, i=0, j=0): + for k in range(i, len(lines)): + index = lines[k].find(tag, j if k == i else 0) + if index >= 0: + return k, index + return None, None + + +def block_iterate(lines, tag): + contents = {'joined': lines} + while True: + contents = block_split(contents['joined'], tag) + if contents is None: + break + + yield contents + + +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): + k = line.find(" ") + tag_args = (line[:k + 1] if k >= 0 else line)[len(tag):] + if len(tag_args) == 0: + return {'': ''} # No name. + tag_args = dict([t.split("=") for t in tag_args.split(";")]) + return tag_args + + if i is None: + return None + else: + start_tag_args = get_tag_args(lines[i][j:]) + START_TAG = f"{tag}={start_tag_args['']}" if '' in start_tag_args else tag + END_TAG = START_TAG + i2, j2 = f2(lines, END_TAG, i=i, j=j+1) + if i2 == None: + END_TAG = tag + i2, j2 = f2(lines, END_TAG, i=i, j=j+1) + if i2 == None: + print("\n".join( lines[i:])) + raise Exception("Did not find matching tag", tag) + + + if i == i2: + # Splitting a single line. To reduce confusion, this will be treated slightly differently: + 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) + return c2 + else: + contents['first'] = lines[:i] + contents['last'] = lines[i2+1:] + + def argpost(line, j): + nx_tag = line.find(stag, j+1) + arg1 = line[j+len(tag):nx_tag] + if nx_tag >= 0: + post = line[nx_tag:] + else: + post = '' + return arg1, post + + contents['arg1'], contents['post1'] = argpost(lines[i], j) + 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['start_tag_args'] = start_tag_args + contents['name'] = start_tag_args[''] + return contents \ No newline at end of file diff --git a/src/snipper/fix_bf.py b/src/snipper/fix_bf.py new file mode 100644 index 0000000..e69de29 diff --git a/src/snipper/fix_cite.py b/src/snipper/fix_cite.py index 475e44d..7fbc1b4 100644 --- a/src/snipper/fix_cite.py +++ b/src/snipper/fix_cite.py @@ -1,34 +1,10 @@ -from snipper.citations import find_tex_cite +from snipper.load_citations import find_tex_cite from snipper.snipper_main import COMMENT -def fix_references(lines, info, strict=True): - for cmd in info['new_references']: - lines = fix_single_reference(lines, cmd, info['new_references'][cmd], strict=strict) - return lines -def fix_single_reference(lines, cmd, aux, strict=True): - references = aux - s = "\n".join(lines) - i = 0 - while True: - (i, j), reference, txt = find_tex_cite(s, start=i, key=cmd) - if i < 0: - break - if reference not in references: - er = "cref label not found for label: " + reference - if strict: - raise IndexError(er) - else: - print(er) - continue - r = references[reference] - rtxt = r['nicelabel'] - s = s[:i] + rtxt + s[j + 1:] - i = i + len(rtxt) - print(cmd, rtxt) - - lines = s.splitlines(keepends=False) - return lines +def fix_citations(): + # This should be the master function. + pass def fix_aux_special(lines, aux, command='\\nref', bibref='herlau'): @@ -70,4 +46,35 @@ def fix_bibtex(lines, bibtex): s = s[:i] + "References:\n" + "\n".join(all_refs) +"\n"+ s[i:] # s = s.replace(cpr, info['code_copyright']) - return s.splitlines() \ No newline at end of file + return s.splitlines() + + + +def fix_references(lines, info, strict=True): + for cmd in info['new_references']: + lines = fix_single_reference(lines, cmd, info['new_references'][cmd], strict=strict) + return lines + +def fix_single_reference(lines, cmd, aux, strict=True): + references = aux + s = "\n".join(lines) + i = 0 + while True: + (i, j), reference, txt = find_tex_cite(s, start=i, key=cmd) + if i < 0: + break + if reference not in references: + er = "cref label not found for label: " + reference + if strict: + raise IndexError(er) + else: + print(er) + continue + r = references[reference] + rtxt = r['nicelabel'] + s = s[:i] + rtxt + s[j + 1:] + i = i + len(rtxt) + print(cmd, rtxt) + + lines = s.splitlines(keepends=False) + return lines \ No newline at end of file diff --git a/src/snipper/fix_s.py b/src/snipper/fix_s.py index 0eed3c8..b8f1d9b 100644 --- a/src/snipper/fix_s.py +++ b/src/snipper/fix_s.py @@ -1,79 +1,6 @@ -import functools from collections import defaultdict -from snipper.snipper_main import full_strip, block_process - -def f2(lines, tag, i=0, j=0): - for k in range(i, len(lines)): - index = lines[k].find(tag, j if k == i else 0) - if index >= 0: - return k, index - return None, None - -def block_iterate(lines, tag): - contents = {'joined': lines} - while True: - contents = block_split(contents['joined'], tag) - if contents is None: - break - - yield contents - -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): - k = line.find(" ") - tag_args = (line[:k + 1] if k >= 0 else line)[len(tag):] - if len(tag_args) == 0: - return {'': ''} # No name. - tag_args = dict([t.split("=") for t in tag_args.split(";")]) - return tag_args - - if i is None: - return None - else: - start_tag_args = get_tag_args(lines[i][j:]) - START_TAG = f"{tag}={start_tag_args['']}" if '' in start_tag_args else tag - END_TAG = START_TAG - i2, j2 = f2(lines, END_TAG, i=i, j=j+1) - if i2 == None: - END_TAG = tag - i2, j2 = f2(lines, END_TAG, i=i, j=j+1) - - if i == i2: - # Splitting a single line. To reduce confusion, this will be treated slightly differently: - 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) - return c2 - else: - contents['first'] = lines[:i] - contents['last'] = lines[i2+1:] - - def argpost(line, j): - nx_tag = line.find(stag, j+1) - arg1 = line[j+len(tag):nx_tag] - if nx_tag >= 0: - post = line[nx_tag:] - else: - post = '' - return arg1, post - - contents['arg1'], contents['post1'] = argpost(lines[i], j) - 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['start_tag_args'] = start_tag_args - contents['name'] = start_tag_args[''] - return contents +import os +from snipper.block_parsing import block_iterate def get_s(lines): @@ -86,8 +13,6 @@ def get_s(lines): output[name] = [l for c in co for l in c['block']] return output -import os - def save_s(lines, output_dir, file_path): # save file snips to disk content = get_s(lines) if not os.path.isdir(output_dir): @@ -99,30 +24,6 @@ def save_s(lines, output_dir, file_path): # save file snips to disk with open(output_dir + "/" + os.path.basename(file_path)[:-3] + ("_" + name if len(name) > 0 else name) + ".py", 'w') as f: f.write(out) - # out = "\n".join([f"# {include_path_base}"] + ["\n".join(v[1]) for v in c if v[0] == outf]) - # with open(outf, 'w') as f: - # f.write(out) - - # def block_fun(lines, start_extra, end_extra, art, output, **kwargs): - # outf = output + ("_" + art if art is not None and len(art) > 0 else "") + ".py" - # lines = full_strip(lines) - # return lines, [outf, lines] - # try: - # a,b,c,_ = block_process(lines, tag="#!s", block_fun=functools.partial(block_fun, output=output)) - # if len(c)>0: - # kvs= { v[0] for v in c} - # for outf in kvs: - # out = "\n".join([f"# {include_path_base}"] + ["\n".join(v[1]) for v in c if v[0] == outf] ) - # with open(outf, 'w') as f: - # f.write(out) - # - # except Exception as e: - # print("lines are") - # print("\n".join(lines)) - # print("Bad thing in #!s command in file", file) - # raise e - # return lines - s1 = """ L1 L2 #!s=a @@ -147,5 +48,3 @@ if __name__ == "__main__": # contents = block_split(s1.splitlines(), tag="#!s") # contents = block_split(contents['joined'], tag="#!s") # lines2 = contents['first'] + - a = 234 - pass \ No newline at end of file diff --git a/src/snipper/citations.py b/src/snipper/load_citations.py similarity index 100% rename from src/snipper/citations.py rename to src/snipper/load_citations.py diff --git a/src/snipper/snip_dir.py b/src/snipper/snip_dir.py index 0a68a9d..15657af 100644 --- a/src/snipper/snip_dir.py +++ b/src/snipper/snip_dir.py @@ -5,7 +5,15 @@ import time import fnmatch -def snip_dir(source_dir, dest_dir, exclude=None, clean_destination_dir=True): +def snip_dir(source_dir, # Sources + dest_dir, # 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): + + if references == None: + references = dict(aux=None, bibtex=None, commands=[]) + if exclude == None: exclude = [] if not os.path.exists(dest_dir): diff --git a/src/snipper/snipper_main.py b/src/snipper/snipper_main.py index 1886033..dc6bbdc 100644 --- a/src/snipper/snipper_main.py +++ b/src/snipper/snipper_main.py @@ -315,7 +315,6 @@ def censor_code(lines, keep=True): - def censor_file(file, info, paths, run_files=True, run_out_dirs=None, cut_files=True, solution_list=None, censor_files=True, include_path_base=None, -- GitLab