Contributing to rst2pdf
#######################

This project is actively maintained and contributions from developers of all levels are very, very welcome. We recommend opening an issue before starting work on anything big so that we can discuss with you any details that might be relevant - but an issue is not required. Changes are welcome however they arrive :)

Start by making sure the project is running from source - instructions in the ``README`` for setting up local project.

Code of Conduct
===============

rst2pdf is an inclusive and welcoming community. To participate in this project, everyone is bound by our `Community Code of Conduct`__.

__ CODE_OF_CONDUCT.rst

Open an Issue
=============

Issues are always welcome here! Please give as much detail as you can; small replication cases showing what doesn't work help us a lot - bonus points if you can turn that into a test! (more on testing later)

Documentation Changes
=====================

Documentation fixes are *at least* as valuable as code ones. The manual is in the file `doc/manual.rst` and gets converted to both PDF and HTML for https://rst2pdf.org. Please go ahead and open a pull request for each of the changes you think we need.

Open a Pull Request
===================

We love pull requests!

Please open a pull request if you have changes/fixes/improvements to share. This project is for all of us and we welcome changes. Your PR should include:

* A detailed description of what is being changed and importantly *why*.
* Tests to cover the new feature, including reference PDFs.
* An update to the manual if needed.

Please be patient with us, we are all volunteers with busy lives.

Project Structure
=================

The code for the project is in ``rst2pdf`` inside the main project directory.

Tests are in ``tests`` directory. Within this folder:

* ``input`` holds the instructions for running a test.

  - ``[name].rst`` holds the rst source for the test
  - ``[name].style`` has any stylesheet that should be applied for this test
  - ``[name].cli`` allows adding extra commands to the test (look for examples)
  - ``[name].depends`` allows specifying dependencies for the test, so that in
    case they aren't met, the test is skipped. Each dependency should be added
    in a separate line. To add a new one, first add it in the
    ``check_dependency`` list inside ``conftest.py``.
  - ``test_[name].retcode`` allows for specifying an expected non-zero return code for expected error cases
  - ``test_[name].nopdf`` is a text file whose existence indicates that the test does not create a PDF output file
  - ``test_[name].expected_log`` allow for specifying expected text within the log output. If this file exists, then
    the existence of ``test_[name].nopdf`` implies that any generated PDF file is to be ignored.

* ``output`` holds the PDFs that were generated by the tests running.

* ``reference`` holds the "correct" version of the PDF for this test. When adding a test, put the desired PDF output into this file as well as supplying the tests in the ``input`` folder.

Run Checks Locally
==================

When you open a pull request, we run some automated checks to make sure everything is in order. We recommend you
install these tools locally to check things over as you go along. We use the `pre-commit`__ framework, which you can
install with ``uv``::

    uv tool install pre-commit

Once installed, enable it by running this command::

    pre-commit install --allow-missing-config

.. __: https://pre-commit.com/

It will let you know if any of the formatting/build tools are reporting problems when you commit your changes.

To run the pre-commit checks manually, run this command::

    pre-commit run --all-files --show-diff-on-failure

Run the Tests
=============

Please run the tests :) They also run automatically along with some style checking when you open or update a pull request. The first run of the tests needs some setup so check out the steps below.

Context
*******

The *rst2pdf* test suite generates PDFs - stored in ``tests/output`` -
which are then compared against reference PDFs - stored in
``tests/reference`` - using the `PyMuPDF`__ Python bindings for the
`MuPDF`__ library. *rst2pdf* depends on a number of different tools and
libraries, such as `ReportLab`__, and the output of these can vary slightly
between releases. The *PyMuPDF* library allows us to compare the structure
of the PDFs, with a minor amount of fuzzing to allow for minor differences
caused by these changes in underlying dependencies.

.. __: https://pymupdf.readthedocs.io/en/latest/
.. __: https://mupdf.com/
.. __: https://www.reportlab.com/

Set up to run tests
*******************

To run the tests for the first time, you will need to do some setup (after
this, any ``uv`` commands will automatically work within the right virtual
environment)::

    uv sync --all-extras

If you don't have ``uv``, please see `the installation docs <https://docs.astral.sh/uv/getting-started/installation/>`_

Run tests
*********

To run all tests, run::

    uv run pytest

You can also run tests in parallel by passing the ``-n auto`` flag::

    uv run pytest -n auto

Running a single test
*********************

To run one test only, pass the file or directory to pytest. For example::

    uv run pytest tests/input/sphinx-repeat-table-rows

This will run one test and show the output.

Skipping tests
**************

To skip a test, create a text file in the ``tests/input`` directory
called ``[test].ignore`` containing a note on why the test is skipped. This
will mark the test as skipped when the test suite runs. This could be useful
for inherited tests that we aren't confident of the correct output for, but
where we don't want to delete/lose the test entirely.

Updating dependencies
*********************

The specific versions of all dependencies that are used for CI testing are stored in ``uv.lock``.

To upgrade all dependencies to their latest versions (while satisfying any constraints in ``pyproject.toml``), run::

    uv lock --upgrade

To update an existing dependency, e.g., to add a lower bound to the reportlab version::

    uv add 'reportlab>4.0.0'

Tips and Tricks
===============

Git config
**********

After the mass-reformatting in PR 877, it is helpful to ignore the relevant
commits that simply reformatted the code when using git blame.

The ``.git-blame-ignore-revs`` file contains the list of commits to ignore and
you can use this git config line to make ``git blame`` work more usefully::

    git config blame.ignoreRevsFile .git-blame-ignore-revs
