Bopytex/bopytex/bopytex.py

271 lines
7.5 KiB
Python
Raw Normal View History

2013-09-27 18:09:38 +00:00
#!/usr/bin/env python
# encoding: utf-8
2017-04-16 08:36:27 +00:00
"""
Producing then compiling templates
"""
2019-10-16 20:45:00 +00:00
import csv
import os
import logging
2017-04-16 08:36:27 +00:00
import optparse
import sys
from path import Path
import pytex
from mapytex import Expression, Integer, Decimal
2017-04-17 14:00:22 +00:00
import bopytex.filters as filters
formatter = logging.Formatter("%(name)s :: %(levelname)s :: %(message)s")
steam_handler = logging.StreamHandler()
steam_handler.setLevel(logging.DEBUG)
steam_handler.setFormatter(formatter)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.addHandler(steam_handler)
2017-04-17 07:42:13 +00:00
def setup():
Expression.set_render("tex")
logger.debug(f"Render for Expression is {Expression.RENDER}")
2017-04-17 07:42:13 +00:00
mapytex_tools = {
"Expression": Expression,
"Integer": Integer,
"Decimal": Decimal,
2019-06-28 07:16:17 +00:00
# "Polynom": mapytex.Polynom,
# "Fraction": mapytex.Fraction,
# "Equation": mapytex.Equation,
# "random_str": mapytex.random_str,
# "random_pythagore": mapytex.random_pythagore,
# "Dataset": mapytex.Dataset,
# "WeightedDataset": mapytex.WeightedDataset,
}
2017-04-17 07:42:13 +00:00
pytex.update_export_dict(mapytex_tools)
pytex.add_filter("calculus", filters.do_calculus)
2015-01-06 08:22:52 +00:00
2013-09-27 20:21:46 +00:00
def get_working_dir(options):
""" Get the working directory """
if options.working_dir:
working_dir = Path(options.working_dir)
else:
try:
template = Path(options.template)
except TypeError:
raise ValueError(
"Need to set the working directory \
or to give a template"
)
else:
working_dir = template.dirname()
logger.debug(f"The output directory will be {working_dir}")
return working_dir
def activate_printanswers(
texfile, noans=r"solution/print = false", ans=r"solution/print = true"
):
""" Activate printanswers mod in texfile """
output_fname = "corr_" + texfile
with open(texfile, "r") as input_f:
with open(output_fname, "w") as output_f:
for line in input_f.readlines():
output_f.write(line.replace(noans, ans))
return output_fname
def deactivate_printanswers(corr_fname):
""" Activate printanswers mod in texfile """
Path(corr_fname).remove()
def pdfjoin(pdf_files, destname, working_dir=".", rm_pdfs=1):
"""TODO: Docstring for pdfjoin.
:param pdf_files: list of pdf files to join
:param destname: name for joined pdf
:param working_dir: the working directory
:param rm_pdfs: Remove pdf_files after joining them
:returns: TODO
2013-09-27 20:21:46 +00:00
"""
joined_pdfs = Path(working_dir) / Path(destname)
pdf_files_str = " ".join(pdf_files)
pdfjam = f"pdfjam {pdf_files_str} -o {joined_pdfs}"
logger.debug(f"Run {pdfjam}")
logger.info("Joining pdf files")
os.system(pdfjam)
if rm_pdfs:
logger.info(f"Remove {pdf_files_str}")
os.system(f"rm {pdf_files_str}")
2014-09-03 17:30:09 +00:00
2014-08-29 13:29:57 +00:00
2019-10-16 20:45:00 +00:00
def extract_student_csv(csv_filename):
""" Extract student list from csv_filename """
with open(csv_filename, "r") as csvfile:
reader = csv.DictReader(csvfile)
return [r["Élève"] for r in reader]
def produce_and_compile(options):
""" Produce and compile subjects
"""
working_dir = get_working_dir(options)
2013-09-27 20:21:46 +00:00
2016-02-02 07:12:28 +00:00
if options.only_corr:
options.corr = True
tex_files = working_dir.files("[0-9]*_*.tex")
2016-02-02 07:12:28 +00:00
else:
template = Path(options.template).name
logger.debug(f"Template will be {template}")
2019-10-16 20:45:00 +00:00
if options.student_csv:
list_infos = [
{"num": f"{i+1:02d}", "name": s}
for (i, s) in enumerate(extract_student_csv(options.student_csv))
]
else:
list_infos = [{"num": f"{i+1:02d}"} for i in range(options.num_subj)]
tex_files = []
2016-02-02 07:12:28 +00:00
for infos in list_infos:
dest = working_dir / Path(template.replace("tpl", infos["num"]))
logger.debug(f"Feeding template toward {dest}")
tex_files.append(dest)
pytex.feed(working_dir / template, {"infos": infos}, output=dest, force=1)
logger.debug(f"{dest} fed")
if not options.no_compil:
pdf_files = []
for texfile in tex_files:
logger.debug(f"Start compiling {texfile}")
pytex.pdflatex(texfile)
logger.debug(f"End compiling {texfile}")
pdf_files.append(str(texfile[:-4] + ".pdf"))
logger.debug(f"Compiled files : {pdf_files}")
2016-02-02 07:12:28 +00:00
if not options.no_join and not options.no_compil:
pdfjoin(
pdf_files,
template.replace("tpl", "all").replace(".tex", ".pdf"),
working_dir,
rm_pdfs=1,
)
2016-02-02 07:12:28 +00:00
if options.corr:
pdf_files = []
for texfile in tex_files:
corr_fname = activate_printanswers(texfile)
if not options.no_compil:
logger.debug(f"Start compiling {texfile}")
pytex.pdflatex(corr_fname)
logger.debug(f"End compiling {texfile}")
pdf_files.append(str(corr_fname[:-4] + ".pdf"))
deactivate_printanswers(corr_fname)
if not options.no_join and not options.no_compil:
pdfjoin(
pdf_files,
template.replace("tpl", "corr").replace(".tex", ".pdf"),
working_dir,
rm_pdfs=1,
)
2013-09-27 20:21:46 +00:00
if not options.dirty:
pytex.clean(working_dir)
2014-01-19 20:37:46 +00:00
2017-04-16 08:36:27 +00:00
2015-05-16 08:42:39 +00:00
def main():
2017-04-17 07:42:13 +00:00
setup()
2013-09-27 20:21:46 +00:00
parser = optparse.OptionParser()
2017-04-16 08:36:27 +00:00
parser.add_option(
"-t",
"--template",
action="store",
type="string",
dest="template",
help="File with the template. The name should have the following form tpl_... .",
)
2017-04-16 08:36:27 +00:00
parser.add_option(
"-w",
"--working-dir",
2017-04-16 08:36:27 +00:00
action="store",
type="string",
dest="working_dir",
help="Where fed templates and compiled files will be placed",
)
2017-04-16 08:36:27 +00:00
parser.add_option(
"-N",
"--number_subjects",
action="store",
type="int",
dest="num_subj",
default=1,
help="The number of subjects to make",
)
2019-10-16 20:45:00 +00:00
parser.add_option(
"-s",
"--students",
action="store",
type="string",
dest="student_csv",
help="CSV containing list of students names",
)
2017-04-16 08:36:27 +00:00
parser.add_option(
"-d",
"--dirty",
action="store_true",
dest="dirty",
help="Do not clean after compilation",
)
2017-04-16 08:36:27 +00:00
parser.add_option(
"-n",
"--no-compile",
action="store_true",
dest="no_compil",
help="Do not compile source code",
)
2017-04-16 08:36:27 +00:00
parser.add_option(
"-j",
"--no-join",
action="store_true",
dest="no_join",
help="Do not join pdf and clean single pdf",
)
2017-04-16 08:36:27 +00:00
parser.add_option(
"-O",
2017-04-16 08:36:27 +00:00
"--only-corr",
action="store_true",
dest="only_corr",
help="Create and compile only correction from existing subjects",
)
2017-04-16 08:36:27 +00:00
parser.add_option(
"-c",
"--corr",
action="store_true",
dest="corr",
help="Create and compile correction while making subjects",
)
2017-04-16 08:36:27 +00:00
(options, _) = parser.parse_args()
2013-09-27 20:21:46 +00:00
logger.debug(f"CI parser gets {options}")
2013-09-27 20:21:46 +00:00
if not options.template:
print("I need a template!")
sys.exit(0)
2015-05-16 08:42:39 +00:00
produce_and_compile(options)
2017-04-16 08:36:27 +00:00
if __name__ == "__main__":
2015-05-16 08:42:39 +00:00
main()
2013-09-27 18:09:38 +00:00
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
2017-04-16 08:36:27 +00:00
# cursor: 16 del