This adds a new test decorator: skip_unless_feature(). The argument is
the same as passed to features.check(). If the feature is not supported,
the test will be skipped.
This removes several kinds of boilerplate copied and pasted around tests
so test feature checking is handled and displayed more consistently.
Refs #4193
These modules are safe to import and this better follows PEP 8.
From https://www.python.org/dev/peps/pep-0008/#imports
> Imports are always put at the top of the file, just after any module
> comments and docstrings, and before module globals and constants.
Appeared in the form:
ResourceWarning: unclosed file <_io.BufferedReader name='Tests/images/invalid-exif-without-x-resolution.jpg'>
Enable all warnings to always display during tests to help catch these
warnings earlier.
Follow Python's file object semantics. User code is responsible for
closing resources (usually through a context manager) in a deterministic
way.
To achieve this, remove __del__ functions. These functions used to
closed open file handlers in an attempt to silence Python
ResourceWarnings. However, using __del__ has the following drawbacks:
- __del__ isn't called until the object's reference count reaches 0.
Therefore, resource handlers remain open or in use longer than
necessary.
- The __del__ method isn't guaranteed to execute on system exit. See the
Python documentation:
https://docs.python.org/3/reference/datamodel.html#object.__del__
> It is not guaranteed that __del__() methods are called for objects
> that still exist when the interpreter exits.
- Exceptions that occur inside __del__ are ignored instead of raised.
This has the potential of hiding bugs. This is also in the Python
documentation:
> Warning: Due to the precarious circumstances under which __del__()
> methods are invoked, exceptions that occur during their execution
> are ignored, and a warning is printed to sys.stderr instead.
Instead, always close resource handlers when they are no longer in use.
This will close the file handler at a specified point in the user's code
and not wait until the interpreter chooses to. It is always guaranteed
to run. And, if an exception occurs while closing the file handler, the
bug will not be ignored.
Now, when code receives a ResourceWarning, it will highlight an area
that is mishandling resources. It should not simply be silenced, but
fixed by closing resources with a context manager.
All warnings that were emitted during tests have been cleaned up. To
enable warnings, I passed the `-Wa` CLI option to Python. This exposed
some mishandling of resources in ImageFile.__init__() and
SpiderImagePlugin.loadImageSeries(), they too were fixed.
Similar to the recent adoption of Black. isort is a Python utility to
sort imports alphabetically and automatically separate into sections. By
using isort, contributors can quickly and automatically conform to the
projects style without thinking. Just let the tool do it.
Uses the configuration recommended by the Black to avoid conflicts of
style.
Rewrite TestImageQt.test_deprecated to no rely on import order.
With the introduction and use of pytest, it is simple and easy to
execute specific tests in isolation through documented command line
arguments. Either by specifying the module path or through the `-k
EXPRESSION` argument. There is no longer any need to provide the
boilerplate:
if __name__ == '__main__':
unittest.main()
To every test file. It is simply noise.
The pattern remains in test files that aren't named with `test_*` as
those files are not discovered and executed by pytest by default.
The previous test configuration made it difficult to run a single test
with the pytest CLI. There were two major issues:
- The Tests directory was not a package. It now includes a __init__.py
file and imports from other tests modules are done with relative
imports.
- setup.cfg always specified the Tests directory. So even if a specific
test were specified as a CLI arg, this configuration would also always
include all tests. This configuration has been removed to allow
specifying a single test on the command line.
Contributors can now run specific tests with a single command such as:
$ tox -e py37 -- Tests/test_file_pdf.py::TestFilePdf.test_rgb
This makes it easy and faster to iterate on a single test failure and is
very familiar to those that have previously used tox and pytest.
When running tox or pytest with no arguments, they still discover and
runs all tests in the Tests directory.
Instead, allow exceptions to bubble up to the unittest exception
handler.
Prevents replacing the exception trace with a less informative
message. As the exceptions are always unexpected, should not need to
catch them explicitly in tests.
We were encountering some errors when saving specific JPEG images.
The error was shown in stderr as:
IOError: encoder error -2 when writing image file
And on stdout it printed:
Suspension not allowed here
The problem was the bufsize not contemplating the icc_profile block.
iter(dict) is equivalent to iter(dict.keys()), so simply act on the dict
instead of adding the extra call.
Inspired by Lennart Regebro's PyCon 2017 presentation "Prehistoric
Patterns in Python". Available at:
https://www.youtube.com/watch?v=V5-JH23Vk0I
* DPI is a tuple
* Some EXIF only contains an X resolution for DPI
* Refactor
* Test with no DPI in EXIF
* Handle EXIF with no DPI
* Created with: exiftool "-*resolution*"= photoshop-200dpi.jpg
* Test when not in EXIF, DPI==72,72
* Use X resolution for Y, default to 72,72 dpi
* Created with: exiftool -exif:ResolutionUnit=cm photoshop-200dpi.jpg
* Test for EXIF with dpcm instead of dpi
* Convert dpcm to dpi, and default to inches if unit unknown
When saving a JPEG and specifying 'keep' for quality or subsampling,
if the source JPEG image is in grayscale mode, don't try to find the
subsampling of the source, because grayscale images don't have any
subsampling (it's only for color components).
For the moment the fix also ignores subsampling of CMYK JPEG because
currently Pillow doesn't support encoding JPEG in YCCK mode (and
subsampling doesn't make sense in CMYK, but Pillow permits saving CMYK
JPEG with subsampling, that's a bug). This fix pass those errors
silently, i.e. it doesn't raise an error when 'keep' is used but it's
not possible to keep the subsampling (because the image is grayscale
or CMYK). I think it's the proper behavior but I'm not sure.
value (in dictionary format).
Previously, this would throw a TypeError when checking if the qtables
value was actually a preset. By adding an isStringType check, we can
avoid this error.
when the jpeg encoder sees the flags optimize or progressive (or progression)
it will write the full image in one shot.
The bufsize needs to be big enough to hold the entire image. The current heuristic
is that the entire compressed image will fit in width * height bytes, but this
heuristic is only applied to save operations with the flag "optimize" and not to
save operations with the flag "progressive".
This patch fixes this oversight.
(Btw, it will probably be a good idea to have a loop that retries with a bigger
bufsize in case this guess is not big enough.)
Most of the differences are in tobytes/tostring naming and expected
behavior of the bytes() constructor. The latter was usually easy to fix
with the right bytes literal.
This is a good preview of what will have to happen in the Python 3 code.
This is Christoph Gohlke's test suite from his personal PIL package found
at http://www.lfd.uci.edu/~gohlke/pythonlibs/.
This is just to bring it in as a separate commit. Future commits will align
it with Pillow.