import os import io import tempfile import subprocess import logging import zipfile from contextlib import contextmanager logger = logging.getLogger(__name__) @contextmanager def _setenv(**mapping): """ ``with`` context to temporarily modify the environment variables Usage: def test_myapp_respects_this_envvar(): with _setenv(MYAPP_PLUGINS_DIR='testsandbox/plugins'): myapp.plugins.register() [...] """ backup = os.environ.copy() os.environ.update(mapping) try: yield finally: os.environ.clear() os.environ.update(backup) @contextmanager def _chdir(dirname): """ ``with`` context to temporarily chdir to a directory """ current = os.getcwd() os.chdir(dirname) try: yield finally: os.chdir(current) def make_pdf_from_zip(src_zip): """ Returns the bytes of the PDF """ with tempfile.TemporaryDirectory() as tmpdirname: zipfile.ZipFile(io.BytesIO(src_zip)).extractall(path=tmpdirname) with _setenv( PATH=(os.environ["PATH"] + ":/opt/texlive/2017/bin/x86_64-linux/"), HOME=tmpdirname, PERL5LIB=(os.environ.get("PERL5LIB", "") + ":/opt/texlive/2017/tlpkg/TeXLive/"), ): with _chdir(tmpdirname): # Run pdflatex... r = subprocess.run( [ "latexmk", "-verbose", "-interaction=batchmode", "-pdf", "-output-directory={}".format(tmpdirname), "document.tex", ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) stdout = r.stdout.decode("utf-8") logger.info(stdout) with open("document.pdf", "rb") as f: pdf = f.read() return pdf def make_pdf_from_tex(tex): """ Make a PDF from contexts of a .tex file """ buf = io.BytesIO() with zipfile.ZipFile(buf, "w") as zipf: zipf.writestr("document.tex", tex) return make_pdf_from_zip(buf.getvalue())