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

Documentation and API cleanups on Image #2348

Merged
merged 2 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changes/2347.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The error returned when an Image is created with no source has been clarified.
1 change: 1 addition & 0 deletions changes/2348.doc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The difference between Icon and Image was clarified, and a note about the lack of an ``on_press`` handler on ImageView was added.
15 changes: 9 additions & 6 deletions core/src/toga/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,16 @@
ImageContent: TypeAlias = PathLike | BytesLike | ImageLike


NOT_PROVIDED = object()


class Image:
def __init__(
self,
src: ImageContent | None = None,
src: ImageContent = NOT_PROVIDED,
*,
path=None, # DEPRECATED
data=None, # DEPRECATED
path=NOT_PROVIDED, # DEPRECATED
data=NOT_PROVIDED, # DEPRECATED
):
"""Create a new image.

Expand All @@ -56,21 +59,21 @@ def __init__(
######################################################################
# 2023-11: Backwards compatibility
######################################################################
num_provided = sum(arg is not None for arg in (src, path, data))
num_provided = sum(arg is not NOT_PROVIDED for arg in (src, path, data))
if num_provided > 1:
raise ValueError("Received multiple arguments to constructor.")
if num_provided == 0:
raise TypeError(
"Image.__init__() missing 1 required positional argument: 'src'"
)
if path is not None:
if path is not NOT_PROVIDED:
src = path
warn(
"Path argument is deprecated, use src instead.",
DeprecationWarning,
stacklevel=2,
)
elif data is not None:
elif data is not NOT_PROVIDED:
src = data
warn(
"Data argument is deprecated, use src instead.",
Expand Down
21 changes: 20 additions & 1 deletion core/tests/test_images.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,33 @@ def test_create_from_raw():
assert_action_performed_with(copy, "load image from raw")


def test_not_enough_arguments():
def test_no_source():
"""If no source is provided, an error is raised"""
with pytest.raises(
TypeError,
match=r"Image.__init__\(\) missing 1 required positional argument: 'src'",
):
toga.Image()


def test_empty_image():
"""If the image source is provided as None, an error is raised"""
with pytest.raises(
TypeError,
match=r"Unsupported source type for Image",
):
toga.Image(None)


def test_empty_image_explicit():
"""If src is explicitly provided as None, an error is raised"""
with pytest.raises(
TypeError,
match=r"Unsupported source type for Image",
):
toga.Image(src=None)


def test_invalid_input_format():
"""Trying to create an image with an invalid input should raise an error"""
with pytest.raises(
Expand Down
16 changes: 16 additions & 0 deletions docs/reference/api/resources/icons.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@ A small, square image, used to provide easily identifiable visual context to a w
Usage
-----

.. admonition:: Icons and Images are *not* the same!

Toga draws a distinction between an *Icon* and an *Image*. An :class:`~toga.Icon` is
small, square, and might vary between platforms. It is a visual element that is
often used as part of an interactive element such as a button, toolbar item, or tab
selector - but the Icon *itself* isn't an interactive element.

An :class:`~toga.Image`, on the other hand, can have an arbitrary size or aspect
ratio, and is *not* platform dependent - the same image will be used on *every*
platform. An Image is *not* an interactive element, because there is no visual cue
to the user that the image *can* be interacted with.

If you are looking for a widget that the user can click on, you're looking for a
widget configured to use an Icon (probably :class:`~toga.Button`), *not* an
``on_press`` handler on an :class:`~toga.Image` or :class:`~toga.ImageView`.

The filename specified for an icon should be specified *without* an extension; the
platform will determine an appropriate extension, and may also modify the name of the
icon to include a platform and/or size qualifier.
Expand Down
17 changes: 17 additions & 0 deletions docs/reference/api/resources/images.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,23 @@ Graphical content of arbitrary size.
Usage
-----

.. admonition:: Images and Icons are *not* the same!

Toga draws a distinction between an *Image* and an *Icon*. An :class:`~toga.Image`
can have an arbitrary size or aspect ratio, and is *not* platform dependent - the
same image will be used on *every* platform. An Image is *not* an interactive
element, because there is no visual cue to the user that the image *can* be
interacted with.

An :class:`~toga.Icon`, on the other hand, is small, square, and might vary between
platforms. It is a visual element that is often used as part of an interactive
element such as a button, a toolbar item, or a tab selector - but the Icon *itself*
isn't an interactive element.

If you are looking for a widget that the user can click on, you're looking for a
widget configured to use an Icon (probably :class:`~toga.Button`), *not* an
``on_press`` handler on an :class:`~toga.Image` or :class:`~toga.ImageView`.

An image can be constructed from a :any:`wide range of sources <ImageContent>`:

.. code-block:: python
Expand Down
7 changes: 7 additions & 0 deletions docs/reference/api/widgets/imageview.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ A widget that displays an image.
Usage
-----

An :class:`~toga.ImageView` provides a mechanism to display an :class:`~toga.Image` as
part of an interface.

.. code-block:: python

import toga
Expand All @@ -56,6 +59,10 @@ Usage
Notes
-----

* An ImageView **is not** an interactive element - there is no ``on_press`` handler for
ImageView. If you want a graphical element that can be clicked or pressed, try using a
:any:`toga.Button` that uses an :any:`toga.Icon`.

* The default size of the view is the size of the image, or 0x0 if ``image`` is
``None``.

Expand Down