-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #448 from pep-dortmund/example-report-exercise-steps
WIP: Example report exercise steps
- Loading branch information
Showing
42 changed files
with
2,989 additions
and
0 deletions.
There are no files selected for viewing
213 changes: 213 additions & 0 deletions
213
exercises-toolbox/8-all/example-report/Makefile-loesung
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
datafilenames = Messwerte_Bahn.txt \ | ||
Messwerte_Frames_Kugel.txt \ | ||
Messwerte_Frames_Zylinder.txt \ | ||
Messwerte_Kamera.txt \ | ||
Messwerte_Kugel.txt \ | ||
Messwerte_Zylinder.txt | ||
|
||
advanced_mpl_filenames = matplotlibrc header-matplotlib.tex | ||
|
||
steps = 01 02 03 04 05 06 07 08 09 10 11 | ||
|
||
### Directories | ||
|
||
# build/example-report-step-{01,...,11}/ | ||
step_dirs = $(foreach step, $(steps),build/example-report-step-$(step)/) | ||
|
||
# build/example-report-step-{01,...,11}/loesung | ||
solution_dirs = $(addsuffix loesung/, $(step_dirs)) | ||
|
||
|
||
# build/example-report-step-{06,...,11}/loesung/v16516/ | ||
report_dirs = $(addsuffix v16516/, $(wordlist 6,11,$(solution_dirs))) | ||
|
||
# build/example-report-step-{01,05}/data/ | ||
step_data_dirs = $(addsuffix data/, $(word 1,$(step_dirs)) $(word 5,$(step_dirs))) | ||
|
||
# build/example-report-step-{01,...,05}/loesung/data/ | ||
solution_data_dirs = $(addsuffix data/, $(wordlist 1,5,$(solution_dirs))) | ||
|
||
# build/example-report-step-{06,...,11}/loesung/v16516/data | ||
report_data_dirs = $(addsuffix data/, $(report_dirs)) | ||
|
||
# all */data dirs | ||
data_dirs = $(solution_data_dirs) $(report_data_dirs) $(step_data_dirs) | ||
data_dirs_without_unc = $(wordlist 1,4,$(data_dirs)) $(word 12,$(data_dirs)) | ||
data_dirs_with_unc = $(wordlist 5,11,$(data_dirs)) $(word 13,$(data_dirs)) | ||
|
||
# build/example-report-step-{09,...,10}/loesung/v16516/graphics/ | ||
graphics_dirs = $(addsuffix v16516/graphics/, $(wordlist 9,10,$(solution_dirs))) $(addsuffix graphics/, $(word 9,$(step_dirs))) | ||
|
||
# solution_dirs containing tex files | ||
solution_dirs_with_tex = $(wordlist 7,11,$(solution_dirs)) | ||
#build/example-report-step-{07,...,11}/loesung/v16516/content/ | ||
content_dirs = $(addsuffix v16516/content/, $(solution_dirs_with_tex)) | ||
|
||
### Taskfiles | ||
|
||
task_files = $(addsuffix aufgabe.txt,$(step_dirs)) | ||
|
||
### Datafiles | ||
|
||
append_datafilenames = $(foreach filename,$(datafilenames),$(addsuffix $(filename), $(1))) | ||
|
||
data_files_without_unc = $(call append_datafilenames,$(data_dirs_without_unc)) | ||
data_files_with_unc = $(call append_datafilenames, $(data_dirs_with_unc)) | ||
data_files = $(data_files_without_unc) $(data_files_with_unc) | ||
|
||
### Python files | ||
solution_python_files = $(addsuffix auswertung.py, $(wordlist 1,5,$(solution_dirs))) | ||
report_python_files = $(addsuffix auswertung.py, $(report_dirs)) | ||
python_files = $(solution_python_files) $(report_python_files) | ||
|
||
### LaTeX Files | ||
header_tex_files=$(addsuffix header.tex, $(solution_dirs_with_tex)) | ||
main_tex_files= $(addsuffix v16516/v16516.tex, $(solution_dirs_with_tex)) | ||
implementation_tex_files=$(addsuffix durchfuehrung.tex, $(content_dirs)) | ||
theory_tex_files=$(addsuffix theorie.tex, $(content_dirs)) | ||
evaluation_tex_files=$(addsuffix auswertung.tex, $(content_dirs)) | ||
discussion_tex_files=$(addsuffix diskussion.tex, $(content_dirs)) | ||
|
||
setup_image_files = $(addsuffix versuchsaufbau.png, $(graphics_dirs)) | ||
|
||
lit_bib_files = $(addsuffix lit.bib, $(wordlist 9,11,$(solution_dirs)) $(word 9,$(step_dirs))) | ||
programms_bib_files = $(addsuffix programme.bib, $(wordlist 9,11,$(solution_dirs)) $(word 9,$(step_dirs))) | ||
bib_files = $(lit_bib_files) $(programms_bib_files) | ||
|
||
matplotlibrc_files= $(addsuffix matplotlibrc, $(wordlist 10,11,$(solution_dirs)) $(word 10,$(step_dirs))) | ||
header_matplotlib_files = $(addsuffix header-matplotlib.tex, $(wordlist 10,11,$(solution_dirs)) $(word 10,$(step_dirs))) | ||
|
||
advanced_mpl_files = $(matplotlibrc_files) $(header_matplotlib_files) | ||
|
||
tex_files = $(header_tex_files) \ | ||
$(main_tex_files) \ | ||
$(implementation_tex_files) \ | ||
$(theory_tex_files) \ | ||
$(evaluation_tex_files) \ | ||
$(discussion_tex_files) \ | ||
$(bib_files) \ | ||
$(advanced_mpl_files) | ||
|
||
### Makefiles | ||
solution_makefile_files = $(addsuffix Makefile-loesung, $(wordlist 2,5,$(solution_dirs))) \ | ||
$(addsuffix v16516/Makefile-loesung, $(wordlist 6,9,$(solution_dirs))) | ||
|
||
target_makefile_files = $(addsuffix v16516/Makefile, $(wordlist 10,11,$(solution_dirs))) | ||
makefile_files = $(solution_makefile_files) $(target_makefile_files) | ||
|
||
python_libs = $(addprefix build/example-report-step-11/loesung/v16516/, curve_fit.py latex_formatting.py) | ||
|
||
run: all | ||
# Run all Makefile-loesung | ||
set -- $(wordlist 1, 5,$(solution_dirs)); \ | ||
for i do\ | ||
make -C $$i -f Makefile-loesung; \ | ||
done | ||
# Run all Makefile-loesung in the additional subdir v16516 | ||
set -- $(addsuffix v16516/, $(wordlist 6, 9,$(solution_dirs))); \ | ||
for i do\ | ||
make -C $$i -f Makefile-loesung; \ | ||
done | ||
# Run the Makefile in the last two steps | ||
set -- $(addsuffix v16516/, $(wordlist 10, 11,$(solution_dirs))); \ | ||
for i do\ | ||
make -C $$i -f Makefile; \ | ||
done | ||
# copy the final report into the first step_dir | ||
cp $(addsuffix v16516/build/v16516.pdf,$(word 11, $(solution_dirs))) $(addsuffix v16516.pdf,$(word 1, $(solution_dirs))) | ||
|
||
|
||
all: $(task_files) \ | ||
$(python_files) \ | ||
$(data_files) \ | ||
$(tex_files) \ | ||
$(setup_image_files) \ | ||
$(makefile_files)\ | ||
$(python_libs) | ||
|
||
$(word 1, $(python_libs)): templates/curve_fit.py | $(report_dirs) | ||
cp $< $@ | ||
|
||
$(word 2, $(python_libs)): templates/latex_formatting.py | $(report_dirs) | ||
cp $< $@ | ||
|
||
|
||
build/example-report-step-%/aufgabe.txt &: $(template_task_files) | $(step_dirs) | ||
cp templates/aufgabe-step-$*.txt build/example-report-step-$*/aufgabe.txt | ||
|
||
copy_file_loop=set -- $(2); for i do cp $(1) $$i; done | ||
|
||
$(solution_makefile_files) &: templates/Makefile-loesung_template | $(solution_dirs) $(report_dirs) | ||
python generate-step-files.py -t $< -s 2 $(addprefix -o=,$(solution_makefile_files)) | ||
|
||
$(target_makefile_files) &: templates/Makefile | $(report_dirs) | ||
$(call copy_file_loop, $<, $(target_makefile_files)) | ||
|
||
$(matplotlibrc_files) &: templates/matplotlibrc | $(solution_dirs) | ||
$(call copy_file_loop, $<,$(matplotlibrc_files)) | ||
|
||
$(programms_bib_files) &: templates/programme.bib | $(solution_dirs) | ||
$(call copy_file_loop, $<, $(programms_bib_files)) | ||
|
||
$(lit_bib_files) &: templates/lit.bib | $(solution_dirs) | ||
$(call copy_file_loop, $<, $(lit_bib_files)) | ||
|
||
$(setup_image_files) &: templates/versuchsaufbau.png | $(graphics_dirs) | ||
$(call copy_file_loop, $<, $(setup_image_files)) | ||
|
||
$(header_matplotlib_files) &: templates/header-matplotlib.tex | $(solution_dirs) | ||
$(call copy_file_loop, $<, $(header_matplotlib_files)) | ||
|
||
$(header_tex_files) &: templates/latex/header_tex_template | $(solution_dirs) | ||
python generate-step-files.py -t $< -s 7 $(addprefix -o=,$(header_tex_files)) | ||
|
||
$(main_tex_files) &: templates/latex/v16516_tex_template | $(content_dirs) | ||
python generate-step-files.py -t $< -s 7 $(addprefix -o=,$(main_tex_files)) | ||
|
||
$(theory_tex_files) &: templates/latex/theorie_tex_template | $(content_dirs) | ||
python generate-step-files.py -t $< -s 7 $(addprefix -o=,$(theory_tex_files)) | ||
|
||
$(implementation_tex_files) &: templates/latex/durchfuehrung_tex_template | $(content_dirs) | ||
python generate-step-files.py -t $< -s 7 $(addprefix -o=,$(implementation_tex_files)) | ||
|
||
$(evaluation_tex_files) &: templates/latex/auswertung_tex_template | $(content_dirs) | ||
python generate-step-files.py -t $< -s 7 $(addprefix -o=,$(evaluation_tex_files)) | ||
|
||
$(discussion_tex_files) &: templates/latex/diskussion_tex_template | $(content_dirs) | ||
python generate-step-files.py -t $< -s 7 $(addprefix -o=,$(discussion_tex_files)) | ||
|
||
$(python_files) &: templates/auswertung_py_template | $(solution_dirs) $(report_dirs) | ||
touch build/example-report-step-01/loesung/auswertung.py | ||
python generate-step-files.py -t templates/auswertung_py_template $(addprefix -o=,$(python_files)) | ||
|
||
|
||
copy_dir_loop=set -- $(2); for i do cp -r $(1) $$i; done | ||
$(data_files_without_unc) &: templates/data_without_uncertainties/* | $(solution_dirs) $(report_dirs) | ||
$(call copy_dir_loop, templates/data_without_uncertainties, $(data_dirs_without_unc)) | ||
|
||
$(data_files_with_unc) &: templates/data_with_uncertainties/* | $(solution_dirs) $(report_dirs) | ||
$(call copy_dir_loop, templates/data_with_uncertainties, $(data_dirs_with_unc)) | ||
|
||
$(content_dirs) &:|$(report_dirs) | ||
mkdir -p $(content_dirs) | ||
|
||
$(graphics_dirs)&: |$(report_dirs) | ||
mkdir -p $(graphics_dirs) | ||
|
||
$(report_dirs)&: | $(solution_dirs) | ||
mkdir -p $(report_dirs) | ||
|
||
$(solution_dirs) &: | $(step_dirs) | ||
mkdir -p $(solution_dirs) | ||
|
||
$(step_dirs): | build | ||
mkdir -p $(step_dirs) | ||
|
||
build: | ||
mkdir -p build | ||
|
||
clean: | ||
rm -r build | ||
|
||
.PHONY: all clean | ||
|
151 changes: 151 additions & 0 deletions
151
exercises-toolbox/8-all/example-report/generate-step-files.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
import argparse | ||
import re | ||
import sys | ||
from collections import defaultdict | ||
from dataclasses import dataclass | ||
from collections.abc import Iterable | ||
|
||
STEPRANGEREGEX = re.compile(r"(?:#|%)\s*<(\d*)(-(\d*)|)>") | ||
|
||
@dataclass | ||
class Templateline: | ||
linenumber: int | ||
line: str | ||
output_file_indices: Iterable | ||
pattern: str | ||
|
||
def __str__(self): | ||
pattern_length = len(self.pattern) | ||
indicies = f"{self.output_file_indices[0]},...,{self.output_file_indices[-1]}" | ||
# magic number 10: the amount of padding necessary to print a pattern with two two-digit numbers | ||
return f"({self.pattern} → [{indicies}]) {" "*(10-pattern_length)} {self.linenumber:>3} {self.line}" | ||
|
||
|
||
def setup_arg_parser(): | ||
parser = argparse.ArgumentParser( | ||
prog="generate-step-files", | ||
description="Generate multiple (step)files containing lines from a template file", | ||
epilog='') | ||
|
||
parser.add_argument('-v', '--verbose', action='store_true', | ||
help="Get info on parsed args, the step maximum steprange in the template and to be removed lines.") | ||
parser.add_argument('-n', '--dry-run', action='store_true', | ||
help="Print the content of each output file to stdout instead of generating any files.") | ||
# This option allows to use the same step numbering in differnt independent files | ||
parser.add_argument('-s', '--start-step', type=int, default=1, | ||
help="Set the step that should be considered step 1 for this file") | ||
parser.add_argument('-t','--template_filepath', dest='template_filepath', required=True, | ||
help="Filepath to the template file.") | ||
parser.add_argument('-o', '--output_filepaths', dest='output_filepaths', action="append", required=True, | ||
help="Filepaths to the output files (you need to use one Option -o <file> for each file). Hint: use -o=file{1,2,3} for example, to generate the multiple options.)") | ||
return parser | ||
|
||
def parse_lines_and_stepranges(lines, start_step, end_step): | ||
template_lines = [] | ||
removed_lines = [] | ||
for i,l in enumerate(lines, start=1): | ||
found = STEPRANGEREGEX.search(l) | ||
|
||
# a line containing no pattern will not be saved to any output file, hence 'removed' | ||
if found is None: | ||
removed_lines.append(Templateline(i,l, [], "")) | ||
continue | ||
groups = found.groups() | ||
|
||
try: | ||
lower_step_limit = int(groups[0]) | ||
except ValueError: | ||
raise ValueError(f"The pattern ({found.group()}) in line {i} of the template file has not starting step.") | ||
|
||
# Since the end_step is calculated from the number of output files given | ||
# the lower index has to be changed to be less then the upper index | ||
lower_index = lower_step_limit - start_step | ||
if lower_index < 0: | ||
raise ValueError(f"The given star_step {start_step} is higher then the lower limit in the pattern '{found.group()}' in line {i} of the template file.") | ||
|
||
# The dash and second number can be omitted: | ||
# e.g. <4> is equivalent to <4-4> | ||
if (not groups[1]) and (groups[2] is None): | ||
# To include anything the upper index has to be increased by 1 | ||
step_limits = (lower_index, lower_index + 1) | ||
|
||
# If the second number is omitted but the dash is not, the upper limit is the last step: | ||
# e.g. <4-> is equivalent to <4-10> if 10 output files are generated | ||
elif not groups[2]: | ||
# the number of files given is used for the upper index (it is already 1 greater then the highest possible index) | ||
upper_index = end_step | ||
step_limits = (lower_index, upper_index) | ||
|
||
# both numbers are present in the pattern | ||
else: | ||
upper_step_limit = int(groups[2]) | ||
upper_index = upper_step_limit - start_step + 1 | ||
|
||
step_limits = (lower_index, upper_index) | ||
|
||
num_files_with_current_line = (step_limits[1] - step_limits[0]) | ||
if num_files_with_current_line > end_step: | ||
raise ValueError(f"The number of given output files is {end_step}," | ||
f" but line {i} of the template file is expected to appear in {num_files_with_current_line} output files (pattern: {found.group()}).") | ||
|
||
# remove the steprange pattern and spaces between line content and pattern | ||
line_content = STEPRANGEREGEX.sub("", l).rstrip() | ||
template_lines.append(Templateline(i, line_content, list(range(*step_limits)), found.group())) | ||
|
||
return template_lines, removed_lines | ||
|
||
|
||
def split_stepfile_lines(template_lines, output_filepaths): | ||
|
||
lines_per_stepfile = defaultdict(list) | ||
for line in template_lines: | ||
for step in line.output_file_indices: | ||
lines_per_stepfile[output_filepaths[step]].append(line) | ||
|
||
return lines_per_stepfile | ||
|
||
|
||
def main(): | ||
parser = setup_arg_parser() | ||
args = parser.parse_args() | ||
|
||
template_filepath = args.template_filepath | ||
output_filepaths = args.output_filepaths | ||
|
||
|
||
if args.verbose: | ||
print("Input:") | ||
print(' '.join(sys.argv)) | ||
print("Parsed:") | ||
print(f" - template file: {template_filepath}") | ||
print(f" - output files: {output_filepaths}") | ||
print(f" - start step: {args.start_step}") | ||
|
||
|
||
with open(template_filepath) as fh: | ||
template_lines = fh.readlines() | ||
|
||
template_lines, removed_lines = parse_lines_and_stepranges(template_lines, args.start_step, len(output_filepaths)) | ||
|
||
lines_per_stepfiles = split_stepfile_lines(template_lines, output_filepaths) | ||
|
||
if args.verbose: | ||
print("Removed lines:") | ||
print(f"{'\n'.join(str(rl) for rl in removed_lines)}") | ||
print(f"Found steps: {lines_per_stepfiles.keys()}") | ||
|
||
|
||
if args.dry_run: | ||
for stepfile, lines in lines_per_stepfiles.items(): | ||
print(f"\nOutput file '{stepfile}' with index ({output_filepaths.index(stepfile)}) would contain these lines from the template file:") | ||
print(f"pattern → indicies{" "*9}ln line") | ||
print(f"{"\n".join(str(l) for l in lines)}") | ||
return | ||
|
||
|
||
for stepfile, lines in lines_per_stepfiles.items(): | ||
with open(stepfile, "w") as fh: | ||
fh.write("\n".join(l.line for l in lines).strip()) | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
all: build/v16516.pdf | ||
|
||
# hier Python-Skripte: | ||
build/plot-I_kugel.pdf build/plot-I_zylinder.pdf build/plot-g_kugel.pdf build/plot-g_zylinder.pdf: auswertung.py ../matplotlibrc ../header-matplotlib.tex | build | ||
# so that matplotlib can find the tex header when running | ||
# LaTeX in the tmp directory | ||
# and set the matplotlibrc | ||
TEXINPUTS=$$(pwd)/..: MATPLOTLIBRC=../matplotlibrc python auswertung.py | ||
|
||
# hier weitere Abhängigkeiten für build/vXXX.pdf deklarieren: | ||
build/v16516.pdf: build/plot-I_kugel.pdf build/plot-I_zylinder.pdf build/plot-g_kugel.pdf build/plot-g_zylinder.pdf | ||
|
||
build/v16516.pdf: FORCE | build | ||
# to find header and bib files in the main directory | ||
TEXINPUTS=..: \ | ||
BIBINPUTS=..: \ | ||
max_print_line=1048576 \ | ||
latexmk \ | ||
--lualatex \ | ||
--output-directory=build \ | ||
--interaction=nonstopmode \ | ||
--halt-on-error \ | ||
v16516.tex | ||
|
||
build: | ||
mkdir -p build | ||
|
||
clean: | ||
rm -rf build | ||
|
||
FORCE: | ||
|
||
.PHONY: all clean |
Oops, something went wrong.