fromarray: add type hints by adamjstewart · Pull Request #7936 · python-pillow/Pillow

@adamjstewart

Really excited to see type hints in the latest release!

The only feature I'm using that was missing type hints is fromarray, so I added them. Not 100% sure if numpy.typing.ArrayLike is the right way to go, but feel free to suggest alternatives.

@adamjstewart

@pre-commit-ci

@Yay295

I think the actual type would be numpy.ndarray, but that would require importing numpy.

@adamjstewart

@Yay295

The other half of the NumPy support, which also isn't typed yet, is here:

@property
def __array_interface__(self):
# numpy array interface support
new = {"version": 3}
try:
if self.mode == "1":
# Binary images need to be extended from bits to bytes
# See: https://github.com/python-pillow/Pillow/issues/350
new["data"] = self.tobytes("raw", "L")
else:
new["data"] = self.tobytes()
except Exception as e:
if not isinstance(e, (MemoryError, RecursionError)):
try:
import numpy
from packaging.version import parse as parse_version
except ImportError:
pass
else:
if parse_version(numpy.__version__) < parse_version("1.23"):
warnings.warn(str(e))
raise
new["shape"], new["typestr"] = _conv_type_shape(self)
return new

@Yay295

I think numpy.typing.ArrayLike is too broad, since it includes scalars and sequences, whereas Image.fromarray() only supports the NumPy array interface.

@nulano

I think you may need to add numpy to the list of dependencies here

typing = [
'typing-extensions; python_version < "3.10"',
]
or in a new block to fix the mypy error.

@Yay295

Something like

from typing import Protocol, Sequence, TypedDict
class ArrayInterfaceDict(TypedDict):
    shape: Sequence[int]
    typestr: str
class ArrayInterface(Protocol):
    __array_interface__: ArrayInterfaceDict

would be a more exact definition of what Pillow requires.

@nulano

Something like

from typing import Protocol, Sequence, TypedDict
class ArrayInterfaceDict(TypedDict):
    shape: Sequence[int]
    typestr: str
class ArrayInterface(Protocol):
    __array_interface__: ArrayInterfaceDict

would be a more exact definition of what Pillow requires.

Adding that to PIL._typing would probably be a better option than requiring numpy be installed.

@radarhere

@radarhere

@adamjstewart

Added SupportsArrayInterface

@adamjstewart

Thanks for the help @radarhere!

P.S. Love the profile pic @Yay295, excited for season 3 coming out this weekend!

radarhere

nulano



def fromarray(obj, mode=None):
class SupportsArrayInterface(Protocol):

Choose a reason for hiding this comment

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

Since (I assume) this is not intended to be exported, I would expect we either want this to be private, i.e.

class SupportsArrayInterface(Protocol):
class _SupportsArrayInterface(Protocol):

or in a private module, i.e. PIL._typing.SupportsArrayInterface.

@radarhere what do you think?

Choose a reason for hiding this comment

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

I was modelling this after our implementation of SupportsGetMesh.

#7812 (comment)

If we're using _SupportsGetMesh as a type hint, this probably is something users might want to use, so should be accessible as a non-underscore thing?

Choose a reason for hiding this comment

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

I feel like the difference is that SupportsGetMesh is a Pillow protocol, whereas SupportsArrayInterface seems to be a numpy protocol. Similarly, we have PIL._typing.SupportsRead for a builtin Python protocol. I would therefore expect users to either use the actual numpy type (e.g. numpy.ndarray) or define their own protocol.

@hugovk Do you have any thoughts as the author of the quoted comment?

Choose a reason for hiding this comment

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

Hmm, let's go for SupportsArrayInterface, it's probably more useful that way, and it's only a small class. We an always deprecate/remove later if needed.

@nulano

nulano

@radarhere

Co-authored-by: Ondrej Baranovič <ondreko.tiba@gmail.com>

@adamjstewart

Anything else needed for this PR?

@radarhere

There's an unresolved debate, but I expect it will be resolved sooner or later before the next release.

@hugovk