Skip to content

Commit

Permalink
Merge branch 'main' into cascading-windows
Browse files Browse the repository at this point in the history
  • Loading branch information
freakboy3742 committed Jun 12, 2024
2 parents 28174c2 + cd7ca2f commit c4014ba
Show file tree
Hide file tree
Showing 66 changed files with 168 additions and 118 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ jobs:
merge-multiple: true

- name: Generate Coverage Report
run: tox -e coverage-html-fail
run: tox -e coverage-html-fail-platform

- name: Upload HTML Coverage Report
uses: actions/[email protected]
Expand Down Expand Up @@ -304,7 +304,7 @@ jobs:
timeout-minutes: 15
run: |
${{ matrix.briefcase-run-prefix }} \
briefcase run ${{ matrix.platform }} --test ${{ matrix.briefcase-run-args }}
briefcase run ${{ matrix.platform }} --log --test ${{ matrix.briefcase-run-args }}
- name: Upload Logs
uses: actions/[email protected]
Expand Down
2 changes: 1 addition & 1 deletion android/src/toga_android/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,9 @@ def create(self):
# The `_listener` listens for activity event callbacks. For simplicity,
# the app's `.native` is the listener's native Java class.
self._listener = TogaApp(self)

# Call user code to populate the main window
self.interface._startup()
self.create_app_commands()

######################################################################
# Commands and menus
Expand Down
1 change: 0 additions & 1 deletion changes/2252.feature.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2301.feature.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2307.feature.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2325.bugfix.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2388.feature.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2446.bugfix.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2454.feature.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2565.doc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2566.doc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2567.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2568.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2569.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2570.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2571.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2576.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2577.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2578.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2579.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2580.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2583.bugfix.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2588.doc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2589.bugfix.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2593.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2600.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2601.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2602.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2604.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2605.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2606.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2614.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2617.doc.rst

This file was deleted.

1 change: 1 addition & 0 deletions changes/2619.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The order of creation of system-level commands is now consistent between platforms, and menu creation is deferred until the user's startup method has been invoked.
1 change: 0 additions & 1 deletion changes/2621.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2625.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2626.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2627.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2629.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2631.misc.rst

This file was deleted.

1 change: 0 additions & 1 deletion changes/2632.misc.rst

This file was deleted.

1 change: 1 addition & 0 deletions changes/2635.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The testbed app always creates a Briefcase logfile in CI now.
1 change: 1 addition & 0 deletions changes/2638.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The type of SplitContainer's content was modified to be a list, rather than a tuple.
1 change: 1 addition & 0 deletions changes/2640.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support for conditional coverage based on the Python version was added for unit testing.
10 changes: 3 additions & 7 deletions cocoa/src/toga_cocoa/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,13 @@ def create(self):
self.appDelegate.native = self.native
self.native.setDelegate_(self.appDelegate)

self.create_app_commands()
# Create the lookup table for menu items
self._menu_groups = {}
self._menu_items = {}

# Call user code to populate the main window
self.interface._startup()

# Create the lookup table of menu items,
# then force the creation of the menus.
self._menu_groups = {}
self._menu_items = {}
self.create_menus()

######################################################################
# Commands and menus
######################################################################
Expand Down
1 change: 1 addition & 0 deletions core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ dependencies = [
# ensure environment consistency.
dev = [
"coverage[toml] == 7.5.3",
"coverage-conditional-plugin == 0.9.0",
"Pillow == 10.3.0",
# Pre-commit 3.6.0 deprecated support for Python 3.8
"pre-commit == 3.5.0 ; python_version < '3.9'",
Expand Down
5 changes: 4 additions & 1 deletion core/src/toga/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,10 @@ def _package_version(file: Path | str | None, name: str) -> str:
# Excluded from coverage because a pure test environment (such as the one
# used by tox in CI) won't have setuptools_scm
return get_version(root="../../..", relative_to=file) # pragma: no cover
except (ModuleNotFoundError, LookupError):
except (
ModuleNotFoundError,
LookupError,
): # pragma: no-cover-if-missing-setuptools_scm
# If setuptools_scm isn't in the environment, the call to import will fail.
# If it *is* in the environment, but the code isn't a git checkout (e.g.,
# it's been pip installed non-editable) the call to get_version() will fail.
Expand Down
14 changes: 11 additions & 3 deletions core/src/toga/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,11 +484,9 @@ def __init__(

self._full_screen_windows: tuple[Window, ...] | None = None

# Create the implementation. This will trigger any startup logic.
self._create_impl()

# Now that we have an impl, set the on_change handler for commands
self.commands.on_change = self._impl.create_menus

def _create_impl(self) -> None:
self.factory.App(interface=self)

Expand Down Expand Up @@ -636,11 +634,21 @@ def _verify_startup(self) -> None:
)

def _startup(self) -> None:
# App commands are created before the startup method so that the user's
# code has the opportunity to remove/change the default commands.
self._impl.create_app_commands()

# This is a wrapper around the user's startup method that performs any
# post-setup validation.
self.startup()
self._verify_startup()

# Manifest the initial state of the menus.
self._impl.create_menus()

# Now that we have a finalized impl, set the on_change handler for commands
self.commands.on_change = self._impl.create_menus

def startup(self) -> None:
"""Create and show the main window for the application.
Expand Down
4 changes: 2 additions & 2 deletions core/src/toga/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
import toga
from toga.platform import get_platform_factory

if sys.version_info >= (3, 10):
if sys.version_info >= (3, 10): # pragma: no-cover-if-lt-py310
from importlib.metadata import entry_points
else:
else: # pragma: no-cover-if-gte-py310
# Before Python 3.10, entry_points did not support the group argument;
# so, the backport package must be used on older versions.
from importlib_metadata import entry_points
Expand Down
4 changes: 2 additions & 2 deletions core/src/toga/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
from functools import lru_cache
from types import ModuleType

if sys.version_info >= (3, 10): # pragma: no cover
if sys.version_info >= (3, 10): # pragma: no-cover-if-lt-py310
from importlib.metadata import entry_points
else: # pragma: no cover
else: # pragma: no-cover-if-gte-py310
# Before Python 3.10, entry_points did not support the group argument;
# so, the backport package must be used on older versions.
from importlib_metadata import entry_points
Expand Down
4 changes: 2 additions & 2 deletions core/src/toga/plugins/image_formats.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
try:
import PIL.Image

PIL_imported = True
PIL_imported = True # pragma: no-cover-if-missing-PIL

except ImportError: # pragma: no cover
except ImportError: # pragma: no-cover-if-PIL-installed
PIL_imported = False


Expand Down
21 changes: 9 additions & 12 deletions core/src/toga/widgets/splitcontainer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import sys
from collections.abc import Sequence
from typing import TYPE_CHECKING

from toga.app import App
Expand All @@ -27,7 +28,7 @@ def __init__(
id: str | None = None,
style: StyleT | None = None,
direction: Direction = Direction.VERTICAL,
content: tuple[SplitContainerContentT, SplitContainerContentT] = (None, None),
content: Sequence[SplitContainerContentT] | None = None,
):
"""Create a new SplitContainer.

Expand All @@ -42,15 +43,13 @@ def __init__(
of the container. Defaults to both panels being empty.
"""
super().__init__(id=id, style=style)
self._content: tuple[SplitContainerContentT, SplitContainerContentT] = (
None,
None,
)
self._content: list[SplitContainerContentT] = [None, None]

# Create a platform specific implementation of a SplitContainer
self._impl = self.factory.SplitContainer(interface=self)

self.content = content
if content:
self.content = content
self.direction = direction

@property
Expand All @@ -71,7 +70,7 @@ def focus(self) -> None:
pass

@property
def content(self) -> tuple[SplitContainerContentT, SplitContainerContentT]:
def content(self) -> list[SplitContainerContentT]:
"""The widgets displayed in the SplitContainer.

This property accepts a sequence of exactly 2 elements, each of which can be
Expand All @@ -89,9 +88,7 @@ def content(self) -> tuple[SplitContainerContentT, SplitContainerContentT]:
return self._content

@content.setter
def content(
self, content: tuple[SplitContainerContentT, SplitContainerContentT]
) -> None:
def content(self, content: Sequence[SplitContainerContentT]) -> None:
try:
if len(content) != 2:
raise TypeError()
Expand Down Expand Up @@ -128,10 +125,10 @@ def content(
widget.window = self.window

self._impl.set_content(
tuple(w._impl if w is not None else None for w in _content),
list(w._impl if w is not None else None for w in _content),
flex,
)
self._content = tuple(_content)
self._content = list(_content)
self.refresh()

@Widget.app.setter
Expand Down
24 changes: 23 additions & 1 deletion core/tests/app/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -459,14 +459,25 @@ def test_show_hide_cursor(app):

def test_startup_method(event_loop):
"""If an app provides a startup method, it will be invoked during startup."""
startup = Mock()

def startup_assertions(app):
# At time startup is invoked, there should be an app command installed
assert len(app.commands) == 1
return toga.Box()

startup = Mock(side_effect=startup_assertions)

app = toga.App(
formal_name="Test App",
app_id="org.example.test",
startup=startup,
)

assert_action_performed(app, "create App commands")
startup.assert_called_once_with(app)
assert_action_performed(app, "create App menus")
# There is only 1 menu item - the app command
assert app._impl.n_menu_items == 1


def test_startup_subclass(event_loop):
Expand All @@ -476,11 +487,22 @@ class SubclassedApp(toga.App):
def startup(self):
self.main_window = toga.MainWindow()

# At time startup is invoked, there should be an app command installed
assert len(self.commands) == 1

# Add an extra user command
self.commands.add(toga.Command(None, "User command"))

app = SubclassedApp(formal_name="Test App", app_id="org.example.test")

# The main window will exist, and will have the app's formal name.
assert app.main_window.title == "Test App"

assert_action_performed(app, "create App commands")
assert_action_performed(app, "create App menus")
# 2 menu items have been created
assert app._impl.n_menu_items == 2


def test_startup_subclass_no_main_window(event_loop):
"""If a subclassed app doesn't define a main window, an error is raised."""
Expand Down
6 changes: 6 additions & 0 deletions core/tests/command/test_commandset.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ def test_create_with_values():
@pytest.mark.parametrize("change_handler", [(None), (Mock())])
def test_add_clear(app, change_handler):
"""Commands can be added and removed from a commandset."""
# Make sure the app commands are clear to start with.
app.commands.clear()

# Put some commands into the app
cmd_a = toga.Command(None, text="App command a")
cmd_b = toga.Command(None, text="App command b", order=10)
Expand Down Expand Up @@ -68,6 +71,9 @@ def test_add_clear(app, change_handler):
@pytest.mark.parametrize("change_handler", [(None), (Mock())])
def test_add_clear_with_app(app, change_handler):
"""Commands can be added and removed from a commandset that is linked to an app."""
# Make sure the app commands are clear to start with.
app.commands.clear()

# Put some commands into the app
cmd_a = toga.Command(None, text="App command a")
cmd_b = toga.Command(None, text="App command b", order=10)
Expand Down
Loading

0 comments on commit c4014ba

Please sign in to comment.