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

Raise a TypeError when Image() is called #7461

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions Tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ def test_sanity(self) -> None:
# with pytest.raises(MemoryError):
# Image.new("L", (1000000, 1000000))

def test_direct(self) -> None:
with pytest.raises(TypeError):
Image.Image()

def test_repr_pretty(self) -> None:
class Pretty:
def text(self, text: str) -> None:
Expand Down
77 changes: 45 additions & 32 deletions src/PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,16 +526,11 @@ class Image:
_close_exclusive_fp_after_loading = True

def __init__(self):
# FIXME: take "new" parameters / other image?
# FIXME: turn mode and size into delegating properties?
self.im = None
self._mode = ""
self._size = (0, 0)
self.palette = None
self.info = {}
self.readonly = 0
self.pyaccess = None
self._exif = None
msg = (
"Images should not be instantiated directly. "
"Use the module new() function instead."
)
raise TypeError(msg)

@property
def width(self) -> int:
Expand All @@ -553,18 +548,33 @@ def size(self) -> tuple[int, int]:
def mode(self):
return self._mode

def _new(self, im) -> Image:
new = Image()
new.im = im
new._mode = im.mode
new._size = im.size
def _prepare(self):
self.im = None
self._mode = ""
self._size = (0, 0)
self.palette = None
self.info = {}
self.readonly = 0
self.pyaccess = None
self._exif = None

@classmethod
def _init(cls, im):
self = cls.__new__(cls)
self._prepare()
self.im = im
self._mode = im.mode
self._size = im.size
if im.mode in ("P", "PA"):
if self.palette:
new.palette = self.palette.copy()
else:
from . import ImagePalette
from . import ImagePalette

self.palette = ImagePalette.ImagePalette()
return self

new.palette = ImagePalette.ImagePalette()
def _new(self, im) -> Image:
new = Image._init(im)
if im.mode in ("P", "PA") and self.palette:
new.palette = self.palette.copy()
new.info = self.info.copy()
return new

Expand Down Expand Up @@ -744,7 +754,7 @@ def __getstate__(self):
return [self.info, self.mode, self.size, self.getpalette(), im_data]

def __setstate__(self, state) -> None:
Image.__init__(self)
self._prepare()
info, mode, size, palette, data = state
self.info = info
self._mode = mode
Expand Down Expand Up @@ -2970,7 +2980,7 @@ def transform(
def _wedge() -> Image:
"""Create grayscale wedge (for debugging only)"""

return Image()._new(core.wedge("L"))
return Image._init(core.wedge("L"))


def _check_size(size):
Expand Down Expand Up @@ -3019,7 +3029,7 @@ def new(

if color is None:
# don't initialize
return Image()._new(core.new(mode, size))
return Image._init(core.new(mode, size))

if isinstance(color, str):
# css3-style specifier
Expand All @@ -3028,7 +3038,7 @@ def new(

color = ImageColor.getcolor(color, mode)

im = Image()
rgb_color = False
if (
mode == "P"
and isinstance(color, (list, tuple))
Expand All @@ -3037,11 +3047,14 @@ def new(
color_ints: tuple[int, ...] = cast(Tuple[int, ...], tuple(color))
if len(color_ints) == 3 or len(color_ints) == 4:
# RGB or RGBA value for a P image
from . import ImagePalette
rgb_color = True

im.palette = ImagePalette.ImagePalette()
color = im.palette.getcolor(color_ints)
return im._new(core.fill(mode, size, color))
# This will be the first color allocated to the palette
color = 0
im = Image._init(core.fill(mode, size, color))
if rgb_color:
im.palette.getcolor(color_ints)
return im


def frombytes(mode, size, data, decoder_name: str = "raw", *args) -> Image:
Expand Down Expand Up @@ -3685,7 +3698,7 @@ def effect_mandelbrot(
(x0, y0, x1, y1).
:param quality: Quality.
"""
return Image()._new(core.effect_mandelbrot(size, extent, quality))
return Image._init(core.effect_mandelbrot(size, extent, quality))


def effect_noise(size: tuple[int, int], sigma: float) -> Image:
Expand All @@ -3696,7 +3709,7 @@ def effect_noise(size: tuple[int, int], sigma: float) -> Image:
(width, height).
:param sigma: Standard deviation of noise.
"""
return Image()._new(core.effect_noise(size, sigma))
return Image._init(core.effect_noise(size, sigma))


def linear_gradient(mode: str) -> Image:
Expand All @@ -3705,7 +3718,7 @@ def linear_gradient(mode: str) -> Image:

:param mode: Input mode.
"""
return Image()._new(core.linear_gradient(mode))
return Image._init(core.linear_gradient(mode))


def radial_gradient(mode: str) -> Image:
Expand All @@ -3714,7 +3727,7 @@ def radial_gradient(mode: str) -> Image:

:param mode: Input mode.
"""
return Image()._new(core.radial_gradient(mode))
return Image._init(core.radial_gradient(mode))


# --------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/ImageFile.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class ImageFile(Image.Image):
"""Base class for image file format handlers."""

def __init__(self, fp=None, filename=None):
super().__init__()
super()._prepare()

self._min_frame = 0

Expand Down