From 4b241c4f5c861f32da1cbbc97ede7812dae21c65 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Fri, 5 Jan 2018 14:01:55 +0000 Subject: [PATCH] Typing: Image.fromarray --- src/PIL/Image.py | 18 ++++++++++-------- src/PIL/aliases.py | 21 ++++++++++++++++++++- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 23865a325..1c0cc1e68 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -691,9 +691,9 @@ class Image(object): @property def __array_interface__(self): - # type: () -> Dict[unicode, Any] + # type: () -> ArrayInterfaceStruct # numpy array interface support - new = {} # type: Dict[unicode, Any] + new = {} # type: ArrayInterfaceStruct shape, typestr = _conv_type_shape(self) new['shape'] = shape new['typestr'] = typestr @@ -2538,8 +2538,7 @@ def frombuffer(mode, size, data, decoder_name="raw", *args): # typing -- Getting this to cleanly realize that args is a # correctly formatted tuple is harder than it's worth im = im._new( - core.map_buffer(data, size, decoder_name, None, 0, args) - ) # type: ignore + core.map_buffer(data, size, decoder_name, None, 0, args)) # type: ignore im.readonly = 1 return im @@ -2547,7 +2546,7 @@ def frombuffer(mode, size, data, decoder_name="raw", *args): def fromarray(obj, mode=None): - # type: (object, Optional[Mode]) -> Image + # type: (SupportsArrayInterface, Optional[Mode]) -> Image """ Creates an image memory from an object exporting the array interface (using the buffer protocol). @@ -2585,13 +2584,16 @@ def fromarray(obj, mode=None): raise ValueError("Too many dimensions: %d > %d." % (ndim, ndmax)) size = shape[1], shape[0] + + obj_bytes = None # type: bytes if strides is not None: if hasattr(obj, 'tobytes'): - obj = obj.tobytes() + obj_bytes = obj.tobytes() else: - obj = obj.tostring() + obj_bytes = obj.tostring() - return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) + # UNDONE typing: can from buffer et al take an array_interface exporting object? + return frombuffer(mode, size, obj_bytes or obj, "raw", rawmode, 0, 1) def fromqimage(im): diff --git a/src/PIL/aliases.py b/src/PIL/aliases.py index 78f5e852a..4121c2f70 100644 --- a/src/PIL/aliases.py +++ b/src/PIL/aliases.py @@ -1,4 +1,5 @@ -from typing import Tuple, Union +from typing import Dict, Tuple, Union, Any, Protocol +from abc import abstractmethod, abstractproperty # Type aliases; names subject to change LURD = Tuple[int, int, int, int] # left, up(per), right, down = x0, y0, x1, y1 @@ -14,3 +15,21 @@ MultiChannelExtrema = SingleChannelExtrema # Note: currently only a Tuple[int,in Extrema = Union[SingleChannelExtrema, Tuple[MultiChannelExtrema, ...]] Color = Union[int, float, Tuple[int, int], Tuple[int, int, int], Tuple[int, int, int, int]] + +ArrayInterfaceStruct = Dict[unicode, Any] + +class SupportsArrayInterface(Protocol): + @abstractproperty + def __array_interface__(self): + # type: () -> ArrayInterfaceStruct + pass + + @abstractmethod + def tostring(self): + # type: () -> str + pass + + @abstractmethod + def tobytes(self): + # type: () -> bytes + pass