From c4cb5e323d1409c566682c7c21ca808dfb9a435e Mon Sep 17 00:00:00 2001 From: Max Weiner Date: Fri, 4 Feb 2022 15:30:27 +0100 Subject: [PATCH 01/16] first implementation latexmk build step --- src/pytask_latex/build_steps.py | 53 ++++++++++++++++ src/pytask_latex/collect.py | 107 +++++++++++++------------------- 2 files changed, 97 insertions(+), 63 deletions(-) create mode 100644 src/pytask_latex/build_steps.py diff --git a/src/pytask_latex/build_steps.py b/src/pytask_latex/build_steps.py new file mode 100644 index 0000000..c7599d8 --- /dev/null +++ b/src/pytask_latex/build_steps.py @@ -0,0 +1,53 @@ +import os +import subprocess + +# each build step constructor must return a callable with the following signature: +# run_step(main_file: Path, job_name: Optional[str], out_dir: Optional[Path]) +import warnings +from pathlib import Path + + +def _get_relative_out_dir(main_file, out_dir): + """The output folder needs to be declared as a relative path to the directory where the + latex source lies. + + 1. It must be relative because bibtex / biber, which is necessary for + bibliographies, does not accept full paths as a safety measure. + 2. Due to the ``--cd`` flag, latexmk will change the directory to the one where the + source files are. Thus, relative to the latex sources. + + See this `discussion on Github + `_ + for additional information. + """ + return Path( + os.path.relpath(out_dir, main_file.parent) + ).as_posix() + + +def default_steps(): + return ["latexmk"] + + +def latexmk(options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd")): + """Build step that calls latexmk. + """ + options = [str(i) for i in options] + + def run_latexmk(main_file, job_name, out_dir): + job_name_opt = [f"--jobname={job_name}"] if job_name else [] + out_dir_opt = [f"--output-directory={_get_relative_out_dir(main_file, out_dir)}"] if out_dir else [] + cmd = ( + [ + "latexmk", + *options, + ] + + job_name_opt + + out_dir_opt + + [ + main_file.as_posix(), + ] + ) + subprocess.run(cmd, check=True) + + return run_latexmk diff --git a/src/pytask_latex/collect.py b/src/pytask_latex/collect.py index 5aaa097..f87e5b0 100644 --- a/src/pytask_latex/collect.py +++ b/src/pytask_latex/collect.py @@ -3,8 +3,9 @@ import functools import os import subprocess +import warnings from pathlib import Path -from typing import Iterable +from typing import Iterable, Callable from typing import Optional from typing import Sequence from typing import Union @@ -19,31 +20,17 @@ from _pytask.parametrize import _copy_func from latex_dependency_scanner import scan +from . import build_steps -DEFAULT_OPTIONS = ["--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd"] - -def latex(options: Optional[Union[str, Iterable[str]]] = None): - """Specify command line options for latexmk. - - Parameters - ---------- - options : Optional[Union[str, Iterable[str]]] - One or multiple command line options passed to latexmk. - - """ - if options is None: - options = DEFAULT_OPTIONS.copy() - else: - options = _to_list(options) - options = [str(i) for i in options] - return options - - -def compile_latex_document(latex): +def compile_latex_document(build_steps, main_file, job_name, out_dir): """Replaces the dummy function provided by the user.""" - print("Executing " + " ".join(latex) + ".") # noqa: T001 - subprocess.run(latex, check=True) + + for step in build_steps: + try: + step(main_file, job_name, out_dir) + except Exception as e: + raise RuntimeError(f"Build step {step.__name__} failed.") from e @hookimpl @@ -80,23 +67,23 @@ def pytask_collect_task_teardown(session, task): task.produces, session.config["latex_document_key"] ) if not ( - isinstance(document, FilePathNode) - and document.value.suffix in [".pdf", ".ps", ".dvi"] + isinstance(document, FilePathNode) + and document.value.suffix in [".pdf", ".ps", ".dvi"] ): raise ValueError( "The first or sole product of a LaTeX task must point to a .pdf, .ps " "or .dvi file which is the compiled document." ) - latex_function = _copy_func(compile_latex_document) - latex_function.pytaskmark = copy.deepcopy(task.function.pytaskmark) + task_function = _copy_func(compile_latex_document) + task_function.pytaskmark = copy.deepcopy(task.function.pytaskmark) merged_mark = _merge_all_markers(task) - args = latex(*merged_mark.args, **merged_mark.kwargs) - options = _prepare_cmd_options(session, task, args) - latex_function = functools.partial(latex_function, latex=options) + steps = get_build_steps(merged_mark) + args = get_build_step_args(session, task) + task_function = functools.partial(task_function, build_steps=steps, **args) - task.function = latex_function + task.function = task_function if session.config["infer_latex_dependencies"]: task = _add_latex_dependencies_retroactively(task, session) @@ -169,22 +156,30 @@ def _merge_all_markers(task): return mark -def _prepare_cmd_options(session, task, args): - """Prepare the command line arguments to compile the LaTeX document. +def get_build_steps(latex_mark: Mark): + if isinstance(list, latex_mark.args[0]): + warnings.warn( + "The old argument syntax for latexmk is deprecated and will be removed in the next minor update. Afterwards a given list will be interpreted as list of build steps.") + yield build_steps.latexmk(_to_list(latex_mark.args[0])) - The output folder needs to be declared as a relative path to the directory where the - latex source lies. + elif "build_steps" in latex_mark.kwargs: + for step in latex_mark.kwargs["build_steps"]: + if isinstance(step, str): + yield getattr(build_steps, step)() # create step with default args + continue - 1. It must be relative because bibtex / biber, which is necessary for - bibliographies, does not accept full paths as a safety measure. - 2. Due to the ``--cd`` flag, latexmk will change the directory to the one where the - source files are. Thus, relative to the latex sources. + if isinstance(step, Callable): + yield step # already step function + continue - See this `discussion on Github - `_ - for additional information. + raise ValueError("Unrecognized item given in build_steps") - """ + else: + yield from build_steps.default_steps() + + +def get_build_step_args(session, task): + """Prepare arguments for build step functions""" latex_document = _get_node_from_dictionary( task.depends_on, session.config["latex_source_key"] ).value @@ -192,28 +187,14 @@ def _prepare_cmd_options(session, task, args): task.produces, session.config["latex_document_key"] ).value - # Jobname controls the name of the compiled document. No suffix! - if latex_document.stem != compiled_document.stem: - jobname = [f"--jobname={compiled_document.stem}"] - else: - jobname = [] + job_name = compiled_document.stem - # The path to the output directory must be relative from the location of the source - # file. See docstring for more information. - out_relative_to_latex_source = Path( - os.path.relpath(compiled_document.parent, latex_document.parent) - ).as_posix() + out_dir = compiled_document.parent - return ( - [ - "latexmk", - *args, - ] - + jobname - + [ - f"--output-directory={out_relative_to_latex_source}", - latex_document.as_posix(), - ] + return dict( + main_file=latex_document, + job_name=job_name, + out_dir=out_dir ) From 8cec675a196d02f6e0bea09829177292762ff951 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Tue, 1 Mar 2022 18:09:17 +0100 Subject: [PATCH 02/16] make tests running. --- src/pytask_latex/build_steps.py | 31 +++++++---------- src/pytask_latex/collect.py | 25 +++++-------- tests/test_collect.py | 62 --------------------------------- 3 files changed, 21 insertions(+), 97 deletions(-) diff --git a/src/pytask_latex/build_steps.py b/src/pytask_latex/build_steps.py index c7599d8..3d45e59 100644 --- a/src/pytask_latex/build_steps.py +++ b/src/pytask_latex/build_steps.py @@ -1,15 +1,14 @@ import os import subprocess +from pathlib import Path # each build step constructor must return a callable with the following signature: # run_step(main_file: Path, job_name: Optional[str], out_dir: Optional[Path]) -import warnings -from pathlib import Path def _get_relative_out_dir(main_file, out_dir): - """The output folder needs to be declared as a relative path to the directory where the - latex source lies. + """The output folder needs to be declared as a relative path to the directory where + the latex source lies. 1. It must be relative because bibtex / biber, which is necessary for bibliographies, does not accept full paths as a safety measure. @@ -19,10 +18,9 @@ def _get_relative_out_dir(main_file, out_dir): See this `discussion on Github `_ for additional information. + """ - return Path( - os.path.relpath(out_dir, main_file.parent) - ).as_posix() + return Path(os.path.relpath(out_dir, main_file.parent)).as_posix() def default_steps(): @@ -30,23 +28,18 @@ def default_steps(): def latexmk(options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd")): - """Build step that calls latexmk. - """ + """Build step that calls latexmk.""" options = [str(i) for i in options] def run_latexmk(main_file, job_name, out_dir): job_name_opt = [f"--jobname={job_name}"] if job_name else [] - out_dir_opt = [f"--output-directory={_get_relative_out_dir(main_file, out_dir)}"] if out_dir else [] + out_dir_opt = ( + [f"--output-directory={_get_relative_out_dir(main_file, out_dir)}"] + if out_dir + else [] + ) cmd = ( - [ - "latexmk", - *options, - ] - + job_name_opt - + out_dir_opt - + [ - main_file.as_posix(), - ] + ["latexmk", *options] + job_name_opt + out_dir_opt + [main_file.as_posix()] ) subprocess.run(cmd, check=True) diff --git a/src/pytask_latex/collect.py b/src/pytask_latex/collect.py index f87e5b0..563a11b 100644 --- a/src/pytask_latex/collect.py +++ b/src/pytask_latex/collect.py @@ -1,14 +1,9 @@ """Collect tasks.""" import copy import functools -import os -import subprocess import warnings -from pathlib import Path -from typing import Iterable, Callable -from typing import Optional +from typing import Callable from typing import Sequence -from typing import Union from _pytask.config import hookimpl from _pytask.mark import Mark @@ -19,8 +14,7 @@ from _pytask.nodes import PythonFunctionTask from _pytask.parametrize import _copy_func from latex_dependency_scanner import scan - -from . import build_steps +from pytask_latex import build_steps def compile_latex_document(build_steps, main_file, job_name, out_dir): @@ -67,8 +61,8 @@ def pytask_collect_task_teardown(session, task): task.produces, session.config["latex_document_key"] ) if not ( - isinstance(document, FilePathNode) - and document.value.suffix in [".pdf", ".ps", ".dvi"] + isinstance(document, FilePathNode) + and document.value.suffix in [".pdf", ".ps", ".dvi"] ): raise ValueError( "The first or sole product of a LaTeX task must point to a .pdf, .ps " @@ -159,7 +153,10 @@ def _merge_all_markers(task): def get_build_steps(latex_mark: Mark): if isinstance(list, latex_mark.args[0]): warnings.warn( - "The old argument syntax for latexmk is deprecated and will be removed in the next minor update. Afterwards a given list will be interpreted as list of build steps.") + "The old argument syntax for latexmk is deprecated and will be removed in " + "the next minor update. Afterwards a given list will be interpreted as " + "list of build steps." + ) yield build_steps.latexmk(_to_list(latex_mark.args[0])) elif "build_steps" in latex_mark.kwargs: @@ -191,11 +188,7 @@ def get_build_step_args(session, task): out_dir = compiled_document.parent - return dict( - main_file=latex_document, - job_name=job_name, - out_dir=out_dir - ) + return {"main_file": latex_document, "job_name": job_name, "out_dir": out_dir} def _to_list(scalar_or_iter): diff --git a/tests/test_collect.py b/tests/test_collect.py index dd48cbf..dd4af07 100644 --- a/tests/test_collect.py +++ b/tests/test_collect.py @@ -6,9 +6,6 @@ from _pytask.nodes import FilePathNode from pytask_latex.collect import _get_node_from_dictionary from pytask_latex.collect import _merge_all_markers -from pytask_latex.collect import _prepare_cmd_options -from pytask_latex.collect import DEFAULT_OPTIONS -from pytask_latex.collect import latex from pytask_latex.collect import pytask_collect_task from pytask_latex.collect import pytask_collect_task_teardown @@ -42,20 +39,6 @@ def test_merge_all_markers(marks, expected): assert out == expected -@pytest.mark.unit -@pytest.mark.parametrize( - "latex_args, expected", - [ - (None, DEFAULT_OPTIONS), - ("--some-option", ["--some-option"]), - (["--a", "--b"], ["--a", "--b"]), - ], -) -def test_latex(latex_args, expected): - options = latex(latex_args) - assert options == expected - - @pytest.mark.unit @pytest.mark.parametrize( "name, expected", @@ -136,48 +119,3 @@ def test_pytask_collect_task_teardown( def test_get_node_from_dictionary(obj, key, expected): result = _get_node_from_dictionary(obj, key) assert result == expected - - -@pytest.mark.unit -@pytest.mark.parametrize( - "args", - [ - [], - ["a"], - ["a", "b"], - ], -) -@pytest.mark.parametrize("latex_source_key", ["source", "script"]) -@pytest.mark.parametrize("latex_document_key", ["document", "compiled_doc"]) -@pytest.mark.parametrize("input_name", ["source", "main"]) -@pytest.mark.parametrize("output_name", ["source", "doc"]) -def test_prepare_cmd_options( - args, latex_source_key, latex_document_key, input_name, output_name -): - session = DummyClass() - session.config = { - "latex_source_key": latex_source_key, - "latex_document_key": latex_document_key, - } - - dependency = DummyClass() - dependency.value = Path(f"{input_name}.tex") - product = DummyClass() - product.value = Path(f"{output_name}.pdf") - task = DummyClass() - task.depends_on = {latex_source_key: dependency} - task.produces = {latex_document_key: product} - task.name = "task" - - result = _prepare_cmd_options(session, task, args) - - jobname = ( - [] - if dependency.value.stem == product.value.stem - else [f"--jobname={product.value.stem}"] - ) - - assert result == ["latexmk", *args] + jobname + [ - "--output-directory=.", - f"{input_name}.tex", - ] From e7fd277235bfa19255ba7d023f202289e31d7256 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Wed, 2 Mar 2022 00:46:19 +0100 Subject: [PATCH 03/16] Fix tests and parse latex decorator with function. --- environment.yml | 1 - src/pytask_latex/build_steps.py | 2 + src/pytask_latex/collect.py | 94 ++++++++++++++++++++++----------- tests/test_execute.py | 9 ++-- tests/test_parallel.py | 12 +++-- tests/test_parametrize.py | 3 +- 6 files changed, 81 insertions(+), 40 deletions(-) diff --git a/environment.yml b/environment.yml index 42d89f1..9734833 100644 --- a/environment.yml +++ b/environment.yml @@ -19,7 +19,6 @@ dependencies: - black - jupyterlab - matplotlib - - pdbpp - pre-commit - pytest - pytest-cov diff --git a/src/pytask_latex/build_steps.py b/src/pytask_latex/build_steps.py index 3d45e59..2c3a435 100644 --- a/src/pytask_latex/build_steps.py +++ b/src/pytask_latex/build_steps.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import subprocess from pathlib import Path diff --git a/src/pytask_latex/collect.py b/src/pytask_latex/collect.py index c4bf19b..5618ad3 100644 --- a/src/pytask_latex/collect.py +++ b/src/pytask_latex/collect.py @@ -4,9 +4,13 @@ import copy import functools import warnings +from subprocess import CalledProcessError +from typing import Any from typing import Callable +from typing import Iterable from typing import Sequence +import latex_dependency_scanner as lds from _pytask.config import hookimpl from _pytask.mark import Mark from _pytask.mark_utils import get_specific_markers_from_task @@ -15,8 +19,63 @@ from _pytask.nodes import FilePathNode from _pytask.nodes import PythonFunctionTask from _pytask.parametrize import _copy_func -from latex_dependency_scanner import scan -from pytask_latex import build_steps +from pytask_latex import build_steps as bs + + +_DEPRECATION_WARNING = """The old syntax for using @pytask.mark.latex is deprecated \ +and will be removed in v0.2.0. To pass custom options to latexmk and the compilation \ +process convert + + @pytask.mark.latex(options) + def task_func(): + ... + +to + + from pytask_latex import build_steps + + @pytask.mark.latex(build_steps.latexmk(options)) + def task_func(): + ... + +""" + + +def latex( + options: str | Iterable[str] | None = None, + *, + build_steps: str | Callable[..., Any] | Sequence[str | Callable[..., Any]] = None, +): + """Specify command line options for latexmk. + + Parameters + ---------- + options + One or multiple command line options passed to latexmk. + build_steps + Build steps to compile the document. + + """ + build_steps = ["latexmk"] if build_steps is None else build_steps + + if options is not None: + warnings.warn(_DEPRECATION_WARNING, DeprecationWarning) + out = [bs.latexmk(_to_list(options))] + + else: + out = [] + for step in _to_list(build_steps): + if isinstance(step, str): + parsed_step = getattr(bs, step) + if parsed_step is None: + raise ValueError(f"Build step {step!r} is unknown.") + out.append(parsed_step()) + elif callable(step): + out.append(step) + else: + raise ValueError(f"Build step {step!r} is not a valid step.") + + return out def compile_latex_document(build_steps, main_file, job_name, out_dir): @@ -25,7 +84,7 @@ def compile_latex_document(build_steps, main_file, job_name, out_dir): for step in build_steps: try: step(main_file, job_name, out_dir) - except Exception as e: + except CalledProcessError as e: raise RuntimeError(f"Build step {step.__name__} failed.") from e @@ -75,7 +134,7 @@ def pytask_collect_task_teardown(session, task): task_function.pytaskmark = copy.deepcopy(task.function.pytaskmark) merged_mark = _merge_all_markers(task) - steps = get_build_steps(merged_mark) + steps = latex(*merged_mark.args, **merged_mark.kwargs) args = get_build_step_args(session, task) task_function = functools.partial(task_function, build_steps=steps, **args) @@ -116,7 +175,7 @@ def _add_latex_dependencies_retroactively(task, session): ) # Scan the LaTeX document for included files. - latex_dependencies = set(scan(source.path)) + latex_dependencies = set(lds.scan(source.path)) # Remove duplicated dependencies which have already been added by the user and those # which do not exist. @@ -152,31 +211,6 @@ def _merge_all_markers(task): return mark -def get_build_steps(latex_mark: Mark): - if isinstance(list, latex_mark.args[0]): - warnings.warn( - "The old argument syntax for latexmk is deprecated and will be removed in " - "the next minor update. Afterwards a given list will be interpreted as " - "list of build steps." - ) - yield build_steps.latexmk(_to_list(latex_mark.args[0])) - - elif "build_steps" in latex_mark.kwargs: - for step in latex_mark.kwargs["build_steps"]: - if isinstance(step, str): - yield getattr(build_steps, step)() # create step with default args - continue - - if isinstance(step, Callable): - yield step # already step function - continue - - raise ValueError("Unrecognized item given in build_steps") - - else: - yield from build_steps.default_steps() - - def get_build_step_args(session, task): """Prepare arguments for build step functions""" latex_document = _get_node_from_dictionary( diff --git a/tests/test_execute.py b/tests/test_execute.py index cfd4f71..d99aced 100644 --- a/tests/test_execute.py +++ b/tests/test_execute.py @@ -2,7 +2,6 @@ import textwrap from contextlib import ExitStack as does_not_raise # noqa: N813 -from subprocess import CalledProcessError import pytest from _pytask.mark import Mark @@ -270,7 +269,8 @@ def task_compile_document(): """ tmp_path.joinpath("document.tex").write_text(textwrap.dedent(latex_source)) - result = runner.invoke(cli, [tmp_path.as_posix()]) + with pytest.warns(DeprecationWarning, match="The old syntax"): + result = runner.invoke(cli, [tmp_path.as_posix()]) assert result.exit_code == 0 assert tmp_path.joinpath("document.pdf").exists() @@ -413,11 +413,12 @@ def task_compile_document(): """ tmp_path.joinpath("sub", "document.tex").write_text(textwrap.dedent(latex_source)) - session = main({"paths": tmp_path}) + with pytest.warns(DeprecationWarning, match="The old syntax"): + session = main({"paths": tmp_path}) assert session.exit_code == 1 assert len(session.tasks) == 1 - assert isinstance(session.execution_reports[0].exc_info[1], CalledProcessError) + assert isinstance(session.execution_reports[0].exc_info[1], RuntimeError) @needs_latexmk diff --git a/tests/test_parallel.py b/tests/test_parallel.py index 77afd8d..02c7b27 100644 --- a/tests/test_parallel.py +++ b/tests/test_parallel.py @@ -22,7 +22,6 @@ ) -@pytest.mark.xfail(reason="I don't know.") @needs_latexmk @skip_on_github_actions_with_win @pytest.mark.end_to_end @@ -58,6 +57,7 @@ def task_compile_latex_document(): start = time.time() result = runner.invoke(cli, [tmp_path.as_posix()]) + assert result.exit_code == 0 duration_normal = time.time() - start @@ -66,13 +66,13 @@ def task_compile_latex_document(): start = time.time() result = runner.invoke(cli, [tmp_path.as_posix(), "-n", 2]) + assert result.exit_code == 0 duration_parallel = time.time() - start assert duration_parallel < duration_normal -@pytest.mark.xfail(reason="I don't know.") @needs_latexmk @skip_on_github_actions_with_win @pytest.mark.end_to_end @@ -108,7 +108,9 @@ def task_compile_latex_document(): tmp_path.joinpath("document.tex").write_text(textwrap.dedent(latex_source)) start = time.time() - result = runner.invoke(cli, [tmp_path.as_posix()]) + with pytest.warns(DeprecationWarning, match="The old syntax"): + result = runner.invoke(cli, [tmp_path.as_posix()]) + assert result.exit_code == 0 duration_normal = time.time() - start @@ -116,7 +118,9 @@ def task_compile_latex_document(): tmp_path.joinpath(name).unlink() start = time.time() - result = runner.invoke(cli, [tmp_path.as_posix(), "-n", 2]) + with pytest.warns(DeprecationWarning, match="The old syntax"): + result = runner.invoke(cli, [tmp_path.as_posix(), "-n", 2]) + assert result.exit_code == 0 duration_parallel = time.time() - start diff --git a/tests/test_parametrize.py b/tests/test_parametrize.py index c15a734..e4b8883 100644 --- a/tests/test_parametrize.py +++ b/tests/test_parametrize.py @@ -99,7 +99,8 @@ def task_compile_latex_document(): """ tmp_path.joinpath("document.tex").write_text(textwrap.dedent(latex_source)) - session = main({"paths": tmp_path}) + with pytest.warns(DeprecationWarning, match="The old syntax"): + session = main({"paths": tmp_path}) assert session.exit_code == 0 assert tmp_path.joinpath("document.pdf").exists() From 16b9ea4a4f92040b0408582a2acd9819dc346fec Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Wed, 2 Mar 2022 01:06:12 +0100 Subject: [PATCH 04/16] Duplicate tests with deprecation warnings and change them to use the new api. --- src/pytask_latex/parametrize.py | 5 ++- tests/test_execute.py | 70 +++++++++++++++++++++++++++++++++ tests/test_parallel.py | 57 +++++++++++++++++++++++++++ tests/test_parametrize.py | 44 +++++++++++++++++++++ 4 files changed, 175 insertions(+), 1 deletion(-) diff --git a/src/pytask_latex/parametrize.py b/src/pytask_latex/parametrize.py index 918c2c8..aa4b492 100644 --- a/src/pytask_latex/parametrize.py +++ b/src/pytask_latex/parametrize.py @@ -10,4 +10,7 @@ def pytask_parametrize_kwarg_to_marker(obj, kwargs): """Register kwargs as latex marker.""" if callable(obj): if "latex" in kwargs: - mark.latex(kwargs.pop("latex"))(obj) + if isinstance(kwargs["latex"], dict): + mark.latex(**kwargs.pop("latex"))(obj) + else: + mark.latex(kwargs.pop("latex"))(obj) diff --git a/tests/test_execute.py b/tests/test_execute.py index d99aced..81e0303 100644 --- a/tests/test_execute.py +++ b/tests/test_execute.py @@ -276,6 +276,41 @@ def task_compile_document(): assert tmp_path.joinpath("document.pdf").exists() +@needs_latexmk +@skip_on_github_actions_with_win +@pytest.mark.end_to_end +def test_compile_latex_document_w_xelatex_new_api(runner, tmp_path): + task_source = """ + import pytask + from pytask_latex import build_steps + + @pytask.mark.latex( + build_steps=build_steps.latexmk( + ["--xelatex", "--interaction=nonstopmode", "--synctex=1", "--cd"] + ) + ) + @pytask.mark.depends_on("document.tex") + @pytask.mark.produces("document.pdf") + def task_compile_document(): + pass + + """ + tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source)) + + latex_source = r""" + \documentclass{report} + \begin{document} + I got, I got, I got, I got loyalty, got royalty inside my DNA. + \end{document} + """ + tmp_path.joinpath("document.tex").write_text(textwrap.dedent(latex_source)) + + result = runner.invoke(cli, [tmp_path.as_posix()]) + + assert result.exit_code == 0 + assert tmp_path.joinpath("document.pdf").exists() + + @needs_latexmk @skip_on_github_actions_with_win @pytest.mark.end_to_end @@ -421,6 +456,41 @@ def task_compile_document(): assert isinstance(session.execution_reports[0].exc_info[1], RuntimeError) +@needs_latexmk +@skip_on_github_actions_with_win +@pytest.mark.end_to_end +def test_compile_document_w_wrong_flag_new_api(tmp_path): + """Test that wrong flags raise errors.""" + tmp_path.joinpath("sub").mkdir(parents=True) + + task_source = """ + import pytask + from pytask_latex import build_steps + + @pytask.mark.latex(build_steps=build_steps.latexmk("--wrong-flag")) + @pytask.mark.depends_on("document.tex") + @pytask.mark.produces("out/document.pdf") + def task_compile_document(): + pass + + """ + tmp_path.joinpath("sub", "task_dummy.py").write_text(textwrap.dedent(task_source)) + + latex_source = r""" + \documentclass{report} + \begin{document} + The book of love is long and boring ... + \end{document} + """ + tmp_path.joinpath("sub", "document.tex").write_text(textwrap.dedent(latex_source)) + + session = main({"paths": tmp_path}) + + assert session.exit_code == 1 + assert len(session.tasks) == 1 + assert isinstance(session.execution_reports[0].exc_info[1], RuntimeError) + + @needs_latexmk @pytest.mark.end_to_end def test_compile_document_w_image(runner, tmp_path): diff --git a/tests/test_parallel.py b/tests/test_parallel.py index 02c7b27..261f4ef 100644 --- a/tests/test_parallel.py +++ b/tests/test_parallel.py @@ -125,3 +125,60 @@ def task_compile_latex_document(): duration_parallel = time.time() - start assert duration_parallel < duration_normal + + +@needs_latexmk +@skip_on_github_actions_with_win +@pytest.mark.end_to_end +def test_parallel_parametrization_over_source_file_new_api(runner, tmp_path): + source = """ + import pytask + from pytask_latex import build_steps + + @pytask.mark.depends_on("document.tex") + @pytask.mark.parametrize( + "produces, latex", + [ + ( + "document.pdf", + {"build_steps": build_steps.latexmk( + ("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd") + )} + ), + ( + "document.dvi", + {"build_steps": build_steps.latexmk( + ("--dvi", "--interaction=nonstopmode", "--synctex=1", "--cd") + )} + ), + ], + ) + def task_compile_latex_document(): + pass + """ + tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(source)) + + latex_source = r""" + \documentclass{report} + \begin{document} + Ma il mio mistero e chiuso in me + \end{document} + """ + tmp_path.joinpath("document.tex").write_text(textwrap.dedent(latex_source)) + + start = time.time() + result = runner.invoke(cli, [tmp_path.as_posix()]) + + assert result.exit_code == 0 + duration_normal = time.time() - start + + for name in ["document.pdf", "document.dvi"]: + tmp_path.joinpath(name).unlink() + + start = time.time() + result = runner.invoke(cli, [tmp_path.as_posix(), "-n", 2]) + + assert result.exit_code == 0 + duration_parallel = time.time() - start + + assert duration_parallel < duration_normal diff --git a/tests/test_parametrize.py b/tests/test_parametrize.py index e4b8883..870ea37 100644 --- a/tests/test_parametrize.py +++ b/tests/test_parametrize.py @@ -105,3 +105,47 @@ def task_compile_latex_document(): assert session.exit_code == 0 assert tmp_path.joinpath("document.pdf").exists() assert tmp_path.joinpath("document.dvi").exists() + + +@needs_latexmk +@skip_on_github_actions_with_win +@pytest.mark.end_to_end +def test_parametrizing_latex_options_new_api(tmp_path): + task_source = """ + import pytask + from pytask_latex import build_steps + + @pytask.mark.parametrize("depends_on, produces, latex", [ + ( + "document.tex", + "document.pdf", + {"build_steps": build_steps.latexmk( + ("--interaction=nonstopmode", "--pdf", "--cd")) + } + ), + ( + "document.tex", + "document.dvi", + {"build_steps": build_steps.latexmk( + ("--interaction=nonstopmode", "--dvi", "--cd")) + } + ), + ]) + def task_compile_latex_document(): + pass + """ + tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source)) + + latex_source = r""" + \documentclass{report} + \begin{document} + I can't stop this feeling. Deep inside of me. + \end{document} + """ + tmp_path.joinpath("document.tex").write_text(textwrap.dedent(latex_source)) + + session = main({"paths": tmp_path}) + + assert session.exit_code == 0 + assert tmp_path.joinpath("document.pdf").exists() + assert tmp_path.joinpath("document.dvi").exists() From d13c148ea7116850a609d97dd1bbf208643af2a4 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Wed, 2 Mar 2022 01:08:55 +0100 Subject: [PATCH 05/16] polish build_steps.py. --- src/pytask_latex/build_steps.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/pytask_latex/build_steps.py b/src/pytask_latex/build_steps.py index 2c3a435..774a78d 100644 --- a/src/pytask_latex/build_steps.py +++ b/src/pytask_latex/build_steps.py @@ -1,12 +1,21 @@ +"""This module contains build steps for compiling a LaTeX document. + +Each build step must have the following signature: + +.. code-block:: + + def build_step(main_file: Path, job_name: Optional[str], out_dir: Optional[Path]): + ... + +A build step constructor must yield a function with this signature. + +""" from __future__ import annotations import os import subprocess from pathlib import Path -# each build step constructor must return a callable with the following signature: -# run_step(main_file: Path, job_name: Optional[str], out_dir: Optional[Path]) - def _get_relative_out_dir(main_file, out_dir): """The output folder needs to be declared as a relative path to the directory where @@ -25,10 +34,6 @@ def _get_relative_out_dir(main_file, out_dir): return Path(os.path.relpath(out_dir, main_file.parent)).as_posix() -def default_steps(): - return ["latexmk"] - - def latexmk(options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd")): """Build step that calls latexmk.""" options = [str(i) for i in options] From 74a8416dd362fb40fb043d08f1ff3dfe81cbeb90 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Wed, 2 Mar 2022 01:21:55 +0100 Subject: [PATCH 06/16] Update changes. --- CHANGES.rst | 57 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index af79573..85e6087 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,96 +7,103 @@ all releases are available on `Anaconda.org `_. +0.1.2 - 2022-xx-xx +------------------ + +- :pull:`32` implements a new interface to the compilation process which consists of + composable build steps. (Many thanks to :user:`axtimhaus`!:tada:) + + 0.1.1 - 2022-02-08 ------------------ -- :gh:`30` skips concurrent CI builds. -- :gh:`31` deprecates Python 3.6 and add support for Python 3.10. +- :pull:`30` skips concurrent CI builds. +- :pull:`31` deprecates Python 3.6 and add support for Python 3.10. 0.1.0 - 2021-07-21 ------------------ -- :gh:`23` updates the ``README.rst``. -- :gh:`24` replaces versioneer with setuptools-scm. -- :gh:`26` aligns pytask-latex with pytask v0.1.0. +- :pull:`23` updates the ``README.rst``. +- :pull:`24` replaces versioneer with setuptools-scm. +- :pull:`26` aligns pytask-latex with pytask v0.1.0. 0.0.12 - 2021-03-05 ------------------- -- :gh:`19` fixes some post-release issues. -- :gh:`21` adds dependencies to ``setup.py`` and install via ``conda-forge``. +- :pull:`19` fixes some post-release issues. +- :pull:`21` adds dependencies to ``setup.py`` and install via ``conda-forge``. 0.0.11 - 2021-02-25 ------------------- -- :gh:`18` prepares pytask-latex to be published on PyPI, adds versioneer and more. +- :pull:`18` prepares pytask-latex to be published on PyPI, adds versioneer and more. 0.0.10 - 2021-01-16 ------------------- -- :gh:`16` fixes the scanner by keeping only scanned dependencies which exist. Convert +- :pull:`16` fixes the scanner by keeping only scanned dependencies which exist. Convert args to strings. 0.0.9 - 2020-12-28 ------------------ -- :gh:`12` integrates the latex-dependency-scanner to automatically detect dependencies - of a LaTeX document and releases v0.0.9. -- :gh:`13` fixes the CI. +- :pull:`12` integrates the latex-dependency-scanner to automatically detect + dependencies of a LaTeX document and releases v0.0.9. +- :pull:`13` fixes the CI. 0.0.8 - 2020-10-29 ------------------ -- :gh:`11` makes pytask-latex work with pytask v0.0.9. +- :pull:`11` makes pytask-latex work with pytask v0.0.9. 0.0.7 - 2020-10-14 ------------------ -- :gh:`10` fixes error that ``outputdirectory`` has to be relative to latex document due - to security problems. +- :pull:`10` fixes error that ``outputdirectory`` has to be relative to latex document + due to security problems. 0.0.6 - 2020-10-14 ------------------ -- :gh:`9` fixes the last release and the ``pytask_collect_task_teardown`` call. +- :pull:`9` fixes the last release and the ``pytask_collect_task_teardown`` call. 0.0.5 - 2020-10-04 ------------------ -- :gh:`5` fixes some errors in the test suite due to pytask v0.0.6. -- :gh:`6` check that exit codes are equal to zero. -- :gh:`7` fixes the README. -- :gh:`8` works with pytask v0.0.7 and releases v0.0.5. +- :pull:`5` fixes some errors in the test suite due to pytask v0.0.6. +- :pull:`6` check that exit codes are equal to zero. +- :pull:`7` fixes the README. +- :pull:`8` works with pytask v0.0.7 and releases v0.0.5. 0.0.4 - 2020-08-21 ------------------ -- :gh:`4` changes the default options. latexmk will step into the source directory +- :pull:`4` changes the default options. latexmk will step into the source directory before compiling the document. Releases 0.0.4. 0.0.3 - 2020-08-12 ------------------ -- :gh:`3` prepares pytask-latex for pytask v0.0.5 and releases v0.0.3. +- :pull:`3` prepares pytask-latex for pytask v0.0.5 and releases v0.0.3. 0.0.2 - 2020-07-22 ------------------ -- :gh:`1` allowed LaTeX tasks to have more than one dependency and allows to parametrize - over latex options and latex documents. It also prepares release v0.0.2. -- :gh:`2` fixes the release. +- :pull:`1` allowed LaTeX tasks to have more than one dependency and allows to + parametrize over latex options and latex documents. It also prepares release v0.0.2. +- :pull:`2` fixes the release. 0.0.1 - 2020-07-20 From 413640d0638ee47cab3976b2509af4abea56cba0 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Wed, 2 Mar 2022 01:25:19 +0100 Subject: [PATCH 07/16] xfail parallel tests in CI. --- tests/test_parallel.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/test_parallel.py b/tests/test_parallel.py index 261f4ef..bcc4812 100644 --- a/tests/test_parallel.py +++ b/tests/test_parallel.py @@ -1,6 +1,7 @@ """Contains test which ensure that the plugin works with pytask-parallel.""" from __future__ import annotations +import os import textwrap import time @@ -22,6 +23,15 @@ ) +if "CI" in os.environ: + xfail_on_remote = pytest.xfail(reason="Does not succeed on CI.") +else: + + def xfail_on_remote(func): + return func + + +@xfail_on_remote @needs_latexmk @skip_on_github_actions_with_win @pytest.mark.end_to_end @@ -73,6 +83,7 @@ def task_compile_latex_document(): assert duration_parallel < duration_normal +@xfail_on_remote @needs_latexmk @skip_on_github_actions_with_win @pytest.mark.end_to_end @@ -127,6 +138,7 @@ def task_compile_latex_document(): assert duration_parallel < duration_normal +@xfail_on_remote @needs_latexmk @skip_on_github_actions_with_win @pytest.mark.end_to_end From bfbb3fe5f80cc832ecea82c1713ccf3a4cd905f0 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Wed, 2 Mar 2022 01:31:03 +0100 Subject: [PATCH 08/16] Fix xfail. --- tests/test_parallel.py | 2 +- tox.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_parallel.py b/tests/test_parallel.py index bcc4812..1a8c07d 100644 --- a/tests/test_parallel.py +++ b/tests/test_parallel.py @@ -23,7 +23,7 @@ ) -if "CI" in os.environ: +if os.environ.get("CI") == "true": xfail_on_remote = pytest.xfail(reason="Does not succeed on CI.") else: diff --git a/tox.ini b/tox.ini index a0b4f89..178e860 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ skipsdist = True skip_missing_interpreters = True [testenv] -passenv = GITHUB_ACTIONS +passenv = CI GITHUB_ACTIONS basepython = python [testenv:pytest] From db25785261427a31d055b3b38c715b5c61d2046f Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Wed, 2 Mar 2022 01:42:05 +0100 Subject: [PATCH 09/16] fix xfail again. --- tests/test_parallel.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/test_parallel.py b/tests/test_parallel.py index 1a8c07d..5ac853e 100644 --- a/tests/test_parallel.py +++ b/tests/test_parallel.py @@ -22,13 +22,9 @@ not _IS_PYTASK_PARALLEL_INSTALLED, reason="Tests require pytask-parallel." ) - -if os.environ.get("CI") == "true": - xfail_on_remote = pytest.xfail(reason="Does not succeed on CI.") -else: - - def xfail_on_remote(func): - return func +xfail_on_remote = pytest.mark.xfail( + condition=os.environ.get("CI") == "true", reason="Does not succeed on CI." +) @xfail_on_remote From ec7491f7dc5b4caad713bdf97a7d4cd736fa62f4 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Mon, 7 Mar 2022 18:28:24 +0100 Subject: [PATCH 10/16] Move to_list. --- src/pytask_latex/build_steps.py | 4 +++- src/pytask_latex/collect.py | 31 +++---------------------------- src/pytask_latex/utils.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 29 deletions(-) create mode 100644 src/pytask_latex/utils.py diff --git a/src/pytask_latex/build_steps.py b/src/pytask_latex/build_steps.py index 774a78d..444cd89 100644 --- a/src/pytask_latex/build_steps.py +++ b/src/pytask_latex/build_steps.py @@ -16,6 +16,8 @@ def build_step(main_file: Path, job_name: Optional[str], out_dir: Optional[Path] import subprocess from pathlib import Path +from pytask_latex.utils import to_list + def _get_relative_out_dir(main_file, out_dir): """The output folder needs to be declared as a relative path to the directory where @@ -36,7 +38,7 @@ def _get_relative_out_dir(main_file, out_dir): def latexmk(options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd")): """Build step that calls latexmk.""" - options = [str(i) for i in options] + options = [str(i) for i in to_list(options)] def run_latexmk(main_file, job_name, out_dir): job_name_opt = [f"--jobname={job_name}"] if job_name else [] diff --git a/src/pytask_latex/collect.py b/src/pytask_latex/collect.py index 5618ad3..06d5f16 100644 --- a/src/pytask_latex/collect.py +++ b/src/pytask_latex/collect.py @@ -20,6 +20,7 @@ from _pytask.nodes import PythonFunctionTask from _pytask.parametrize import _copy_func from pytask_latex import build_steps as bs +from pytask_latex.utils import to_list _DEPRECATION_WARNING = """The old syntax for using @pytask.mark.latex is deprecated \ @@ -60,11 +61,11 @@ def latex( if options is not None: warnings.warn(_DEPRECATION_WARNING, DeprecationWarning) - out = [bs.latexmk(_to_list(options))] + out = [bs.latexmk(options)] else: out = [] - for step in _to_list(build_steps): + for step in to_list(build_steps): if isinstance(step, str): parsed_step = getattr(bs, step) if parsed_step is None: @@ -225,29 +226,3 @@ def get_build_step_args(session, task): out_dir = compiled_document.parent return {"main_file": latex_document, "job_name": job_name, "out_dir": out_dir} - - -def _to_list(scalar_or_iter): - """Convert scalars and iterables to list. - - Parameters - ---------- - scalar_or_iter : str or list - - Returns - ------- - list - - Examples - -------- - >>> _to_list("a") - ['a'] - >>> _to_list(["b"]) - ['b'] - - """ - return ( - [scalar_or_iter] - if isinstance(scalar_or_iter, str) or not isinstance(scalar_or_iter, Sequence) - else list(scalar_or_iter) - ) diff --git a/src/pytask_latex/utils.py b/src/pytask_latex/utils.py new file mode 100644 index 0000000..7de13e8 --- /dev/null +++ b/src/pytask_latex/utils.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from typing import Sequence + + +def to_list(scalar_or_iter): + """Convert scalars and iterables to list. + + Parameters + ---------- + scalar_or_iter : str or list + + Returns + ------- + list + + Examples + -------- + >>> to_list("a") + ['a'] + >>> to_list(["b"]) + ['b'] + + """ + return ( + [scalar_or_iter] + if isinstance(scalar_or_iter, str) or not isinstance(scalar_or_iter, Sequence) + else list(scalar_or_iter) + ) From 323b5e7caebd06306f357829da59dc4bf04059d3 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Mon, 7 Mar 2022 19:02:23 +0100 Subject: [PATCH 11/16] Refactor to _relative_to. --- src/pytask_latex/build_steps.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/pytask_latex/build_steps.py b/src/pytask_latex/build_steps.py index 444cd89..93d1203 100644 --- a/src/pytask_latex/build_steps.py +++ b/src/pytask_latex/build_steps.py @@ -19,8 +19,10 @@ def build_step(main_file: Path, job_name: Optional[str], out_dir: Optional[Path] from pytask_latex.utils import to_list -def _get_relative_out_dir(main_file, out_dir): - """The output folder needs to be declared as a relative path to the directory where +def _relative_to(path, relative_to): + """Create a relative path from one path to another as a string. + + The output folder needs to be declared as a relative path to the directory where the latex source lies. 1. It must be relative because bibtex / biber, which is necessary for @@ -32,8 +34,20 @@ def _get_relative_out_dir(main_file, out_dir): `_ for additional information. + Example + ------- + >>> import sys + >>> from pathlib import Path + >>> if sys.platform == "win32": + ... p = Path("C:/Users/user/documents/file.tex") + ... else: + ... p = Path("/home/user/documents/file.tex") + >>> out = p.parents[2].joinpath("bld", "docs") + >>> _relative_to(p, out) + '../../bld/docs' + """ - return Path(os.path.relpath(out_dir, main_file.parent)).as_posix() + return Path(os.path.relpath(relative_to, path.parent)).as_posix() def latexmk(options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd")): @@ -43,7 +57,7 @@ def latexmk(options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd" def run_latexmk(main_file, job_name, out_dir): job_name_opt = [f"--jobname={job_name}"] if job_name else [] out_dir_opt = ( - [f"--output-directory={_get_relative_out_dir(main_file, out_dir)}"] + [f"--output-directory={_relative_to(main_file, out_dir)}"] if out_dir else [] ) From 3eb10a1269ab3b58e64f14d113a82b1d8e3d7262 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Mon, 7 Mar 2022 21:31:14 +0100 Subject: [PATCH 12/16] Simplify signature of build steps which now accept only path to tex and to compiled file. --- src/pytask_latex/build_steps.py | 19 ++++++++++--------- src/pytask_latex/collect.py | 12 ++++-------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/pytask_latex/build_steps.py b/src/pytask_latex/build_steps.py index 93d1203..e515f86 100644 --- a/src/pytask_latex/build_steps.py +++ b/src/pytask_latex/build_steps.py @@ -4,7 +4,7 @@ .. code-block:: - def build_step(main_file: Path, job_name: Optional[str], out_dir: Optional[Path]): + def build_step(path_to_tex: Path, path_to_document: Path): ... A build step constructor must yield a function with this signature. @@ -54,15 +54,16 @@ def latexmk(options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd" """Build step that calls latexmk.""" options = [str(i) for i in to_list(options)] - def run_latexmk(main_file, job_name, out_dir): - job_name_opt = [f"--jobname={job_name}"] if job_name else [] - out_dir_opt = ( - [f"--output-directory={_relative_to(main_file, out_dir)}"] - if out_dir - else [] - ) + def run_latexmk(path_to_tex, path_to_document): + job_name_opt = [f"--jobname={path_to_document.stem}"] + out_dir_opt = [ + f"--output-directory={_relative_to(path_to_tex, path_to_document.parent)}" + ] cmd = ( - ["latexmk", *options] + job_name_opt + out_dir_opt + [main_file.as_posix()] + ["latexmk", *options] + + job_name_opt + + out_dir_opt + + [path_to_tex.as_posix()] ) subprocess.run(cmd, check=True) diff --git a/src/pytask_latex/collect.py b/src/pytask_latex/collect.py index 06d5f16..80ae4cc 100644 --- a/src/pytask_latex/collect.py +++ b/src/pytask_latex/collect.py @@ -79,12 +79,12 @@ def latex( return out -def compile_latex_document(build_steps, main_file, job_name, out_dir): +def compile_latex_document(build_steps, path_to_tex, path_to_document): """Replaces the dummy function provided by the user.""" for step in build_steps: try: - step(main_file, job_name, out_dir) + step(path_to_tex=path_to_tex, path_to_document=path_to_document) except CalledProcessError as e: raise RuntimeError(f"Build step {step.__name__} failed.") from e @@ -213,7 +213,7 @@ def _merge_all_markers(task): def get_build_step_args(session, task): - """Prepare arguments for build step functions""" + """Prepare arguments passe to each build step.""" latex_document = _get_node_from_dictionary( task.depends_on, session.config["latex_source_key"] ).value @@ -221,8 +221,4 @@ def get_build_step_args(session, task): task.produces, session.config["latex_document_key"] ).value - job_name = compiled_document.stem - - out_dir = compiled_document.parent - - return {"main_file": latex_document, "job_name": job_name, "out_dir": out_dir} + return {"path_to_tex": latex_document, "path_to_document": compiled_document} From 100877224af11802d660aa6b8cbce2863387309a Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Mon, 7 Mar 2022 21:36:46 +0100 Subject: [PATCH 13/16] Update readme. --- README.rst | 96 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 27 deletions(-) diff --git a/README.rst b/README.rst index 74069b0..f27f572 100644 --- a/README.rst +++ b/README.rst @@ -37,8 +37,8 @@ pytask-latex pytask-latex allows you to compile LaTeX documents. It also tries to infer the dependency of the LaTeX document such as included images, -bibliography files and other .tex files automatically to compile LaTeX documents when it -is possible. +bibliography files and other ``.tex`` files automatically to compile LaTeX documents +when it is possible. Installation @@ -72,7 +72,7 @@ popular LaTeX distributions, like `MiKTeX `_, `TeX Live Usage ----- -Here is an example where you want to compile ``document.tex`` to a PDF. +Compiling your PDF can be as simple as writing the following task. .. code-block:: python @@ -85,9 +85,9 @@ Here is an example where you want to compile ``document.tex`` to a PDF. def task_compile_latex_document(): pass -When the task is executed, you find a ``document.pdf`` in the same folder as your -``document.tex``, but you could also compile the report into a another folder by -changing the path in ``produces``. +Use ``@pytask.mark.latex`` to indicate that this task compiles a LaTeX document. +``@pytask.mark.depends_on`` points to the source file which is compiled and +``@pytask.mark.produces`` is the path of the compiled PDF. Multiple dependencies and products @@ -139,39 +139,72 @@ The same applies to the compiled document which is either in the first position, the key ``"document"`` or ``0``. -Command Line Arguments -~~~~~~~~~~~~~~~~~~~~~~ +Customizing the compilation +~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To customize the compilation, you can pass some command line arguments to ``latexmk`` -via the ``@pytask.mark.latex`` marker. The default is the following. +pytask-latex uses latexmk by default to compile the document because it handles most +use-cases automatically. The following is equivalent to a bare ``@pytask.mark.latex`` +decorator. .. code-block:: python - @pytask.mark.latex(["--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd"]) + @pytask.mark.latex(build_steps="latexmk") def task_compile_latex_document(): - pass + ... + +The ``@pytask.mark.latex`` decorator has a keyword argument called ``build_steps`` which +accepts which accepts strings or list of strings pointing to internally implemented +build steps. Using strings will use the default configuration of this build step. It is +equivalent to the following. + +.. code-block:: + + from pytask_latex import build_steps + + + @pytask.mark.latex( + build_steps=build_steps.latexmk( + options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd") + ) + ) + def task_compile_latex_document(): + ... + +In this example, ``build_steps.latexmk`` is a build step constructor which accepts a set +of options and creates a build step function out of it. -For example, to compile your document with XeLaTeX, use +You can pass different options to change the compilation process with latexmk. Here is +an example for generating a ``.dvi``. .. code-block:: python - @pytask.mark.latex(["--xelatex", "--interaction=nonstopmode"]) + @pytask.mark.latex( + build_steps=build_steps.latexmk( + options=("--dvi", "--interaction=nonstopmode", "--synctex=1", "--cd") + ) + ) def task_compile_latex_document(): - pass + ... -The options ``--jobname``, ``--output-directory`` and the ``.tex`` file which will be -compiled are automatically handled and inferred from the ``@pytask.mark.depends_on`` and -``@pytask.mark.produces`` markers. +``build_step.latexmk(options)`` generates a build step which is a function with the +following signature: -The ``@pytask.mark.latex`` accepts both, a string or a list of strings with options. +.. code-block:: -For more options and their explanations, visit the `latexmk manual -`_ or type the following commands. + from pathlib import Path + import subprocess -.. code-block:: console - $ latexmk -h - $ latexmk -showextraoptions + def custom_build_step(path_to_tex: Path, path_to_document: Path) -> None: + ... + subproces.run(..., check=True) + +Each build step receives the path to the LaTeX source file and the path to the final +document which it uses to call some program on the command line to run another step in +the compilation process. + +In the future, pytask-latex will provide more build steps for compiling bibliographies, +glossaries and the like. Parametrization @@ -195,7 +228,8 @@ The following task compiles two latex documents. If you want to compile the same document with different command line options, you have to include the latex decorator in the parametrization just like with -``@pytask.mark.depends_on`` and ``@pytask.mark.produces``. +``@pytask.mark.depends_on`` and ``@pytask.mark.produces``. Pass a dictionary for +possible build steps and their options. .. code-block:: python @@ -205,11 +239,19 @@ to include the latex decorator in the parametrization just like with [ ( "document.pdf", - ("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd"), + { + "build_steps": build_steps.latexmk( + ("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd") + ) + }, ), ( "document.dvi", - ("--dvi", "--interaction=nonstopmode", "--synctex=1", "--cd"), + { + "build_steps": build_steps.latexmk( + ("--dvi", "--interaction=nonstopmode", "--synctex=1", "--cd") + ) + }, ), ], ) From 7833c248c44b253cb409e52a20f99ae47e101bca Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Mon, 7 Mar 2022 21:52:20 +0100 Subject: [PATCH 14/16] Last touches. --- README.rst | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index f27f572..3eda19f 100644 --- a/README.rst +++ b/README.rst @@ -34,11 +34,12 @@ pytask-latex ============ -pytask-latex allows you to compile LaTeX documents. +pytask-latex allows you to compile LaTeX documents with pytask -It also tries to infer the dependency of the LaTeX document such as included images, -bibliography files and other ``.tex`` files automatically to compile LaTeX documents -when it is possible. +It also uses `latex-dependency-scanner +`_ to automatically infer the +dependencies of the LaTeX document such as images, bibliographies and other ``.tex`` +files which are necessary to compile the LaTeX document. Installation @@ -65,8 +66,8 @@ following on the command line $ latexmk --help If an error is shown instead of a help page, you can install ``latexmk`` with one of the -popular LaTeX distributions, like `MiKTeX `_, `TeX Live -`_, `MacTeX `_ or others. +popular LaTeX distributions, like `TeX Live `_, `MiKTeX +`_, `MacTeX `_ or others. Usage @@ -171,7 +172,7 @@ equivalent to the following. ... In this example, ``build_steps.latexmk`` is a build step constructor which accepts a set -of options and creates a build step function out of it. +of options and creates a build step function. You can pass different options to change the compilation process with latexmk. Here is an example for generating a ``.dvi``. @@ -199,6 +200,9 @@ following signature: ... subproces.run(..., check=True) +You can also pass your custom build step with the same signature to the ``build_steps`` +keyword argument of the decorator. + Each build step receives the path to the LaTeX source file and the path to the final document which it uses to call some program on the command line to run another step in the compilation process. @@ -210,8 +214,8 @@ glossaries and the like. Parametrization ~~~~~~~~~~~~~~~ -You can also parametrize the compilation, meaning compiling multiple .tex documents -as well as compiling a .tex document with different command line arguments. +You can also parametrize the compilation, meaning compiling multiple ``.tex`` documents +as well as compiling a ``.tex`` document with different command line arguments. The following task compiles two latex documents. From b915ca906a0356be01c6dd6682d1346ebf7baec5 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Wed, 9 Mar 2022 01:01:11 +0100 Subject: [PATCH 15/16] Rename build steps to compilation steps. --- CHANGES.rst | 2 +- README.rst | 46 +++++++++--------- src/pytask_latex/build_steps.py | 70 --------------------------- src/pytask_latex/collect.py | 42 ++++++++-------- src/pytask_latex/compilation_steps.py | 38 +++++++++++++++ src/pytask_latex/path.py | 36 ++++++++++++++ tests/test_execute.py | 8 +-- tests/test_parallel.py | 6 +-- tests/test_parametrize.py | 6 +-- 9 files changed, 131 insertions(+), 123 deletions(-) delete mode 100644 src/pytask_latex/build_steps.py create mode 100644 src/pytask_latex/compilation_steps.py create mode 100644 src/pytask_latex/path.py diff --git a/CHANGES.rst b/CHANGES.rst index 85e6087..7c96190 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -11,7 +11,7 @@ all releases are available on `Anaconda.org ------------------ - :pull:`32` implements a new interface to the compilation process which consists of - composable build steps. (Many thanks to :user:`axtimhaus`!:tada:) + composable compilation steps. (Many thanks to :user:`axtimhaus`!:tada:) 0.1.1 - 2022-02-08 diff --git a/README.rst b/README.rst index 3eda19f..ac5ce14 100644 --- a/README.rst +++ b/README.rst @@ -149,30 +149,30 @@ decorator. .. code-block:: python - @pytask.mark.latex(build_steps="latexmk") + @pytask.mark.latex(compilation_steps="latexmk") def task_compile_latex_document(): ... -The ``@pytask.mark.latex`` decorator has a keyword argument called ``build_steps`` which -accepts which accepts strings or list of strings pointing to internally implemented -build steps. Using strings will use the default configuration of this build step. It is -equivalent to the following. +The ``@pytask.mark.latex`` decorator has a keyword argument called ``compilation_steps`` +which accepts which accepts strings or list of strings pointing to internally +implemented compilation steps. Using strings will use the default configuration of this +compilation step. It is equivalent to the following. .. code-block:: - from pytask_latex import build_steps + from pytask_latex import compilation_steps @pytask.mark.latex( - build_steps=build_steps.latexmk( + compilation_steps=compilation_steps.latexmk( options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd") ) ) def task_compile_latex_document(): ... -In this example, ``build_steps.latexmk`` is a build step constructor which accepts a set -of options and creates a build step function. +In this example, ``compilation_steps.latexmk`` is a compilation step constructor which +accepts a set of options and creates a compilation step function. You can pass different options to change the compilation process with latexmk. Here is an example for generating a ``.dvi``. @@ -180,15 +180,15 @@ an example for generating a ``.dvi``. .. code-block:: python @pytask.mark.latex( - build_steps=build_steps.latexmk( + compilation_steps=compilation_steps.latexmk( options=("--dvi", "--interaction=nonstopmode", "--synctex=1", "--cd") ) ) def task_compile_latex_document(): ... -``build_step.latexmk(options)`` generates a build step which is a function with the -following signature: +``compilation_step.latexmk(options)`` generates a compilation step which is a function +with the following signature: .. code-block:: @@ -196,19 +196,19 @@ following signature: import subprocess - def custom_build_step(path_to_tex: Path, path_to_document: Path) -> None: + def custom_compilation_step(path_to_tex: Path, path_to_document: Path) -> None: ... subproces.run(..., check=True) -You can also pass your custom build step with the same signature to the ``build_steps`` -keyword argument of the decorator. +You can also pass your custom compilation step with the same signature to the +``compilation_steps`` keyword argument of the decorator. -Each build step receives the path to the LaTeX source file and the path to the final -document which it uses to call some program on the command line to run another step in -the compilation process. +Each compilation step receives the path to the LaTeX source file and the path to the +final document which it uses to call some program on the command line to run another +step in the compilation process. -In the future, pytask-latex will provide more build steps for compiling bibliographies, -glossaries and the like. +In the future, pytask-latex will provide more compilation steps for compiling +bibliographies, glossaries and the like. Parametrization @@ -233,7 +233,7 @@ The following task compiles two latex documents. If you want to compile the same document with different command line options, you have to include the latex decorator in the parametrization just like with ``@pytask.mark.depends_on`` and ``@pytask.mark.produces``. Pass a dictionary for -possible build steps and their options. +possible compilation steps and their options. .. code-block:: python @@ -244,7 +244,7 @@ possible build steps and their options. ( "document.pdf", { - "build_steps": build_steps.latexmk( + "compilation_steps": compilation_steps.latexmk( ("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd") ) }, @@ -252,7 +252,7 @@ possible build steps and their options. ( "document.dvi", { - "build_steps": build_steps.latexmk( + "compilation_steps": compilation_steps.latexmk( ("--dvi", "--interaction=nonstopmode", "--synctex=1", "--cd") ) }, diff --git a/src/pytask_latex/build_steps.py b/src/pytask_latex/build_steps.py deleted file mode 100644 index e515f86..0000000 --- a/src/pytask_latex/build_steps.py +++ /dev/null @@ -1,70 +0,0 @@ -"""This module contains build steps for compiling a LaTeX document. - -Each build step must have the following signature: - -.. code-block:: - - def build_step(path_to_tex: Path, path_to_document: Path): - ... - -A build step constructor must yield a function with this signature. - -""" -from __future__ import annotations - -import os -import subprocess -from pathlib import Path - -from pytask_latex.utils import to_list - - -def _relative_to(path, relative_to): - """Create a relative path from one path to another as a string. - - The output folder needs to be declared as a relative path to the directory where - the latex source lies. - - 1. It must be relative because bibtex / biber, which is necessary for - bibliographies, does not accept full paths as a safety measure. - 2. Due to the ``--cd`` flag, latexmk will change the directory to the one where the - source files are. Thus, relative to the latex sources. - - See this `discussion on Github - `_ - for additional information. - - Example - ------- - >>> import sys - >>> from pathlib import Path - >>> if sys.platform == "win32": - ... p = Path("C:/Users/user/documents/file.tex") - ... else: - ... p = Path("/home/user/documents/file.tex") - >>> out = p.parents[2].joinpath("bld", "docs") - >>> _relative_to(p, out) - '../../bld/docs' - - """ - return Path(os.path.relpath(relative_to, path.parent)).as_posix() - - -def latexmk(options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd")): - """Build step that calls latexmk.""" - options = [str(i) for i in to_list(options)] - - def run_latexmk(path_to_tex, path_to_document): - job_name_opt = [f"--jobname={path_to_document.stem}"] - out_dir_opt = [ - f"--output-directory={_relative_to(path_to_tex, path_to_document.parent)}" - ] - cmd = ( - ["latexmk", *options] - + job_name_opt - + out_dir_opt - + [path_to_tex.as_posix()] - ) - subprocess.run(cmd, check=True) - - return run_latexmk diff --git a/src/pytask_latex/collect.py b/src/pytask_latex/collect.py index 80ae4cc..ff02d24 100644 --- a/src/pytask_latex/collect.py +++ b/src/pytask_latex/collect.py @@ -19,7 +19,7 @@ from _pytask.nodes import FilePathNode from _pytask.nodes import PythonFunctionTask from _pytask.parametrize import _copy_func -from pytask_latex import build_steps as bs +from pytask_latex import compilation_steps as cs from pytask_latex.utils import to_list @@ -33,9 +33,9 @@ def task_func(): to - from pytask_latex import build_steps + from pytask_latex import compilation_steps - @pytask.mark.latex(build_steps.latexmk(options)) + @pytask.mark.latex(compilation_steps.latexmk(options)) def task_func(): ... @@ -45,7 +45,9 @@ def task_func(): def latex( options: str | Iterable[str] | None = None, *, - build_steps: str | Callable[..., Any] | Sequence[str | Callable[..., Any]] = None, + compilation_steps: str + | Callable[..., Any] + | Sequence[str | Callable[..., Any]] = None, ): """Specify command line options for latexmk. @@ -53,40 +55,40 @@ def latex( ---------- options One or multiple command line options passed to latexmk. - build_steps - Build steps to compile the document. + compilation_steps + Compilation steps to compile the document. """ - build_steps = ["latexmk"] if build_steps is None else build_steps + compilation_steps = ["latexmk"] if compilation_steps is None else compilation_steps if options is not None: warnings.warn(_DEPRECATION_WARNING, DeprecationWarning) - out = [bs.latexmk(options)] + out = [cs.latexmk(options)] else: out = [] - for step in to_list(build_steps): + for step in to_list(compilation_steps): if isinstance(step, str): - parsed_step = getattr(bs, step) + parsed_step = getattr(cs, step) if parsed_step is None: - raise ValueError(f"Build step {step!r} is unknown.") + raise ValueError(f"Compilation step {step!r} is unknown.") out.append(parsed_step()) elif callable(step): out.append(step) else: - raise ValueError(f"Build step {step!r} is not a valid step.") + raise ValueError(f"Compilation step {step!r} is not a valid step.") return out -def compile_latex_document(build_steps, path_to_tex, path_to_document): +def compile_latex_document(compilation_steps, path_to_tex, path_to_document): """Replaces the dummy function provided by the user.""" - for step in build_steps: + for step in compilation_steps: try: step(path_to_tex=path_to_tex, path_to_document=path_to_document) except CalledProcessError as e: - raise RuntimeError(f"Build step {step.__name__} failed.") from e + raise RuntimeError(f"Compilation step {step.__name__} failed.") from e @hookimpl @@ -136,8 +138,10 @@ def pytask_collect_task_teardown(session, task): merged_mark = _merge_all_markers(task) steps = latex(*merged_mark.args, **merged_mark.kwargs) - args = get_build_step_args(session, task) - task_function = functools.partial(task_function, build_steps=steps, **args) + args = get_compilation_step_args(session, task) + task_function = functools.partial( + task_function, compilation_steps=steps, **args + ) task.function = task_function @@ -212,8 +216,8 @@ def _merge_all_markers(task): return mark -def get_build_step_args(session, task): - """Prepare arguments passe to each build step.""" +def get_compilation_step_args(session, task): + """Prepare arguments passe to each compilation step.""" latex_document = _get_node_from_dictionary( task.depends_on, session.config["latex_source_key"] ).value diff --git a/src/pytask_latex/compilation_steps.py b/src/pytask_latex/compilation_steps.py new file mode 100644 index 0000000..ac7ba9a --- /dev/null +++ b/src/pytask_latex/compilation_steps.py @@ -0,0 +1,38 @@ +"""This module contains compilation steps for compiling a LaTeX document. + +Each compilation step must have the following signature: + +.. code-block:: + + def compilation_step(path_to_tex: Path, path_to_document: Path): + ... + +A compilation step constructor must yield a function with this signature. + +""" +from __future__ import annotations + +import subprocess + +from pytask_latex.path import relative_to +from pytask_latex.utils import to_list + + +def latexmk(options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd")): + """Compilation step that calls latexmk.""" + options = [str(i) for i in to_list(options)] + + def run_latexmk(path_to_tex, path_to_document): + job_name_opt = [f"--jobname={path_to_document.stem}"] + out_dir_opt = [ + f"--output-directory={relative_to(path_to_tex, path_to_document.parent)}" + ] + cmd = ( + ["latexmk", *options] + + job_name_opt + + out_dir_opt + + [path_to_tex.as_posix()] + ) + subprocess.run(cmd, check=True) + + return run_latexmk diff --git a/src/pytask_latex/path.py b/src/pytask_latex/path.py new file mode 100644 index 0000000..b048ef9 --- /dev/null +++ b/src/pytask_latex/path.py @@ -0,0 +1,36 @@ +"""This module contains functions related to handling paths.""" +from __future__ import annotations + +import os +from pathlib import Path + + +def relative_to(path: Path, relative_to_: Path) -> str: + """Create a relative path from one path to another as a string. + + The output folder needs to be declared as a relative path to the directory where + the latex source lies. + + 1. It must be relative because bibtex / biber, which is necessary for + bibliographies, does not accept full paths as a safety measure. + 2. Due to the ``--cd`` flag, latexmk will change the directory to the one where the + source files are. Thus, relative to the latex sources. + + See this `discussion on Github + `_ + for additional information. + + Example + ------- + >>> import sys + >>> from pathlib import Path + >>> if sys.platform == "win32": + ... p = Path("C:/Users/user/documents/file.tex") + ... else: + ... p = Path("/home/user/documents/file.tex") + >>> out = p.parents[2].joinpath("bld", "docs") + >>> relative_to(p, out) + '../../bld/docs' + + """ + return Path(os.path.relpath(relative_to_, path.parent)).as_posix() diff --git a/tests/test_execute.py b/tests/test_execute.py index 81e0303..e30a9b8 100644 --- a/tests/test_execute.py +++ b/tests/test_execute.py @@ -282,10 +282,10 @@ def task_compile_document(): def test_compile_latex_document_w_xelatex_new_api(runner, tmp_path): task_source = """ import pytask - from pytask_latex import build_steps + from pytask_latex import compilation_steps @pytask.mark.latex( - build_steps=build_steps.latexmk( + compilation_steps=compilation_steps.latexmk( ["--xelatex", "--interaction=nonstopmode", "--synctex=1", "--cd"] ) ) @@ -465,9 +465,9 @@ def test_compile_document_w_wrong_flag_new_api(tmp_path): task_source = """ import pytask - from pytask_latex import build_steps + from pytask_latex import compilation_steps - @pytask.mark.latex(build_steps=build_steps.latexmk("--wrong-flag")) + @pytask.mark.latex(compilation_steps=compilation_steps.latexmk("--wrong-flag")) @pytask.mark.depends_on("document.tex") @pytask.mark.produces("out/document.pdf") def task_compile_document(): diff --git a/tests/test_parallel.py b/tests/test_parallel.py index 5ac853e..401e719 100644 --- a/tests/test_parallel.py +++ b/tests/test_parallel.py @@ -141,7 +141,7 @@ def task_compile_latex_document(): def test_parallel_parametrization_over_source_file_new_api(runner, tmp_path): source = """ import pytask - from pytask_latex import build_steps + from pytask_latex import compilation_steps @pytask.mark.depends_on("document.tex") @pytask.mark.parametrize( @@ -149,13 +149,13 @@ def test_parallel_parametrization_over_source_file_new_api(runner, tmp_path): [ ( "document.pdf", - {"build_steps": build_steps.latexmk( + {"compilation_steps": compilation_steps.latexmk( ("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd") )} ), ( "document.dvi", - {"build_steps": build_steps.latexmk( + {"compilation_steps": compilation_steps.latexmk( ("--dvi", "--interaction=nonstopmode", "--synctex=1", "--cd") )} ), diff --git a/tests/test_parametrize.py b/tests/test_parametrize.py index 870ea37..b4a9e67 100644 --- a/tests/test_parametrize.py +++ b/tests/test_parametrize.py @@ -113,20 +113,20 @@ def task_compile_latex_document(): def test_parametrizing_latex_options_new_api(tmp_path): task_source = """ import pytask - from pytask_latex import build_steps + from pytask_latex import compilation_steps @pytask.mark.parametrize("depends_on, produces, latex", [ ( "document.tex", "document.pdf", - {"build_steps": build_steps.latexmk( + {"compilation_steps": compilation_steps.latexmk( ("--interaction=nonstopmode", "--pdf", "--cd")) } ), ( "document.tex", "document.dvi", - {"build_steps": build_steps.latexmk( + {"compilation_steps": compilation_steps.latexmk( ("--interaction=nonstopmode", "--dvi", "--cd")) } ), From 56321d5748cc77ad44eaa62251f2bf90fdc32548 Mon Sep 17 00:00:00 2001 From: Tobias Raabe Date: Thu, 10 Mar 2022 12:53:53 +0100 Subject: [PATCH 16/16] Remove unnecessary hook. --- src/pytask_latex/collect.py | 19 ------------------- tests/test_collect.py | 20 -------------------- 2 files changed, 39 deletions(-) diff --git a/src/pytask_latex/collect.py b/src/pytask_latex/collect.py index ff02d24..98ac9f0 100644 --- a/src/pytask_latex/collect.py +++ b/src/pytask_latex/collect.py @@ -14,10 +14,8 @@ from _pytask.config import hookimpl from _pytask.mark import Mark from _pytask.mark_utils import get_specific_markers_from_task -from _pytask.mark_utils import has_marker from _pytask.nodes import _collect_nodes from _pytask.nodes import FilePathNode -from _pytask.nodes import PythonFunctionTask from _pytask.parametrize import _copy_func from pytask_latex import compilation_steps as cs from pytask_latex.utils import to_list @@ -91,23 +89,6 @@ def compile_latex_document(compilation_steps, path_to_tex, path_to_document): raise RuntimeError(f"Compilation step {step.__name__} failed.") from e -@hookimpl -def pytask_collect_task(session, path, name, obj): - """Collect a task which is a function. - - There is some discussion on how to detect functions in this `thread - `_. :class:`types.FunctionType` does not - detect built-ins which is not possible anyway. - - """ - if name.startswith("task_") and callable(obj) and has_marker(obj, "latex"): - task = PythonFunctionTask.from_path_name_function_session( - path, name, obj, session - ) - - return task - - @hookimpl def pytask_collect_task_teardown(session, task): """Perform some checks.""" diff --git a/tests/test_collect.py b/tests/test_collect.py index cb1959a..d94c6d1 100644 --- a/tests/test_collect.py +++ b/tests/test_collect.py @@ -1,14 +1,12 @@ from __future__ import annotations from contextlib import ExitStack as does_not_raise # noqa: N813 -from pathlib import Path import pytest from _pytask.mark import Mark from _pytask.nodes import FilePathNode from pytask_latex.collect import _get_node_from_dictionary from pytask_latex.collect import _merge_all_markers -from pytask_latex.collect import pytask_collect_task from pytask_latex.collect import pytask_collect_task_teardown @@ -41,24 +39,6 @@ def test_merge_all_markers(marks, expected): assert out == expected -@pytest.mark.unit -@pytest.mark.parametrize( - "name, expected", - [("task_dummy", True), ("invalid_name", None)], -) -def test_pytask_collect_task(name, expected): - session = DummyClass() - path = Path("some_path") - task_dummy.pytaskmark = [Mark("latex", (), {})] - - task = pytask_collect_task(session, path, name, task_dummy) - - if expected: - assert task - else: - assert not task - - @pytest.mark.unit @pytest.mark.parametrize( "depends_on, produces, expectation",