Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Packing tests #2694

Merged
merged 12 commits into from
Aug 28, 2017
Merged

Packing tests #2694

merged 12 commits into from
Aug 28, 2017

Conversation

homm
Copy link
Member

@homm homm commented Aug 22, 2017

Decided to implement all and improved tests for packing and unpacking.

Added many missed tests. At the end all possible modes should be covered. Most tests improved, for example with line interleave.

@wiredfool
Copy link
Member

From the bigendian machine:

======================================================================
FAIL: TestLibUnpack.test_F_float
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/erics/Pillow/Tests/test_lib_pack.py", line 318, in test_F_float
    1.539989614439558e-36, 4.063216068939723e-34)
  File "/home/erics/Pillow/Tests/test_lib_pack.py", line 78, in assert_unpack
    self.assertEqual(pixel, im.getpixel((x, 0)))
AssertionError: 1.539989614439558e-36 != 2.387939260590663e-38

======================================================================
FAIL: TestLibUnpack.test_I
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/erics/Pillow/Tests/test_lib_pack.py", line 254, in test_I
    self.assert_unpack("I", "I", 4, 0x04030201, 0x08070605)
  File "/home/erics/Pillow/Tests/test_lib_pack.py", line 78, in assert_unpack
    self.assertEqual(pixel, im.getpixel((x, 0)))
AssertionError: 67305985 != 16909060

======================================================================
FAIL: TestLibUnpack.test_I16
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/erics/Pillow/Tests/test_lib_pack.py", line 347, in test_I16
    self.assert_unpack("I;16", "I;16N", 2, 0x0201, 0x0403, 0x0605)
  File "/home/erics/Pillow/Tests/test_lib_pack.py", line 78, in assert_unpack
    self.assertEqual(pixel, im.getpixel((x, 0)))
AssertionError: 513 != 258

@homm
Copy link
Member Author

homm commented Aug 23, 2017

It's interesting. I've fixed test_I16, it's my fault. The problem with test_F_float and test_I, because in both cases just copy4 is used. So one of the following is correct: rawmode F and I actually means F;32N and I;32N (native) or we should replace copy4 with unpackI32 unpacker.

Could you test the latest commit?

@wiredfool
Copy link
Member

I'm getting this now:

 ======================================================================
FAIL: TestImageArray.test_fromarray
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/erics/Pillow/Tests/test_image_array.py", line 50, in test_fromarray
    self.assertEqual(test("I"), ("I", (128, 100), True))
AssertionError: Tuples differ: ('I', (128, 100), False) != ('I', (128, 100), True)

First differing element 2:
False
True

- ('I', (128, 100), False)
?                   ^^^^

+ ('I', (128, 100), True)
?                   ^^^

There's also an ongoing error that's also in the latest releases:

======================================================================
FAIL: TestImageFile.test_parser
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/erics/Pillow/Tests/test_imagefile.py", line 66, in test_parser
    self.assert_image_similar(im1, im2.convert('L'), 20)
  File "/home/erics/Pillow/Tests/helper.py", line 110, in assert_image_similar
    ave_diff, epsilon))
AssertionError:  average pixel value difference 84.7002 > epsilon 20.0000

@homm
Copy link
Member Author

homm commented Aug 24, 2017

@wiredfool What do you think about this in general?

So one of the following is correct: rawmode F and I actually means F;32N and I;32N (native) or we should replace copy4 with unpackI32 unpacker.

Should be consider F as F;32N and add at least comments, or fix it and continue investigate why tests failed?

@wiredfool
Copy link
Member

I think that for any sort of resampling or image ops, it would be completely goofy to store non-native endian in I or F storage. It has to be native mode.

Historically, the native versions were added for integer modes because of libtiff, which returns multibyte pixels in the native format, so it's just a copy operation to add it to storage. Our tiff implementation needed to decode the endianness to get it right.

@homm
Copy link
Member Author

homm commented Aug 24, 2017

I think that for any sort of resampling or image ops, it would be completely goofy to store non-native endian in I or F storage.

For sure. In Pillow objects we store all data only in native order. The question is how to interpret the data from external sources in 'F' and 'I' rawmodes. There are two sources which can contain ramodes:

  • in our file decoders. In this case that rawmodes definitely means non-native endian. As the vast majority of systems is little endian, it should be.
  • in user code with Image.frombytes(). Users can get data arrays from numpy, for example, and apply them with Image.frombytes(). Depending on numpy behavior, user can expect that we will decode bytes as native endings.

For me the best solution is align those modes with current rawmode format (where "default is little endian") and add appropriate section in Release Notes.

I've installed QEMU with powerpc architecture, it is damn slow but works. I see the error in TestImageArray.test_fromarray, but I have no errors in TestImageFile.test_parser.

self.assertRaises(ValueError, lambda: unpack("CMYK", "CMYK", 2))
def assert_pack(self, mode, rawmode, data, *pixels):
"""
data - eather raw bytes with data or just number of bytes in rawmode.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

either

class TestLibUnpack(PillowTestCase):
def assert_unpack(self, mode, rawmode, data, *pixels):
"""
data - eather raw bytes with data or just number of bytes in rawmode.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

either

@homm
Copy link
Member Author

homm commented Aug 26, 2017

Changed packers and unpackers for I and F modes to platform-independent format. All tests passed on my big-endian qemu-ppc system.

@homm homm changed the title [WIP] Packing tests Packing tests Aug 26, 2017
@homm homm requested a review from wiredfool August 26, 2017 08:36
@wiredfool
Copy link
Member

Ok, mostly afk this weekend, but will check on mon.

@homm homm added this to the 4.3.0 milestone Aug 26, 2017
@homm homm mentioned this pull request Aug 26, 2017
@wiredfool
Copy link
Member

(fwiw, my mini is at ~ 70 seconds for a test run, which is roughly equivalent to a raspberry pi)

Ok, I get your point now.

We should not change the meaning of the I and F modes now from copy4 to byteswap. This will break anyone on PPC who's using I or F images. It does trip one test on my PPC which you're probably not hitting:

FAIL: TestNumpy.test_to_array
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/erics/Pillow/Tests/test_numpy.py", line 185, in test_to_array
    _to_array(*mode)
  File "/home/erics/Pillow/Tests/test_numpy.py", line 166, in _to_array
    self._test_img_equals_nparray(img, np_img)
  File "/home/erics/Pillow/Tests/test_numpy.py", line 122, in _test_img_equals_nparray
    self.assert_deep_equal(px[x, y], np[y, x])
  File "/home/erics/Pillow/Tests/helper.py", line 66, in assert_deep_equal
    self.assertEqual(a, b, msg)
AssertionError: 26 != 436207616

re: "default is little endian" comment

There's something of a disconnect between the storage modes, which are limited in number and expressiveness and fixed to native endian and the pack/unpack raw modes, where the flagged details default to LE if not specified. The disconnect comes when there's identically named storage and raw modes with conflicting defaults.

There are modes that do what you're proposing, I;32 and F;32 that are the default LE versions of the unpackers corresponding to the F;32B and I;32B modes.

@homm
Copy link
Member Author

homm commented Aug 28, 2017

It does trip one test on my PPC which you're probably not hitting

You are right, I didn't install numpy.

We should not change the meaning of the I and F modes now from copy4 to byteswap.

Ok, reverted. Could you check again?

@homm homm removed the Do Not Merge label Aug 28, 2017
self.assert_pack("I", "I;16B", 2, 0x0102, 0x0304)
self.assert_pack("I", "I;32S",
b'\x83\x00\x00\x01\x01\x00\x00\x83',
0x01000083, -2097151999)

if sys.byteorder == 'little':
self.assert_pack("I", "I", 4, 0x04030201, 0x08070605)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you missed moving the unpack version of these tests.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. Done.

@wiredfool
Copy link
Member

Ok, tests are passing here.

@homm homm merged commit 6b4b1dc into python-pillow:master Aug 28, 2017
@homm homm deleted the packing-tests branch August 28, 2017 16:42
@radarhere radarhere mentioned this pull request Feb 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants