diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f4340bcbea..27f06ecbc2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,7 +95,7 @@ jobs: TOGA_INSTALL_COMMAND="python -m pip install ../$(ls core/dist/toga_core-*.whl)[dev] ../$(ls dummy/dist/toga_dummy-*.whl)" tox -e py mv core/.coverage core/.coverage.${{ matrix.platform }}.${{ matrix.python-version }} - name: Store coverage data - uses: actions/upload-artifact@v4.1.0 + uses: actions/upload-artifact@v4.3.0 with: name: core-coverage-data-${{ matrix.platform }}-${{ matrix.python-version }} path: "core/.coverage.*" @@ -131,7 +131,7 @@ jobs: python -m coverage html --skip-covered --skip-empty python -m coverage report --rcfile ../pyproject.toml --fail-under=100 - name: Upload HTML report if check failed. - uses: actions/upload-artifact@v4.1.0 + uses: actions/upload-artifact@v4.3.0 if: failure() with: name: html-coverage-report @@ -232,7 +232,7 @@ jobs: run: ${{ matrix.briefcase-run-prefix }} briefcase run ${{ matrix.backend }} --test ${{ matrix.briefcase-run-args }} - name: Upload logs - uses: actions/upload-artifact@v4.1.0 + uses: actions/upload-artifact@v4.3.0 if: failure() with: name: testbed-failure-logs-${{ matrix.backend }} @@ -245,7 +245,7 @@ jobs: cp -r "${{ matrix.app-user-data-path }}" testbed/app_data/testbed-app_data-${{ matrix.backend }} - name: Upload app data - uses: actions/upload-artifact@v4.1.0 + uses: actions/upload-artifact@v4.3.0 if: failure() && matrix.backend != 'android' with: name: testbed-failure-app-data-${{ matrix.backend }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 431c20c303..6a95e18eb4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -19,7 +19,7 @@ repos: hooks: - id: isort - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.12.1 + rev: 24.1.1 hooks: - id: black language_version: python3 diff --git a/android/src/toga_android/widgets/base.py b/android/src/toga_android/widgets/base.py index 5acba9a5fb..90a05849d4 100644 --- a/android/src/toga_android/widgets/base.py +++ b/android/src/toga_android/widgets/base.py @@ -68,8 +68,7 @@ def __init__(self, interface): self.interface.style.reapply() @abstractmethod - def create(self): - ... + def create(self): ... def set_app(self, app): pass diff --git a/changes/2211.bugfix.rst b/changes/2211.bugfix.rst new file mode 100644 index 0000000000..dd26dd9947 --- /dev/null +++ b/changes/2211.bugfix.rst @@ -0,0 +1 @@ +`App.current_window` on Gtk now returns `None` when all windows are hidden. diff --git a/changes/2355.bugfix.rst b/changes/2355.bugfix.rst new file mode 100644 index 0000000000..b64e85021f --- /dev/null +++ b/changes/2355.bugfix.rst @@ -0,0 +1 @@ +On macOS, `toga.Image()` objects can now be created from raw data that didn't originate from a file. diff --git a/changes/2357.misc.rst b/changes/2357.misc.rst new file mode 100644 index 0000000000..b5895459bd --- /dev/null +++ b/changes/2357.misc.rst @@ -0,0 +1 @@ +Updated actions/upload-artifact from 4.1.0 to 4.2.0. diff --git a/changes/2358.misc.rst b/changes/2358.misc.rst new file mode 100644 index 0000000000..e159c5ff74 --- /dev/null +++ b/changes/2358.misc.rst @@ -0,0 +1 @@ +Updated tox from 4.12.0 to 4.12.1 in /core. diff --git a/changes/2359.misc.rst b/changes/2359.misc.rst new file mode 100644 index 0000000000..85d291fdcb --- /dev/null +++ b/changes/2359.misc.rst @@ -0,0 +1 @@ +Updated sphinx-tabs from 3.4.4 to 3.4.5 in /core. diff --git a/changes/2367.misc.rst b/changes/2367.misc.rst new file mode 100644 index 0000000000..b1398828d0 --- /dev/null +++ b/changes/2367.misc.rst @@ -0,0 +1 @@ +Updated actions/upload-artifact from 4.2.0 to 4.3.0. diff --git a/changes/2368.misc.rst b/changes/2368.misc.rst new file mode 100644 index 0000000000..bd8bb5d7c4 --- /dev/null +++ b/changes/2368.misc.rst @@ -0,0 +1 @@ +The ``pre-commit`` hook for ``black-pre-commit-mirror`` was updated to its latest version. diff --git a/changes/2369.misc.rst b/changes/2369.misc.rst new file mode 100644 index 0000000000..39c36e17c2 --- /dev/null +++ b/changes/2369.misc.rst @@ -0,0 +1 @@ +Updated coverage[toml] from 7.4.0 to 7.4.1 in /core. diff --git a/changes/2370.misc.rst b/changes/2370.misc.rst new file mode 100644 index 0000000000..b7ec5b6c2d --- /dev/null +++ b/changes/2370.misc.rst @@ -0,0 +1 @@ +Updated pytest-asyncio from 0.23.3 to 0.23.4 in /core. diff --git a/changes/2371.misc.rst b/changes/2371.misc.rst new file mode 100644 index 0000000000..34a2ed0614 --- /dev/null +++ b/changes/2371.misc.rst @@ -0,0 +1 @@ +Updated sphinx-autodoc-typehints from 1.25.2 to 1.25.3 in /core. diff --git a/cocoa/src/toga_cocoa/images.py b/cocoa/src/toga_cocoa/images.py index 034f5ba581..901d426d40 100644 --- a/cocoa/src/toga_cocoa/images.py +++ b/cocoa/src/toga_cocoa/images.py @@ -55,13 +55,14 @@ def get_height(self): return self.native.size.height def get_data(self): - return nsdata_to_bytes( - NSBitmapImageRep.representationOfImageRepsInArray( - self.native.representations, - usingType=NSBitmapImageFileType.PNG, - properties=None, - ) + # A file created from a data source won't necessarily have a pre-existing PNG + # representation. Create a TIFF representation, then convert to PNG. + bitmap_rep = NSBitmapImageRep.imageRepWithData(self.native.TIFFRepresentation) + image_data = bitmap_rep.representationUsingType( + NSBitmapImageFileType.PNG, + properties=None, ) + return nsdata_to_bytes(image_data) def save(self, path): path = Path(path) diff --git a/cocoa/src/toga_cocoa/widgets/base.py b/cocoa/src/toga_cocoa/widgets/base.py index e400af7b41..28da6271fb 100644 --- a/cocoa/src/toga_cocoa/widgets/base.py +++ b/cocoa/src/toga_cocoa/widgets/base.py @@ -17,8 +17,7 @@ def __init__(self, interface): self.interface.style.reapply() @abstractmethod - def create(self): - ... + def create(self): ... def set_app(self, app): pass @@ -116,5 +115,4 @@ def refresh(self): self.rehint() @abstractmethod - def rehint(self): - ... + def rehint(self): ... diff --git a/core/pyproject.toml b/core/pyproject.toml index 63c1fcd3dc..2de35e4286 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -65,16 +65,16 @@ dependencies = [ # Extras used by developers *of* briefcase are pinned to specific versions to # ensure environment consistency. dev = [ - "coverage[toml] == 7.4.0", + "coverage[toml] == 7.4.1", "Pillow == 10.2.0", # Pre-commit 3.6.0 deprecated support for Python 3.8 "pre-commit == 3.5.0 ; python_version < '3.9'", "pre-commit == 3.6.0 ; python_version >= '3.9'", "pytest == 7.4.4", - "pytest-asyncio == 0.23.3", + "pytest-asyncio == 0.23.4", "pytest-freezer == 0.4.8", "setuptools-scm == 8.0.4", - "tox == 4.12.0", + "tox == 4.12.1", # typing-extensions needed for TypeAlias added in Py 3.10 "typing-extensions == 4.9.0 ; python_version < '3.10'" ] @@ -85,9 +85,9 @@ docs = [ # Sphinx 7.2 deprecated support for Python 3.8 "sphinx == 7.1.2 ; python_version < '3.9'", "sphinx == 7.2.6 ; python_version >= '3.9'", - "sphinx_tabs == 3.4.4", + "sphinx_tabs == 3.4.5", "sphinx-autobuild == 2021.3.14", - "sphinx-autodoc-typehints == 1.25.2", + "sphinx-autodoc-typehints == 1.25.3", "sphinx-csv-filter == 0.4.1", "sphinx-copybutton == 0.5.2", "sphinx-toolbox == 3.5.0", diff --git a/core/src/toga/widgets/canvas.py b/core/src/toga/widgets/canvas.py index fea640b2d3..8af764942c 100644 --- a/core/src/toga/widgets/canvas.py +++ b/core/src/toga/widgets/canvas.py @@ -58,8 +58,7 @@ def __repr__(self): return f"{self.__class__.__name__}()" @abstractmethod - def _draw(self, impl, **kwargs): - ... + def _draw(self, impl, **kwargs): ... class BeginPath(DrawingObject): diff --git a/core/src/toga/widgets/optioncontainer.py b/core/src/toga/widgets/optioncontainer.py index ba3e9fa35a..601be4cada 100644 --- a/core/src/toga/widgets/optioncontainer.py +++ b/core/src/toga/widgets/optioncontainer.py @@ -270,8 +270,7 @@ def index(self, value: str | int | OptionItem): def append( self, text_or_item: OptionItem, - ): - ... + ): ... @overload def append( @@ -281,8 +280,7 @@ def append( *, icon: IconContent | None = None, enabled: bool = True, - ): - ... + ): ... def append( self, @@ -311,8 +309,7 @@ def insert( self, index: int | str | OptionItem, text_or_item: OptionItem, - ): - ... + ): ... @overload def insert( @@ -323,8 +320,7 @@ def insert( *, icon: IconContent | None = None, enabled: bool = True, - ): - ... + ): ... def insert( self, diff --git a/core/src/toga/widgets/slider.py b/core/src/toga/widgets/slider.py index 28d129af8d..98e559483f 100644 --- a/core/src/toga/widgets/slider.py +++ b/core/src/toga/widgets/slider.py @@ -318,36 +318,28 @@ def range(self, range): class SliderImpl(ABC): @abstractmethod - def get_value(self): - ... + def get_value(self): ... @abstractmethod - def set_value(self, value): - ... + def set_value(self, value): ... @abstractmethod - def get_min(self): - ... + def get_min(self): ... @abstractmethod - def set_min(self, value): - ... + def set_min(self, value): ... @abstractmethod - def get_max(self): - ... + def get_max(self): ... @abstractmethod - def set_max(self, value): - ... + def set_max(self, value): ... @abstractmethod - def get_tick_count(self): - ... + def get_tick_count(self): ... @abstractmethod - def set_tick_count(self, tick_count): - ... + def set_tick_count(self, tick_count): ... class IntSliderImpl(SliderImpl): @@ -407,21 +399,16 @@ def on_change(self): self.interface.on_change() @abstractmethod - def get_int_value(self): - ... + def get_int_value(self): ... @abstractmethod - def set_int_value(self, value): - ... + def set_int_value(self, value): ... @abstractmethod - def get_int_max(self): - ... + def get_int_max(self): ... @abstractmethod - def set_int_max(self, max): - ... + def set_int_max(self, max): ... @abstractmethod - def set_ticks_visible(self, visible): - ... + def set_ticks_visible(self, visible): ... diff --git a/core/src/toga/window.py b/core/src/toga/window.py index bfd6057f91..2304b5f45e 100644 --- a/core/src/toga/window.py +++ b/core/src/toga/window.py @@ -516,8 +516,7 @@ def stack_trace_dialog( content: str, retry: Literal[False] = False, on_result: DialogResultHandler[None] | None = None, - ) -> Dialog: - ... + ) -> Dialog: ... @overload def stack_trace_dialog( @@ -527,8 +526,7 @@ def stack_trace_dialog( content: str, retry: Literal[True] = False, on_result: DialogResultHandler[bool] | None = None, - ) -> Dialog: - ... + ) -> Dialog: ... @overload def stack_trace_dialog( @@ -538,8 +536,7 @@ def stack_trace_dialog( content: str, retry: bool = False, on_result: DialogResultHandler[bool | None] | None = None, - ) -> Dialog: - ... + ) -> Dialog: ... def stack_trace_dialog( self, @@ -632,8 +629,7 @@ def open_file_dialog( multiple_select: Literal[False] = False, on_result: DialogResultHandler[Path | None] | None = None, multiselect=None, # DEPRECATED - ) -> Dialog: - ... + ) -> Dialog: ... @overload def open_file_dialog( @@ -644,8 +640,7 @@ def open_file_dialog( multiple_select: Literal[True] = True, on_result: DialogResultHandler[list[Path] | None] | None = None, multiselect=None, # DEPRECATED - ) -> Dialog: - ... + ) -> Dialog: ... @overload def open_file_dialog( @@ -656,8 +651,7 @@ def open_file_dialog( multiple_select: bool = False, on_result: DialogResultHandler[list[Path] | Path | None] | None = None, multiselect=None, # DEPRECATED - ) -> Dialog: - ... + ) -> Dialog: ... def open_file_dialog( self, @@ -724,8 +718,7 @@ def select_folder_dialog( multiple_select: Literal[False] = False, on_result: DialogResultHandler[Path | None] | None = None, multiselect=None, # DEPRECATED - ) -> Dialog: - ... + ) -> Dialog: ... @overload def select_folder_dialog( @@ -735,8 +728,7 @@ def select_folder_dialog( multiple_select: Literal[True] = True, on_result: DialogResultHandler[list[Path] | None] | None = None, multiselect=None, # DEPRECATED - ) -> Dialog: - ... + ) -> Dialog: ... @overload def select_folder_dialog( @@ -746,8 +738,7 @@ def select_folder_dialog( multiple_select: bool = False, on_result: DialogResultHandler[list[Path] | Path | None] | None = None, multiselect=None, # DEPRECATED - ) -> Dialog: - ... + ) -> Dialog: ... def select_folder_dialog( self, diff --git a/core/tests/widgets/test_progressbar.py b/core/tests/widgets/test_progressbar.py index b35287e3c0..9b82f80511 100644 --- a/core/tests/widgets/test_progressbar.py +++ b/core/tests/widgets/test_progressbar.py @@ -103,9 +103,11 @@ def test_set_max(progressbar, value, actual, determinate): ( object(), TypeError, - r"must be a string or a number" - if sys.version_info < (3, 10) - else r"must be a string or a real number", + ( + r"must be a string or a number" + if sys.version_info < (3, 10) + else r"must be a string or a real number" + ), ), # Non-coercible to float ( -42, diff --git a/examples/optioncontainer/optioncontainer/app.py b/examples/optioncontainer/optioncontainer/app.py index bc6de7add0..052c397b47 100644 --- a/examples/optioncontainer/optioncontainer/app.py +++ b/examples/optioncontainer/optioncontainer/app.py @@ -39,9 +39,9 @@ def on_insert_option(self, button): def on_enable_option(self, button): index = int(self.select_option.value) try: - self.optioncontainer.content[ - index - ].enabled = not self.optioncontainer.content[index].enabled + self.optioncontainer.content[index].enabled = ( + not self.optioncontainer.content[index].enabled + ) except ValueError as e: self.main_window.info_dialog("Oops", str(e)) diff --git a/examples/positron-django/src/webapp/urls.py b/examples/positron-django/src/webapp/urls.py index f8bd49391d..df2c234804 100644 --- a/examples/positron-django/src/webapp/urls.py +++ b/examples/positron-django/src/webapp/urls.py @@ -13,6 +13,7 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ + from django.contrib import admin from django.urls import path diff --git a/gtk/src/toga_gtk/app.py b/gtk/src/toga_gtk/app.py index 6b44181fac..d85db4e896 100644 --- a/gtk/src/toga_gtk/app.py +++ b/gtk/src/toga_gtk/app.py @@ -222,7 +222,8 @@ def exit(self): # pragma: no cover self.native.quit() def get_current_window(self): - return self.native.get_active_window()._impl + current_window = self.native.get_active_window()._impl + return current_window if current_window.interface.visible else None def set_current_window(self, window): window._impl.native.present() @@ -267,9 +268,9 @@ def gtk_startup(self, data=None): m.open_file_dialog( self.interface.formal_name, file_types=self.interface.document_types.keys(), - on_result=lambda dialog, path: self.interface._open(path) - if path - else self.exit(), + on_result=lambda dialog, path: ( + self.interface._open(path) if path else self.exit() + ), ) def open_file(self, widget, **kwargs): diff --git a/gtk/src/toga_gtk/widgets/base.py b/gtk/src/toga_gtk/widgets/base.py index 100a6075d8..d397d25eeb 100644 --- a/gtk/src/toga_gtk/widgets/base.py +++ b/gtk/src/toga_gtk/widgets/base.py @@ -28,8 +28,7 @@ def __init__(self, interface): self.interface.style.reapply() @abstractmethod - def create(self): - ... + def create(self): ... def set_app(self, app): pass diff --git a/gtk/src/toga_gtk/widgets/scrollcontainer.py b/gtk/src/toga_gtk/widgets/scrollcontainer.py index 914ab7087b..ce13d9fa29 100644 --- a/gtk/src/toga_gtk/widgets/scrollcontainer.py +++ b/gtk/src/toga_gtk/widgets/scrollcontainer.py @@ -47,9 +47,11 @@ def get_horizontal(self): def set_horizontal(self, value): self.native.set_policy( Gtk.PolicyType.AUTOMATIC if value else Gtk.PolicyType.NEVER, - Gtk.PolicyType.AUTOMATIC - if self.interface.vertical - else Gtk.PolicyType.NEVER, + ( + Gtk.PolicyType.AUTOMATIC + if self.interface.vertical + else Gtk.PolicyType.NEVER + ), ) # Disabling scrolling implies a position reset; that's a scroll event. if not value: @@ -61,9 +63,11 @@ def get_vertical(self): def set_vertical(self, value): self.native.set_policy( - Gtk.PolicyType.AUTOMATIC - if self.interface.horizontal - else Gtk.PolicyType.NEVER, + ( + Gtk.PolicyType.AUTOMATIC + if self.interface.horizontal + else Gtk.PolicyType.NEVER + ), Gtk.PolicyType.AUTOMATIC if value else Gtk.PolicyType.NEVER, ) # Disabling scrolling implies a position reset; that's a scroll event. diff --git a/iOS/src/toga_iOS/dialogs.py b/iOS/src/toga_iOS/dialogs.py index 137a1de1ce..caf15fa793 100644 --- a/iOS/src/toga_iOS/dialogs.py +++ b/iOS/src/toga_iOS/dialogs.py @@ -33,8 +33,7 @@ def __init__(self, interface, title, message): ) @abstractmethod - def populate_dialog(self, native): - ... + def populate_dialog(self, native): ... def response(self, value): self.interface.set_result(value) diff --git a/iOS/src/toga_iOS/widgets/base.py b/iOS/src/toga_iOS/widgets/base.py index c14513dfe4..59cb4f241b 100644 --- a/iOS/src/toga_iOS/widgets/base.py +++ b/iOS/src/toga_iOS/widgets/base.py @@ -17,8 +17,7 @@ def __init__(self, interface): self.interface.style.reapply() @abstractmethod - def create(self): - ... + def create(self): ... def set_app(self, app): pass @@ -123,5 +122,4 @@ def refresh(self): self.rehint() @abstractmethod - def rehint(self): - ... + def rehint(self): ... diff --git a/iOS/src/toga_iOS/widgets/detailedlist.py b/iOS/src/toga_iOS/widgets/detailedlist.py index 6212de3504..c124c65068 100644 --- a/iOS/src/toga_iOS/widgets/detailedlist.py +++ b/iOS/src/toga_iOS/widgets/detailedlist.py @@ -86,9 +86,11 @@ def tableView_trailingSwipeActionsConfigurationForRowAtIndexPath_( if self.impl.primary_action_enabled: actions = [ UIContextualAction.contextualActionWithStyle( - UIContextualActionStyle.Destructive - if self.interface._primary_action in self.impl.DESTRUCTIVE_NAMES - else UIContextualActionStyle.Normal, + ( + UIContextualActionStyle.Destructive + if self.interface._primary_action in self.impl.DESTRUCTIVE_NAMES + else UIContextualActionStyle.Normal + ), title=self.interface._primary_action, handler=self.impl.primary_action_handler(indexPath.row), ) @@ -105,9 +107,12 @@ def tableView_leadingSwipeActionsConfigurationForRowAtIndexPath_( if self.impl.secondary_action_enabled: actions = [ UIContextualAction.contextualActionWithStyle( - UIContextualActionStyle.Destructive - if self.interface._secondary_action in self.impl.DESTRUCTIVE_NAMES - else UIContextualActionStyle.Normal, + ( + UIContextualActionStyle.Destructive + if self.interface._secondary_action + in self.impl.DESTRUCTIVE_NAMES + else UIContextualActionStyle.Normal + ), title=self.interface._secondary_action, handler=self.impl.secondary_action_handler(indexPath.row), ) diff --git a/testbed/tests/test_images.py b/testbed/tests/test_images.py index a72ccf69ae..42a0f4cbc9 100644 --- a/testbed/tests/test_images.py +++ b/testbed/tests/test_images.py @@ -41,8 +41,8 @@ async def test_bad_image_file(app): toga.Image(__file__) -async def test_data_image(app): - "An image can be constructed from data" +async def test_buffer_image(app): + "An image can be constructed from buffer data" # Generate an image using pillow pil_image = PIL_Image.new("RGBA", size=(110, 30)) draw_context = PIL_ImageDraw.Draw(pil_image) @@ -51,17 +51,37 @@ async def test_data_image(app): buffer = io.BytesIO() pil_image.save(buffer, format="png", compress_level=0) - # Construct a Toga image. + # Construct a Toga image from buffer data. image = toga.Image(buffer.getvalue()) assert image.width == 110 assert image.height == 30 - # Construct a second image from the first image's data - image2 = toga.Image(image.data) - assert image2.width == 110 - assert image2.height == 30 +async def test_pil_raw_and_data_image(app): + "An image can be created from PIL, platform's raw representation and `toga.Image` data" + # Generate an image using pillow + pil_image = PIL_Image.new("RGBA", size=(110, 30)) + draw_context = PIL_ImageDraw.Draw(pil_image) + draw_context.text((20, 10), "Hello World", fill="green") + + # Construct a Toga image from PIL image + image_from_pil = toga.Image(pil_image) + + assert image_from_pil.width == 110 + assert image_from_pil.height == 30 + + # Construct a Toga image using the native image type + image_from_native = toga.Image(image_from_pil._impl.native) + + assert image_from_native.width == 110 + assert image_from_native.height == 30 + + # Construct an image from `image_from_native`'s data + image_from_data = toga.Image(image_from_native.data) + + assert image_from_data.width == 110 + assert image_from_data.height == 30 async def test_bad_image_data(app): diff --git a/testbed/tests/widgets/test_table.py b/testbed/tests/widgets/test_table.py index 10752e90a5..91e684268c 100644 --- a/testbed/tests/widgets/test_table.py +++ b/testbed/tests/widgets/test_table.py @@ -477,9 +477,11 @@ async def test_cell_widget(widget, probe): "a": f"A{i}", "b": f"B{i}", # Toga widgets. - "c": toga.Button(f"C{i}") - if i % 2 == 0 - else toga.TextInput(value=f"edit C{i}"), + "c": ( + toga.Button(f"C{i}") + if i % 2 == 0 + else toga.TextInput(value=f"edit C{i}") + ), } for i in range(0, 50) ] diff --git a/testbed/tests/widgets/test_tree.py b/testbed/tests/widgets/test_tree.py index 19555bc9bf..4899d9fa2c 100644 --- a/testbed/tests/widgets/test_tree.py +++ b/testbed/tests/widgets/test_tree.py @@ -660,9 +660,11 @@ async def test_cell_widget(widget, probe): "a": f"A{i}", "b": f"B{i}", # Toga widgets. - "c": toga.Button(f"C{i}") - if i % 2 == 0 - else toga.TextInput(value=f"edit C{i}"), + "c": ( + toga.Button(f"C{i}") + if i % 2 == 0 + else toga.TextInput(value=f"edit C{i}") + ), }, None, ) diff --git a/winforms/src/toga_winforms/widgets/base.py b/winforms/src/toga_winforms/widgets/base.py index c966dfd219..123c98f257 100644 --- a/winforms/src/toga_winforms/widgets/base.py +++ b/winforms/src/toga_winforms/widgets/base.py @@ -53,8 +53,7 @@ def __init__(self, interface): self.interface.style.reapply() @abstractmethod - def create(self): - ... + def create(self): ... def set_app(self, app): # No special handling required