Compare commits

...

8 Commits

7 changed files with 174 additions and 21 deletions

View File

@ -1,6 +1,6 @@
# Pytex # Pytex
Pytex is a simple package which make aa bridge between Latex and Python. Pytex is a simple package which make a bridge between Latex and Python.
## texenv: Bring Python inside latex ## texenv: Bring Python inside latex

View File

@ -0,0 +1,60 @@
#!/usr/bin/env python
# encoding: utf-8
"""
Parsing latex error to bubble up import ones
"""
from functools import wraps
def coroutine(func):
@wraps(func)
def start(*args, **kwargs):
cr = func(*args, **kwargs)
next(cr)
return cr
return start
@coroutine
def generic_sink(func):
""" Generic sink
:param function: function that define the end of the sink
>>> print_sink = generic_sink(print)
>>> print_sink.send("coucou")
coucou
"""
while True:
c = (yield)
if c:
func(c)
@coroutine
def filter_errors(target):
""" Filter pdflatex log to bubble up error
https://en.wikibooks.org/wiki/LaTeX/Errors_and_Warnings
>>> s = generic_sink(print)
>>> tex_filter = filter_errors(s)
>>> tex_filter.send("! Undefined control sequence.")
! Undefined control sequence.
>>> tex_filter.send("l.43 \\includegraphics")
l.43 \\includegraphics
>>> tex_filter.send("l.43 \\includegraphics")
>>>
"""
while True:
line = (yield)
if line.startswith("!"):
target.send(line)
line = (yield)
while not line.startswith('See'):
target.send(line)
line = (yield)
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

View File

@ -9,10 +9,21 @@ import logging
import math as m import math as m
import subprocess import subprocess
import random as rd import random as rd
from path import Path from pathlib import Path
import os
from .texenv import * from .texenv import *
from .latex_error_parser import generic_sink, filter_errors
formatter = logging.Formatter('%(name)s :: %(levelname)s :: %(message)s')
steam_handler = logging.StreamHandler()
steam_handler.setLevel(logging.DEBUG)
steam_handler.setFormatter(formatter)
# création de l'objet logger qui va nous servir à écrire dans les logs
# on met le niveau du logger à DEBUG, comme ça il écrit tout
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.setLevel(logging.ERROR)
logger.addHandler(steam_handler)
EXPORT_DICT = {} EXPORT_DICT = {}
EXPORT_DICT.update(m.__dict__) EXPORT_DICT.update(m.__dict__)
@ -38,6 +49,8 @@ def feed(template, data, output="", force=0):
:param output: name of the output file :param output: name of the output file
(by default: tpl is replaced by a 2 digits number) (by default: tpl is replaced by a 2 digits number)
:param force: Override is the output already exists :param force: Override is the output already exists
:return: name of fed template
""" """
logger.info(f"Getting template {template}") logger.info(f"Getting template {template}")
tpl = texenv.get_template(str(template)) tpl = texenv.get_template(str(template))
@ -55,56 +68,62 @@ def feed(template, data, output="", force=0):
logger.error(f"{output} exists. Use force=1 do override it") logger.error(f"{output} exists. Use force=1 do override it")
raise ValueError(f"{output} exists. Use force=1 do override it") raise ValueError(f"{output} exists. Use force=1 do override it")
output_dir = output_p.dirname() output_dir = output_p.parent
if output_dir and not output_dir.exists(): if output_dir and not output_dir.exists():
output_dir.mkdir_p() logger.debug(f"Creating output dir {output_dir}")
output_dir.mkdir(exist_ok=True)
with open(output_p, "w") as output_f: with open(output_p, "w") as output_f:
output_f.write(tpl.render(**EXPORT_DICT, **data)) output_f.write(tpl.render(**EXPORT_DICT, **data))
logger.info(f"{template} has been rendered to {output}.") logger.info(f"{template} has been rendered to {output}.")
return output_p
def pdflatex(latex_file, output_dir=""): def pdflatex(tex_filename, output_dir=""):
""" Compile latex file """ Compile a latex file with pdflatex
If output_dir is not set, it produce it next to the latex file. If output_dir is not set, it produce it next to the latex file.
""" """
latex_file = Path(tex_filename)
if not output_dir: if not output_dir:
output_dir = Path(latex_file).dirname().abspath() output_dir = latex_file.parent.resolve()
logger.debug(f"output_dir for dflatex is {output_dir}") logger.debug(f"output_dir for pdflatex is {output_dir}")
pwd = Path('./').abspath() prev_cwd = Path.cwd()
Path(output_dir).cd() os.chdir(output_dir)
compilation = subprocess.Popen( compilation = subprocess.Popen(
[ [
"pdflatex", "pdflatex",
# f"-output-directory={output_dir}", f"-output-directory={output_dir}",
# "-halt-on-error", # "-halt-on-error",
"-interaction=nonstopmode", "-interaction=nonstopmode",
"-shell-escape", "-shell-escape",
str(Path(latex_file).name), str(latex_file.name),
], ],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
# shell=True # shell=True
) )
latex_error_logger = filter_errors(generic_sink(logger.error))
for line in compilation.stdout: for line in compilation.stdout:
if b"Error" in line: latex_error_logger.send(line.decode("latin-1").rstrip('\r\n'))
logger.error(line) compilation_status = compilation.wait()
logger.debug(f"{latex_file.name} has been compiled in {output_dir}") logger.debug(f"{latex_file.name} has been compiled in {output_dir}")
pwd.cd()
os.chdir(prev_cwd)
def clean(dirname=".", garbages=["*.aux", "*.log"]): def clean(dirname="", garbages=["*.aux", "*.log"]):
""" Clean the directory from aux and log latex files """ """ Clean the directory from aux and log latex files """
if not dirname: if not dirname:
dirname = Path("./") dirname = Path("./")
for g in garbages: for g in garbages:
g_files = Path(dirname).files(g) g_files = Path(dirname).glob(g)
logger.debug(f"Remove {g_files}") logger.debug(f"Remove {g_files}")
for g_file in g_files: for g_file in g_files:
g_file.remove() g_file.unlink()
# ----------------------------- # -----------------------------
# Reglages pour 'vim' # Reglages pour 'vim'

View File

@ -24,7 +24,6 @@ texenv = jinja2.Environment(
line_statement_prefix='%-', line_statement_prefix='%-',
line_comment_prefix='%#', line_comment_prefix='%#',
loader=jinja2.ChoiceLoader([ loader=jinja2.ChoiceLoader([
# jinja2.PackageLoader("notes_tools.reports", "templates"),
jinja2.FileSystemLoader(['./']), jinja2.FileSystemLoader(['./']),
]), ]),
extensions=['jinja2.ext.do'] extensions=['jinja2.ext.do']

View File

@ -5,7 +5,7 @@ from setuptools import setup, find_packages
setup( setup(
name='mypytex', name='mypytex',
version='0.2', version='0.3',
description='Writing latex files and compile it with python and jinja2', description='Writing latex files and compile it with python and jinja2',
url='https://git.opytex.org/lafrite/Pytex', url='https://git.opytex.org/lafrite/Pytex',
author='Bertrand Benjamin', author='Bertrand Benjamin',
@ -14,7 +14,6 @@ setup(
packages=find_packages(), packages=find_packages(),
install_requires=[ install_requires=[
'jinja2', 'jinja2',
'path.py',
], ],
) )

61
tests/test_pytex.py Normal file
View File

@ -0,0 +1,61 @@
#!/usr/bin/env python
# encoding: utf-8
from pytex import feed, pdflatex, clean
import os
from shutil import copyfile
from pathlib import Path
import pytest
TESTDIR = Path("tests")
GOOD_TEMPLATE = TESTDIR / "tpl_good.tex"
GOOD_DATA = {
"name": "Bob",
"repetitions": 4,
}
@pytest.fixture()
def prepare_templates(tmpdir):
wdir = tmpdir
good_tpl = Path(GOOD_TEMPLATE)
copyfile(good_tpl, wdir / good_tpl.name)
prev_cwd = Path.cwd()
os.chdir(wdir)
yield wdir
os.chdir(prev_cwd)
def test_feed_once(prepare_templates):
output = feed(GOOD_TEMPLATE.name, GOOD_DATA)
def test_feed_twice(prepare_templates):
output1 = feed(GOOD_TEMPLATE.name, GOOD_DATA)
output2 = feed(GOOD_TEMPLATE.name, GOOD_DATA)
def test_feed_output(prepare_templates):
dest = "./tests/special_name.tex"
output = feed(GOOD_TEMPLATE.name, GOOD_DATA, dest)
assert output.samefile(dest)
def test_feed_output_noforce():
pass
# output = feed(GOOD_TEMPLATE, GOOD_DATA, )
# os.system(f"rm {output}")
def test_feed_pdflatex(prepare_templates):
latex_file = feed(GOOD_TEMPLATE.name, GOOD_DATA)
pdflatex(latex_file)
clean(garbages=["*.aux", "*.log", "*.pdf"])
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del

15
tests/tpl_good.tex Normal file
View File

@ -0,0 +1,15 @@
\documentclass{article}
\usepackage[utf8]{inputenc} % Unicode support (Umlauts etc.)
\usepackage[french]{babel} % Change hyphenation rules
\begin{document}
Coucou comment allez vous?
Je m'appelle \Var{name}.
%- for j in range(repetitions)
Je peux faire \Var{j} \\
%- endfor
\end{document}