diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 9dbe9d4..72a5962 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,24 +1,21 @@
----
+______________________________________________________________________
-name: Bug Report
-about: Create a bug report to help us improve pytask-latex
-title: "BUG:"
-labels: "bug"
+name: Bug Report about: Create a bug report to help us improve pytask-latex title:
+"BUG:" labels: "bug"
----
+______________________________________________________________________
- [ ] I have checked that this issue has not already been reported.
- [ ] I have confirmed this bug exists on the latest version of pytask-latex.
-- [ ] (optional) I have confirmed this bug exists on the `main` branch of
- pytask-latex.
+- [ ] (optional) I have confirmed this bug exists on the `main` branch of pytask-latex.
----
+______________________________________________________________________
-**Note**: Please read [this
-guide](https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports) detailing
-how to provide the necessary information for us to reproduce your bug.
+**Note**: Please read
+[this guide](https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports)
+detailing how to provide the necessary information for us to reproduce your bug.
#### Code Sample, a copy-pastable example
diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md
index 2a6cb13..a7419fd 100644
--- a/.github/ISSUE_TEMPLATE/documentation.md
+++ b/.github/ISSUE_TEMPLATE/documentation.md
@@ -1,11 +1,9 @@
----
+______________________________________________________________________
-name: Documentation Improvement
-about: Report wrong or missing documentation
-title: "DOC:"
-labels: "documentation"
+name: Documentation Improvement about: Report wrong or missing documentation title:
+"DOC:" labels: "documentation"
----
+______________________________________________________________________
#### Location of the documentation
diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md
index e09dfaf..6409c05 100644
--- a/.github/ISSUE_TEMPLATE/enhancement.md
+++ b/.github/ISSUE_TEMPLATE/enhancement.md
@@ -1,16 +1,14 @@
----
+______________________________________________________________________
-name: Enhancement
-about: Suggest an idea for pytask-latex
-title: "ENH:"
-labels: "enhancement"
+name: Enhancement about: Suggest an idea for pytask-latex title: "ENH:" labels:
+"enhancement"
----
+______________________________________________________________________
#### Is your feature request related to a problem?
-Provide a description of what the problem is, e.g. "I wish I could use pytask-latex
-to do [...]".
+Provide a description of what the problem is, e.g. "I wish I could use pytask-latex to
+do \[...\]".
#### Describe the solution you'd like
diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md
index 073ae3b..530c08a 100644
--- a/.github/ISSUE_TEMPLATE/question.md
+++ b/.github/ISSUE_TEMPLATE/question.md
@@ -1,17 +1,15 @@
----
+______________________________________________________________________
-name: Submit Question
-about: Ask a general question about pytask-latex
-title: "QST:"
+name: Submit Question about: Ask a general question about pytask-latex title: "QST:"
labels: "question"
----
+______________________________________________________________________
#### Question about pytask-latex
-**Note**: If you'd still like to submit a question, please read [this guide](
-https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports) detailing how to
-provide the necessary information for us to reproduce your question.
+**Note**: If you'd still like to submit a question, please read
+[this guide](https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports)
+detailing how to provide the necessary information for us to reproduce your question.
```python
# Your code here, if applicable
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 1817a2f..b627f37 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -6,4 +6,4 @@ Provide a description and/or bullet points to describe the changes in this PR.
- [ ] Reference issues which can be closed due to this PR with "Closes #x".
- [ ] Review whether the documentation needs to be updated.
-- [ ] Document PR in docs/changes.rst.
+- [ ] Document PR in CHANGES.md.
diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/main.yml
similarity index 97%
rename from .github/workflows/continuous-integration-workflow.yml
rename to .github/workflows/main.yml
index c35a940..c6e429d 100644
--- a/.github/workflows/continuous-integration-workflow.yml
+++ b/.github/workflows/main.yml
@@ -1,4 +1,4 @@
-name: Continuous Integration Workflow
+name: main
# Automatically cancel a previous run.
concurrency:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 7d27758..07e365d 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -24,9 +24,6 @@ repos:
- id: python-no-eval
- id: python-no-log-warn
- id: python-use-type-annotations
- - id: rst-backticks
- - id: rst-directive-colons
- - id: rst-inline-touching-normal
- id: text-unicode-replacement-char
- repo: https://github.com/asottile/pyupgrade
rev: v2.32.0
@@ -72,15 +69,20 @@ repos:
pydocstyle,
Pygments,
]
-- repo: https://github.com/PyCQA/doc8
- rev: 0.11.1
- hooks:
- - id: doc8
- repo: https://github.com/econchick/interrogate
rev: 1.5.0
hooks:
- id: interrogate
args: [-v, --fail-under=40, src, tests]
+- repo: https://github.com/executablebooks/mdformat
+ rev: 0.7.14
+ hooks:
+ - id: mdformat
+ additional_dependencies: [
+ mdformat-gfm,
+ mdformat-black,
+ ]
+ args: [--wrap, "88"]
- repo: https://github.com/codespell-project/codespell
rev: v2.1.0
hooks:
@@ -90,6 +92,8 @@ repos:
rev: "0.48"
hooks:
- id: check-manifest
+ args: [--no-build-isolation]
+ additional_dependencies: [setuptools-scm, toml]
- repo: meta
hooks:
- id: check-hooks-apply
diff --git a/CHANGES.md b/CHANGES.md
new file mode 100644
index 0000000..0c549f2
--- /dev/null
+++ b/CHANGES.md
@@ -0,0 +1,88 @@
+# Changes
+
+This is a record of all past pytask-latex releases and what went into them in reverse
+chronological order. Releases follow [semantic versioning](https://semver.org/) and all
+releases are available on [Anaconda.org](https://anaconda.org/conda-forge/pytask-latex).
+
+## 0.2.0 - 2022-04-16
+
+- {pull}`33` aligns pytask-latex with the pytask v0.2.
+- {pull}`34` deprecates the old api.
+
+## 0.1.2 - 2022-03-26
+
+- {pull}`32` implements a new interface to the compilation process which consists of
+ composable compilation steps. (Many thanks to `axtimhaus`{.interpreted-text
+ role="user"}!:tada:)
+- {pull}`36` fixes some issues.
+- {pull}`37` updates the release notes.
+
+## 0.1.1 - 2022-02-08
+
+- {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
+
+- {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
+
+- {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
+
+- {pull}`18` prepares pytask-latex to be published on PyPI, adds versioneer and more.
+
+## 0.0.10 - 2021-01-16
+
+- {pull}`16` fixes the scanner by keeping only scanned dependencies which exist. Convert
+ args to strings.
+
+## 0.0.9 - 2020-12-28
+
+- {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
+
+- {pull}`11` makes pytask-latex work with pytask v0.0.9.
+
+## 0.0.7 - 2020-10-14
+
+- {pull}`10` fixes error that `outputdirectory` has to be relative to latex document due
+ to security problems.
+
+## 0.0.6 - 2020-10-14
+
+- {pull}`9` fixes the last release and the `pytask_collect_task_teardown` call.
+
+## 0.0.5 - 2020-10-04
+
+- {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
+
+- {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
+
+- {pull}`3` prepares pytask-latex for pytask v0.0.5 and releases v0.0.3.
+
+## 0.0.2 - 2020-07-22
+
+- {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
+
+- Releases v0.0.1.
diff --git a/CHANGES.rst b/CHANGES.rst
deleted file mode 100644
index 6699b50..0000000
--- a/CHANGES.rst
+++ /dev/null
@@ -1,120 +0,0 @@
-Changes
-=======
-
-This is a record of all past pytask-latex releases and what went into them in reverse
-chronological order. Releases follow `semantic versioning `_ and
-all releases are available on `Anaconda.org
-`_.
-
-
-0.2.0 - 2022-xx-xx
-------------------
-
-- :pull:`34` deprecates the old api.
-
-
-0.1.2 - 2022-03-26
-------------------
-
-- :pull:`32` implements a new interface to the compilation process which consists of
- composable compilation steps. (Many thanks to :user:`axtimhaus`!:tada:)
-- :pull:`36` fixes some issues.
-- :pull:`37` updates the release notes.
-
-
-0.1.1 - 2022-02-08
-------------------
-
-- :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
-------------------
-
-- :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
--------------------
-
-- :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
--------------------
-
-- :pull:`18` prepares pytask-latex to be published on PyPI, adds versioneer and more.
-
-
-0.0.10 - 2021-01-16
--------------------
-
-- :pull:`16` fixes the scanner by keeping only scanned dependencies which exist. Convert
- args to strings.
-
-
-0.0.9 - 2020-12-28
-------------------
-
-- :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
-------------------
-
-- :pull:`11` makes pytask-latex work with pytask v0.0.9.
-
-
-0.0.7 - 2020-10-14
-------------------
-
-- :pull:`10` fixes error that ``outputdirectory`` has to be relative to latex document
- due to security problems.
-
-
-0.0.6 - 2020-10-14
-------------------
-
-- :pull:`9` fixes the last release and the ``pytask_collect_task_teardown`` call.
-
-
-0.0.5 - 2020-10-04
-------------------
-
-- :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
-------------------
-
-- :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
-------------------
-
-- :pull:`3` prepares pytask-latex for pytask v0.0.5 and releases v0.0.3.
-
-
-0.0.2 - 2020-07-22
-------------------
-
-- :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
-------------------
-
-- Releases v0.0.1.
diff --git a/MANIFEST.in b/MANIFEST.in
index 2897539..dd67fec 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,12 +1,9 @@
-prune .conda
prune tests
-exclude *.rst
+exclude *.md
exclude *.yml
exclude *.yaml
exclude tox.ini
-include README.rst
+include README.md
include LICENSE
-include versioneer.py
-include src/pytask_latex/_version.py
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..6d72645
--- /dev/null
+++ b/README.md
@@ -0,0 +1,205 @@
+# pytask-latex
+
+[](https://pypi.org/project/pytask-latex)
+[](https://pypi.org/project/pytask-latex)
+[](https://anaconda.org/conda-forge/pytask-latex)
+[](https://anaconda.org/conda-forge/pytask-latex)
+[](https://pypi.org/project/pytask-latex)
+[](https://github.com/pytask-dev/pytask-latex/actions?query=branch%3Amain)
+[](https://codecov.io/gh/pytask-dev/pytask-latex)
+[](https://results.pre-commit.ci/latest/github/pytask-dev/pytask-latex/main)
+[](https://github.com/psf/black)
+
+______________________________________________________________________
+
+pytask-latex allows you to compile LaTeX documents with pytask
+
+It also uses
+[latex-dependency-scanner](https://github.com/pytask-dev/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
+
+pytask-latex is available on [PyPI](https://pypi.org/project/pytask-latex) and
+[Anaconda.org](https://anaconda.org/conda-forge/pytask-latex). Install it with
+
+```console
+$ pip install pytask-latex
+
+# or
+
+$ conda install -c conda-forge pytask-latex
+```
+
+You also need to have `latexmk` installed which determines the necessary number of
+compilation steps ([here](https://tex.stackexchange.com/a/249243/194826) is an
+explanation for what latexmk achieves). To test whether it is installed, type the
+following on the command line
+
+```console
+$ latexmk --help
+```
+
+If an error is shown instead of a help page, you can install `latexmk` with one of the
+popular LaTeX distributions, like [TeX Live](https://www.tug.org/texlive/),
+[MiKTeX](https://miktex.org/), [MacTeX](http://www.tug.org/mactex/) or others.
+
+## Usage
+
+Compiling your PDF can be as simple as writing the following task.
+
+```python
+import pytask
+
+
+@pytask.mark.latex(script="document.tex", document="document.pdf")
+def task_compile_latex_document():
+ pass
+```
+
+Use `@pytask.mark.latex` to indicate that this task compiles a LaTeX document. The
+`script` and the `document` keywords provide absolute paths or paths relative to the
+task module to the LaTeX file and the compiled document.
+
+### Dependencies and Products
+
+Dependencies and products can be added as with a normal pytask task using the
+`@pytask.mark.depends_on` and `@pytask.mark.produces` decorators. which is explained in
+this
+[tutorial](https://pytask-dev.readthedocs.io/en/stable/tutorials/defining_dependencies_products.html).
+
+### Customizing the compilation
+
+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.
+
+```python
+@pytask.mark.latex(
+ script="document.tex",
+ document="document.pdf",
+ compilation_steps="latexmk",
+)
+def task_compile_latex_document():
+ ...
+```
+
+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.
+
+```python
+from pytask_latex import compilation_steps as cs
+
+
+@pytask.mark.latex(
+ script="document.tex",
+ document="document.pdf",
+ compilation_steps=cs.latexmk(
+ options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd")
+ ),
+)
+def task_compile_latex_document():
+ ...
+```
+
+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`.
+
+```python
+@pytask.mark.latex(
+ script="document.tex",
+ document="document.pdf",
+ compilation_steps=cs.latexmk(
+ options=("--dvi", "--interaction=nonstopmode", "--synctex=1", "--cd")
+ ),
+)
+def task_compile_latex_document():
+ ...
+```
+
+`compilation_step.latexmk(options)` generates a compilation step which is a function
+with the following signature:
+
+```python
+from pathlib import Path
+import subprocess
+
+
+def custom_compilation_step(path_to_tex: Path, path_to_document: Path) -> None:
+ ...
+ subproces.run(..., check=True)
+```
+
+You can also pass your custom compilation step with the same signature to the
+`compilation_steps` keyword argument of the decorator.
+
+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 compilation steps for compiling
+bibliographies, glossaries and the like.
+
+### Repeating tasks with different scripts or inputs
+
+You can compile multiple LaTeX documents as well as compiling a single `.tex` document
+with different command line arguments.
+
+The following task compiles two latex documents.
+
+```python
+for i in range(2):
+
+ @pytask.mark.task
+ @pytask.mark.latex(script=f"document_{i}.tex", document=f"document_{i}.pdf")
+ def task_compile_latex_document():
+ pass
+```
+
+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
+compilation steps and their options.
+
+```python
+for format_ in ("pdf", "dvi"):
+
+ @pytask.mark.task
+ @pytask.mark.latex(
+ script="document.tex",
+ document=f"document.{format_}",
+ compilation_steps=cs.latexmk(
+ (f"--{format_}", "--interaction=nonstopmode", "--synctex=1", "--cd")
+ ),
+ )
+ def task_compile_latex_document():
+ pass
+```
+
+## Configuration
+
+*`infer_latex_dependencies`*
+
+pytask-latex tries to scan your LaTeX document for included files with the help of
+[latex-dependency-scanner](https://github.com/pytask-dev/latex-dependency-scanner) if
+the following configuration value is true which is also the default.
+
+```toml
+[tool.pytask.ini_options]
+infer_latex_dependencies = true
+```
+
+Since the package is in its early development phase and LaTeX provides a myriad of ways
+to include files as well as providing shortcuts for paths (e.g., `\graphicspath`), there
+are definitely some rough edges left. File an issue here or in the other project in case
+of a problem.
+
+## Changes
+
+Consult the [release notes](CHANGES.md) to find out about what is new.
diff --git a/README.rst b/README.rst
deleted file mode 100644
index 3a4dc40..0000000
--- a/README.rst
+++ /dev/null
@@ -1,303 +0,0 @@
-.. image:: https://img.shields.io/pypi/v/pytask-latex?color=blue
- :alt: PyPI
- :target: https://pypi.org/project/pytask-latex
-
-.. image:: https://img.shields.io/pypi/pyversions/pytask-latex
- :alt: PyPI - Python Version
- :target: https://pypi.org/project/pytask-latex
-
-.. image:: https://img.shields.io/conda/vn/conda-forge/pytask-latex.svg
- :target: https://anaconda.org/conda-forge/pytask-latex
-
-.. image:: https://img.shields.io/conda/pn/conda-forge/pytask-latex.svg
- :target: https://anaconda.org/conda-forge/pytask-latex
-
-.. image:: https://img.shields.io/pypi/l/pytask-latex
- :alt: PyPI - License
- :target: https://pypi.org/project/pytask-latex
-
-.. image:: https://img.shields.io/github/workflow/status/pytask-dev/pytask-latex/Continuous%20Integration%20Workflow/main
- :target: https://github.com/pytask-dev/pytask-latex/actions?query=branch%3Amain
-
-.. image:: https://codecov.io/gh/pytask-dev/pytask-latex/branch/main/graph/badge.svg
- :target: https://codecov.io/gh/pytask-dev/pytask-latex
-
-.. image:: https://results.pre-commit.ci/badge/github/pytask-dev/pytask-latex/main.svg
- :target: https://results.pre-commit.ci/latest/github/pytask-dev/pytask-latex/main
- :alt: pre-commit.ci status
-
-.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
- :target: https://github.com/psf/black
-
-------
-
-pytask-latex
-============
-
-pytask-latex allows you to compile LaTeX documents with pytask
-
-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
-------------
-
-pytask-latex is available on `PyPI `_ and
-`Anaconda.org `_. Install it with
-
-.. code-block:: console
-
- $ pip install pytask-latex
-
- # or
-
- $ conda install -c conda-forge pytask-latex
-
-You also need to have ``latexmk`` installed which determines the necessary number of
-compilation steps (`here `_ is an
-explanation for what latexmk achieves). To test whether it is installed, type the
-following on the command line
-
-.. code-block:: console
-
- $ latexmk --help
-
-If an error is shown instead of a help page, you can install ``latexmk`` with one of the
-popular LaTeX distributions, like `TeX Live `_, `MiKTeX
-`_, `MacTeX `_ or others.
-
-
-Usage
------
-
-Compiling your PDF can be as simple as writing the following task.
-
-.. code-block:: python
-
- import pytask
-
-
- @pytask.mark.latex
- @pytask.mark.depends_on("document.tex")
- @pytask.mark.produces("document.pdf")
- def task_compile_latex_document():
- pass
-
-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
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-In general, you might not need to add dependencies other than the main LaTeX file
-because pytask-latex tries to infer other dependencies automatically. See the
-explanation for ``infer_latex_dependencies`` below.
-
-What happens if you need to add more dependencies to a task because they are not found
-automatically? You could use a list, but ensure that the LaTeX document which should be
-compiled is in the first position of the list.
-
-.. code-block:: python
-
- @pytask.mark.latex
- @pytask.mark.depends_on(["document.tex", "image.png"])
- @pytask.mark.produces("document.pdf")
- def task_compile_latex_document():
- pass
-
-If you use a dictionary to pass dependencies to the task, pytask-latex will, first, look
-for a ``"source"`` key in the dictionary and, secondly, under the key ``0``.
-
-.. code-block:: python
-
- @pytask.mark.depends_on({"source": "document.tex", "image": "image.png"})
- def task_compile_document():
- pass
-
-
- # or
-
-
- @pytask.mark.depends_on({0: "document.tex", "image": "image.png"})
- def task_compile_document():
- pass
-
-
- # or two decorators for the function, if you do not assign a name to the image.
-
-
- @pytask.mark.depends_on({"source": "document.tex"})
- @pytask.mark.depends_on("image.png")
- def task_compile_document():
- pass
-
-The same applies to the compiled document which is either in the first position, under
-the key ``"document"`` or ``0``.
-
-
-Customizing the compilation
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-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(compilation_steps="latexmk")
- def task_compile_latex_document():
- ...
-
-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:: python
-
- from pytask_latex import compilation_steps as cs
-
-
- @pytask.mark.latex(
- compilation_steps=cs.latexmk(
- options=("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd")
- )
- )
- def task_compile_latex_document():
- ...
-
-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``.
-
-.. code-block:: python
-
- @pytask.mark.latex(
- compilation_steps=compilation_steps.latexmk(
- options=("--dvi", "--interaction=nonstopmode", "--synctex=1", "--cd")
- )
- )
- def task_compile_latex_document():
- ...
-
-``compilation_step.latexmk(options)`` generates a compilation step which is a function
-with the following signature:
-
-.. code-block:: python
-
- from pathlib import Path
- import subprocess
-
-
- def custom_compilation_step(path_to_tex: Path, path_to_document: Path) -> None:
- ...
- subproces.run(..., check=True)
-
-You can also pass your custom compilation step with the same signature to the
-``compilation_steps`` keyword argument of the decorator.
-
-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 compilation steps for compiling
-bibliographies, 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.
-
-The following task compiles two latex documents.
-
-.. code-block:: python
-
- @pytask.mark.latex
- @pytask.mark.parametrize(
- "depends_on, produces",
- [("document_1.tex", "document_1.pdf"), ("document_2.tex", "document_2.pdf")],
- )
- def task_compile_latex_document():
- pass
-
-
-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 compilation steps and their options.
-
-.. code-block:: python
-
- @pytask.mark.depends_on("document.tex")
- @pytask.mark.parametrize(
- "produces, latex",
- [
- (
- "document.pdf",
- {
- "compilation_steps": compilation_steps.latexmk(
- ("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd")
- )
- },
- ),
- (
- "document.dvi",
- {
- "compilation_steps": compilation_steps.latexmk(
- ("--dvi", "--interaction=nonstopmode", "--synctex=1", "--cd")
- )
- },
- ),
- ],
- )
- def task_compile_latex_document():
- pass
-
-
-Configuration
--------------
-
-latex_source_key
- If you want to change the name of the key which identifies the source file, change
- the following default configuration in your pytask configuration file.
-
- .. code-block:: ini
-
- latex_source_key = source
-
-latex_document_key
- If you want to change the name of the key which identifies the compiled document,
- change the following default configuration in your pytask configuration file.
-
- .. code-block:: ini
-
- latex_source_key = source
-
-infer_latex_dependencies
- pytask-latex tries to scan your LaTeX document for included files with the help of
- `latex-dependency-scanner `_
- if the following configuration value is true which is also the default.
-
- .. code-block:: ini
-
- infer_latex_dependencies = true
-
- Since the package is in its early development phase and LaTeX provides a myriad of
- ways to include files as well as providing shortcuts for paths (e.g.,
- ``\graphicspath``), there are definitely some rough edges left. File an issue here
- or in the other project in case of a problem.
-
-
-Changes
--------
-
-Consult the `release notes `_ to find out about what is new.
diff --git a/codecov.yml b/codecov.yml
index e6cec4d..b37c2a8 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -21,6 +21,4 @@ coverage:
ignore:
- ".tox/**/*"
- - "setup.py"
- - "versioneer.py"
- "src/pytask_latex/_version.py"
diff --git a/environment.yml b/environment.yml
index 9734833..8d14852 100644
--- a/environment.yml
+++ b/environment.yml
@@ -11,9 +11,10 @@ dependencies:
- toml
# Package dependencies
- - pytask >= 0.1.0
- - pytask-parallel >= 0.1.0
- - latex-dependency-scanner
+ - pytask >= 0.2
+ - pytask-parallel >= 0.1
+ - latex-dependency-scanner >=0.1.1
+ - pybaum >=0.1.1
# Misc
- black
diff --git a/pyproject.toml b/pyproject.toml
index 44cd0b7..b2714c9 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,5 +1,6 @@
[build-system]
requires = ["setuptools>=45", "wheel", "setuptools_scm[toml]>=6.0"]
+build-backend = "setuptools.build_meta"
[tool.setuptools_scm]
diff --git a/setup.cfg b/setup.cfg
index 42a0ae6..1995fc9 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,8 +1,8 @@
[metadata]
name = pytask_latex
description = Compile LaTeX documents with pytask.
-long_description = file: README.rst
-long_description_content_type = text/x-rst
+long_description = file: README.md
+long_description_content_type = text/markdown
url = https://github.com/pytask-dev/pytask-latex
author = Tobias Raabe
author_email = raabe@posteo.de
@@ -20,7 +20,7 @@ classifiers =
Programming Language :: Python :: 3.9
Programming Language :: Python :: 3.10
project_urls =
- Changelog = https://github.com/pytask-dev/pytask-latex/blob/main/CHANGES.rst
+ Changelog = https://github.com/pytask-dev/pytask-latex/blob/main/CHANGES.md
Documentation = https://github.com/pytask-dev/pytask-latex
Github = https://github.com/pytask-dev/pytask-latex
Tracker = https://github.com/pytask-dev/pytask-latex/issues
@@ -30,7 +30,8 @@ packages = find:
install_requires =
click
latex-dependency-scanner>=0.1.1
- pytask>=0.1.7
+ pybaum>=0.1.1
+ pytask>=0.2
python_requires = >=3.7
include_package_data = True
package_dir = =src
diff --git a/setup.py b/setup.py
deleted file mode 100644
index c21a9ee..0000000
--- a/setup.py
+++ /dev/null
@@ -1,7 +0,0 @@
-from __future__ import annotations
-
-from setuptools import setup
-
-
-if __name__ == "__main__":
- setup()
diff --git a/src/pytask_latex/__init__.py b/src/pytask_latex/__init__.py
index f493641..dcc8e73 100644
--- a/src/pytask_latex/__init__.py
+++ b/src/pytask_latex/__init__.py
@@ -2,7 +2,7 @@
try:
from ._version import version as __version__
-except ImportError:
+except ImportError: # pragma: no cover
# broken installation, we don't even try unknown only works because we do poor mans
# version compare
__version__ = "unknown"
diff --git a/src/pytask_latex/collect.py b/src/pytask_latex/collect.py
index c30fc2c..66b561d 100644
--- a/src/pytask_latex/collect.py
+++ b/src/pytask_latex/collect.py
@@ -1,30 +1,75 @@
"""Collect tasks."""
from __future__ import annotations
-import copy
import functools
+from pathlib import Path
from subprocess import CalledProcessError
+from types import FunctionType
from typing import Any
from typing import Callable
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
-from _pytask.nodes import _collect_nodes
-from _pytask.nodes import FilePathNode
-from _pytask.parametrize import _copy_func
+from pybaum.tree_util import tree_map
+from pytask import depends_on
+from pytask import FilePathNode
+from pytask import has_mark
+from pytask import hookimpl
+from pytask import Mark
+from pytask import MetaNode
+from pytask import NodeNotCollectedError
+from pytask import parse_nodes
+from pytask import produces
+from pytask import remove_marks
+from pytask import Session
+from pytask import Task
from pytask_latex import compilation_steps as cs
from pytask_latex.utils import to_list
+_ERROR_MSG = """The old syntax for @pytask.mark.latex was suddenly deprecated starting \
+with pytask-latex v0.2 to provide a better user experience. Thank you for your \
+understanding!
+
+It is recommended to upgrade to the new syntax, so you enjoy all the benefits of v0.2 of
+pytask and a better interface for pytask-latex.
+
+You can find a manual here: \
+https://github.com/pytask-dev/pytask-latex/blob/v0.2.0/README.md
+
+Upgrading can be as easy as rewriting your current task from
+
+ @pytask.mark.latex("--some-option")
+ @pytask.mark.depends_on({"source": "script.tex")
+ @pytask.mark.produces("document.pdf")
+ def task_latex():
+ ...
+
+to
+
+ @pytask.mark.latex(
+ script="script.tex",
+ document="document.pdf",
+ options="--some-options"
+ )
+ def task_latex():
+ ...
+
+You can also fix the version of pytask and pytask-latex to <0.2, so you do not have to \
+to upgrade. At the same time, you will not enjoy the improvements released with \
+version v0.2 of pytask and pytask-latex.
+
+"""
+
+
def latex(
*,
+ script: str | Path = None,
+ document: str | Path = None,
compilation_steps: str
| Callable[..., Any]
| Sequence[str | Callable[..., Any]] = None,
-):
+) -> tuple[str | Path | None, list[Callable[..., Any]]]:
"""Specify command line options for latexmk.
Parameters
@@ -35,26 +80,13 @@ def latex(
Compilation steps to compile the document.
"""
- compilation_steps = ["latexmk"] if compilation_steps is None else compilation_steps
-
- out = []
- for step in to_list(compilation_steps):
- if isinstance(step, str):
- parsed_step = getattr(cs, step)
- if parsed_step is None:
- raise ValueError(f"Compilation step {step!r} is unknown.")
- out.append(parsed_step())
- elif callable(step):
- out.append(step)
- else:
- raise ValueError(f"Compilation step {step!r} is not a valid step.")
-
- return out
+ if script is None or document is None:
+ raise RuntimeError(_ERROR_MSG)
+ return script, document, compilation_steps
def compile_latex_document(compilation_steps, path_to_tex, path_to_document):
"""Replaces the dummy function provided by the user."""
-
for step in compilation_steps:
try:
step(path_to_tex=path_to_tex, path_to_document=path_to_document)
@@ -63,50 +95,89 @@ def compile_latex_document(compilation_steps, path_to_tex, path_to_document):
@hookimpl
-def pytask_collect_task_teardown(session, task):
+def pytask_collect_task(session, path, name, obj):
"""Perform some checks."""
- if get_specific_markers_from_task(task, "latex"):
- source = _get_node_from_dictionary(
- task.depends_on, session.config["latex_source_key"]
- )
- if not (isinstance(source, FilePathNode) and source.value.suffix == ".tex"):
+ __tracebackhide__ = True
+
+ if (
+ (name.startswith("task_") or has_mark(obj, "task"))
+ and callable(obj)
+ and has_mark(obj, "latex")
+ ):
+ obj, marks = remove_marks(obj, "latex")
+
+ if len(marks) > 1:
raise ValueError(
- "The first or sole dependency of a LaTeX task must be the document "
- "which will be compiled and has a .tex extension."
+ f"Task {name!r} has multiple @pytask.mark.latex marks, but only one is "
+ "allowed."
)
+ latex_mark = marks[0]
+ script, document, compilation_steps = latex(**latex_mark.kwargs)
+
+ parsed_compilation_steps = _parse_compilation_steps(compilation_steps)
+
+ obj.pytask_meta.markers.append(latex_mark)
+
+ dependencies = parse_nodes(session, path, name, obj, depends_on)
+ products = parse_nodes(session, path, name, obj, produces)
- document = _get_node_from_dictionary(
- task.produces, session.config["latex_document_key"]
+ markers = obj.pytask_meta.markers if hasattr(obj, "pytask_meta") else []
+ kwargs = obj.pytask_meta.kwargs if hasattr(obj, "pytask_meta") else {}
+
+ task = Task(
+ base_name=name,
+ path=path,
+ function=_copy_func(compile_latex_document),
+ depends_on=dependencies,
+ produces=products,
+ markers=markers,
+ kwargs=kwargs,
+ )
+
+ script_node = session.hook.pytask_collect_node(
+ session=session, path=path, node=script
+ )
+ document_node = session.hook.pytask_collect_node(
+ session=session, path=path, node=document
)
+
if not (
- isinstance(document, FilePathNode)
- and document.value.suffix in [".pdf", ".ps", ".dvi"]
+ isinstance(script_node, FilePathNode) and script_node.value.suffix == ".tex"
):
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."
+ "The 'script' keyword of the @pytask.mark.latex decorator must point "
+ "to LaTeX file with the .tex suffix."
)
- task_function = _copy_func(compile_latex_document)
- task_function.pytaskmark = copy.deepcopy(task.function.pytaskmark)
+ if not (
+ isinstance(document_node, FilePathNode)
+ and document_node.value.suffix in [".pdf", ".ps", ".dvi"]
+ ):
+ raise ValueError(
+ "The 'document' keyword of the @pytask.mark.latex decorator must point "
+ "to a .pdf, .ps or .dvi file."
+ )
- merged_mark = _merge_all_markers(task)
- steps = latex(*merged_mark.args, **merged_mark.kwargs)
- args = get_compilation_step_args(session, task)
- task_function = functools.partial(
- task_function, compilation_steps=steps, **args
- )
+ if isinstance(task.depends_on, dict):
+ task.depends_on["__script"] = script_node
+ else:
+ task.depends_on = {0: task.depends_on, "__script": script_node}
+ if isinstance(task.produces, dict):
+ task.produces["__document"] = document_node
+ else:
+ task.produces = {0: task.produces, "__document": document_node}
- task.function = task_function
+ task.function = functools.partial(
+ task.function,
+ compilation_steps=parsed_compilation_steps,
+ path_to_tex=script_node.path,
+ path_to_document=document_node.path,
+ )
if session.config["infer_latex_dependencies"]:
task = _add_latex_dependencies_retroactively(task, session)
-
-def _get_node_from_dictionary(obj, key, fallback=0):
- if isinstance(obj, dict):
- obj = obj.get(key) or obj.get(fallback)
- return obj
+ return task
def _add_latex_dependencies_retroactively(task, session):
@@ -125,16 +196,12 @@ def _add_latex_dependencies_retroactively(task, session):
----------
task
The LaTeX task.
- session : _pytask.session.Session
+ session : pytask.Session
The session.
"""
- source = _get_node_from_dictionary(
- task.depends_on, session.config["latex_source_key"]
- )
-
# Scan the LaTeX document for included files.
- latex_dependencies = set(lds.scan(source.path))
+ latex_dependencies = set(lds.scan(task.depends_on["__script"].path))
# Remove duplicated dependencies which have already been added by the user and those
# which do not exist.
@@ -143,17 +210,13 @@ def _add_latex_dependencies_retroactively(task, session):
}
new_deps = latex_dependencies - existing_paths
new_existing_deps = {i for i in new_deps if i.exists()}
-
- # Put scanned dependencies in a dictionary with incrementing keys.
- used_integer_keys = [i for i in task.depends_on if isinstance(i, int)]
- max_int = max(used_integer_keys) if used_integer_keys else 0
- new_existing_deps = dict(enumerate(new_existing_deps, max_int + 1))
+ new_numbered_deps = dict(enumerate(new_existing_deps))
# Collect new dependencies and add them to the task.
- collected_dependencies = _collect_nodes(
- session, task.path, task.name, new_existing_deps
+ collected_dependencies = tree_map(
+ lambda x: _collect_node(session, task.path, task.name, x), new_numbered_deps
)
- task.depends_on = {**task.depends_on, **collected_dependencies}
+ task.depends_on["__scanned_dependencies"] = collected_dependencies
# Mark the task as being delayed to avoid conflicts with unmatched dependencies.
task.markers.append(Mark("try_last", (), {}))
@@ -161,22 +224,87 @@ def _add_latex_dependencies_retroactively(task, session):
return task
-def _merge_all_markers(task):
- """Combine all information from markers for the compile latex function."""
- latex_marks = get_specific_markers_from_task(task, "latex")
- mark = latex_marks[0]
- for mark_ in latex_marks[1:]:
- mark = mark.combined_with(mark_)
- return mark
+def _copy_func(func: FunctionType) -> FunctionType:
+ """Create a copy of a function.
+
+ Based on https://stackoverflow.com/a/13503277/7523785.
+
+ Example
+ -------
+ >>> def _func(): pass
+ >>> copied_func = _copy_func(_func)
+ >>> _func is copied_func
+ False
+
+ """
+ new_func = FunctionType(
+ func.__code__,
+ func.__globals__,
+ name=func.__name__,
+ argdefs=func.__defaults__,
+ closure=func.__closure__,
+ )
+ new_func = functools.update_wrapper(new_func, func)
+ new_func.__kwdefaults__ = func.__kwdefaults__
+ return new_func
+
+
+def _collect_node(
+ session: Session, path: Path, name: str, node: str | Path
+) -> dict[str, MetaNode]:
+ """Collect nodes for a task.
+
+ Parameters
+ ----------
+ session : pytask.Session
+ The session.
+ path : Path
+ The path to the task whose nodes are collected.
+ name : str
+ The name of the task.
+ nodes : Dict[str, Union[str, Path]]
+ A dictionary of nodes parsed from the ``depends_on`` or ``produces`` markers.
+
+ Returns
+ -------
+ Dict[str, MetaNode]
+ A dictionary of node names and their paths.
+
+ Raises
+ ------
+ NodeNotCollectedError
+ If the node could not collected.
+
+ """
+ collected_node = session.hook.pytask_collect_node(
+ session=session, path=path, node=node
+ )
+ if collected_node is None:
+ raise NodeNotCollectedError(
+ f"{node!r} cannot be parsed as a dependency or product for task "
+ f"{name!r} in {path!r}."
+ )
+
+ return collected_node
+
+def _parse_compilation_steps(compilation_steps):
+ """Parse compilation steps."""
+ __tracebackhide__ = True
-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
- compiled_document = _get_node_from_dictionary(
- task.produces, session.config["latex_document_key"]
- ).value
+ compilation_steps = ["latexmk"] if compilation_steps is None else compilation_steps
+
+ parsed_compilation_steps = []
+ for step in to_list(compilation_steps):
+ if isinstance(step, str):
+ try:
+ parsed_step = getattr(cs, step)
+ except AttributeError:
+ raise ValueError(f"Compilation step {step!r} is unknown.")
+ parsed_compilation_steps.append(parsed_step())
+ elif callable(step):
+ parsed_compilation_steps.append(step)
+ else:
+ raise ValueError(f"Compilation step {step!r} is not a valid step.")
- return {"path_to_tex": latex_document, "path_to_document": compiled_document}
+ return parsed_compilation_steps
diff --git a/src/pytask_latex/config.py b/src/pytask_latex/config.py
index 3414499..c3e964f 100644
--- a/src/pytask_latex/config.py
+++ b/src/pytask_latex/config.py
@@ -1,22 +1,62 @@
"""Configure pytask."""
from __future__ import annotations
-from _pytask.config import hookimpl
-from _pytask.shared import convert_truthy_or_falsy_to_bool
-from _pytask.shared import get_first_non_none_value
+from typing import Any
+from typing import Callable
+
+from pytask import hookimpl
@hookimpl
def pytask_parse_config(config, config_from_file):
"""Register the latex marker in the configuration."""
config["markers"]["latex"] = "Tasks which compile LaTeX documents."
- config["latex_source_key"] = config_from_file.get("latex_source_key", "source")
- config["latex_document_key"] = config_from_file.get(
- "latex_document_key", "document"
- )
- config["infer_latex_dependencies"] = get_first_non_none_value(
+ config["infer_latex_dependencies"] = _get_first_non_none_value(
config_from_file,
key="infer_latex_dependencies",
- callback=convert_truthy_or_falsy_to_bool,
+ callback=_convert_truthy_or_falsy_to_bool,
default=True,
)
+
+
+def _convert_truthy_or_falsy_to_bool(x: bool | str | None) -> bool:
+ """Convert truthy or falsy value in .ini to Python boolean."""
+ if x in [True, "True", "true", "1"]:
+ out = True
+ elif x in [False, "False", "false", "0"]:
+ out = False
+ elif x in [None, "None", "none"]:
+ out = None
+ else:
+ raise ValueError(
+ f"Input {x!r} is neither truthy (True, true, 1) or falsy (False, false, 0)."
+ )
+ return out
+
+
+def _get_first_non_none_value(
+ *configs: dict[str, Any],
+ key: str,
+ default: Any | None = None,
+ callback: Callable[..., Any] | None = None,
+) -> Any:
+ """Get the first non-None value for a key from a list of dictionaries.
+
+ This function allows to prioritize information from many configurations by changing
+ the order of the inputs while also providing a default.
+
+ Examples
+ --------
+ >>> _get_first_non_none_value({"a": None}, {"a": 1}, key="a")
+ 1
+ >>> _get_first_non_none_value({"a": None}, {"a": None}, key="a", default="default")
+ 'default'
+ >>> _get_first_non_none_value({}, {}, key="a", default="default")
+ 'default'
+ >>> _get_first_non_none_value({"a": None}, {"a": "b"}, key="a")
+ 'b'
+
+ """
+ callback = (lambda x: x) if callback is None else callback # noqa: E731
+ processed_values = (callback(config.get(key)) for config in configs)
+ return next((value for value in processed_values if value is not None), default)
diff --git a/src/pytask_latex/execute.py b/src/pytask_latex/execute.py
index 87ec03e..e378532 100644
--- a/src/pytask_latex/execute.py
+++ b/src/pytask_latex/execute.py
@@ -3,14 +3,14 @@
import shutil
-from _pytask.config import hookimpl
-from _pytask.mark_utils import get_specific_markers_from_task
+from pytask import has_mark
+from pytask import hookimpl
@hookimpl
def pytask_execute_task_setup(task):
"""Check that latexmk is found on the PATH if a LaTeX task should be executed."""
- if get_specific_markers_from_task(task, "latex"):
+ if has_mark(task, "latex"):
if shutil.which("latexmk") is None:
raise RuntimeError(
"latexmk is needed to compile LaTeX documents, but it is not found on "
diff --git a/src/pytask_latex/parametrize.py b/src/pytask_latex/parametrize.py
index aa4b492..5041761 100644
--- a/src/pytask_latex/parametrize.py
+++ b/src/pytask_latex/parametrize.py
@@ -1,8 +1,8 @@
"""Parametrize tasks."""
from __future__ import annotations
-from _pytask.config import hookimpl
-from _pytask.mark import MARK_GEN as mark # noqa: N811
+import pytask
+from pytask import hookimpl
@hookimpl
@@ -10,7 +10,4 @@ def pytask_parametrize_kwarg_to_marker(obj, kwargs):
"""Register kwargs as latex marker."""
if callable(obj):
if "latex" in kwargs:
- if isinstance(kwargs["latex"], dict):
- mark.latex(**kwargs.pop("latex"))(obj)
- else:
- mark.latex(kwargs.pop("latex"))(obj)
+ pytask.mark.latex(**kwargs.pop("latex"))(obj)
diff --git a/src/pytask_latex/plugin.py b/src/pytask_latex/plugin.py
index 3325a1f..ca67c7a 100644
--- a/src/pytask_latex/plugin.py
+++ b/src/pytask_latex/plugin.py
@@ -1,7 +1,7 @@
"""Entry-point for the plugin."""
from __future__ import annotations
-from _pytask.config import hookimpl
+from pytask import hookimpl
from pytask_latex import collect
from pytask_latex import config
from pytask_latex import execute
diff --git a/tests/conftest.py b/tests/conftest.py
index 1fdb7db..1ae27ba 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -18,7 +18,7 @@
)
skip_on_github_actions_with_win = pytest.mark.skipif(
- os.environ.get("GITHUB_ACTIONS", "false") == "true" and sys.platform == "win32",
+ condition=os.environ.get("CI") == "true" and sys.platform == "win32",
reason="TinyTeX does not work on Windows.",
)
diff --git a/tests/test_collect.py b/tests/test_collect.py
index d94c6d1..efc3ddd 100644
--- a/tests/test_collect.py
+++ b/tests/test_collect.py
@@ -3,101 +3,41 @@
from contextlib import ExitStack as does_not_raise # noqa: N813
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_teardown
-
-
-class DummyClass:
- pass
-
-
-def task_dummy():
- pass
+from pytask_latex.collect import latex
@pytest.mark.unit
@pytest.mark.parametrize(
- "marks, expected",
+ "kwargs, expectation, expected",
[
+ ({}, pytest.raises(RuntimeError, match="The old syntax"), None),
(
- [Mark("latex", ("--a",), {}), Mark("latex", ("--b",), {})],
- Mark("latex", ("--a", "--b"), {}),
+ {"document": "document.pdf"},
+ pytest.raises(RuntimeError, match="The old syntax"),
+ None,
),
(
- [Mark("latex", ("--a",), {}), Mark("latex", (), {"latex": "--b"})],
- Mark("latex", ("--a",), {"latex": "--b"}),
+ {"script": "script.tex"},
+ pytest.raises(RuntimeError, match="The old syntax"),
+ None,
+ ),
+ (
+ {"script": "script.tex", "document": "document.pdf"},
+ does_not_raise(),
+ ("script.tex", "document.pdf", None),
+ ),
+ (
+ {
+ "script": "script.tex",
+ "document": "document.pdf",
+ "compilation_steps": "latexmk",
+ },
+ does_not_raise(),
+ ("script.tex", "document.pdf", "latexmk"),
),
],
)
-def test_merge_all_markers(marks, expected):
- task = DummyClass()
- task.markers = marks
- out = _merge_all_markers(task)
- assert out == expected
-
-
-@pytest.mark.unit
-@pytest.mark.parametrize(
- "depends_on, produces, expectation",
- [
- (["document.tex"], ["document.pdf"], does_not_raise()),
- (["document.tex"], ["document.ps"], does_not_raise()),
- (["document.tex"], ["document.dvi"], does_not_raise()),
- (["document.txt"], ["document.pdf"], pytest.raises(ValueError)),
- (["document.txt"], ["document.ps"], pytest.raises(ValueError)),
- (["document.txt"], ["document.dvi"], pytest.raises(ValueError)),
- (["document.tex"], ["document.txt"], pytest.raises(ValueError)),
- (["document.txt", "document.tex"], ["document.pdf"], pytest.raises(ValueError)),
- (["document.tex"], ["document.out", "document.pdf"], pytest.raises(ValueError)),
- ],
-)
-@pytest.mark.parametrize("latex_source_key", ["source", "script", "main"])
-@pytest.mark.parametrize("latex_document_key", ["document", "compiled_doc"])
-@pytest.mark.parametrize("infer_latex_dependencies", [True, False])
-def test_pytask_collect_task_teardown(
- tmp_path,
- depends_on,
- produces,
- expectation,
- latex_source_key,
- latex_document_key,
- infer_latex_dependencies,
-):
- if infer_latex_dependencies:
- tmp_path.joinpath(depends_on[0]).touch()
-
- session = DummyClass()
- session.config = {
- "latex_source_key": latex_source_key,
- "latex_document_key": latex_document_key,
- "infer_latex_dependencies": infer_latex_dependencies,
- }
-
- task = DummyClass()
- task.path = tmp_path / "task_dummy.py"
- task.name = tmp_path.as_posix() + "task_dummy.py::task_dummy"
- task.depends_on = {
- i: FilePathNode.from_path(tmp_path / n) for i, n in enumerate(depends_on)
- }
- task.produces = {
- i: FilePathNode.from_path(tmp_path / n) for i, n in enumerate(produces)
- }
- task.markers = [Mark("latex", (), {})]
- task.function = task_dummy
- task.function.pytaskmark = task.markers
-
+def test_latex(kwargs, expectation, expected):
with expectation:
- pytask_collect_task_teardown(session, task)
-
-
-@pytest.mark.unit
-@pytest.mark.parametrize(
- "obj, key, expected",
- [(1, "asds", 1), (1, None, 1), ({"a": 1}, "a", 1), ({0: 1}, "a", 1)],
-)
-def test_get_node_from_dictionary(obj, key, expected):
- result = _get_node_from_dictionary(obj, key)
- assert result == expected
+ result = latex(**kwargs)
+ assert result == expected
diff --git a/tests/test_config.py b/tests/test_config.py
index 40976b4..3ed5b90 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -1,11 +1,37 @@
from __future__ import annotations
+from contextlib import ExitStack as does_not_raise # noqa: N813
+
import pytest
from pytask import main
+from pytask_latex.config import _convert_truthy_or_falsy_to_bool
@pytest.mark.end_to_end
def test_marker_is_configured(tmp_path):
session = main({"paths": tmp_path})
-
assert "latex" in session.config["markers"]
+
+
+@pytest.mark.unit
+@pytest.mark.parametrize(
+ "value, expectation, expected",
+ [
+ (True, does_not_raise(), True),
+ ("True", does_not_raise(), True),
+ ("true", does_not_raise(), True),
+ ("1", does_not_raise(), True),
+ (False, does_not_raise(), False),
+ ("False", does_not_raise(), False),
+ ("false", does_not_raise(), False),
+ ("0", does_not_raise(), False),
+ (None, does_not_raise(), None),
+ ("None", does_not_raise(), None),
+ ("none", does_not_raise(), None),
+ ("asklds", pytest.raises(ValueError, match="Input"), None),
+ ],
+)
+def test_convert_truthy_or_falsy_to_bool(value, expectation, expected):
+ with expectation:
+ result = _convert_truthy_or_falsy_to_bool(value)
+ assert result == expected
diff --git a/tests/test_execute.py b/tests/test_execute.py
index 5a61973..5321196 100644
--- a/tests/test_execute.py
+++ b/tests/test_execute.py
@@ -1,76 +1,47 @@
from __future__ import annotations
import textwrap
-from contextlib import ExitStack as does_not_raise # noqa: N813
+from pathlib import Path
import pytest
-from _pytask.mark import Mark
from conftest import needs_latexmk
from conftest import skip_on_github_actions_with_win
from conftest import TEST_RESOURCES
from pytask import cli
+from pytask import ExitCode
from pytask import main
+from pytask import Mark
+from pytask import Task
from pytask_latex.execute import pytask_execute_task_setup
-class DummyTask:
- pass
-
-
@pytest.mark.unit
-@pytest.mark.parametrize(
- "found_latexmk, expectation",
- [
- (True, does_not_raise()),
- (None, pytest.raises(RuntimeError)),
- ],
-)
-def test_pytask_execute_task_setup(monkeypatch, found_latexmk, expectation):
+def test_pytask_execute_task_setup(monkeypatch):
"""Make sure that the task setup raises errors."""
# Act like latexmk is installed since we do not test this.
monkeypatch.setattr(
- "pytask_latex.execute.shutil.which", lambda x: found_latexmk # noqa: U100
+ "pytask_latex.execute.shutil.which", lambda x: None # noqa: U100
)
-
- task = DummyTask()
- task.markers = [Mark("latex", (), {})]
-
- with expectation:
+ task = Task(
+ base_name="example", path=Path(), function=None, markers=[Mark("latex", (), {})]
+ )
+ with pytest.raises(RuntimeError, match="latexmk is needed"):
pytask_execute_task_setup(task)
@needs_latexmk
@skip_on_github_actions_with_win
@pytest.mark.end_to_end
-@pytest.mark.parametrize(
- "depends_on",
- [
- "'document.tex'",
- {"source": "document.tex"},
- {0: "document.tex"},
- {"script": "document.tex"},
- ],
-)
-@pytest.mark.parametrize(
- "produces",
- [
- "'document.pdf'",
- {"document": "document.pdf"},
- {0: "document.pdf"},
- {"compiled_doc": "document.pdf"},
- ],
-)
-def test_compile_latex_document(runner, tmp_path, depends_on, produces):
+def test_compile_latex_document_raise_error_old_api(runner, tmp_path):
"""Test simple compilation."""
- task_source = f"""
+ task_source = """
import pytask
@pytask.mark.latex
- @pytask.mark.depends_on({depends_on})
- @pytask.mark.produces({produces})
+ @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))
@@ -82,21 +53,36 @@ def task_compile_document():
"""
tmp_path.joinpath("document.tex").write_text(textwrap.dedent(latex_source))
- config = "[pytask]\n"
- if (
- isinstance(depends_on, dict)
- and "source" not in depends_on
- and 0 not in depends_on
- ):
- config += "latex_source_key = script\n"
- if isinstance(produces, dict) and "document" not in produces and 0 not in produces:
- config += "latex_document_key = compiled_doc\n"
- tmp_path.joinpath("pytask.ini").write_text(config)
-
result = runner.invoke(cli, [tmp_path.as_posix()])
- assert result.exit_code == 0
- assert tmp_path.joinpath("document.pdf").exists()
+ assert result.exit_code == ExitCode.COLLECTION_FAILED
+ assert "The old syntax for @pytask.mark.latex" in result.output
+
+
+@needs_latexmk
+@skip_on_github_actions_with_win
+@pytest.mark.end_to_end
+def test_compile_latex_document(runner, tmp_path):
+ """Test simple compilation."""
+ task_source = """
+ import pytask
+
+ @pytask.mark.latex(script="document.tex", document="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 was tired of my lady
+ \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 == ExitCode.OK
@needs_latexmk
@@ -107,9 +93,10 @@ def test_compile_latex_document_w_relative(runner, tmp_path):
task_source = f"""
import pytask
- @pytask.mark.latex
- @pytask.mark.depends_on("document.tex")
- @pytask.mark.produces("{tmp_path.joinpath("bld", "document.pdf").as_posix()}")
+ @pytask.mark.latex(
+ script="document.tex",
+ document="{tmp_path.joinpath("bld", "document.pdf").as_posix()}"
+ )
def task_compile_document():
pass
@@ -127,9 +114,7 @@ def task_compile_document():
tmp_path.joinpath("src", "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("bld", "document.pdf").exists()
+ assert result.exit_code == ExitCode.OK
@needs_latexmk
@@ -140,9 +125,7 @@ def test_compile_latex_document_to_different_name(runner, tmp_path):
task_source = """
import pytask
- @pytask.mark.latex
- @pytask.mark.depends_on("in.tex")
- @pytask.mark.produces("out.pdf")
+ @pytask.mark.latex(script="in.tex", document="out.pdf")
def task_compile_document():
pass
@@ -158,25 +141,21 @@ def task_compile_document():
tmp_path.joinpath("in.tex").write_text(textwrap.dedent(latex_source))
result = runner.invoke(cli, [tmp_path.as_posix()])
-
- assert result.exit_code == 0
- assert tmp_path.joinpath("out.pdf").exists()
+ assert result.exit_code == ExitCode.OK
@needs_latexmk
@skip_on_github_actions_with_win
@pytest.mark.end_to_end
-def test_compile_w_bibliography(tmp_path):
+def test_compile_w_bibliography(runner, tmp_path):
"""Compile a LaTeX document with bibliography."""
task_source = """
import pytask
- @pytask.mark.latex
- @pytask.mark.depends_on(["in_w_bib.tex", "references.bib"])
- @pytask.mark.produces("out_w_bib.pdf")
+ @pytask.mark.latex(script="in_w_bib.tex", document="out_w_bib.pdf")
+ @pytask.mark.depends_on("references.bib")
def task_compile_document():
pass
-
"""
tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source))
@@ -201,10 +180,8 @@ def task_compile_document():
"""
tmp_path.joinpath("references.bib").write_text(textwrap.dedent(bib_source))
- session = main({"paths": tmp_path})
-
- assert session.exit_code == 0
- assert tmp_path.joinpath("out_w_bib.pdf").exists()
+ session = runner.invoke(cli, [tmp_path.as_posix()])
+ assert session.exit_code == ExitCode.OK
@needs_latexmk
@@ -214,12 +191,9 @@ def test_raise_error_if_latexmk_is_not_found(tmp_path, monkeypatch):
task_source = """
import pytask
- @pytask.mark.latex
- @pytask.mark.depends_on("document.tex")
- @pytask.mark.produces("document.pdf")
+ @pytask.mark.latex(script="document.tex", document="document.pdf")
def task_compile_document():
pass
-
"""
tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source))
@@ -239,7 +213,7 @@ def task_compile_document():
session = main({"paths": tmp_path})
- assert session.exit_code == 1
+ assert session.exit_code == ExitCode.FAILED
assert isinstance(session.execution_reports[0].exc_info[1], RuntimeError)
@@ -252,12 +226,12 @@ def test_compile_latex_document_w_xelatex(runner, tmp_path):
from pytask_latex import compilation_steps
@pytask.mark.latex(
+ script="document.tex",
+ document="document.pdf",
compilation_steps=compilation_steps.latexmk(
["--xelatex", "--interaction=nonstopmode", "--synctex=1", "--cd"]
)
)
- @pytask.mark.depends_on("document.tex")
- @pytask.mark.produces("document.pdf")
def task_compile_document():
pass
@@ -274,7 +248,7 @@ def task_compile_document():
result = runner.invoke(cli, [tmp_path.as_posix()])
- assert result.exit_code == 0
+ assert result.exit_code == ExitCode.OK
assert tmp_path.joinpath("document.pdf").exists()
@@ -285,12 +259,10 @@ def test_compile_latex_document_w_two_dependencies(runner, tmp_path):
task_source = """
import pytask
- @pytask.mark.latex
- @pytask.mark.depends_on(["document.tex", "in.txt"])
- @pytask.mark.produces("document.pdf")
+ @pytask.mark.latex(script="document.tex", document="document.pdf")
+ @pytask.mark.depends_on("in.txt")
def task_compile_document():
pass
-
"""
tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source))
@@ -301,28 +273,24 @@ def task_compile_document():
\end{document}
"""
tmp_path.joinpath("document.tex").write_text(textwrap.dedent(latex_source))
-
tmp_path.joinpath("in.txt").touch()
result = runner.invoke(cli, [tmp_path.as_posix()])
-
- assert result.exit_code == 0
+ assert result.exit_code == ExitCode.OK
assert tmp_path.joinpath("document.pdf").exists()
@needs_latexmk
@skip_on_github_actions_with_win
@pytest.mark.end_to_end
-def test_fail_because_latex_document_is_not_first_dependency(tmp_path):
+def test_fail_because_script_is_not_latex(tmp_path):
task_source = """
import pytask
- @pytask.mark.latex
- @pytask.mark.depends_on(["in.txt", "document.tex"])
- @pytask.mark.produces("document.pdf")
+ @pytask.mark.latex(script="document.text", document="document.pdf")
+ @pytask.mark.depends_on("in.txt")
def task_compile_document():
pass
-
"""
tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source))
@@ -333,12 +301,10 @@ def task_compile_document():
\end{document}
"""
tmp_path.joinpath("document.tex").write_text(textwrap.dedent(latex_source))
-
tmp_path.joinpath("in.txt").touch()
session = main({"paths": tmp_path})
-
- assert session.exit_code == 3
+ assert session.exit_code == ExitCode.COLLECTION_FAILED
assert isinstance(session.collection_reports[0].exc_info[1], ValueError)
@@ -359,12 +325,10 @@ def test_compile_document_to_out_if_document_has_relative_resources(tmp_path):
task_source = """
import pytask
- @pytask.mark.latex
- @pytask.mark.depends_on(["document.tex", "resources/content.tex"])
- @pytask.mark.produces("out/document.pdf")
+ @pytask.mark.latex(script="document.tex", document="out/document.pdf")
+ @pytask.mark.depends_on("resources/content.tex")
def task_compile_document():
pass
-
"""
tmp_path.joinpath("sub", "task_dummy.py").write_text(textwrap.dedent(task_source))
@@ -383,8 +347,7 @@ def task_compile_document():
tmp_path.joinpath("sub", "resources", "content.tex").write_text(resources)
session = main({"paths": tmp_path})
-
- assert session.exit_code == 0
+ assert session.exit_code == ExitCode.OK
assert len(session.tasks) == 1
@@ -399,9 +362,11 @@ def test_compile_document_w_wrong_flag(tmp_path):
import pytask
from pytask_latex import compilation_steps
- @pytask.mark.latex(compilation_steps=compilation_steps.latexmk("--wrong-flag"))
- @pytask.mark.depends_on("document.tex")
- @pytask.mark.produces("out/document.pdf")
+ @pytask.mark.latex(
+ script="document.tex",
+ document="out/document.pdf",
+ compilation_steps=compilation_steps.latexmk("--wrong-flag"),
+ )
def task_compile_document():
pass
@@ -417,8 +382,7 @@ def task_compile_document():
tmp_path.joinpath("sub", "document.tex").write_text(textwrap.dedent(latex_source))
session = main({"paths": tmp_path})
-
- assert session.exit_code == 1
+ assert session.exit_code == ExitCode.FAILED
assert len(session.tasks) == 1
assert isinstance(session.execution_reports[0].exc_info[1], RuntimeError)
@@ -437,12 +401,9 @@ def task_create_image():
"{tmp_path.joinpath("image.png").as_posix()}"
)
- @pytask.mark.latex
- @pytask.mark.depends_on("document.tex")
- @pytask.mark.produces("document.pdf")
+ @pytask.mark.latex(script="document.tex", document="document.pdf")
def task_compile_document():
pass
-
"""
tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source))
@@ -456,5 +417,170 @@ def task_compile_document():
tmp_path.joinpath("document.tex").write_text(textwrap.dedent(latex_source))
result = runner.invoke(cli, [tmp_path.as_posix()])
+ assert result.exit_code == ExitCode.OK
+
+
+@needs_latexmk
+@skip_on_github_actions_with_win
+@pytest.mark.end_to_end
+def test_compile_latex_document_w_multiple_marks(runner, tmp_path):
+ """Test simple compilation."""
+ task_source = """
+ import pytask
+
+ @pytask.mark.latex(script="document.text")
+ @pytask.mark.latex(script="document.tex", document="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 was tired of my lady
+ \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 == ExitCode.COLLECTION_FAILED
+ assert "has multiple @pytask.mark.latex marks" in result.output
+
- assert result.exit_code == 0
+@needs_latexmk
+@skip_on_github_actions_with_win
+@pytest.mark.end_to_end
+def test_compile_latex_document_with_wrong_extension(runner, tmp_path):
+ """Test simple compilation."""
+ task_source = """
+ import pytask
+
+ @pytask.mark.latex(script="document.tex", document="document.file")
+ 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 was tired of my lady
+ \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 == ExitCode.COLLECTION_FAILED
+ assert "The 'document' keyword of the" in result.output
+
+
+@needs_latexmk
+@skip_on_github_actions_with_win
+@pytest.mark.end_to_end
+def test_compile_w_bibliography_and_keep_bbl(runner, tmp_path):
+ """Compile a LaTeX document with bibliography."""
+ task_source = """
+ import pytask
+
+ @pytask.mark.produces("out_w_bib.bbl")
+ @pytask.mark.latex(
+ script="in_w_bib.tex",
+ document="out_w_bib.pdf",
+ )
+ @pytask.mark.depends_on("references.bib")
+ def task_compile_document():
+ pass
+ """
+ tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source))
+
+ latex_source = r"""
+ \documentclass{report}
+ \usepackage{natbib}
+ \begin{document}
+ \cite{pytask}
+ \bibliographystyle{plain}
+ \bibliography{references}
+ \end{document}
+ """
+ tmp_path.joinpath("in_w_bib.tex").write_text(textwrap.dedent(latex_source))
+
+ bib_source = r"""
+ @Article{pytask,
+ author = {Tobias Raabe},
+ title = {pytask},
+ journal = {Unpublished},
+ year = {2020},
+ }
+ """
+ tmp_path.joinpath("references.bib").write_text(textwrap.dedent(bib_source))
+
+ session = runner.invoke(cli, [tmp_path.as_posix()])
+ assert session.exit_code == ExitCode.OK
+
+
+@needs_latexmk
+@skip_on_github_actions_with_win
+@pytest.mark.end_to_end
+@pytest.mark.parametrize(
+ "step, message",
+ [
+ ("'unknown'", "Compilation step 'unknown' is unknown."),
+ (1, "Compilation step 1 is not a valid step."),
+ ],
+)
+def test_compile_latex_document_w_unknown_compilation_step(
+ runner, tmp_path, step, message
+):
+ """Test simple compilation."""
+ task_source = f"""
+ import pytask
+
+ @pytask.mark.latex(
+ script="document.tex",
+ document="document.pdf",
+ compilation_steps={step},
+ )
+ 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 was tired of my lady
+ \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 == ExitCode.COLLECTION_FAILED
+ assert message in result.output
+
+
+@needs_latexmk
+@skip_on_github_actions_with_win
+@pytest.mark.end_to_end
+def test_compile_latex_document_with_task_decorator(runner, tmp_path):
+ """Test simple compilation."""
+ task_source = """
+ import pytask
+
+ @pytask.mark.latex(script="document.tex", document="document.pdf")
+ @pytask.mark.task
+ def compile_document():
+ pass
+ """
+ tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source))
+
+ latex_source = r"""
+ \documentclass{report}
+ \begin{document}
+ I was tired of my lady
+ \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 == ExitCode.OK
diff --git a/tests/test_latex_dependency_scanner.py b/tests/test_latex_dependency_scanner.py
index 760389e..0c33aaf 100644
--- a/tests/test_latex_dependency_scanner.py
+++ b/tests/test_latex_dependency_scanner.py
@@ -5,22 +5,21 @@
import pytest
from conftest import needs_latexmk
from conftest import skip_on_github_actions_with_win
+from pytask import ExitCode
from pytask import main
@needs_latexmk
@skip_on_github_actions_with_win
@pytest.mark.end_to_end
-def test_infer_dependencies_from_task(tmp_path):
+@pytest.mark.parametrize("infer_dependencies", [True, False])
+def test_infer_dependencies_from_task(tmp_path, infer_dependencies):
task_source = """
import pytask
- @pytask.mark.latex
- @pytask.mark.depends_on("document.tex")
- @pytask.mark.produces("document.pdf")
+ @pytask.mark.latex(script="document.tex", document="document.pdf")
def task_compile_document():
pass
-
"""
tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source))
@@ -33,8 +32,14 @@ def task_compile_document():
tmp_path.joinpath("document.tex").write_text(textwrap.dedent(latex_source))
tmp_path.joinpath("sub_document.tex").write_text("Lorem ipsum.")
- session = main({"paths": tmp_path})
+ tmp_path.joinpath("pytask.ini").write_text(
+ f"[pytask]\ninfer_latex_dependencies = {infer_dependencies}"
+ )
- assert session.exit_code == 0
+ session = main({"paths": tmp_path})
+ assert session.exit_code == ExitCode.OK
assert len(session.tasks) == 1
- assert len(session.tasks[0].depends_on) == 2
+ if infer_dependencies:
+ assert len(session.tasks[0].depends_on) == 2
+ else:
+ assert len(session.tasks[0].depends_on) == 1
diff --git a/tests/test_normal_execution_w_plugin.py b/tests/test_normal_execution_w_plugin.py
index ee19252..4a810eb 100644
--- a/tests/test_normal_execution_w_plugin.py
+++ b/tests/test_normal_execution_w_plugin.py
@@ -5,6 +5,7 @@
import pytest
from pytask import cli
+from pytask import ExitCode
@pytest.mark.end_to_end
@@ -35,4 +36,4 @@ def task_dummy(depends_on, produces):
tmp_path.joinpath(dependency).touch()
result = runner.invoke(cli, [tmp_path.as_posix()])
- assert result.exit_code == 0
+ assert result.exit_code == ExitCode.OK
diff --git a/tests/test_parallel.py b/tests/test_parallel.py
index 60f7a5d..3162d53 100644
--- a/tests/test_parallel.py
+++ b/tests/test_parallel.py
@@ -9,10 +9,12 @@
from conftest import needs_latexmk
from conftest import skip_on_github_actions_with_win
from pytask import cli
+from pytask import ExitCode
+
try:
import pytask_parallel # noqa: F401
-except ImportError:
+except ImportError: # pragma: no cover
_IS_PYTASK_PARALLEL_INSTALLED = False
else:
_IS_PYTASK_PARALLEL_INSTALLED = True
@@ -31,14 +33,16 @@
@needs_latexmk
@skip_on_github_actions_with_win
@pytest.mark.end_to_end
-def test_parallel_parametrization_over_source_files(runner, tmp_path):
+def test_parallel_parametrization_over_source_files_w_parametrize(runner, tmp_path):
source = """
import pytask
- @pytask.mark.latex
@pytask.mark.parametrize(
- "depends_on, produces",
- [("document_1.tex", "document_1.pdf"), ("document_2.tex", "document_2.pdf")],
+ "latex",
+ [
+ {"script": "document_1.tex", "document": "document_1.pdf"},
+ {"script": "document_2.tex", "document": "document_2.pdf"}
+ ],
)
def task_compile_latex_document():
pass
@@ -64,7 +68,58 @@ def task_compile_latex_document():
start = time.time()
result = runner.invoke(cli, [tmp_path.as_posix()])
- assert result.exit_code == 0
+ assert result.exit_code == ExitCode.OK
+ duration_normal = time.time() - start
+
+ for name in ["document_1.pdf", "document_2.pdf"]:
+ tmp_path.joinpath(name).unlink()
+
+ start = time.time()
+ result = runner.invoke(cli, [tmp_path.as_posix(), "-n", 2])
+
+ assert result.exit_code == ExitCode.OK
+ duration_parallel = time.time() - start
+
+ assert duration_parallel < duration_normal
+
+
+@xfail_on_remote
+@needs_latexmk
+@skip_on_github_actions_with_win
+@pytest.mark.end_to_end
+def test_parallel_parametrization_over_source_files_w_loop(runner, tmp_path):
+ source = """
+ import pytask
+
+ for i in range(1, 3):
+
+ @pytask.mark.task
+ @pytask.mark.latex(script=f"document_{i}.tex", document=f"document_{i}.pdf")
+ def task_compile_latex_document():
+ pass
+ """
+ tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(source))
+
+ latex_source = r"""
+ \documentclass{report}
+ \begin{document}
+ He said yeah.
+ \end{document}
+ """
+ tmp_path.joinpath("document_1.tex").write_text(textwrap.dedent(latex_source))
+
+ latex_source = r"""
+ \documentclass{report}
+ \begin{document}
+ You better come out with your hands up.
+ \end{document}
+ """
+ tmp_path.joinpath("document_2.tex").write_text(textwrap.dedent(latex_source))
+
+ start = time.time()
+ result = runner.invoke(cli, [tmp_path.as_posix()])
+
+ assert result.exit_code == ExitCode.OK
duration_normal = time.time() - start
for name in ["document_1.pdf", "document_2.pdf"]:
@@ -73,7 +128,7 @@ def task_compile_latex_document():
start = time.time()
result = runner.invoke(cli, [tmp_path.as_posix(), "-n", 2])
- assert result.exit_code == 0
+ assert result.exit_code == ExitCode.OK
duration_parallel = time.time() - start
assert duration_parallel < duration_normal
@@ -83,28 +138,29 @@ def task_compile_latex_document():
@needs_latexmk
@skip_on_github_actions_with_win
@pytest.mark.end_to_end
-def test_parallel_parametrization_over_source_file(runner, tmp_path):
+def test_parallel_parametrization_over_source_file_w_parametrize(runner, tmp_path):
source = """
import pytask
- from pytask_latex import compilation_steps
+ from pytask_latex import compilation_steps as cs
- @pytask.mark.depends_on("document.tex")
@pytask.mark.parametrize(
- "produces, latex",
+ "latex",
[
- (
- "document.pdf",
- {"compilation_steps": compilation_steps.latexmk(
+ {
+ "script": "document.tex",
+ "document": "document.pdf",
+ "compilation_steps": cs.latexmk(
("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd")
- )}
- ),
- (
- "document.dvi",
- {"compilation_steps": compilation_steps.latexmk(
+ ),
+ },
+ {
+ "script": "document.tex",
+ "document": "document.dvi",
+ "compilation_steps": cs.latexmk(
("--dvi", "--interaction=nonstopmode", "--synctex=1", "--cd")
- )}
- ),
- ],
+ ),
+ }
+ ]
)
def task_compile_latex_document():
pass
@@ -122,7 +178,57 @@ def task_compile_latex_document():
start = time.time()
result = runner.invoke(cli, [tmp_path.as_posix()])
- assert result.exit_code == 0
+ assert result.exit_code == ExitCode.OK
+ 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 == ExitCode.OK
+ duration_parallel = time.time() - start
+
+ assert duration_parallel < duration_normal
+
+
+@xfail_on_remote
+@needs_latexmk
+@skip_on_github_actions_with_win
+@pytest.mark.end_to_end
+def test_parallel_parametrization_over_source_file_w_loop(runner, tmp_path):
+ source = """
+ import pytask
+ from pytask_latex import compilation_steps as cs
+
+ for ending in ("pdf", "dvi"):
+
+ @pytask.mark.task
+ @pytask.mark.latex(
+ script="document.tex",
+ document=f"document.{ending}",
+ compilation_steps=cs.latexmk(
+ (f"--{ending}", "--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 == ExitCode.OK
duration_normal = time.time() - start
for name in ["document.pdf", "document.dvi"]:
@@ -131,7 +237,7 @@ def task_compile_latex_document():
start = time.time()
result = runner.invoke(cli, [tmp_path.as_posix(), "-n", 2])
- assert result.exit_code == 0
+ assert result.exit_code == ExitCode.OK
duration_parallel = time.time() - start
assert duration_parallel < duration_normal
diff --git a/tests/test_parametrize.py b/tests/test_parametrize.py
index 153c60e..6209986 100644
--- a/tests/test_parametrize.py
+++ b/tests/test_parametrize.py
@@ -5,48 +5,60 @@
import pytest
from conftest import needs_latexmk
from conftest import skip_on_github_actions_with_win
+from pytask import ExitCode
from pytask import main
-from pytask_latex.parametrize import pytask_parametrize_kwarg_to_marker
-def func():
- pass
+@needs_latexmk
+@skip_on_github_actions_with_win
+@pytest.mark.end_to_end
+def test_parametrized_compilation_of_latex_documents_w_parametrize(tmp_path):
+ task_source = """
+ import pytask
+ @pytask.mark.parametrize("latex", [
+ {"script": "document_1.tex", "document": "document_1.pdf"},
+ {"script": "document_2.tex", "document": "document_2.pdf"},
+ ])
+ def task_compile_latex_document():
+ pass
+ """
+ tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source))
-@pytest.mark.unit
-@pytest.mark.parametrize(
- "obj, kwargs, expected",
- [(len, {}, None), (func, {"latex": ["--dummy-option"]}, func), (func, {}, None)],
-)
-def test_pytask_generate_tasks_add_marker(obj, kwargs, expected):
- pytask_parametrize_kwarg_to_marker(obj, kwargs)
+ for name, content in [
+ ("document_1.tex", "Like a worn out recording"),
+ ("document_2.tex", "Of a favorite song"),
+ ]:
+ latex_source = rf"""
+ \documentclass{{report}}
+ \begin{{document}}
+ {content}
+ \end{{document}}
+ """
+ tmp_path.joinpath(name).write_text(textwrap.dedent(latex_source))
- if expected is None:
- assert not hasattr(obj, "pytaskmark")
- else:
- assert obj.pytaskmark
+ session = main({"paths": tmp_path})
- # Cleanup necessary since func is changed in-place.
- if hasattr(obj, "pytaskmark"):
- delattr(obj, "pytaskmark")
+ assert session.exit_code == ExitCode.OK
+ assert tmp_path.joinpath("document_1.pdf").exists()
+ assert tmp_path.joinpath("document_2.pdf").exists()
@needs_latexmk
@skip_on_github_actions_with_win
@pytest.mark.end_to_end
-def test_parametrized_compilation_of_latex_documents(tmp_path):
- task_source = """
+def test_parametrized_compilation_of_latex_documents_w_loop(tmp_path):
+ source = """
import pytask
- @pytask.mark.latex
- @pytask.mark.parametrize("depends_on, produces", [
- ("document_1.tex", "document_1.pdf"),
- ("document_2.tex", "document_2.pdf"),
- ])
- def task_compile_latex_document():
- pass
+ for i in range(1, 3):
+
+ @pytask.mark.task
+ @pytask.mark.latex(script=f"document_{i}.tex", document=f"document_{i}.pdf")
+ def task_compile_latex_document():
+ pass
"""
- tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(task_source))
+ tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(source))
for name, content in [
("document_1.tex", "Like a worn out recording"),
@@ -62,7 +74,7 @@ def task_compile_latex_document():
session = main({"paths": tmp_path})
- assert session.exit_code == 0
+ assert session.exit_code == ExitCode.OK
assert tmp_path.joinpath("document_1.pdf").exists()
assert tmp_path.joinpath("document_2.pdf").exists()
@@ -70,27 +82,30 @@ def task_compile_latex_document():
@needs_latexmk
@skip_on_github_actions_with_win
@pytest.mark.end_to_end
-def test_parametrizing_latex_options(tmp_path):
+def test_parametrizing_latex_options_w_parametrize(tmp_path):
task_source = """
import pytask
- from pytask_latex import compilation_steps
-
- @pytask.mark.parametrize("depends_on, produces, latex", [
- (
- "document.tex",
- "document.pdf",
- {"compilation_steps": compilation_steps.latexmk(
- ("--interaction=nonstopmode", "--pdf", "--cd"))
+ from pytask_latex import compilation_steps as cs
+
+ @pytask.mark.parametrize(
+ "latex",
+ [
+ {
+ "script": "document.tex",
+ "document": "document.pdf",
+ "compilation_steps": cs.latexmk(
+ ("--pdf", "--interaction=nonstopmode", "--synctex=1", "--cd")
+ ),
+ },
+ {
+ "script": "document.tex",
+ "document": "document.dvi",
+ "compilation_steps": cs.latexmk(
+ ("--dvi", "--interaction=nonstopmode", "--synctex=1", "--cd")
+ ),
}
- ),
- (
- "document.tex",
- "document.dvi",
- {"compilation_steps": compilation_steps.latexmk(
- ("--interaction=nonstopmode", "--dvi", "--cd"))
- }
- ),
- ])
+ ]
+ )
def task_compile_latex_document():
pass
"""
@@ -106,6 +121,44 @@ def task_compile_latex_document():
session = main({"paths": tmp_path})
- assert session.exit_code == 0
+ assert session.exit_code == ExitCode.OK
+ 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_w_loop(tmp_path):
+ source = """
+ import pytask
+ from pytask_latex import compilation_steps as cs
+
+ for ending in ("pdf", "dvi"):
+
+ @pytask.mark.task
+ @pytask.mark.latex(
+ script="document.tex",
+ document=f"document.{ending}",
+ compilation_steps=cs.latexmk(
+ (f"--{ending}", "--interaction=nonstopmode", "--synctex=1", "--cd")
+ )
+ )
+ def compile_latex_document():
+ pass
+ """
+ tmp_path.joinpath("task_dummy.py").write_text(textwrap.dedent(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 == ExitCode.OK
assert tmp_path.joinpath("document.pdf").exists()
assert tmp_path.joinpath("document.dvi").exists()
diff --git a/tox.ini b/tox.ini
index 178e860..a2f750d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -4,13 +4,13 @@ skipsdist = True
skip_missing_interpreters = True
[testenv]
-passenv = CI GITHUB_ACTIONS
+passenv = CI
basepython = python
[testenv:pytest]
conda_deps =
- pytask >=0.1.0
- pytask-parallel >=0.1.0
+ pytask >=0.2
+ pytask-parallel >=0.1
latex-dependency-scanner
pytest
pytest-cov
@@ -22,10 +22,6 @@ commands =
pip install -e . --no-deps
pytest {posargs}
-[doc8]
-ignore = D002, D004
-max-line-length = 89
-
[flake8]
docstring-convention = numpy
ignore =