mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-04-21 01:32:00 +03:00
Merge remote-tracking branch 'origin/Sofija' into Sofija
This commit is contained in:
commit
56cac18b23
BIN
Tests/images/mcidas_mode_L.ara
Normal file
BIN
Tests/images/mcidas_mode_L.ara
Normal file
Binary file not shown.
|
@ -1,64 +0,0 @@
|
|||
import unittest
|
||||
from PIL import Image
|
||||
import unittest
|
||||
|
||||
|
||||
class TestFromBytes(unittest.TestCase):
|
||||
def test_frombytes(self):
|
||||
# Test case 1: Empty bytes
|
||||
data = b""
|
||||
image = Image.frombytes("RGB", (0, 0), data)
|
||||
self.assertEqual(image.size, (0, 0))
|
||||
|
||||
# Test case 2: Non-empty bytes
|
||||
data = b"\x00\x00\xFF\xFF\x00\x00"
|
||||
image = Image.frombytes("RGB", (2, 1), data)
|
||||
self.assertEqual(image.size, (2, 1))
|
||||
self.assertEqual(image.getpixel((0, 0)), (0, 0, 255))
|
||||
self.assertEqual(image.getpixel((1, 0)), (255, 0, 0))
|
||||
|
||||
# Test case 3: Invalid mode
|
||||
data = b"\x00\x00\xFF\xFF\x00\x00"
|
||||
with self.assertRaises(ValueError):
|
||||
Image.frombytes("RGBA", (2, 1), data)
|
||||
|
||||
# Test case 4: Non-RGB mode
|
||||
data = b"\x00\x00\xFF\xFF\x00\x00"
|
||||
image = Image.frombytes("L", (2, 1), data)
|
||||
self.assertEqual(image.size, (2, 1))
|
||||
self.assertEqual(image.getpixel((0, 0)), 0)
|
||||
# self.assertEqual(image.getpixel((1, 0)), 255)
|
||||
|
||||
# Test case 5: Zero width
|
||||
data = b""
|
||||
image = Image.frombytes("RGB", (0, 1), data)
|
||||
self.assertEqual(image.size, (0, 1))
|
||||
|
||||
# Test case 6: Zero height
|
||||
data = b""
|
||||
image = Image.frombytes("RGB", (1, 0), data)
|
||||
self.assertEqual(image.size, (1, 0))
|
||||
|
||||
# Test case 7: s[0] < 0
|
||||
data = b"\x00\x00\xFF\xFF\x00\x00"
|
||||
s = (-1, 1)
|
||||
with self.assertRaises(ValueError):
|
||||
Image.frombytes("RGB", s, data)
|
||||
|
||||
# Test case 8: s[1] == 0
|
||||
data = b"\x00\x00\xFF\xFF\x00\x00"
|
||||
s = (2, 0)
|
||||
# with self.assertRaises(ValueError):
|
||||
# Image.frombytes("RGB", s, data)
|
||||
|
||||
# Test case 5: Different size
|
||||
data = b"\x00\x00\xFF\xFF\x00\x00\xFF\xFF\x00\x00"
|
||||
image = Image.frombytes("RGB", (3, 1), data)
|
||||
self.assertEqual(image.size, (3, 1))
|
||||
self.assertEqual(image.getpixel((0, 0)), (0, 0, 255))
|
||||
self.assertEqual(image.getpixel((1, 0)), (255, 0, 0))
|
||||
# self.assertEqual(image.getpixel((2, 0)), (255, 0, 0))
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
@ -39,7 +39,6 @@ HAVE_PROFILE = os.path.exists(SRGB)
|
|||
def setup_module() -> None:
|
||||
try:
|
||||
from PIL import ImageCms
|
||||
|
||||
# need to hit getattr to trigger the delayed import error
|
||||
ImageCms.core.profile_open
|
||||
except ImportError as v:
|
||||
|
@ -699,3 +698,37 @@ def test_deprecation() -> None:
|
|||
assert ImageCms.VERSION == "1.0.0 pil"
|
||||
with pytest.warns(DeprecationWarning):
|
||||
assert isinstance(ImageCms.FLAGS, dict)
|
||||
|
||||
def test_buildTransform_flags_non_integer():
|
||||
with pytest.raises(ImageCms.PyCMSError):
|
||||
ImageCms.buildTransform(
|
||||
inputProfile="path/to/input/profile",
|
||||
outputProfile="path/to/output/profile",
|
||||
inMode="RGB",
|
||||
outMode="CMYK",
|
||||
renderingIntent=ImageCms.Intent.PERCEPTUAL,
|
||||
flags=123
|
||||
)
|
||||
|
||||
def test_buildTransform_flags_invalid():
|
||||
with pytest.raises(ImageCms.PyCMSError):
|
||||
ImageCms.buildTransform(
|
||||
inputProfile="path/to/input/profile",
|
||||
outputProfile="path/to/output/profile",
|
||||
inMode="RGB",
|
||||
outMode="CMYK",
|
||||
renderingIntent=ImageCms.Intent.PERCEPTUAL,
|
||||
flags=999999
|
||||
)
|
||||
|
||||
def test_rendering_intent_non_integer():
|
||||
with pytest.raises(ImageCms.PyCMSError) as exc_info:
|
||||
ImageCms.buildTransform(
|
||||
inputProfile="path/to/input/profile",
|
||||
outputProfile="path/to/output/profile",
|
||||
inMode="RGB",
|
||||
outMode="CMYK",
|
||||
renderingIntent="not an integer",
|
||||
flags=0
|
||||
)
|
||||
assert str(exc_info.value) == "renderingIntent must be an integer between 0 and 3"
|
||||
|
|
|
@ -216,19 +216,44 @@ class MockPyDecoder(ImageFile.PyDecoder):
|
|||
|
||||
|
||||
class MockPyEncoder(ImageFile.PyEncoder):
|
||||
last: MockPyEncoder | None
|
||||
last = None
|
||||
|
||||
def __init__(self, mode: str, *args: Any) -> None:
|
||||
super().__init__(mode, *args)
|
||||
self._pushes_fd = False
|
||||
self.cleanup_called = False
|
||||
MockPyEncoder.last = self
|
||||
|
||||
super().__init__(mode, *args)
|
||||
|
||||
def encode(self, buffer):
|
||||
# Simulate encoding
|
||||
if buffer is None:
|
||||
raise NotImplementedError
|
||||
return 1, 1, b""
|
||||
|
||||
def cleanup(self) -> None:
|
||||
self.cleanup_called = True
|
||||
|
||||
def test_encode_to_file() -> None:
|
||||
encoder = MockPyEncoder("RGBA")
|
||||
|
||||
with pytest.raises(NotImplementedError):
|
||||
encoder.encode_to_file(None, None)
|
||||
|
||||
encoder._pushes_fd = True
|
||||
with pytest.raises(NotImplementedError):
|
||||
encoder.encode_to_file(None, None)
|
||||
|
||||
buffer = BytesIO(b"\x00" * 10)
|
||||
encoder._pushes_fd = False
|
||||
encoder.encode = lambda buffer: (1, 1, b"")
|
||||
try:
|
||||
encoder.encode_to_file(buffer, None)
|
||||
except NotImplementedError:
|
||||
pass
|
||||
|
||||
encoder.encode = lambda buffer: (_ for _ in ()).throw(NotImplementedError)
|
||||
with pytest.raises(NotImplementedError):
|
||||
encoder.encode_to_file(buffer, None)
|
||||
|
||||
xoff, yoff, xsize, ysize = 10, 20, 100, 100
|
||||
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
import tkinter as tk
|
||||
from unittest import mock
|
||||
|
||||
from PIL import Image
|
||||
from PIL import ImageTk
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
|
||||
from .helper import assert_image_equal, hopper
|
||||
|
||||
TK_MODES = ("1", "L", "P", "RGB", "RGBA")
|
||||
|
||||
try:
|
||||
import tkinter as tk
|
||||
|
||||
from PIL import ImageTk
|
||||
|
||||
dir(ImageTk)
|
||||
HAS_TK = True
|
||||
except (OSError, ImportError):
|
||||
# Skipped via pytestmark
|
||||
HAS_TK = False
|
||||
|
||||
TK_MODES = ("1", "L", "P", "RGB", "RGBA")
|
||||
|
||||
|
||||
pytestmark = pytest.mark.skipif(not HAS_TK, reason="Tk not installed")
|
||||
|
||||
|
||||
|
@ -27,7 +27,6 @@ def setup_module() -> None:
|
|||
try:
|
||||
# setup tk
|
||||
tk.Frame()
|
||||
# root = tk.Tk()
|
||||
except RuntimeError as v:
|
||||
pytest.skip(f"RuntimeError: {v}")
|
||||
except tk.TclError as v:
|
||||
|
@ -102,3 +101,5 @@ def test_bitmapimage() -> None:
|
|||
|
||||
# reloaded = ImageTk.getimage(im_tk)
|
||||
# assert_image_equal(reloaded, im)
|
||||
|
||||
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
import pytest
|
||||
from PIL import PdfParser
|
||||
|
||||
def test_delitem_new_entries():
|
||||
parser = PdfParser.XrefTable()
|
||||
parser.new_entries["test_key"] = ("value", 0)
|
||||
|
||||
del parser["test_key"]
|
||||
|
||||
assert "test_key" not in parser.new_entries
|
||||
assert parser.deleted_entries["test_key"] == 1
|
||||
|
||||
|
||||
def test_delitem_deleted_entries():
|
||||
parser = PdfParser.XrefTable()
|
||||
parser.deleted_entries["test_key"] = 0
|
||||
|
||||
del parser["test_key"]
|
||||
|
||||
assert parser.deleted_entries["test_key"] == 0
|
||||
|
||||
def test_delitem_nonexistent_key():
|
||||
parser = PdfParser.XrefTable()
|
||||
|
||||
with pytest.raises(IndexError):
|
||||
import pytest
|
||||
from PIL import PdfParser
|
||||
|
||||
def test_delitem_new_entries():
|
||||
parser = PdfParser.XrefTable()
|
||||
parser.new_entries["test_key"] = ("value", 0)
|
||||
|
||||
del parser["test_key"]
|
||||
|
||||
assert "test_key" not in parser.new_entries
|
||||
assert parser.deleted_entries["test_key"] == 1
|
||||
|
||||
|
||||
def test_delitem_deleted_entries():
|
||||
parser = PdfParser.XrefTable()
|
||||
parser.deleted_entries["test_key"] = 0
|
||||
|
||||
del parser["test_key"]
|
||||
|
||||
assert parser.deleted_entries["test_key"] == 0
|
||||
|
||||
def test_delitem_nonexistent_key():
|
||||
parser = PdfParser.XrefTable()
|
||||
|
||||
with pytest.raises(IndexError):
|
||||
del parser["nonexistent_key"]
|
22
conftest.py
22
conftest.py
|
@ -6,25 +6,24 @@ from PIL import Image
|
|||
from PIL import PdfParser
|
||||
from PIL import SpiderImagePlugin
|
||||
from PIL import MpegImagePlugin
|
||||
from PIL import ImageCms
|
||||
from PIL import McIdasImagePlugin
|
||||
from PIL import BlpImagePlugin
|
||||
from PIL import IcnsImagePlugin
|
||||
from PIL import ImageFile
|
||||
from PIL import ImageCms
|
||||
|
||||
pytest_plugins = ["Tests.helper"]
|
||||
|
||||
|
||||
def calculate_coverage(test_name):
|
||||
all_branches = {
|
||||
"branches1": Image.branches,
|
||||
"branches2": PdfParser.XrefTable.branches,
|
||||
"branches3": SpiderImagePlugin.branches,
|
||||
"branches4": MpegImagePlugin.BitStream.branches,
|
||||
"branches5": ImageCms.ImageCmsProfile.branches,
|
||||
"branches6": McIdasImagePlugin.McIdasImageFile.branches,
|
||||
"branches7": BlpImagePlugin._BLPBaseDecoder.branches,
|
||||
"branches8": IcnsImagePlugin.branches,
|
||||
# Add more
|
||||
"branches1": Image.branches, # duru
|
||||
"branches2": PdfParser.XrefTable.branches, # duru
|
||||
"branches3": SpiderImagePlugin.branches, # isidora
|
||||
"branches4": MpegImagePlugin.BitStream.branches, # isidora
|
||||
"branches5": ImageCms.branches, # deekshu
|
||||
"branches6": ImageFile.PyEncoder.branches, # deekshu
|
||||
"branches7": BlpImagePlugin._BLPBaseDecoder.branches, # sofija
|
||||
"branches8": IcnsImagePlugin.branches, # sofija
|
||||
}
|
||||
|
||||
for name, branches in all_branches.items():
|
||||
|
@ -58,4 +57,3 @@ def pytest_sessionfinish(session, exitstatus):
|
|||
|
||||
coverage = calculate_coverage(test_name)
|
||||
print("\nBRANCH COVERAGE for", test_name, ":", coverage, "%\n")
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ from typing import IO
|
|||
|
||||
from . import Image, ImageFile
|
||||
|
||||
|
||||
class Format(IntEnum):
|
||||
JPEG = 0
|
||||
|
||||
|
@ -276,22 +277,20 @@ class BlpImageFile(ImageFile.ImageFile):
|
|||
|
||||
|
||||
class _BLPBaseDecoder(ImageFile.PyDecoder):
|
||||
|
||||
branches = {
|
||||
"1": False,
|
||||
"2": False,
|
||||
}
|
||||
|
||||
_pulls_fd = True
|
||||
|
||||
def decode(self, buffer: bytes) -> tuple[int, int]:
|
||||
branches = {
|
||||
"1": False,
|
||||
"2": False,
|
||||
}
|
||||
|
||||
try:
|
||||
branches["1"] = True;
|
||||
_BLPBaseDecoder.branches["1"] = True
|
||||
self._read_blp_header()
|
||||
self._load()
|
||||
except struct.error as e:
|
||||
branches["2"] = True;
|
||||
_BLPBaseDecoder.branches["2"] = True
|
||||
msg = "Truncated BLP file"
|
||||
raise OSError(msg) from e
|
||||
return -1, 0
|
||||
|
|
|
@ -48,11 +48,11 @@ def read_32t(fobj, start_length, size):
|
|||
fobj.seek(start)
|
||||
sig = fobj.read(4)
|
||||
if sig != b"\x00\x00\x00\x00":
|
||||
branches["1"] = True;
|
||||
branches["1"] = True
|
||||
msg = "Unknown signature, expecting 0x00000000"
|
||||
raise SyntaxError(msg)
|
||||
else:
|
||||
branches["2"] = True;
|
||||
branches["2"] = True
|
||||
return read_32(fobj, (start + 4, length - 4), size)
|
||||
|
||||
|
||||
|
|
|
@ -29,6 +29,15 @@ from . import Image, __version__
|
|||
from ._deprecate import deprecate
|
||||
from ._typing import SupportsRead
|
||||
|
||||
branches = {
|
||||
"1": False,
|
||||
"2": False,
|
||||
"3": False,
|
||||
"4": False,
|
||||
"5": False,
|
||||
"6": False,
|
||||
}
|
||||
|
||||
try:
|
||||
from . import _imagingcms as core
|
||||
except ImportError as ex:
|
||||
|
@ -237,17 +246,6 @@ _FLAGS = {
|
|||
|
||||
|
||||
class ImageCmsProfile:
|
||||
branches = {
|
||||
"1": False,
|
||||
"2": False,
|
||||
"3": False,
|
||||
"4": False,
|
||||
"5": False,
|
||||
"6": False,
|
||||
"7": False,
|
||||
"8": False,
|
||||
}
|
||||
|
||||
def __init__(self, profile: str | SupportsRead[bytes] | core.CmsProfile) -> None:
|
||||
"""
|
||||
:param profile: Either a string representing a filename,
|
||||
|
@ -257,28 +255,21 @@ class ImageCmsProfile:
|
|||
"""
|
||||
|
||||
if isinstance(profile, str):
|
||||
ImageCmsProfile.branches["1"] = True
|
||||
if sys.platform == "win32":
|
||||
ImageCmsProfile.branches["2"] = True
|
||||
profile_bytes_path = profile.encode()
|
||||
try:
|
||||
ImageCmsProfile.branches["3"] = True
|
||||
profile_bytes_path.decode("ascii")
|
||||
except UnicodeDecodeError:
|
||||
ImageCmsProfile.branches["4"] = True
|
||||
with open(profile, "rb") as f:
|
||||
ImageCmsProfile.branches["5"] = True
|
||||
self._set(core.profile_frombytes(f.read()))
|
||||
return
|
||||
self._set(core.profile_open(profile), profile)
|
||||
elif hasattr(profile, "read"):
|
||||
ImageCmsProfile.branches["6"] = True
|
||||
self._set(core.profile_frombytes(profile.read()))
|
||||
elif isinstance(profile, core.CmsProfile):
|
||||
ImageCmsProfile.branches["7"] = True
|
||||
self._set(profile)
|
||||
else:
|
||||
ImageCmsProfile.branches["8"] = True
|
||||
|
||||
msg = "Invalid type for Profile" # type: ignore[unreachable]
|
||||
raise TypeError(msg)
|
||||
|
||||
|
@ -582,22 +573,28 @@ def buildTransform(
|
|||
"""
|
||||
|
||||
if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
|
||||
branches["1"] = True
|
||||
msg = "renderingIntent must be an integer between 0 and 3"
|
||||
raise PyCMSError(msg)
|
||||
|
||||
if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
|
||||
branches["2"] = True
|
||||
msg = f"flags must be an integer between 0 and {_MAX_FLAG}"
|
||||
raise PyCMSError(msg)
|
||||
|
||||
try:
|
||||
branches["3"] = True
|
||||
if not isinstance(inputProfile, ImageCmsProfile):
|
||||
branches["4"] = True
|
||||
inputProfile = ImageCmsProfile(inputProfile)
|
||||
if not isinstance(outputProfile, ImageCmsProfile):
|
||||
branches["5"] = True
|
||||
outputProfile = ImageCmsProfile(outputProfile)
|
||||
return ImageCmsTransform(
|
||||
inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags
|
||||
)
|
||||
except (OSError, TypeError, ValueError) as v:
|
||||
branches["6"] = True
|
||||
raise PyCMSError(v) from v
|
||||
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ from . import Image
|
|||
from ._deprecate import deprecate
|
||||
from ._util import is_path
|
||||
|
||||
|
||||
MAXBLOCK = 65536
|
||||
|
||||
SAFEBLOCK = 1024 * 1024
|
||||
|
@ -750,6 +751,11 @@ class PyDecoder(PyCodec):
|
|||
|
||||
|
||||
class PyEncoder(PyCodec):
|
||||
|
||||
branches = {
|
||||
"1": False,
|
||||
"2": False,
|
||||
}
|
||||
"""
|
||||
Python implementation of a format encoder. Override this class and
|
||||
add the decoding logic in the :meth:`encode` method.
|
||||
|
@ -801,7 +807,9 @@ class PyEncoder(PyCodec):
|
|||
"""
|
||||
errcode = 0
|
||||
while errcode == 0:
|
||||
PyEncoder.branches["1"] = True
|
||||
status, errcode, buf = self.encode(bufsize)
|
||||
if status > 0:
|
||||
PyEncoder.branches["2"] = True
|
||||
fh.write(buf[status:])
|
||||
return errcode
|
||||
|
|
|
@ -21,7 +21,6 @@ import struct
|
|||
|
||||
from . import Image, ImageFile
|
||||
|
||||
|
||||
def _accept(prefix: bytes) -> bool:
|
||||
return prefix[:8] == b"\x00\x00\x00\x00\x00\x00\x00\x04"
|
||||
|
||||
|
|
25
src/PIL/test_ImageFile.py
Normal file
25
src/PIL/test_ImageFile.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
from io import BytesIO
|
||||
import pytest
|
||||
from PIL import ImageFile
|
||||
|
||||
def test_encode_to_file_branches():
|
||||
# Create a mock file object
|
||||
mock_file = io.BytesIO()
|
||||
|
||||
# Create a PyEncoder instance
|
||||
encoder = ImageFile.PyEncoder("RGB")
|
||||
|
||||
# Set the branches dictionary to False to ensure both branches are covered
|
||||
encoder.branches = {"1": False, "2": False}
|
||||
|
||||
# Call the encode_to_file method
|
||||
errcode = encoder.encode_to_file(mock_file, 1024)
|
||||
|
||||
# Check that the branches dictionary has been updated
|
||||
assert encoder.branches["1"] is True
|
||||
assert encoder.branches["2"] is True
|
||||
|
||||
# Check that the error code is 0, indicating successful encoding
|
||||
assert errcode == 0
|
||||
|
||||
mock_file = BytesIO()
|
Loading…
Reference in New Issue
Block a user