From 36d182c860011f69c17004b104bb31e29f1b212c Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Sat, 19 May 2018 11:08:29 +0300 Subject: [PATCH 1/7] paths cleaning --- README.rst | 2 +- pytex/pytex.py | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index f6c8560..f020303 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,7 @@ 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 --------------------------------- diff --git a/pytex/pytex.py b/pytex/pytex.py index 0ed0050..e284729 100644 --- a/pytex/pytex.py +++ b/pytex/pytex.py @@ -38,6 +38,8 @@ def feed(template, data, output="", force=0): :param output: name of the output file (by default: tpl is replaced by a 2 digits number) :param force: Override is the output already exists + + :return: name of fed template """ logger.info(f"Getting template {template}") tpl = texenv.get_template(str(template)) @@ -57,21 +59,23 @@ def feed(template, data, output="", force=0): output_dir = output_p.dirname() if output_dir and not output_dir.exists(): + logger.debug(f"Creating output dir {output_dir}") output_dir.mkdir_p() with open(output_p, "w") as output_f: output_f.write(tpl.render(**EXPORT_DICT, **data)) logger.info(f"{template} has been rendered to {output}.") + return output_p def pdflatex(latex_file, 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 not output_dir: output_dir = Path(latex_file).dirname().abspath() - logger.debug(f"output_dir for dflatex is {output_dir}") + logger.debug(f"output_dir for pdflatex is {output_dir}") pwd = Path('./').abspath() Path(output_dir).cd() @@ -96,7 +100,7 @@ def pdflatex(latex_file, output_dir=""): pwd.cd() -def clean(dirname=".", garbages=["*.aux", "*.log"]): +def clean(dirname="", garbages=["*.aux", "*.log"]): """ Clean the directory from aux and log latex files """ if not dirname: dirname = Path("./") From a122e2bba183f7d96989cf4f4a00e20c7084b950 Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Sun, 20 May 2018 11:59:10 +0300 Subject: [PATCH 2/7] Improve latex error bubble up --- pytex/latex_error_parser.py | 60 +++++++++++++++++++++++++++++++++++++ pytex/pytex.py | 17 +++++++++-- 2 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 pytex/latex_error_parser.py diff --git a/pytex/latex_error_parser.py b/pytex/latex_error_parser.py new file mode 100644 index 0000000..3dd8eb0 --- /dev/null +++ b/pytex/latex_error_parser.py @@ -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 diff --git a/pytex/pytex.py b/pytex/pytex.py index e284729..cd11249 100644 --- a/pytex/pytex.py +++ b/pytex/pytex.py @@ -11,8 +11,18 @@ import subprocess import random as rd from path import Path 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.setLevel(logging.DEBUG) +logger.addHandler(steam_handler) + EXPORT_DICT = {} EXPORT_DICT.update(m.__dict__) @@ -82,7 +92,7 @@ def pdflatex(latex_file, output_dir=""): compilation = subprocess.Popen( [ "pdflatex", - # f"-output-directory={output_dir}", + f"-output-directory={output_dir}", # "-halt-on-error", "-interaction=nonstopmode", "-shell-escape", @@ -93,9 +103,10 @@ def pdflatex(latex_file, output_dir=""): # shell=True ) + latex_error_logger = filter_errors(generic_sink(logger.error)) for line in compilation.stdout: - if b"Error" in line: - logger.error(line) + latex_error_logger.send(line.decode("utf-8").rstrip('\r\n')) + logger.debug(f"{latex_file.name} has been compiled in {output_dir}") pwd.cd() From ab850bcedb03423a183d159708ef303b60081189 Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Fri, 7 Dec 2018 08:49:50 +0100 Subject: [PATCH 3/7] Feat: Change encoding --- pytex/pytex.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pytex/pytex.py b/pytex/pytex.py index cd11249..89b8ee7 100644 --- a/pytex/pytex.py +++ b/pytex/pytex.py @@ -20,7 +20,7 @@ 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.setLevel(logging.DEBUG) +logger.setLevel(logging.ERROR) logger.addHandler(steam_handler) @@ -105,7 +105,7 @@ def pdflatex(latex_file, output_dir=""): latex_error_logger = filter_errors(generic_sink(logger.error)) for line in compilation.stdout: - latex_error_logger.send(line.decode("utf-8").rstrip('\r\n')) + latex_error_logger.send(line.decode("latin-1").rstrip('\r\n')) logger.debug(f"{latex_file.name} has been compiled in {output_dir}") pwd.cd() From 6a130d0086f0697612e0d8134e0eb56fb9c32289 Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Sun, 22 Dec 2019 17:30:23 +0100 Subject: [PATCH 4/7] Feat: add test and pyPath to pathlib --- pytex/pytex.py | 19 ++++++++++-------- tests/test_pytex.py | 47 +++++++++++++++++++++++++++++++++++++++++++++ tests/tpl_good.tex | 15 +++++++++++++++ 3 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 tests/test_pytex.py create mode 100644 tests/tpl_good.tex diff --git a/pytex/pytex.py b/pytex/pytex.py index 89b8ee7..d4a8b18 100644 --- a/pytex/pytex.py +++ b/pytex/pytex.py @@ -9,7 +9,8 @@ import logging import math as m import subprocess import random as rd -from path import Path +from pathlib import Path +import os from .texenv import * from .latex_error_parser import generic_sink, filter_errors @@ -67,7 +68,7 @@ def feed(template, data, output="", force=0): logger.error(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(): logger.debug(f"Creating output dir {output_dir}") output_dir.mkdir_p() @@ -84,11 +85,11 @@ def pdflatex(latex_file, output_dir=""): If output_dir is not set, it produce it next to the latex file. """ if not output_dir: - output_dir = Path(latex_file).dirname().abspath() + output_dir = Path(latex_file).parent.resolve() logger.debug(f"output_dir for pdflatex is {output_dir}") - pwd = Path('./').abspath() - Path(output_dir).cd() + prev_cwd = Path.cwd() + os.chdir(output_dir) compilation = subprocess.Popen( [ "pdflatex", @@ -106,9 +107,11 @@ def pdflatex(latex_file, output_dir=""): latex_error_logger = filter_errors(generic_sink(logger.error)) for line in compilation.stdout: latex_error_logger.send(line.decode("latin-1").rstrip('\r\n')) + compilation_status = compilation.wait() logger.debug(f"{latex_file.name} has been compiled in {output_dir}") - pwd.cd() + + os.chdir(prev_cwd) def clean(dirname="", garbages=["*.aux", "*.log"]): @@ -116,10 +119,10 @@ def clean(dirname="", garbages=["*.aux", "*.log"]): if not dirname: dirname = Path("./") for g in garbages: - g_files = Path(dirname).files(g) + g_files = Path(dirname).glob(g) logger.debug(f"Remove {g_files}") for g_file in g_files: - g_file.remove() + g_file.unlink() # ----------------------------- # Reglages pour 'vim' diff --git a/tests/test_pytex.py b/tests/test_pytex.py new file mode 100644 index 0000000..449a807 --- /dev/null +++ b/tests/test_pytex.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from pytex import feed, pdflatex, clean +import os + +TESTDIR = "tests" +GOOD_TEMPLATE = TESTDIR + "/tpl_good.tex" +WRONG_TEMPLATE = TESTDIR + "/tpl_wrong.tex" + +GOOD_DATA = { + "name": "Bob", + "repetitions": 4, +} + +def test_feed_once(): + output = feed(GOOD_TEMPLATE, GOOD_DATA) + os.system(f"rm {output}") + +def test_feed_twice(): + output1 = feed(GOOD_TEMPLATE, GOOD_DATA) + output2 = feed(GOOD_TEMPLATE, GOOD_DATA) + os.system(f"rm {output1}") + os.system(f"rm {output2}") + +def test_feed_output(): + dest = "./tests/special_name.tex" + output = feed(GOOD_TEMPLATE, GOOD_DATA, dest) + assert(output.samefile(dest)) + os.system(f"rm {output}") + +def test_feed_output_noforce(): + pass + # output = feed(GOOD_TEMPLATE, GOOD_DATA, ) + # os.system(f"rm {output}") + +def test_feed_pdflatex(): + latex_file = feed(GOOD_TEMPLATE, GOOD_DATA) + pdflatex(latex_file) + os.system(f"rm {latex_file}") + clean(TESTDIR, ["*.aux", "*.log", "*.pdf"]) + + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del diff --git a/tests/tpl_good.tex b/tests/tpl_good.tex new file mode 100644 index 0000000..445fefc --- /dev/null +++ b/tests/tpl_good.tex @@ -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} From 86d523d222533108e383b28cdef03121b3e9cc2c Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Sun, 22 Dec 2019 17:31:05 +0100 Subject: [PATCH 5/7] Feat: prepare to pack! --- setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.py b/setup.py index b0d577f..d25c896 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from setuptools import setup, find_packages setup( name='mypytex', - version='0.2', + version='0.3', description='Writing latex files and compile it with python and jinja2', url='https://git.opytex.org/lafrite/Pytex', author='Bertrand Benjamin', @@ -14,7 +14,6 @@ setup( packages=find_packages(), install_requires=[ 'jinja2', - 'path.py', ], ) From 737d64e0a8064a6120f902e530c0a2489e7b99af Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Mon, 23 Dec 2019 14:29:15 +0100 Subject: [PATCH 6/7] Feat: test in tmp dir and few bug correction --- pytex/pytex.py | 2 +- pytex/texenv.py | 1 - tests/test_pytex.py | 54 ++++++++++++++++++++++++++++----------------- 3 files changed, 35 insertions(+), 22 deletions(-) diff --git a/pytex/pytex.py b/pytex/pytex.py index d4a8b18..f6e7b3e 100644 --- a/pytex/pytex.py +++ b/pytex/pytex.py @@ -71,7 +71,7 @@ def feed(template, data, output="", force=0): output_dir = output_p.parent if output_dir and not output_dir.exists(): logger.debug(f"Creating output dir {output_dir}") - output_dir.mkdir_p() + output_dir.mkdir(exist_ok=True) with open(output_p, "w") as output_f: output_f.write(tpl.render(**EXPORT_DICT, **data)) diff --git a/pytex/texenv.py b/pytex/texenv.py index 98e792b..a319c72 100644 --- a/pytex/texenv.py +++ b/pytex/texenv.py @@ -24,7 +24,6 @@ texenv = jinja2.Environment( line_statement_prefix='%-', line_comment_prefix='%#', loader=jinja2.ChoiceLoader([ - # jinja2.PackageLoader("notes_tools.reports", "templates"), jinja2.FileSystemLoader(['./']), ]), extensions=['jinja2.ext.do'] diff --git a/tests/test_pytex.py b/tests/test_pytex.py index 449a807..f8e6485 100644 --- a/tests/test_pytex.py +++ b/tests/test_pytex.py @@ -3,42 +3,56 @@ from pytex import feed, pdflatex, clean import os +from shutil import copyfile +from pathlib import Path +import pytest -TESTDIR = "tests" -GOOD_TEMPLATE = TESTDIR + "/tpl_good.tex" -WRONG_TEMPLATE = TESTDIR + "/tpl_wrong.tex" +TESTDIR = Path("tests") +GOOD_TEMPLATE = TESTDIR / "tpl_good.tex" GOOD_DATA = { "name": "Bob", "repetitions": 4, } -def test_feed_once(): - output = feed(GOOD_TEMPLATE, GOOD_DATA) - os.system(f"rm {output}") -def test_feed_twice(): - output1 = feed(GOOD_TEMPLATE, GOOD_DATA) - output2 = feed(GOOD_TEMPLATE, GOOD_DATA) - os.system(f"rm {output1}") - os.system(f"rm {output2}") +@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(): - dest = "./tests/special_name.tex" - output = feed(GOOD_TEMPLATE, GOOD_DATA, dest) - assert(output.samefile(dest)) - os.system(f"rm {output}") def test_feed_output_noforce(): pass # output = feed(GOOD_TEMPLATE, GOOD_DATA, ) # os.system(f"rm {output}") -def test_feed_pdflatex(): - latex_file = feed(GOOD_TEMPLATE, GOOD_DATA) + +def test_feed_pdflatex(prepare_templates): + latex_file = feed(GOOD_TEMPLATE.name, GOOD_DATA) pdflatex(latex_file) - os.system(f"rm {latex_file}") - clean(TESTDIR, ["*.aux", "*.log", "*.pdf"]) + clean(garbages=["*.aux", "*.log", "*.pdf"]) # ----------------------------- From e311deeb6b1874f3c2726daee26764b1a8e96829 Mon Sep 17 00:00:00 2001 From: Bertrand Benjamin Date: Sat, 28 Dec 2019 09:42:38 +0100 Subject: [PATCH 7/7] Feat: pdflatex argument can be a str --- pytex/pytex.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pytex/pytex.py b/pytex/pytex.py index f6e7b3e..2ecffab 100644 --- a/pytex/pytex.py +++ b/pytex/pytex.py @@ -79,13 +79,14 @@ def feed(template, data, output="", force=0): return output_p -def pdflatex(latex_file, output_dir=""): +def pdflatex(tex_filename, output_dir=""): """ Compile a latex file with pdflatex If output_dir is not set, it produce it next to the latex file. """ + latex_file = Path(tex_filename) if not output_dir: - output_dir = Path(latex_file).parent.resolve() + output_dir = latex_file.parent.resolve() logger.debug(f"output_dir for pdflatex is {output_dir}") prev_cwd = Path.cwd() @@ -97,7 +98,7 @@ def pdflatex(latex_file, output_dir=""): # "-halt-on-error", "-interaction=nonstopmode", "-shell-escape", - str(Path(latex_file).name), + str(latex_file.name), ], stdout=subprocess.PIPE, stderr=subprocess.PIPE,