1

I have a function that takes a directory of images, reads them, and stores them in a list.

When pytesting a basic example of reading 3 images, I can't pass the test because the images have an allocation in memory data that makes the assertion to fail.

import os
from PIL import Image

def getImages(imageDir):
    files = os.listdir(imageDir)
    images = []
    for file in files:
        # Getting the full image name
        filePath = os.path.abspath(os.path.join(imageDir, file))
        try:
            # explicit load to prevent resources crunch
            fp = open(filePath, "rb")
            im = Image.open(fp)
            images.append(im)
            # force loading the image data from file
            im.load()
            # close the file
            fp.close()
        except Exception:
            # skip
            print("Invalid image: %s" % (filePath,))
    return images


def test_for_clean_data():
    assert getImages("test_images") == [Image.open("test_images/01.jpg"),
                                        Image.open("test_images/02.jpg"),
                                        Image.open("test_images/03.jpg")]

<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=2448x2765 at 0x1E48F5872C8> <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=2448x2765 at 0x1E48F5878C8>

As shown in the example error provided by the console, same image will have different properties when tested.

Function to test is PIL.Image based.

Perhaps, as someone suggested the test is flawed in its origin. If anyone knows a better way to pytest that the function is properly working, I would be more than happy to try a new idea. There's so much to learn.

Suggestions for correct test naming are also welcome.

Pablo Lazo
  • 11
  • 3
  • It would help to see the code you're testing. – larsks Jan 08 '21 at 14:59
  • Is this really about Pytest or how to test two PIL Images for equality? However, for me, when opening the same image twice, they are `==`. Maybe the images are just opened in a different order? Also, images are `!=` if they are the same file but opened from a different directory (i.e. different relative path). – tobias_k Jan 08 '21 at 15:08
  • The problem is not your function or the list, but your assumption about how the equality of two values returned by `Image.open` is defined. – chepner Jan 08 '21 at 16:18
  • as you point out @chepner, this might be indeed the problem. Any idea about how could I test that the function is properly reading and creating the list other than the assertion I already did? I'm kinda new to this matters so there's a lot to learn. – Pablo Lazo Jan 08 '21 at 19:30
  • @tobias_k this is about me not knowing how to test the result of the function (list of image objects) vs a handmade list of the same objects. So this is about Pytesting two lists of objects and not about comparing if the two sets of images are the same. – Pablo Lazo Jan 08 '21 at 19:34
  • Image equality is kind of weird. The same images sometimes compare equal and sometimes not, depending on how they were loaded, but in your case they should be equal. My guess is that the order of images in the list is simply different. `os.listdir` does _not_ guarantee that the entries are returned in sorted order! – tobias_k Jan 08 '21 at 23:47
  • @tobias_k from the results of the console I can pretty much tell that images are being read in the same order. – Pablo Lazo Jan 11 '21 at 17:10
  • It seems like the images are not entirely equal if you open them with a file handle (`file`) vs. a file name (`str`). Try using the same method as you use in the method, or compare the images actual content (`tobytes`); comparing the filenames does not work, as the images loaded with a file handle to not have a file name. – tobias_k Jan 11 '21 at 18:22

1 Answers1

0

Eyeballing the code, it looks like one potential reason your objects differ is that you call im.load() in getImages(), but not when you open your test images. Does this work? This is just a quick guess, I haven't tested it.

    assert getImages("test_images") == [Image.open("test_images/01.jpg").load(),
                                        Image.open("test_images/02.jpg").load(),
                                        Image.open("test_images/03.jpg").load()]
Jim J
  • 546
  • 3
  • 11
  • this seems not to be the case. Tested again with your suggestion and got a different message comparing PixelAccess Object at 0x000002D49CFC92F0 vs PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=2448x2765 at 0x1E48F5878C8 – Pablo Lazo Jan 08 '21 at 19:17
  • Shoot, sorry! Maybe this old answer, which uses another PIL function, would unblock you? In this case, the actual images are being directly compared visually, not as Python objects: https://stackoverflow.com/a/56280735/1649666 – Jim J Jan 09 '21 at 18:00
  • @jim_j thanks for your time. What I need to pytest is not if the images are the same but if the function getImages is creating the expected list of images. – Pablo Lazo Jan 11 '21 at 17:14