Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
d9e3ba5
Convert and initial config.
kattni Aug 22, 2025
9a60b2b
Prepare proof of concept for MkDocs switch.
kattni Aug 24, 2025
720fd37
Merge branch 'main' into tooling/mkdocs
kattni Aug 24, 2025
908f1cb
Update .readthedocs.yaml
kattni Aug 24, 2025
c7b64a7
Update docs Python version.
kattni Aug 24, 2025
fa68fa1
Upgrade pip on RTD.
kattni Aug 24, 2025
b99ef81
Revert Python version bump.
kattni Aug 24, 2025
54c190b
Requested changes.
kattni Aug 27, 2025
6f22804
Merge branch 'main' into tooling/mkdocs
kattni Aug 27, 2025
6f44f2a
Update version.
kattni Aug 27, 2025
2a9bfb0
Update version.
kattni Aug 27, 2025
f6f0fe7
Updates, deps, RTD config.
kattni Aug 27, 2025
8574194
Requested changes.
kattni Aug 27, 2025
4451135
Review and continued updates.
kattni Sep 24, 2025
8863106
Update build argument in tox.
kattni Sep 25, 2025
798db08
Snippets fixes.
kattni Sep 25, 2025
e783682
Various fixes, prep for running rumdl fmt.
kattni Sep 30, 2025
797be06
Reflow content, other rumdl fixes.
kattni Sep 30, 2025
0ddf93b
Fix canvas.md, merge doc updates from main.
kattni Sep 30, 2025
5e85931
Fixes to deal with rumdl failures.
kattni Sep 30, 2025
423f866
Merge remote-tracking branch 'beeware/main' into tooling/mkdocs
kattni Sep 30, 2025
01f9e96
Convert towncrier to Markdown, fix typo.
kattni Sep 30, 2025
4d24aa6
Fix CI issues with tox and dependency groups.
kattni Oct 2, 2025
afaaeb1
Update rumdl config, fix whitespace issue.
kattni Oct 2, 2025
8cbc5a3
Initial direct Markdown verification, add todos, rumdl fix.
kattni Oct 2, 2025
dff81ea
Add change note.
kattni Oct 2, 2025
1157af0
Batch two of Markdown/class doc validation.
kattni Oct 3, 2025
ee13f5f
Batch three of Markdown/class doc validation.
kattni Oct 3, 2025
1d549ca
Batch four of Markdown/class doc validation.
kattni Oct 3, 2025
ba67655
Batch five of Markdown/class doc validation.
kattni Oct 3, 2025
b958827
Final batch of Markdown/class doc validation.
kattni Oct 4, 2025
0ff788b
Fix current MkDocs build errors.
kattni Oct 4, 2025
4280fbc
Docstring note and code snippet updates.
kattni Oct 5, 2025
9038438
Convert docstrings from rST to Markdown, fixes.
kattni Oct 5, 2025
d73cf37
Merge remote-tracking branch 'beeware/main' into tooling/mkdocs
kattni Oct 5, 2025
6c441c7
Add rumdl to pre-commit, get passing.
kattni Oct 5, 2025
e80f770
Reenable pyspelling, resolve issues.
kattni Oct 5, 2025
be64c6f
Fix build issues.
kattni Oct 5, 2025
9c142b0
nospell table-reader syntax.
kattni Oct 5, 2025
c68c6c9
Fixes, finalise configurations.
kattni Oct 6, 2025
6f2ac82
Merge remote-tracking branch 'beeware/main' into tooling/mkdocs
kattni Oct 6, 2025
732ee01
Remove pre-commit check, restore TypeVar locations.
kattni Oct 6, 2025
23cb64e
Shift docs to docstrings.
kattni Oct 6, 2025
42bc97b
Fixes from final walkthrough.
kattni Oct 6, 2025
9509225
Fixes.
kattni Oct 6, 2025
b4aa4f1
Add missing type declarations.
freakboy3742 Oct 6, 2025
ef90cb0
Update latest changenotes.
kattni Oct 6, 2025
4569763
Revert Read the Docs to using Python 3.12.
kattni Oct 6, 2025
abcc6cd
Update pyproject.toml.
kattni Oct 6, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# MkDocs
_build
comment.md

*.pyc
*~
.*.sw[op]
Expand All @@ -10,7 +14,6 @@ coverage.xml
dist
build
logs
_build
distribute-*
docs/env
local
Expand Down
49 changes: 49 additions & 0 deletions .pyspelling.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
matrix:
- name: markdown
dictionary:
wordlists:
- docs/spelling_wordlist
output: _build/dictionary/python.dic
sources:
- 'docs/**/*.md'
pipeline:
- pyspelling.filters.markdown:
markdown_extensions:
- markdown.extensions.toc
- markdown.extensions.admonition
- markdown.extensions.attr_list
- pymdownx.superfences
- pymdownx.blocks.admonition
- pymdownx.blocks.caption
- pymdownx.blocks.tab
- pymdownx.snippets
- pyspelling.filters.html:
comments: true
attributes:
- title
- alt
ignores:
- 'code'
- 'pre'
- 'figure' # Can be removed once all <figure>s are replaced with Markdown
- 'nospell' # Allows for ignoring a word or words inline.
- pyspelling.filters.context:
context_visible_first: true
escapes: '\\[\\`~]'
delimiters:
# Ignores the Jinja directives and their contents
- open: '{%'
content: '[\d\D]*'
close: '%}'
# Ignore the mkdocstrings syntax and its content
- open: ':::'
content: '[\d\D]*'
close: '\n'
# Ignore the single line Snippets syntax
- open: '-8<\-'
content: '[\d\D]*'
close: '\n'
# Ignore the multiline Snippets syntax
- open: '-8<\-\n'
content: '[\d\D]*'
close: '-8<-\n'
40 changes: 10 additions & 30 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,21 @@
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

# Set the version of Python and other tools you might need
build:
os: ubuntu-22.04
tools:
# Docs are always built on Python 3.12. See also the tox config and contribution docs.
# Docs are always built on Python 3.12. See also the tox config.
python: "3.12"
jobs:
post_checkout:
# RTD defaults to a depth of 50 but Toga versioning may require
# much more git history to accurately determine the SCM version
- git fetch --unshallow
pre_install:
- python -m pip install --upgrade pip
- python -m pip install --group 'tox-uv'
pre_build:
- tox -e docs-lint

# Build documentation in the docs/ directory with Sphinx
sphinx:
builder: html
configuration: docs/conf.py
fail_on_warning: true

# Install extras for build. Order is significant; each entry is a separate call to
# `pip`, and we need Travertino to exist before core is installed. core[dev] is needed
# to run `tox -e docs-lint` as a pre-build step.
python:
install:
# Docs requirements are *mostly* handled by the `docs` extra; but we can't include
# the theme that way, so the theme is installed using a requirements.txt file,
# independent of the docs extra. Ideally, we'd use dependency groups for docs
# dependencies, but RTD doesn't support them yet.
- requirements: requirements-docs.txt
- method: pip
path: travertino
- method: pip
path: core
extra_requirements:
- dev
- docs
- python -m tox -e docs-lint
build:
html:
- python -m tox -e docs-$READTHEDOCS_LANGUAGE -- --output=$READTHEDOCS_OUTPUT/html/
51 changes: 34 additions & 17 deletions core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,21 @@ classifiers = [
"Topic :: Software Development :: Widget Sets",
]

[project.optional-dependencies]
[dependency-groups]
# Extras used by developers *of* Toga are pinned to specific versions to
# ensure environment consistency.
pre-commit = [
"pre-commit == 4.3.0",
]

town-crier = [
"towncrier==24.8.0",
]

tox-uv = [
"tox-uv == 1.28.0",
]

dev = [
"coverage[toml] == 7.10.5",
"coverage-conditional-plugin == 0.9.0",
Expand All @@ -70,26 +82,31 @@ dev = [
"pytest-freezer == 0.4.9",
"pytest-xdist == 3.8.0",
"setuptools-scm == 9.2.0",
"tox == 4.28.4",
{include-group = "pre-commit"},
{include-group = "tox-uv"},
]
# Docs are always built on a specific Python version; see RTD and tox config files,
# and the docs contribution guide.
docs = [
# Docs requirements are *mostly* handled by the `docs` extra; but we can't include
# the theme that way, so the theme is installed using a requirements.txt file,
# independent of the docs extra. Ideally, we'd use dependency groups for docs
# dependencies, but RTD doesn't support them yet.
# "beeware_theme @ git+https://github.com/beeware/beeware-theme",
"furo == 2025.7.19",
"Pillow == 11.3.0",
"pyenchant == 3.2.2",
"sphinx == 8.2.3",
"sphinx_tabs == 3.4.5",
"sphinx-autobuild == 2024.10.3",
"sphinx-csv-filter == 0.4.2",
"sphinx-copybutton == 0.5.2",
"sphinx-toolbox == 4.0.0",
"sphinxcontrib-spelling == 8.0.1",
"beeware-docs-tools @ git+https://github.com/beeware/beeware-docs-tools",
"Pillow == 11.3.0", # Why is this part of the docs?
"black==25.1.0",
"markdown-checker==0.2.5",
"mistletoe==1.4.0",
"mkdocs-autorefs==1.4.2",
"mkdocs-include-markdown-plugin==7.1.6",
"mkdocs-literate-nav==0.6.2",
"mkdocs-macros-plugin==1.3.9",
"mkdocs-material==9.6.17",
"mkdocs-table-reader-plugin==3.1.0",
"mkdocs==1.6.1",
"mkdocstrings-python==1.16.12",
"pymdown-extensions==10.16.1",
"pyspelling==2.10",
"python-Levenshtein==0.27.1",
"PyYAML==6.0.2",
"setuptools-scm==9.2.0",
"translate-toolkit @ git+https://github.com/translate/translate@aa35159f03f53aa536381643dfafbc2a19a24784",
]

[project.urls]
Expand Down
62 changes: 46 additions & 16 deletions core/src/toga/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,43 +25,73 @@
BytesLikeT: TypeAlias = bytes | bytearray | memoryview
ImageLikeT: TypeAlias = Any
ImageContentT: TypeAlias = PathLikeT | BytesLikeT | ImageLikeT
"""
When specifying content for an [`toga.Image`][],
you can provide:

- a string specifying an absolute or relative path to a file in a
[known image format][known-image-formats];
- an absolute or relative [`pathlib.Path`][] object describing a file in a
[known image format][known-image-formats];
- a "blob of bytes" data type ([`bytes`][],
[`bytearray`][], or
[`memoryview`][]) containing raw image
data in a
[known image format][known-image-formats];
- an instance of [toga.Image][];
- if [Pillow](https://pillow.readthedocs.io/) is installed, an
instance of [`PIL.Image.Image`][];
- an image of a class registered via an
[image format plugin][image-format-plugins]
(or a subclass of such a class); or
- an instance of the
[native platform image representation][native-image-rep].

If a relative path is provided, it will be anchored relative to the
module that defines your Toga application class.
"""

# Define a type variable representing an image of an externally defined type.
ExternalImageT = TypeVar("ExternalImageT")


class ImageConverter(Protocol):
"""A class to convert between an externally defined image type and
:any:`toga.Image`.
[`toga.Image`][].
"""

#: The base image class this plugin can interpret.
image_class: type[ExternalImageT]
"""The base image class this plugin can interpret."""

@staticmethod
def convert_from_format(image_in_format: ExternalImageT) -> BytesLikeT:
"""Convert from :any:`image_class` to data in a :ref:`known image format
<known-image-formats>`.
"""Convert from [`image_class`][toga.images.ImageConverter.image_class] to
data in a [known image format][known-image-formats].

Will accept an instance of :any:`image_class`, or subclass of that class.
Will accept an instance of
[`image_class`][toga.images.ImageConverter.image_class],
or subclass of that class.

:param image_in_format: An instance of :any:`image_class` (or a subclass).
:returns: The image data, in a :ref:`known image format <known-image-formats>`.
:param image_in_format: An instance of
[`image_class`][toga.images.ImageConverter.image_class] (or a subclass).
:returns: The image data, in a [known image format][known-image-formats].
"""

@staticmethod
def convert_to_format(
data: BytesLikeT,
image_class: type[ExternalImageT],
) -> ExternalImageT:
"""Convert from data to :any:`image_class` or specified subclass.
"""Convert from data to [`image_class`][toga.images.ImageConverter.image_class]
or specified subclass.

Accepts a bytes-like object representing the image in a
:ref:`known image format <known-image-formats>`, and returns an instance of the
[known image format][known-image-formats], and returns an instance of the
image class specified. This image class is guaranteed to be either the
:any:`image_class` registered by the plugin, or a subclass of that class.
[`image_class`][toga.images.ImageConverter.image_class] registered by the
plugin, or a subclass of that class.

:param data: Image data in a :ref:`known image format <known-image-formats>`.
:param data: Image data in a [known image format][known-image-formats].
:param image_class: The class of image to return.
:returns: The image, as an instance of the image class specified.
"""
Expand All @@ -81,7 +111,7 @@ def __init__(
"""Create a new image.

:param src: The source from which to load the image. Can be any valid
:any:`image content <ImageContentT>` type.
[`ImageContentT`][toga.images.ImageContentT] type.
:param path: **DEPRECATED** - Use ``src``.
:param data: **DEPRECATED** - Use ``src``.
:raises FileNotFoundError: If a path is provided, but that path does not exist.
Expand Down Expand Up @@ -197,10 +227,10 @@ def save(self, path: str | Path) -> None:
def as_format(self, format: type[ImageT]) -> ImageT:
"""Return the image, converted to the image format specified.

:param format: Format to provide. Defaults to :class:`~toga.images.Image`; also
supports :any:`PIL.Image.Image` if Pillow is installed, as well as any
image types defined by installed :doc:`image format plugins
</reference/plugins/image_formats>`.
:param format: Format to provide. Defaults to [`Image`][toga.images.Image]; also
supports [`PIL.Image.Image`][] if Pillow is installed, as well as any
image types defined by installed
[image format plugin][image-format-plugins].
:returns: The image in the requested format
:raises TypeError: If the format supplied is not recognized.
"""
Expand Down
Loading
Loading