pytest-reporter
pytest-reporter is a Pytest plugin that enables the generation of highly customizable test reports using templates. It provides the data context from a Pytest session, allowing users to create various text-based reports like HTML, LaTeX, or CSV by implementing their own rendering logic. The library is actively maintained with a regular release cadence, often addressing compatibility with new `pytest` versions and enhancing report data.
Common errors
-
jinja2.exceptions.TemplateNotFound: my_report.html
cause The template file specified with `--template` was not found in the directories provided by `--template-dir` (or implied by default).fixVerify that the `--template-dir` argument points to the correct directory containing your template, and that the `--template` argument specifies the correct filename within that directory. E.g., `pytest --template-dir=templates --template=my_report.html ...`. -
TypeError: unhashable type: 'dict'
cause This typically occurs within the template rendering logic (e.g., Jinja2) when attempting to use a dictionary as a key in a set or other context where hashable types are required. This can happen with complex custom template filters or logic manipulating context objects.fixInspect the template and any custom filters or Python code invoked by the template for operations that attempt to hash a dictionary. Ensure that dictionary keys are strings or other hashable types. -
KeyError: 'call' during template rendering
cause A template attempted to access `test.phases[].call` when `pytest-xdist` was in use, and for that specific phase, the `call` information was not available.fixModify the template to conditionally check for the existence of `call` before accessing it, like `{% if phase.call %}{{ phase.call.duration }}{% endif %}`. -
No report generated / Report file is empty
cause This can happen if the `--report` command-line option is missing, if the `pytest_reporter_render` hook is not implemented correctly, or if the template itself is malformed and fails to render content.fixEnsure `--report=<output_path>` is specified. Confirm your `pytest_reporter_render` hook in `conftest.py` returns the rendered content. Check the template for syntax errors or issues that prevent it from producing output.
Warnings
- breaking The `function_context` fixture was removed in version 0.5.0. Any custom template or plugin relying on this fixture will break.
- breaking The internal `pytest_warning_captured` hook was replaced by `pytest_warning_recorded` in version 0.5.0. Plugins implementing the older hook will cease to function correctly.
- gotcha The plugin provides data to templates but does not include a rendering engine (like Jinja2) by default. Users must implement the `pytest_reporter_render` hook in `conftest.py` and provide their own template engine integration.
- gotcha When using `pytest-xdist` for parallel execution, the `tests[].phases[].call` item within the template context may be optional or absent for some phases. Accessing it without a check can lead to `KeyError`.
- breaking Version 0.5.3 replaced the use of `pkg_resources`. While this was a fix, environments or custom extensions that implicitly relied on `pytest-reporter`'s previous `pkg_resources` usage might encounter compatibility issues.
Install
-
pip install pytest-reporter
Imports
- Environment, FileSystemLoader, TemplateNotFound
from jinja2 import Environment, FileSystemLoader, TemplateNotFound
Quickstart
# File: conftest.py
from jinja2 import Environment, FileSystemLoader, TemplateNotFound
def pytest_reporter_render(template_name, dirs, context):
"""This hook is called to render a report template."""
env = Environment(loader=FileSystemLoader(dirs))
try:
template = env.get_template(template_name)
except TemplateNotFound:
# Let other template plugins handle it if not found here
return None
return template.render(context)
# File: templates/my_report.html
<!-- Example Jinja2 template -->
<!DOCTYPE html>
<html>
<head><title>Pytest Report</title></head>
<body>
<h1>Test Report</h1>
<p>Started: {{ started|strftime('%Y-%m-%d %H:%M:%S') }}</p>
<p>Total tests: {{ tests|length }}</p>
<ul>
{% for test in tests %}
<li>{{ test.item.nodeid }} - Status: {{ test.status.word }}
{% if test.phases %}
<ul>
{% for phase in test.phases %}
<li>Phase: {{ phase.name }} - Status: {{ phase.status.word }}</li>
{% endfor %}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
</body>
</html>
# File: test_example.py
def test_success():
assert True
def test_failure():
assert False
# To run and generate report (from project root):
# pytest --template-dir=templates --template=my_report.html --report=report.html