Skip to content

Commit

Permalink
Merge pull request #2348 from freakboy3742/image-tweaks
Browse files Browse the repository at this point in the history
Documentation and API cleanups on Image
  • Loading branch information
mhsmith authored Jan 17, 2024
2 parents 61dff56 + 08ba9df commit 8c971a2
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 7 deletions.
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

0 comments on commit 8c971a2

Please sign in to comment.