Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
2.9.0
-----

*UNRELEASED*

* `#218 <https://github.com/ESSS/pytest-regressions/pull/218>`__: ``ImageRegression.check`` now supports receiving an ``PIL.Image`` object directly.

2.8.3
-----

Expand Down
12 changes: 9 additions & 3 deletions src/pytest_regressions/image_regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from typing import Any
from typing import Optional
from typing import TYPE_CHECKING
from typing import Union

import pytest

Expand All @@ -13,6 +14,7 @@

if TYPE_CHECKING:
from pytest_datadir import LazyDataDir
from PIL import Image


class ImageRegressionFixture:
Expand Down Expand Up @@ -140,7 +142,7 @@ def check_result(equal: bool, manhattan_distance: Optional[float]) -> None:

def check(
self,
image_data: bytes,
image_data: Union[bytes, "Image.Image"],
diff_threshold: float = 0.1,
expect_equal: bool = True,
basename: Optional[str] = None,
Expand All @@ -149,7 +151,7 @@ def check(
"""
Checks that the given image contents are comparable with the ones stored in the data directory.

:param image_data: image data
:param image_data: image data bytes which can be read with PIL, or directly a PIL image object.
:param basename: basename to store the information in the data directory. If none, use the name
of the test function.
:param expect_equal: if the image should considered equal below of the given threshold. If False, the
Expand All @@ -170,7 +172,11 @@ def check(
raise ModuleNotFoundError(import_error_message("Pillow"))

def dump_fn(target: Path) -> None:
image = Image.open(io.BytesIO(image_data))
if isinstance(image_data, Image.Image):
image = image_data
else:
image = Image.open(io.BytesIO(image_data))

image.save(str(target), "PNG")

perform_regression_check(
Expand Down
30 changes: 23 additions & 7 deletions tests/test_image_regression.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import io
from functools import partial

import pytest
from PIL import Image

from pytest_regressions.testing import check_regression_fixture_workflow


def test_image_regression(image_regression, lazy_datadir):
@pytest.mark.parametrize("image_type", ["pil", "bytes"])
def test_image_regression(image_regression, lazy_datadir, image_type):
import matplotlib

# this ensures matplot lib does not use a GUI backend (such as Tk)
Expand All @@ -29,19 +33,27 @@ def test_image_regression(image_regression, lazy_datadir):
image_filename = lazy_datadir / "test.png"
fig.savefig(str(image_filename))

image_regression.check(image_filename.read_bytes(), diff_threshold=1.0)
if image_type == "bytes":
image_data = image_filename.read_bytes()
else:
image_data = Image.open(image_filename)
image_regression.check(image_data, diff_threshold=1.0)


def test_image_regression_workflow(pytester, monkeypatch):
@pytest.mark.parametrize("image_type", ["pil", "bytes"])
def test_image_regression_workflow(pytester, monkeypatch, image_type):
import sys

from PIL import Image

def get_image(color):
f = io.BytesIO()
img = Image.new("RGB", (100, 100), color)
img.save(f, "PNG")
return f.getvalue()
if image_type == "pil":
return img
else:
f = io.BytesIO()
img.save(f, "PNG")
return f.getvalue()

monkeypatch.setattr(sys, "get_image", partial(get_image, "white"), raising=False)
source = """
Expand All @@ -54,7 +66,11 @@ def test_1(image_regression):
def get_file_contents():
fn = pytester.path / "test_file" / "test_1.png"
assert fn.is_file()
return fn.read_bytes()
if image_type == "pil":
# Copy is necessary because Image.open returns a ImageFile class
return Image.open(fn).copy()
else:
return fn.read_bytes()

check_regression_fixture_workflow(
pytester,
Expand Down
Loading