From 8a6187c5ba9fede4b17aa325f54140073f61176c Mon Sep 17 00:00:00 2001 From: Marc Bradshaw Date: Mon, 25 Nov 2024 13:48:02 +1100 Subject: [PATCH 01/10] Update the flake8 line limit to 88 This makes it consistent with the limit set in Black. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 869afabd4b..847c4a8107 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ # Flake8 doesn't provide a pyproject configuration, but allows tox.ini [flake8] -max-line-length = 119 +max-line-length = 88 extend-ignore = # whitespace before : # See https://github.com/PyCQA/pycodestyle/issues/373 From b100ab0b28f863ebaba77157cc04803163c77fbe Mon Sep 17 00:00:00 2001 From: Marc Bradshaw Date: Mon, 25 Nov 2024 14:51:32 +1100 Subject: [PATCH 02/10] Reformat existing files so all lines are under 88 characters --- android/src/toga_android/app.py | 9 +- android/src/toga_android/keys.py | 3 +- android/src/toga_android/libs/events.py | 138 +++++++++++------- .../src/toga_android/widgets/detailedlist.py | 3 +- android/src/toga_android/widgets/imageview.py | 3 +- android/src/toga_android/widgets/label.py | 6 +- android/tests_backend/widgets/progressbar.py | 3 +- android/tests_backend/widgets/textinput.py | 3 +- cocoa/src/toga_cocoa/app.py | 4 +- cocoa/src/toga_cocoa/constraints.py | 10 +- cocoa/src/toga_cocoa/hardware/camera.py | 17 ++- .../toga_cocoa/widgets/internal/refresh.py | 11 +- cocoa/src/toga_cocoa/widgets/mapview.py | 10 +- cocoa/src/toga_cocoa/widgets/numberinput.py | 15 +- cocoa/src/toga_cocoa/widgets/table.py | 3 +- cocoa/src/toga_cocoa/widgets/textinput.py | 6 +- cocoa/src/toga_cocoa/widgets/tree.py | 9 +- cocoa/src/toga_cocoa/window.py | 3 +- cocoa/tests_backend/probe.py | 4 +- cocoa/tests_backend/widgets/base.py | 3 +- cocoa/tests_backend/widgets/mapview.py | 7 +- cocoa/tests_backend/widgets/numberinput.py | 3 +- cocoa/tests_backend/widgets/progressbar.py | 3 +- cocoa/tests_backend/widgets/textinput.py | 3 +- core/src/toga/app.py | 12 +- core/src/toga/documents.py | 16 +- core/src/toga/handlers.py | 3 +- core/src/toga/icons.py | 7 +- core/src/toga/images.py | 4 +- core/src/toga/platform.py | 9 +- core/src/toga/sources/base.py | 3 +- core/src/toga/sources/tree_source.py | 5 +- core/src/toga/style/pack.py | 10 +- core/src/toga/validators.py | 3 +- core/src/toga/widgets/base.py | 6 +- core/src/toga/widgets/button.py | 4 +- core/src/toga/widgets/canvas.py | 34 +++-- core/src/toga/widgets/detailedlist.py | 13 +- core/src/toga/widgets/multilinetextinput.py | 4 +- core/src/toga/widgets/optioncontainer.py | 3 +- core/src/toga/widgets/scrollcontainer.py | 3 +- core/src/toga/widgets/selection.py | 4 +- core/src/toga/widgets/slider.py | 21 +-- core/src/toga/widgets/switch.py | 4 +- core/src/toga/window.py | 21 ++- core/tests/app/test_app.py | 13 +- core/tests/app/test_document_app.py | 13 +- core/tests/command/test_command.py | 8 +- core/tests/command/test_group.py | 4 +- core/tests/hardware/test_location.py | 7 +- core/tests/sources/test_list_source.py | 3 +- core/tests/style/pack/test_css.py | 3 +- core/tests/style/pack/utils.py | 6 +- core/tests/test_handlers.py | 24 +-- core/tests/test_icons.py | 3 +- core/tests/test_paths.py | 15 +- core/tests/test_platform.py | 3 +- core/tests/widgets/canvas/test_canvas.py | 21 ++- .../widgets/canvas/test_context_objects.py | 6 +- .../widgets/canvas/test_draw_operations.py | 18 ++- core/tests/widgets/test_optioncontainer.py | 3 +- core/tests/widgets/test_scrollcontainer.py | 3 +- core/tests/widgets/test_slider.py | 4 +- core/tests/widgets/test_webview.py | 3 +- core/tests/window/test_document_window.py | 3 +- .../window/test_filtered_widget_registry.py | 6 +- core/tests/window/test_window.py | 51 ++++--- docs/conf.py | 6 +- examples/beeliza/beeliza/bot.py | 6 +- examples/hardware/hardware/app.py | 6 +- .../positron-django/src/webapp/settings.py | 3 +- examples/resize/resize/app.py | 4 +- examples/screenshot/screenshot/app.py | 10 +- examples/selection/selection/app.py | 3 +- examples/statusiconapp/statusiconapp/app.py | 6 +- examples/webview/webview/app.py | 6 +- gtk/src/toga_gtk/container.py | 14 +- gtk/src/toga_gtk/dialogs.py | 3 +- gtk/src/toga_gtk/icons.py | 8 +- gtk/src/toga_gtk/images.py | 3 +- gtk/src/toga_gtk/libs/fontconfig.py | 3 +- gtk/src/toga_gtk/libs/gtk.py | 3 +- gtk/src/toga_gtk/widgets/activityindicator.py | 3 +- gtk/src/toga_gtk/widgets/base.py | 3 +- gtk/src/toga_gtk/widgets/button.py | 3 +- gtk/src/toga_gtk/widgets/canvas.py | 3 +- gtk/src/toga_gtk/widgets/detailedlist.py | 13 +- gtk/src/toga_gtk/widgets/label.py | 3 +- gtk/src/toga_gtk/widgets/mapview.py | 9 +- gtk/src/toga_gtk/widgets/progressbar.py | 3 +- gtk/src/toga_gtk/widgets/scrollcontainer.py | 3 +- gtk/src/toga_gtk/widgets/slider.py | 3 +- gtk/src/toga_gtk/widgets/switch.py | 3 +- gtk/src/toga_gtk/widgets/textinput.py | 3 +- gtk/src/toga_gtk/widgets/webview.py | 7 +- gtk/src/toga_gtk/window.py | 6 +- gtk/tests_backend/app.py | 8 +- gtk/tests_backend/dialogs.py | 22 +-- gtk/tests_backend/widgets/switch.py | 3 +- gtk/tests_backend/window.py | 8 +- iOS/src/toga_iOS/constraints.py | 10 +- iOS/src/toga_iOS/dialogs.py | 2 +- iOS/src/toga_iOS/hardware/camera.py | 5 +- iOS/src/toga_iOS/hardware/location.py | 6 +- iOS/src/toga_iOS/libs/uikit.py | 3 +- iOS/src/toga_iOS/widgets/label.py | 3 +- iOS/src/toga_iOS/widgets/mapview.py | 10 +- iOS/src/toga_iOS/window.py | 6 +- iOS/tests_backend/widgets/detailedlist.py | 4 +- iOS/tests_backend/widgets/mapview.py | 3 +- iOS/tests_backend/widgets/optioncontainer.py | 3 +- iOS/tests_backend/widgets/switch.py | 3 +- testbed/src/testbed/app.py | 3 +- testbed/tests/app/test_document_app.py | 3 +- testbed/tests/conftest.py | 11 +- testbed/tests/hardware/test_camera.py | 6 +- testbed/tests/hardware/test_location.py | 3 +- testbed/tests/test_fonts.py | 3 +- testbed/tests/test_icons.py | 3 +- testbed/tests/test_images.py | 3 +- testbed/tests/test_statusicons.py | 3 +- testbed/tests/testbed.py | 7 +- testbed/tests/widgets/properties.py | 3 +- testbed/tests/widgets/test_canvas.py | 3 +- testbed/tests/widgets/test_imageview.py | 6 +- testbed/tests/widgets/test_slider.py | 4 +- testbed/tests/window/test_window.py | 15 +- textual/src/toga_textual/dialogs.py | 12 +- winforms/src/toga_winforms/fonts.py | 3 +- winforms/src/toga_winforms/widgets/mapview.py | 5 +- winforms/src/toga_winforms/widgets/table.py | 7 +- winforms/src/toga_winforms/widgets/webview.py | 3 +- winforms/tests_backend/app.py | 8 +- winforms/tests_backend/dialogs.py | 5 +- winforms/tests_backend/widgets/progressbar.py | 3 +- 135 files changed, 644 insertions(+), 414 deletions(-) diff --git a/android/src/toga_android/app.py b/android/src/toga_android/app.py index 1ca3257897..6abc65d76c 100644 --- a/android/src/toga_android/app.py +++ b/android/src/toga_android/app.py @@ -68,7 +68,8 @@ def onActivityResult(self, requestCode, resultCode, resultData): def onRequestPermissionsResult(self, requestCode, permissions, grantResults): print( - f"Toga app: onRequestPermissionsResult {requestCode=} {permissions=} {grantResults=}" + f"Toga app: onRequestPermissionsResult " + f"{requestCode=} {permissions=} {grantResults=}" ) try: # Retrieve the completion callback and invoke it. @@ -227,10 +228,12 @@ def exit(self): pass # pragma: no cover def main_loop(self): - # In order to support user asyncio code, start the Python/Android cooperative event loop. + # In order to support user asyncio code, start the Python/Android + # cooperative event loop. self.loop.run_forever_cooperatively() - # On Android, Toga UI integrates automatically into the main Android event loop by virtue + # On Android, Toga UI integrates automatically into the main Android event + # loop by virtue # of the Android Activity system. self.create() diff --git a/android/src/toga_android/keys.py b/android/src/toga_android/keys.py index 59e8cad444..71d60abd09 100644 --- a/android/src/toga_android/keys.py +++ b/android/src/toga_android/keys.py @@ -70,7 +70,8 @@ KeyEvent.KEYCODE_Y: Key.Y, KeyEvent.KEYCODE_Z: Key.Z, KeyEvent.KEYCODE_TAB: Key.TAB, - # KeyEvent.KEYCODE_LEFT_BRACKET: Key.OPEN_BRACKET,TODO Create handling for num row special keys + # KeyEvent.KEYCODE_LEFT_BRACKET: Key.OPEN_BRACKET, + # TODO Create handling for num row special keys # KeyEvent.KEYCODE_RIGHT_BRACKET: Key.CLOSE_BRACKET, # KeyEvent.KEYCODE_BACKSLASH: Key.BACKSLASH, # KeyEvent.KEY_braceleft: Key.OPEN_BRACE, diff --git a/android/src/toga_android/libs/events.py b/android/src/toga_android/libs/events.py index b553514a87..5eeaa95532 100644 --- a/android/src/toga_android/libs/events.py +++ b/android/src/toga_android/libs/events.py @@ -15,33 +15,38 @@ # Some methods in this file are based on CPython's implementation. # Per https://github.com/python/cpython/blob/master/LICENSE , re-use is permitted # via the Python Software Foundation License Version 2, which includes inclusion -# into this project under its BSD license terms so long as we retain this copyright notice: -# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, -# 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation; All Rights Reserved. +# into this project under its BSD license terms so long as we retain this copyright +# notice: +# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, +# 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation; +# All Rights Reserved. class AndroidEventLoop(asyncio.SelectorEventLoop): - # `AndroidEventLoop` exists to support starting the Python event loop cooperatively with - # the built-in Android event loop. Since it's cooperative, it has a `run_forever_cooperatively()` - # method which returns immediately. This is is different from the parent class's `run_forever()`, - # which blocks. + # `AndroidEventLoop` exists to support starting the Python event loop cooperatively + # with the built-in Android event loop. Since it's cooperative, + # it has a `run_forever_cooperatively()` method which returns immediately. + # This is is different from the parent class's `run_forever()`, which blocks. # - # In some cases, for simplicity of implementation, this class reaches into the internals of the - # parent and grandparent classes. + # In some cases, for simplicity of implementation, this class reaches into the + # internals of the parent and grandparent classes. # - # A Python event loop handles two kinds of tasks. It needs to run delayed tasks after waiting - # the right amount of time, and it needs to do I/O when file descriptors are ready for I/O. + # A Python event loop handles two kinds of tasks. It needs to run delayed tasks + # after waiting the right amount of time, and it needs to do I/O when file + # descriptors are ready for I/O. # - # `SelectorEventLoop` uses an approach we **cannot** use: it calls the `select()` method - # to block waiting for specific file descriptors to be come ready for I/O, or a timeout - # corresponding to the soonest delayed task, whichever occurs sooner. + # `SelectorEventLoop` uses an approach we **cannot** use: it calls the `select()` + # method to block waiting for specific file descriptors to be come ready for I/O, + # or a timeout corresponding to the soonest delayed task, whichever occurs sooner. # - # To handle delayed tasks, `AndroidEventLoop` asks the Android event loop to wake it up when - # its soonest delayed task is ready. To accomplish this, it relies on a `SelectorEventLoop` - # implementation detail: `_scheduled` is a collection of tasks sorted by soonest wakeup time. + # To handle delayed tasks, `AndroidEventLoop` asks the Android event loop to wake + # it up when its soonest delayed task is ready. To accomplish this, + # it relies on a `SelectorEventLoop` implementation detail: `_scheduled` is a + # collection of tasks sorted by soonest wakeup time. # - # To handle waking up when it's possible to do I/O, `AndroidEventLoop` will register file descriptors - # with the Android event loop so the platform can wake it up accordingly. It does not do this yet. + # To handle waking up when it's possible to do I/O, `AndroidEventLoop` will + # register file descriptors with the Android event loop so the platform can wake it + # up accordingly. It does not do this yet. def __init__(self): # Tell the parent constructor to use our custom Selector. selector = AndroidSelector(self) @@ -49,22 +54,24 @@ def __init__(self): # Create placeholders for lazily-created objects. self.android_interop = AndroidInterop() - # Override parent `_call_soon()` to ensure Android wakes us up to do the delayed task. + # Override parent `_call_soon()` to ensure Android wakes us up to do the delayed + # task. def _call_soon(self, callback, args, context): ret = super()._call_soon(callback, args, context) self.enqueue_android_wakeup_for_delayed_tasks() return ret - # Override parent `_add_callback()` to ensure Android wakes us up to do the delayed task. + # Override parent `_add_callback()` to ensure Android wakes us up to do the delayed + # task. def _add_callback(self, handle): ret = super()._add_callback(handle) self.enqueue_android_wakeup_for_delayed_tasks() return ret def run_forever_cooperatively(self): - """Configure the event loop so it is started, doing as little work as possible to - ensure that. Most Android interop objects are created lazily so that the cost of - event loop interop is not paid by apps that don't use the event loop.""" + """Configure the event loop so it is started, doing as little work as possible + to ensure that. Most Android interop objects are created lazily so that the cost + of event loop interop is not paid by apps that don't use the event loop.""" # Based on `BaseEventLoop.run_forever()` in CPython. if self.is_running(): raise RuntimeError( @@ -114,20 +121,23 @@ def enqueue_android_wakeup_for_delayed_tasks(self): return # Ask Android to wake us up to run delayed tasks. Running delayed tasks also - # checks for other tasks that require wakeup by calling this method. The fact that - # running delayed tasks can trigger the next wakeup is what makes this event loop a "loop." + # checks for other tasks that require wakeup by calling this method. The fact + # that running delayed tasks can trigger the next wakeup is what makes this + # event loop a "loop." self.android_interop.call_later(self.run_delayed_tasks, timeout * 1000) def _set_coroutine_origin_tracking(self, debug): - # If running on Python 3.7 or 3.8, integrate with upstream event loop's debug feature, allowing - # unawaited coroutines to have some useful info logged. See https://bugs.python.org/issue32591 + # If running on Python 3.7 or 3.8, integrate with upstream event loop's debug + # feature, allowing unawaited coroutines to have some useful info logged. + # See https://bugs.python.org/issue32591 if hasattr(super(), "_set_coroutine_origin_tracking"): # pragma: no cover super()._set_coroutine_origin_tracking(debug) def _get_next_delayed_task_wakeup(self): - """Compute the time to sleep before we should be woken up to handle delayed tasks.""" - # This is based heavily on the CPython's implementation of `BaseEventLoop._run_once()` - # before it blocks on `select()`. + """Compute the time to sleep before we should be woken up + to handle delayed tasks.""" + # This is based heavily on the CPython's implementation of + # `BaseEventLoop._run_once()` before it blocks on `select()`. _MIN_SCHEDULED_TIMER_HANDLES = 100 _MIN_CANCELLED_TIMER_HANDLES_FRACTION = 0.5 MAXIMUM_SELECT_TIMEOUT = 24 * 3600 @@ -174,8 +184,8 @@ def run_delayed_tasks(self): check if there are more delayed tasks to execute in the future; if so, schedule the next wakeup. """ - # Based heavily on `BaseEventLoop._run_once()` from CPython -- specifically, the part - # after blocking on `select()`. + # Based heavily on `BaseEventLoop._run_once()` from CPython -- specifically, + # the part after blocking on `select()`. # Handle 'later' callbacks that are ready. end_time = self.time() + self._clock_resolution while self._scheduled: @@ -223,9 +233,10 @@ class AndroidInterop: """Encapsulate details of Android event loop cooperation.""" def __init__(self): - # `_runnable_by_fn` is a one-to-one mapping from Python callables to Java Runnables. - # This allows us to avoid creating more than one Java object per Python callable, which - # would prevent removeCallbacks from working. + # `_runnable_by_fn` is a one-to-one mapping from Python callables to + # Java Runnables. + # This allows us to avoid creating more than one Java object per Python + # callable, which would prevent removeCallbacks from working. self._runnable_by_fn = {} # The handler must be created on the Android UI thread. self.handler = Handler() @@ -238,7 +249,8 @@ def get_or_create_runnable(self, fn): return self._runnable_by_fn[fn] def call_later(self, fn, timeout_millis): - """Enqueue a Python callable `fn` to be run after `timeout_millis` milliseconds.""" + """Enqueue a Python callable `fn` to be run after + `timeout_millis` milliseconds.""" runnable = self.get_or_create_runnable(fn) self.handler.removeCallbacks(runnable) self.handler.postDelayed(runnable, int(timeout_millis)) @@ -266,7 +278,8 @@ def __init__(self, loop): self.loop = loop # Lazily-created AndroidSelectorFileDescriptorEventsListener. self._file_descriptor_event_listener = None - # Keep a `_debug` flag so that a developer can modify it for more debug printing. + # Keep a `_debug` flag so that a developer can modify it for more debug + # printing. self._debug = False @property @@ -312,7 +325,8 @@ def _reregister(): if key is None: # pragma: no cover if self._debug: print( - "reregister_with_android_soon reregister_temporarily_ignored_fd exiting early; key=None" + "reregister_with_android_soon " + "reregister_temporarily_ignored_fd exiting early; key=None" ) return if self._debug: # pragma: no cover @@ -323,7 +337,8 @@ def _reregister(): ) self.register_with_android(key.fd, key.events) - # Use `call_later(0, fn)` to ensure the Python event loop runs to completion before re-registering. + # Use `call_later(0, fn)` to ensure the Python event loop runs to + # completion before re-registering. self.loop.call_later(0, _reregister) def register_with_android(self, fileobj, events): @@ -333,11 +348,13 @@ def register_with_android(self, fileobj, events): fileobj=fileobj, events=events ) ) - # `events` is a bitset comprised of `selectors.EVENT_READ` and `selectors.EVENT_WRITE`. + # `events` is a bitset comprised of `selectors.EVENT_READ` and + # `selectors.EVENT_WRITE`. # Register this FD for read and/or write events from Android. self.message_queue.addOnFileDescriptorEventListener( _create_java_fd(fileobj), - events, # Passing `events` as-is because Android and Python use the same values for read & write events. + events, # Passing `events` as-is because Android and Python use + # the same values for read & write events. self.file_descriptor_event_listener, ) @@ -362,7 +379,8 @@ def handle_fd_wakeup(self, fd, events): if key_event_pairs: if self._debug: # pragma: no cover print( - "handle_fd_wakeup() calling parent for key_event_pairs={key_event_pairs}".format( + "handle_fd_wakeup() calling parent for " + "key_event_pairs={key_event_pairs}".format( key_event_pairs=key_event_pairs ) ) @@ -370,7 +388,8 @@ def handle_fd_wakeup(self, fd, events): self.loop._process_events(key_event_pairs) else: # pragma: no cover print( - "Warning: handle_fd_wakeup(): unnecessary wakeup fd={fd} events={events} key={key}".format( + "Warning: handle_fd_wakeup(): unnecessary wakeup " + "fd={fd} events={events} key={key}".format( fd=fd, events=events, key=key ) ) @@ -389,22 +408,26 @@ def select(self, *args, **kwargs): class AndroidSelectorFileDescriptorEventsListener( dynamic_proxy(MessageQueue.OnFileDescriptorEventListener) ): - """Notify an `AndroidSelector` instance when file descriptors become readable/writable.""" + """Notify an `AndroidSelector` instance when file descriptors + become readable/writable.""" def __init__(self, android_selector): super().__init__() self.android_selector = android_selector - # Keep a `_debug` flag so that a developer can modify it for more debug printing. + # Keep a `_debug` flag so that a developer can modify it for more debug + # printing. self._debug = False def onFileDescriptorEvents(self, fd_obj, events): - """Receive a Java FileDescriptor object and notify the Python event loop that the FD + """Receive a Java FileDescriptor object and notify the Python event loop that + the FD is ready for read and/or write. - As an implementation detail, this relies on the fact that Android EVENT_INPUT and Python - selectors.EVENT_READ have the same value (1) and Android EVENT_OUTPUT and Python - selectors.EVENT_WRITE have the same value (2).""" - # Call hidden (non-private) method to get the numeric FD, so we can pass that to Python. + As an implementation detail, this relies on the fact that Android EVENT_INPUT + and Python selectors.EVENT_READ have the same value (1) and Android EVENT_OUTPUT + and Python selectors.EVENT_WRITE have the same value (2).""" + # Call hidden (non-private) method to get the numeric FD, so we can pass that + # to Python. fd = getattr(fd_obj, "getInt$")() if self._debug: # pragma: no cover print( @@ -414,8 +437,8 @@ def onFileDescriptorEvents(self, fd_obj, events): ) # Tell the Python event loop that the FD is ready for read and/or write. self.android_selector.handle_fd_wakeup(fd, events) - # Tell Android we don't want any more wake-ups from this FD until the event loop runs. - # To do that, we return 0. + # Tell Android we don't want any more wake-ups from this FD until the event + # loop runs. To do that, we return 0. # # We also need Python to request wake-ups once the event loop has finished. self.android_selector.reregister_with_android_soon(fd) @@ -424,9 +447,12 @@ def onFileDescriptorEvents(self, fd_obj, events): def _create_java_fd(int_fd): """Given a numeric file descriptor, create a `java.io.FileDescriptor` object.""" - # On Android, the class exposes hidden (non-private) methods `getInt$()` and `setInt$()`. Because - # they aren't valid Python identifier names, we need to use `getattr()` to grab them. - # See e.g. https://android.googlesource.com/platform/prebuilts/fullsdk/sources/android-28/+/refs/heads/master/java/io/FileDescriptor.java#149 # noqa: E501 + # On Android, the class exposes hidden (non-private) methods `getInt$()` and + # `setInt$()`. Because they aren't valid Python identifier names, we need to use + # `getattr()` to grab them. + # See e.g. https://android.googlesource.com + # /platform/prebuilts/fullsdk/sources/android-28/+/refs/heads/master + # /java/io/FileDescriptor.java#149 java_fd = FileDescriptor() getattr(java_fd, "setInt$")(int_fd) return java_fd diff --git a/android/src/toga_android/widgets/detailedlist.py b/android/src/toga_android/widgets/detailedlist.py index 41cd4939e3..6d1520d3c5 100644 --- a/android/src/toga_android/widgets/detailedlist.py +++ b/android/src/toga_android/widgets/detailedlist.py @@ -100,7 +100,8 @@ class DetailedList(Widget): def create(self): if SwipeRefreshLayout is None: # pragma: no cover raise RuntimeError( - "Unable to import SwipeRefreshLayout. Ensure that the AndroidX Swipe Refresh Layout " + "Unable to import SwipeRefreshLayout. " + "Ensure that the AndroidX Swipe Refresh Layout " "widget package (androidx.swiperefreshlayout:swiperefreshlayout:1.1.0) " "is listed in your app's dependencies." ) diff --git a/android/src/toga_android/widgets/imageview.py b/android/src/toga_android/widgets/imageview.py index 6f92541793..89b3a7ac8c 100644 --- a/android/src/toga_android/widgets/imageview.py +++ b/android/src/toga_android/widgets/imageview.py @@ -26,7 +26,8 @@ def rehint(self): # we need to convert all sizes into physical pixels. dpi = self.native.getContext().getResources().getDisplayMetrics().densityDpi # Toga needs to know how the current DPI compares to the platform default, - # which is 160: https://developer.android.com/training/multiscreen/screendensities + # which is 160: + # https://developer.android.com/training/multiscreen/screendensities scale = float(dpi) / 160 width, height, aspect_ratio = rehint_imageview( diff --git a/android/src/toga_android/widgets/label.py b/android/src/toga_android/widgets/label.py index 5737514ae6..e2bcff7a6a 100644 --- a/android/src/toga_android/widgets/label.py +++ b/android/src/toga_android/widgets/label.py @@ -30,9 +30,9 @@ def set_font(self, font): ) def set_background_color(self, value): - # In the case of EditText, this causes any custom color to hide the bottom border - # line, but it's better than set_background_filter, which affects *only* the - # bottom border line. + # In the case of EditText, this causes any custom color to hide the bottom + # border line, but it's better than set_background_filter, which affects *only* + # the bottom border line. self.set_background_simple(value) def set_color(self, value): diff --git a/android/tests_backend/widgets/progressbar.py b/android/tests_backend/widgets/progressbar.py index d5ba788b15..10aac855b3 100644 --- a/android/tests_backend/widgets/progressbar.py +++ b/android/tests_backend/widgets/progressbar.py @@ -20,5 +20,6 @@ def position(self): return self.native.getProgress() / self.native.getMax() async def wait_for_animation(self): - # Android ProgressBar has internal animation handling; no special handling required. + # Android ProgressBar has internal animation handling; + # no special handling required. pass diff --git a/android/tests_backend/widgets/textinput.py b/android/tests_backend/widgets/textinput.py index 2bbc62c4f9..9b9336072e 100644 --- a/android/tests_backend/widgets/textinput.py +++ b/android/tests_backend/widgets/textinput.py @@ -51,7 +51,8 @@ def readonly(self): # TYPE_TEXT_FLAG_NO_SUGGESTIONS is not set if not focusable: raise ValueError( - "TYPE_TEXT_FLAG_NO_SUGGESTIONS has been set when the input is readonly." + "TYPE_TEXT_FLAG_NO_SUGGESTIONS " + "has been set when the input is readonly." ) return not focusable diff --git a/cocoa/src/toga_cocoa/app.py b/cocoa/src/toga_cocoa/app.py index d2cff2172f..969abaa3f5 100644 --- a/cocoa/src/toga_cocoa/app.py +++ b/cocoa/src/toga_cocoa/app.py @@ -387,8 +387,8 @@ def enter_full_screen(self, windows): ) for window, screen in zip(windows, NSScreen.screens): - # The widgets are actually added to window._impl.container.native, instead of - # window.content._impl.native. And window._impl.native.contentView is + # The widgets are actually added to window._impl.container.native, instead + # of window.content._impl.native. And window._impl.native.contentView is # window._impl.container.native. Hence, we need to go fullscreen on # window._impl.container.native instead. window._impl.container.native.enterFullScreenMode(screen, withOptions=opts) diff --git a/cocoa/src/toga_cocoa/constraints.py b/cocoa/src/toga_cocoa/constraints.py index ca635a6301..6cd40e0177 100644 --- a/cocoa/src/toga_cocoa/constraints.py +++ b/cocoa/src/toga_cocoa/constraints.py @@ -55,13 +55,14 @@ def container(self): @container.setter def container(self, value): - # This will *always* remove and then add constraints. It relies on the base widget to - # *not* invoke this setter unless the container is actually changing. + # This will *always* remove and then add constraints. It relies on the base + # widget to *not* invoke this setter unless the container is actually changing. self._remove_constraints() self._container = value if value is not None: - # print(f"Add constraints for {self.widget} in {self.container} {self.widget.interface.layout}) + # print(f"Add constraints for {self.widget} in {self.container} + # {self.widget.interface.layout}) self.left_constraint = NSLayoutConstraint.constraintWithItem( self.widget.native, attribute__1=NSLayoutAttributeLeft, @@ -107,7 +108,8 @@ def container(self, value): self.container.native.addConstraint(self.height_constraint) def update(self, x, y, width, height): - # print(f"UPDATE CONSTRAINTS {self.widget} in {self.container} {width}x{height}@{x},{y}") + # print(f"UPDATE CONSTRAINTS {self.widget} in {self.container} + # {width}x{height}@{x},{y}") self.left_constraint.constant = x self.top_constraint.constant = y diff --git a/cocoa/src/toga_cocoa/hardware/camera.py b/cocoa/src/toga_cocoa/hardware/camera.py index 7657180cc8..005ce276b8 100644 --- a/cocoa/src/toga_cocoa/hardware/camera.py +++ b/cocoa/src/toga_cocoa/hardware/camera.py @@ -88,7 +88,8 @@ def create_preview_window(self): style=Pack(width=200), ) - # The shutter button. Initially disabled until we know we have a camera available + # The shutter button. Initially disabled until we know we + # have a camera available self.shutter_button = toga.Button( icon=toga.Icon("camera", system=True), on_press=self.take_photo, @@ -214,7 +215,7 @@ def change_camera(self, widget=None, **kwargs): self._update_flash_mode() def close_window(self, widget, **kwargs): - # If the user actually takes a photo, the window will be programmatically closed. + # If the user actually takes a photo the window will be programmatically closed. # This handler is only triggered if the user manually closes the window. # Stop the camera session self.camera_session.stopRunning() @@ -261,7 +262,8 @@ def __init__(self, interface): msg = ( "Application metadata does not declare that the app will use " "the camera. See " - "https://toga.readthedocs.io/en/stable/reference/api/hardware/camera.html" + "https://toga.readthedocs.io" + "/en/stable/reference/api/hardware/camera.html" ) if self.interface.app.is_bundled: raise RuntimeError(msg) @@ -278,9 +280,12 @@ def has_permission(self, allow_unknown=False): # tccutil reset Camera # # e.g. - # tccutil reset Camera org.beeware.appname # for a bundled app - # tccutil reset Camera com.microsoft.VSCode # for code running in Visual Studio - # tccutil reset Camera com.apple.Terminal # for code running in the Apple terminal + # tccutil reset Camera org.beeware.appname + # # for a bundled app + # tccutil reset Camera com.microsoft.VSCode + # # for code running in Visual Studio + # tccutil reset Camera com.apple.Terminal + # # for code running in the Apple terminal if allow_unknown: valid_values = { diff --git a/cocoa/src/toga_cocoa/widgets/internal/refresh.py b/cocoa/src/toga_cocoa/widgets/internal/refresh.py index 39316f3617..83f74e0b22 100644 --- a/cocoa/src/toga_cocoa/widgets/internal/refresh.py +++ b/cocoa/src/toga_cocoa/widgets/internal/refresh.py @@ -30,10 +30,11 @@ NSView, ) -######################################################################################### +######################################################################################## # This is broadly derived from Alex Zielenski's ScrollToRefresh implementation: -# https://github.com/alexzielenski/ScrollToRefresh/blob/master/ScrollToRefresh/src/EQSTRScrollView.m -# ======================================================================================= +# https://github.com/ +# alexzielenski/ScrollToRefresh/blob/master/ScrollToRefresh/src/EQSTRScrollView.m +# ====================================================================================== # ScrollToRefresh # # Copyright (C) 2011 by Alex Zielenski. @@ -54,7 +55,7 @@ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# ======================================================================================= +# ====================================================================================== # # HOW THIS WORKS # @@ -78,7 +79,7 @@ # # All of this is also gated by the refreshEnabled flag; when refresh is disabled, it # also makes the refresh widget invisible so that it can't be seen in a bounce scroll. -######################################################################################### +######################################################################################## # The height of the refresh header; also the minimum pull height to trigger a refresh. HEADER_HEIGHT = 45.0 diff --git a/cocoa/src/toga_cocoa/widgets/mapview.py b/cocoa/src/toga_cocoa/widgets/mapview.py index 034f4e032b..2dd8470240 100644 --- a/cocoa/src/toga_cocoa/widgets/mapview.py +++ b/cocoa/src/toga_cocoa/widgets/mapview.py @@ -131,9 +131,9 @@ def get_zoom(self): def set_zoom(self, zoom): if self.backlog is None: - # The zoom level indicates how many degrees of longitude will be displayed in a - # 256 pixel horizontal range. Determine how many degrees of longitude that is, - # and scale to the size of the visible horizontal space. + # The zoom level indicates how many degrees of longitude will be displayed + # in a 256 pixel horizontal range. Determine how many degrees of longitude + # that is, and scale to the size of the visible horizontal space. # The horizontal axis can't show more than 360 degrees of longitude, so clip # the range to that value. The OSM zoom level is based on 360 degrees of @@ -144,8 +144,8 @@ def set_zoom(self, zoom): ) # If we're currently panning to a new location, use the desired *future* - # location as the center of the zoom region. Otherwise use the current center - # coordinate. + # location as the center of the zoom region. Otherwise use the current + # center coordinate. center = ( self.future_location if self.future_location is not None diff --git a/cocoa/src/toga_cocoa/widgets/numberinput.py b/cocoa/src/toga_cocoa/widgets/numberinput.py index 906ebbbee2..d475581ea8 100644 --- a/cocoa/src/toga_cocoa/widgets/numberinput.py +++ b/cocoa/src/toga_cocoa/widgets/numberinput.py @@ -93,7 +93,7 @@ def create(self): # Add constraints to lay out the input and stepper. # Stepper is always top right corner. self.native.addConstraint( - NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( + NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501 self.native, NSLayoutAttributeTop, NSLayoutRelationEqual, @@ -104,7 +104,7 @@ def create(self): ) ) self.native.addConstraint( - NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( + NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501 self.native, NSLayoutAttributeRight, NSLayoutRelationEqual, @@ -117,7 +117,7 @@ def create(self): # Stepper height matches container box height self.native.addConstraint( - NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( + NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501 self.native, NSLayoutAttributeBottom, NSLayoutRelationEqual, @@ -130,7 +130,7 @@ def create(self): # Input is always left, centred vertically on the stepper self.native.addConstraint( - NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( + NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501 self.native_stepper, NSLayoutAttributeCenterY, NSLayoutRelationEqual, @@ -141,7 +141,7 @@ def create(self): ) ) self.native.addConstraint( - NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( + NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501 self.native, NSLayoutAttributeLeft, NSLayoutRelationEqual, @@ -154,7 +154,7 @@ def create(self): # Stepper and input meet in the middle with a small gap self.native.addConstraint( - NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( + NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501 self.native_stepper, NSLayoutAttributeLeft, NSLayoutRelationEqual, @@ -183,7 +183,8 @@ def set_background_color(self, color): def has_focus(self): # When the NSTextField gets focus, a field editor is created, and that editor - # has the original widget as the delegate. The first responder is the Field Editor. + # has the original widget as the delegate. The first responder is the + # Field Editor. return isinstance(self.native.window.firstResponder, NSTextView) and ( self.native.window.firstResponder.delegate == self.native_input ) diff --git a/cocoa/src/toga_cocoa/widgets/table.py b/cocoa/src/toga_cocoa/widgets/table.py index 635cf6e55e..d628c919c4 100644 --- a/cocoa/src/toga_cocoa/widgets/table.py +++ b/cocoa/src/toga_cocoa/widgets/table.py @@ -119,7 +119,8 @@ def tableViewSelectionDidChange_(self, notification) -> None: # value = getattr(data_row, col_identifier, None) # if isinstance(value, toga.Widget): # # if the cell value is a widget, use its height - # heights.append(value._impl.native.intrinsicContentSize().height + margin) + # heights.append(value._impl.native.intrinsicContentSize().height + # + margin) # # return max(heights) diff --git a/cocoa/src/toga_cocoa/widgets/textinput.py b/cocoa/src/toga_cocoa/widgets/textinput.py index 2de4fd10f7..8eb0f1e05a 100644 --- a/cocoa/src/toga_cocoa/widgets/textinput.py +++ b/cocoa/src/toga_cocoa/widgets/textinput.py @@ -162,7 +162,8 @@ def add_error_label(self): @property def has_focus(self): # When the NSTextField gets focus, a field editor is created, and that editor - # has the original widget as the delegate. The first responder is the Field Editor. + # has the original widget as the delegate. The first responder is + # the Field Editor. return ( self.native.window is not None and isinstance(self.native.window.firstResponder, NSTextView) @@ -219,7 +220,8 @@ def rehint(self): # Height of a text input is known and fixed. # Width must be > 100 # print("REHINT TextInput", self, - # self._impl.intrinsicContentSize().width, self._impl.intrinsicContentSize().height + # self._impl.intrinsicContentSize().width, + # self._impl.intrinsicContentSize().height # ) self.interface.intrinsic.width = at_least(self.interface._MIN_WIDTH) self.interface.intrinsic.height = self.native.intrinsicContentSize().height diff --git a/cocoa/src/toga_cocoa/widgets/tree.py b/cocoa/src/toga_cocoa/widgets/tree.py index 889481904b..f546603833 100644 --- a/cocoa/src/toga_cocoa/widgets/tree.py +++ b/cocoa/src/toga_cocoa/widgets/tree.py @@ -95,7 +95,8 @@ def outlineView_viewForTableColumn_item_(self, tree, column, item): tcv = self.makeViewWithIdentifier(identifier, owner=self) if not tcv: # there is no existing view to reuse so create a new one - # tcv = TogaIconView.alloc().initWithFrame(CGRectMake(0, 0, column.width, 16)) + # tcv = TogaIconView.alloc().initWithFrame(CGRectMake( + # 0, 0, column.width, 16)) tcv = TogaIconView.alloc().init() tcv.identifier = identifier @@ -127,7 +128,8 @@ def outlineView_viewForTableColumn_item_(self, tree, column, item): # for column in self.tableColumns: # value = getattr( - # item.attrs["node"], str(column.identifier), self.interface.missing_value + # item.attrs["node"], str(column.identifier), + # self.interface.missing_value # ) # if isinstance(value, toga.Widget): @@ -144,7 +146,8 @@ def outlineView_pasteboardWriterForItem_( return None # @objc_method - # def outlineView_sortDescriptorsDidChange_(self, tableView, oldDescriptors) -> None: + # def outlineView_sortDescriptorsDidChange_(self, + # tableView, oldDescriptors) -> None: # # for descriptor in self.sortDescriptors[::-1]: # accessor = descriptor.key diff --git a/cocoa/src/toga_cocoa/window.py b/cocoa/src/toga_cocoa/window.py index 5a0604c7d6..854104630c 100644 --- a/cocoa/src/toga_cocoa/window.py +++ b/cocoa/src/toga_cocoa/window.py @@ -175,7 +175,8 @@ def __init__(self, interface, title, position, size): self.container = Container(on_refresh=self.content_refreshed) self.native.contentView = self.container.native - # Ensure that the container renders it's background in the same color as the window. + # Ensure that the container renders it's background in the + # same color as the window. self.native.wantsLayer = True self.container.native.backgroundColor = self.native.backgroundColor diff --git a/cocoa/tests_backend/probe.py b/cocoa/tests_backend/probe.py index 1f898b6188..f7d1687cc8 100644 --- a/cocoa/tests_backend/probe.py +++ b/cocoa/tests_backend/probe.py @@ -36,8 +36,8 @@ async def post_event(self, event, delay=None): # this prevents await asyncio.sleep(delay) else: - # Add another event to the queue behind the original event, to notify us once - # it's been processed. + # Add another event to the queue behind the original event, to notify us + # once it's been processed. NSRunLoop.currentRunLoop.performSelector( SEL("onEvent"), target=self.event_listener, diff --git a/cocoa/tests_backend/widgets/base.py b/cocoa/tests_backend/widgets/base.py index 841c7ce9d0..ab5d957d69 100644 --- a/cocoa/tests_backend/widgets/base.py +++ b/cocoa/tests_backend/widgets/base.py @@ -149,7 +149,8 @@ async def type_character(self, char, modifierFlags=0): if modifierFlags: char = None - # This posts a single keyDown followed by a keyUp, matching "normal" keyboard operation. + # This posts a single keyDown followed by a keyUp, matching "normal" + # keyboard operation. await self.post_event( NSEvent.keyEventWithType( NSEventType.KeyDown, diff --git a/cocoa/tests_backend/widgets/mapview.py b/cocoa/tests_backend/widgets/mapview.py index 6f33ef8449..73589252e2 100644 --- a/cocoa/tests_backend/widgets/mapview.py +++ b/cocoa/tests_backend/widgets/mapview.py @@ -29,7 +29,8 @@ async def tile_longitude_span(self): # MKCoordinateRegion assert re.match( ( - r", " + r", " r"span=\)>" ), repr(self.native.region), @@ -75,8 +76,8 @@ async def wait_for_map(self, message, max_delay=0.5): panning = True # Iterate until 2 successive reads of the region, 0.1s apart, return the same - # value; or we've been waiting max_delay seconds. If confirm_pan is True, also confirm - # that the value has actually changed from the initial value. + # value; or we've been waiting max_delay seconds. If confirm_pan is True, also + # confirm that the value has actually changed from the initial value. tick_count = 0 delta = 0.1 while panning and tick_count < (max_delay / delta): diff --git a/cocoa/tests_backend/widgets/numberinput.py b/cocoa/tests_backend/widgets/numberinput.py index 3b376cdcf2..54b5e4be92 100644 --- a/cocoa/tests_backend/widgets/numberinput.py +++ b/cocoa/tests_backend/widgets/numberinput.py @@ -104,7 +104,8 @@ def readonly(self): @property def has_focus(self): # When the NSTextField gets focus, a field editor is created, and that editor - # has the original widget as the delegate. The first responder is the Field Editor. + # has the original widget as the delegate. The first responder is + # the Field Editor. return isinstance(self.native.window.firstResponder, NSTextView) and ( self.native_input.window.firstResponder.delegate == self.native_input ) diff --git a/cocoa/tests_backend/widgets/progressbar.py b/cocoa/tests_backend/widgets/progressbar.py index 02830047e1..c3088fcc1d 100644 --- a/cocoa/tests_backend/widgets/progressbar.py +++ b/cocoa/tests_backend/widgets/progressbar.py @@ -20,5 +20,6 @@ def position(self): return float(self.native.doubleValue / self.native.maxValue) async def wait_for_animation(self): - # Cocoa ProgressBar has internal animation handling; no special handling required. + # Cocoa ProgressBar has internal animation handling; + # no special handling required. pass diff --git a/cocoa/tests_backend/widgets/textinput.py b/cocoa/tests_backend/widgets/textinput.py index bdeee57a29..4cd89acab7 100644 --- a/cocoa/tests_backend/widgets/textinput.py +++ b/cocoa/tests_backend/widgets/textinput.py @@ -79,7 +79,8 @@ def readonly(self): @property def has_focus(self): # When the NSTextField gets focus, a field editor is created, and that editor - # has the original widget as the delegate. The first responder is the Field Editor. + # has the original widget as the delegate. The first responder is + # the Field Editor. return isinstance(self.native.window.firstResponder, NSTextView) and ( self.native.window.firstResponder.delegate == self.native ) diff --git a/core/src/toga/app.py b/core/src/toga/app.py index 7b54c9d4d4..d7e732af73 100644 --- a/core/src/toga/app.py +++ b/core/src/toga/app.py @@ -106,7 +106,7 @@ def __iter__(self) -> Iterator[Widget]: return self.values() def __repr__(self) -> str: - return f"{{{', '.join(f'{k!r}: {v!r}' for k, v in sorted(self._registry.items()))}}}" + return f"{{{', '.join(f'{k!r}: {v!r}' for k, v in sorted(self._registry.items()))}}}" # noqa: E501 def items(self) -> Iterator[tuple[str, Widget]]: return self._registry.items() @@ -428,7 +428,8 @@ def version(self) -> str | None: @property def is_bundled(self) -> bool: - """Has the app been bundled as a standalone binary, or is it running as a Python script?""" + """Has the app been bundled as a standalone binary, + or is it running as a Python script?""" return Path(sys.executable).stem not in { "python", f"python{sys.version_info.major}", @@ -647,8 +648,8 @@ def _startup(self) -> None: self._create_standard_commands() self._impl.create_standard_commands() - # Install the standard status icon commands. Again, this is done *before* startup - # so that the user's code can remove/change the defaults. + # Install the standard status icon commands. Again, this is done *before* + # startup so that the user's code can remove/change the defaults. self.status_icons._create_standard_commands() # Invoke the user's startup method (or the default implementation) @@ -888,7 +889,8 @@ def on_exit(self) -> bool: return True def on_running(self) -> None: - """The event handler that will be invoked when the app's event loop starts running. + """The event handler that will be invoked + when the app's event loop starts running. If necessary, the overridden method can be defined as an ``async`` coroutine. """ diff --git a/core/src/toga/documents.py b/core/src/toga/documents.py index 2a91dde5be..8fb2882ca7 100644 --- a/core/src/toga/documents.py +++ b/core/src/toga/documents.py @@ -21,7 +21,8 @@ class Document(ABC): #: class variable that subclasses should define. description: str - #: A list of extensions that documents of this type might use, without leading dots (e.g., + #: A list of extensions that documents of this type might use, + # without leading dots (e.g., #: ``["doc", "txt"]``). The list must have at least one extension; the first is the #: default extension for documents of this type. This is a class variable that #: subclasses should define. @@ -275,9 +276,9 @@ async def request_open(self) -> Document: if hasattr(self, "_open_dialog"): return - # CLOSE_ON_LAST_WINDOW is a proxy for the GTK/Windows behavior of loading content - # into the existing window. This is actually implemented by creating a new window - # and disposing of the old one; mark the current window for cleanup + # CLOSE_ON_LAST_WINDOW is a proxy for the GTK/Windows behavior of loading + # content into the existing window. This is actually implemented by creating a + # new window and disposing of the old one; mark the current window for cleanup current_window = self.app.current_window if self.app._impl.CLOSE_ON_LAST_WINDOW: if hasattr(self.app.current_window, "_commit"): @@ -311,8 +312,8 @@ async def request_open(self) -> Document: def open(self, path: Path | str) -> Document: """Open a document in the app, and show the document window. - If the provided path is already an open document, the existing representation for - the document will be given focus. + If the provided path is already an open document, the existing representation + for the document will be given focus. :param path: The path to the document to be opened. :returns: The document that was opened. @@ -427,7 +428,8 @@ async def _confirm_close(self, window, **kwargs): if await self.dialog( toga.QuestionDialog( "Save changes?", - "This document has unsaved changes. Do you want to save these changes?", + "This document has unsaved changes. " + "Do you want to save these changes?", ) ): return await self.save() diff --git a/core/src/toga/handlers.py b/core/src/toga/handlers.py index b4620c6f94..b377d99858 100644 --- a/core/src/toga/handlers.py +++ b/core/src/toga/handlers.py @@ -259,7 +259,8 @@ def __await__(self) -> Generator[Any, None, Any]: # All the comparison dunder methods are disabled def __bool__(self, other: object) -> NoReturn: raise RuntimeError( - f"Can't check {self.RESULT_TYPE} result directly; use await or an on_result handler" + f"Can't check {self.RESULT_TYPE} result directly; " + f"use await or an on_result handler" ) __lt__ = __bool__ diff --git a/core/src/toga/icons.py b/core/src/toga/icons.py index 8d45474eb7..3bb55c95da 100644 --- a/core/src/toga/icons.py +++ b/core/src/toga/icons.py @@ -96,8 +96,8 @@ def __init__( """ self.factory = get_platform_factory() try: - # Try to load the icon with the given path snippet. If the request is for the - # app icon, use ``resources/`` as the path. + # Try to load the icon with the given path snippet. If the request is for + # the app icon, use ``resources/`` as the path. if path is _APP_ICON: self.path = Path(f"resources/{toga.App.app.app_name}") else: @@ -149,7 +149,8 @@ def __init__( self._impl = self.DEFAULT_ICON._impl else: print( - f"WARNING: Can't find icon {self.path}; falling back to default icon" + f"WARNING: Can't find icon {self.path}; " + f"falling back to default icon" ) self._impl = self.DEFAULT_ICON._impl diff --git a/core/src/toga/images.py b/core/src/toga/images.py index 0ae0df8efd..8287194e6b 100644 --- a/core/src/toga/images.py +++ b/core/src/toga/images.py @@ -209,8 +209,8 @@ 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 + supports :any:`PIL.Image.Image` if Pillow is installed, as well as any + image types defined by installed :doc:`image format plugins `. :returns: The image in the requested format :raises TypeError: If the format supplied is not recognized. diff --git a/core/src/toga/platform.py b/core/src/toga/platform.py index 91ac859016..2b06436fd8 100644 --- a/core/src/toga/platform.py +++ b/core/src/toga/platform.py @@ -84,7 +84,8 @@ def get_platform_factory() -> ModuleType: elif len(toga_backends) == 1: backend = toga_backends[0] else: - # multiple backends are installed: choose the one that matches the host platform + # multiple backends are installed: choose the one that + # matches the host platform matching_backends = [ backend for backend in toga_backends if backend.name == current_platform ] @@ -94,7 +95,8 @@ def get_platform_factory() -> ModuleType: ) raise RuntimeError( f"Multiple Toga backends are installed ({toga_backends_string}), " - f"but none of them match your current platform ({current_platform!r}). " + f"but none of them match your current platform " + f"({current_platform!r}). " "Install a backend for your current platform, or use " "TOGA_BACKEND to specify a backend." ) @@ -106,7 +108,8 @@ def get_platform_factory() -> ModuleType: ] ) raise RuntimeError( - f"Multiple candidate toga backends found: ({toga_backends_string}). " + f"Multiple candidate toga backends found: " + f"({toga_backends_string}). " "Uninstall the backends you don't require, or use " "TOGA_BACKEND to specify a backend." ) diff --git a/core/src/toga/sources/base.py b/core/src/toga/sources/base.py index 8ea13d2d5b..3b20abd5ed 100644 --- a/core/src/toga/sources/base.py +++ b/core/src/toga/sources/base.py @@ -33,7 +33,8 @@ def clear(self) -> object: class Source: - """A base class for data sources, providing an implementation of data notifications.""" + """A base class for data sources, + providing an implementation of data notifications.""" def __init__(self) -> None: self._listeners: list[Listener] = [] diff --git a/core/src/toga/sources/tree_source.py b/core/src/toga/sources/tree_source.py index ee700aa9a3..41248a6751 100644 --- a/core/src/toga/sources/tree_source.py +++ b/core/src/toga/sources/tree_source.py @@ -40,7 +40,10 @@ def __repr__(self) -> str: if self._children is not None: descriptor += f"; {len(self)} children" - return f"<{'Leaf ' if self._children is None else ''}Node {id(self):x} {descriptor}>" + return ( + f"<{'Leaf ' if self._children is None else ''}Node " + f"{id(self):x} {descriptor}>" + ) ###################################################################### # Methods required by the TreeSource interface diff --git a/core/src/toga/style/pack.py b/core/src/toga/style/pack.py index 6a3b8bf059..a51c2d26a8 100644 --- a/core/src/toga/style/pack.py +++ b/core/src/toga/style/pack.py @@ -143,7 +143,8 @@ def apply(self, prop: str, value: object) -> None: def layout(self, node: Node, viewport: Any) -> None: # self._debug("=" * 80) - # self._debug(f"Layout root {node}, available {viewport.width}x{viewport.height}") + # self._debug(f"Layout root {node}, + # available {viewport.width}x{viewport.height}") self.__class__._depth = -1 self._layout_node( @@ -388,8 +389,8 @@ def _layout_row_children( quantum = (remaining_width + min_flex) / flex_total # In an ideal flex layout, all flex children will have a width proportional # to their flex value. However, if a flex child has a flexible minimum width - # constraint that is greater than the ideal width for a balanced flex layout, - # they need to be removed from the flex calculation. + # constraint that is greater than the ideal width for a balanced flex + # layout, they need to be removed from the flex calculation. # self._debug(f"PASS 1a; {quantum=}") for child in node.children: if child.style.flex and child.intrinsic.width is not None: @@ -590,7 +591,8 @@ def _layout_column_children( elif child.intrinsic.height is not None: if hasattr(child.intrinsic.height, "value"): if child.style.flex: - # self._debug(f"- intrinsic flex height {child.intrinsic.height}") + # self._debug(f"- intrinsic flex height " + # f"{child.intrinsic.height}") flex_total += child.style.flex # Final child content size will be computed in pass 2, after the # amount of flexible space is known. For now, set an initial diff --git a/core/src/toga/validators.py b/core/src/toga/validators.py index 83ae650919..c9850c67d7 100644 --- a/core/src/toga/validators.py +++ b/core/src/toga/validators.py @@ -159,7 +159,8 @@ def __init__( length: int, error_message: str | None = None, ): - """A validator confirming that the length of input does not exceed a maximum size. + """A validator confirming that the length of + input does not exceed a maximum size. :param length: The maximum length of the string (inclusive). :param error_message: Optional; the error message to display when the diff --git a/core/src/toga/widgets/base.py b/core/src/toga/widgets/base.py index 9c00de2cac..a3e4f9db17 100644 --- a/core/src/toga/widgets/base.py +++ b/core/src/toga/widgets/base.py @@ -246,7 +246,8 @@ def window(self, window: Window | None) -> None: # window, remove the widget from the widget registry self.window.app.widgets._remove(self.id) elif self.window is None and window is not None: - # If the widget is being assigned to a window for the first time, add it to the widget registry + # If the widget is being assigned to a window for the first time, add it to + # the widget registry window.app.widgets._add(self) self._window = window @@ -257,7 +258,8 @@ def window(self, window: Window | None) -> None: @property def enabled(self) -> bool: - """Is the widget currently enabled? i.e., can the user interact with the widget?""" + """Is the widget currently enabled? + i.e., can the user interact with the widget?""" return self._impl.get_enabled() @enabled.setter diff --git a/core/src/toga/widgets/button.py b/core/src/toga/widgets/button.py index c6ab49b7b1..f8c2471d9c 100644 --- a/core/src/toga/widgets/button.py +++ b/core/src/toga/widgets/button.py @@ -47,8 +47,8 @@ def __init__( # Create a platform specific implementation of a Button self._impl = self.factory.Button(interface=self) - # Set a dummy handler before installing the actual on_press, because we do not want - # on_press triggered by the initial value being set + # Set a dummy handler before installing the actual on_press, because we do not + # want on_press triggered by the initial value being set self.on_press = None # Set the content of the button - either an icon, or text, but not both. diff --git a/core/src/toga/widgets/canvas.py b/core/src/toga/widgets/canvas.py index 8adf19c1aa..0941a5d8ce 100644 --- a/core/src/toga/widgets/canvas.py +++ b/core/src/toga/widgets/canvas.py @@ -255,7 +255,10 @@ def __init__(self, cpx: float, cpy: float, x: float, y: float): self.y = y def __repr__(self) -> str: - return f"{self.__class__.__name__}(cpx={self.cpx}, cpy={self.cpy}, x={self.x}, y={self.y})" + return ( + f"{self.__class__.__name__}" + f"(cpx={self.cpx}, cpy={self.cpy}, x={self.x}, y={self.y})" + ) def _draw(self, impl: Any, **kwargs: Any) -> None: impl.quadratic_curve_to(self.cpx, self.cpy, self.x, self.y, **kwargs) @@ -1096,8 +1099,8 @@ class StrokeContext(ClosedPathContext): within the context. This is a context manager; it creates a new path, and moves to the start coordinate; - when the context exits, the path is drawn with the stroke. For fine-grained control of - a path, you can use :class:`~toga.widgets.canvas.Context.begin_path`, + when the context exits, the path is drawn with the stroke. For fine-grained control + of a path, you can use :class:`~toga.widgets.canvas.Context.begin_path`, :class:`~toga.widgets.canvas.Context.move_to`, :class:`~toga.widgets.canvas.Context.close_path` and :class:`~toga.widgets.canvas.Context.stroke`. @@ -1105,9 +1108,9 @@ class StrokeContext(ClosedPathContext): If both an x and y coordinate is provided, the drawing context will begin with a ``move_to`` operation in that context. - You should not create a :class:`~toga.widgets.canvas.StrokeContext` context directly; - instead, you should use the :meth:`~toga.widgets.canvas.Context.Stroke` method on - an existing context. + You should not create a :class:`~toga.widgets.canvas.StrokeContext` context + directly; instead, you should use the :meth:`~toga.widgets.canvas.Context.Stroke` + method on an existing context. """ def __init__( @@ -1297,8 +1300,8 @@ def ClosedPath( x: float | None = None, y: float | None = None, ) -> ContextManager[ClosedPathContext]: - """Construct and yield a new :class:`~toga.widgets.canvas.ClosedPathContext` context in - the root context of this canvas. + """Construct and yield a new :class:`~toga.widgets.canvas.ClosedPathContext` + context in the root context of this canvas. :param x: The x coordinate of the path's starting point. :param y: The y coordinate of the path's starting point. @@ -1453,7 +1456,8 @@ def measure_text( font: Font | None = None, tight: None = None, # DEPRECATED ) -> tuple[float, float]: - """Measure the size at which :meth:`~.Context.write_text` would render some text. + """Measure the size at which :meth:`~.Context.write_text` would + render some text. :param text: The text to measure. Newlines will cause line breaks, but long lines will not be wrapped. @@ -1521,7 +1525,8 @@ def bezier_curve_to(self, cp1x, cp1y, cp2x, cp2y, x, y): """**DEPRECATED** - Use :meth:`~toga.widgets.canvas.Context.bezier_curve_to` on :attr:`context`""" warnings.warn( - "Direct canvas operations have been deprecated; use context.bezier_curve_to()", + "Direct canvas operations have been deprecated; " + "use context.bezier_curve_to()", DeprecationWarning, ) return self.context.bezier_curve_to(cp1x, cp1y, cp2x, cp2y, x, y) @@ -1530,7 +1535,8 @@ def quadratic_curve_to(self, cpx: float, cpy: float, x: float, y: float): """**DEPRECATED** - Use :meth:`~toga.widgets.canvas.Context.quadratic_curve_to` on :attr:`context`""" warnings.warn( - "Direct canvas operations have been deprecated; use context.quadratic_curve_to()", + "Direct canvas operations have been deprecated; " + "use context.quadratic_curve_to()", DeprecationWarning, ) return self.context.quadratic_curve_to(cpx, cpy, x, y) @@ -1600,7 +1606,8 @@ def rotate(self, radians: float): return self.context.rotate(radians) def scale(self, sx: float, sy: float): - """**DEPRECATED** - Use :meth:`~toga.widgets.canvas.Context.scale` on :attr:`context`""" + """**DEPRECATED** - Use :meth:`~toga.widgets.canvas.Context.scale` + on :attr:`context`""" warnings.warn( "Direct canvas operations have been deprecated; use context.scale()", DeprecationWarning, @@ -1620,7 +1627,8 @@ def reset_transform(self): """**DEPRECATED** - Use :meth:`~toga.widgets.canvas.Context.reset_transform` on :attr:`context`""" warnings.warn( - "Direct canvas operations have been deprecated; use context.reset_transform()", + "Direct canvas operations have been deprecated; " + "use context.reset_transform()", DeprecationWarning, ) return self.context.reset_transform() diff --git a/core/src/toga/widgets/detailedlist.py b/core/src/toga/widgets/detailedlist.py index a5ec7937e0..a14f698d31 100644 --- a/core/src/toga/widgets/detailedlist.py +++ b/core/src/toga/widgets/detailedlist.py @@ -95,7 +95,8 @@ def __init__( raise ValueError("Cannot specify both on_delete and on_primary_action") else: warnings.warn( - "DetailedList.on_delete has been renamed DetailedList.on_primary_action.", + "DetailedList.on_delete has been renamed " + "DetailedList.on_primary_action.", DeprecationWarning, ) on_primary_action = on_delete @@ -103,7 +104,8 @@ def __init__( # End backwards compatibility. ###################################################################### - # Prime the attributes and handlers that need to exist when the widget is created. + # Prime the attributes and handlers that need to exist when the + # widget is created. self._accessors = accessors self._missing_value = missing_value self._primary_action = primary_action @@ -123,8 +125,8 @@ def __init__( @property def enabled(self) -> Literal[True]: """Is the widget currently enabled? i.e., can the user interact with the widget? - DetailedList widgets cannot be disabled; this property will always return True; any - attempt to modify it will be ignored. + DetailedList widgets cannot be disabled; this property will always return True; + any attempt to modify it will be ignored. """ return True @@ -262,7 +264,8 @@ def on_refresh(self, handler: OnRefreshHandler) -> None: @property def on_select(self) -> OnSelectHandler: - """The callback function that is invoked when a row of the DetailedList is selected.""" + """The callback function that is invoked + when a row of the DetailedList is selected.""" return self._on_select @on_select.setter diff --git a/core/src/toga/widgets/multilinetextinput.py b/core/src/toga/widgets/multilinetextinput.py index d987725c35..afbc10a2b5 100644 --- a/core/src/toga/widgets/multilinetextinput.py +++ b/core/src/toga/widgets/multilinetextinput.py @@ -45,8 +45,8 @@ def __init__( # Create a platform specific implementation of a MultilineTextInput self._impl = self.factory.MultilineTextInput(interface=self) - # Set a dummy handler before installing the actual on_change, because we do not want - # on_change triggered by the initial value being set + # Set a dummy handler before installing the actual on_change, because we do not + # want on_change triggered by the initial value being set self.on_change = None self.value = value diff --git a/core/src/toga/widgets/optioncontainer.py b/core/src/toga/widgets/optioncontainer.py index 8716ebb7c6..a1a6c1fc26 100644 --- a/core/src/toga/widgets/optioncontainer.py +++ b/core/src/toga/widgets/optioncontainer.py @@ -27,7 +27,8 @@ class OnSelectHandler(Protocol): def __call__(self, widget: OptionContainer, /, **kwargs: Any) -> None: - """A handler that will be invoked when a new tab is selected in the OptionContainer. + """A handler that will be invoked when a new tab is selected + in the OptionContainer. :param widget: The OptionContainer that had a selection change. :param kwargs: Ensures compatibility with arguments added in future versions. diff --git a/core/src/toga/widgets/scrollcontainer.py b/core/src/toga/widgets/scrollcontainer.py index 030cbc1bf9..92c7e61722 100644 --- a/core/src/toga/widgets/scrollcontainer.py +++ b/core/src/toga/widgets/scrollcontainer.py @@ -168,7 +168,8 @@ def horizontal_position(self) -> int: def horizontal_position(self, horizontal_position: SupportsInt) -> None: if not self.horizontal: raise ValueError( - "Cannot set horizontal position when horizontal scrolling is not enabled." + "Cannot set horizontal position when " + "horizontal scrolling is not enabled." ) self.position = (horizontal_position, self._impl.get_vertical_position()) diff --git a/core/src/toga/widgets/selection.py b/core/src/toga/widgets/selection.py index 9b9fb5d565..2425c3e716 100644 --- a/core/src/toga/widgets/selection.py +++ b/core/src/toga/widgets/selection.py @@ -181,8 +181,8 @@ def value(self, value: object) -> None: @property def on_change(self) -> OnChangeHandler: - """Handler to invoke when the value of the selection is changed, either by the user - or programmatically.""" + """Handler to invoke when the value of the selection is changed, + either by the user or programmatically.""" return self._on_change @on_change.setter diff --git a/core/src/toga/widgets/slider.py b/core/src/toga/widgets/slider.py index efddce2312..b71f73e2cb 100644 --- a/core/src/toga/widgets/slider.py +++ b/core/src/toga/widgets/slider.py @@ -84,7 +84,8 @@ def __init__( ) else: warnings.warn( - "Slider.range has been deprecated in favor of Slider.min and Slider.max", + "Slider.range has been deprecated in favor of " + "Slider.min and Slider.max", DeprecationWarning, ) min, max = range @@ -98,8 +99,8 @@ def __init__( # End backwards compatibility ###################################################################### - # Set a dummy handler before installing the actual on_change, because we do not want - # on_change triggered by the initial value being set + # Set a dummy handler before installing the actual on_change, because we do not + # want on_change triggered by the initial value being set self.on_change = None self.min = min self.max = max @@ -171,8 +172,8 @@ def min(self) -> float: def min(self, value: SupportsFloat) -> None: with self._programmatic_change() as old_value: # Some backends will clip the current value within the range automatically, - # but do it ourselves to be certain. In discrete mode, setting self.value also - # rounds to the new positions of the ticks. + # but do it ourselves to be certain. In discrete mode, setting self.value + # also rounds to the new positions of the ticks. _min = float(value) _max = self.max if _max < _min: @@ -195,8 +196,8 @@ def max(self) -> float: def max(self, value: SupportsFloat) -> None: with self._programmatic_change() as old_value: # Some backends will clip the current value within the range automatically, - # but do it ourselves to be certain. In discrete mode, setting self.value also - # rounds to the new positions of the ticks. + # but do it ourselves to be certain. In discrete mode, setting self.value + # also rounds to the new positions of the ticks. _min = self.min _max = float(value) if _min > _max: @@ -233,9 +234,9 @@ def tick_count(self, tick_count: float | None) -> None: raise ValueError("tick count must be at least 2") with self._programmatic_change() as old_value: # Some backends will round the current value to the nearest tick - # automatically, but do it ourselves to be certain. Some backends also require - # the value to be refreshed when moving between discrete and continuous mode, - # because this causes a change in the native range. + # automatically, but do it ourselves to be certain. Some backends also + # require the value to be refreshed when moving between discrete and + # continuous mode, because this causes a change in the native range. self._impl.set_tick_count(tick_count) self.value = old_value diff --git a/core/src/toga/widgets/switch.py b/core/src/toga/widgets/switch.py index 17c0dfb354..1fd202301f 100644 --- a/core/src/toga/widgets/switch.py +++ b/core/src/toga/widgets/switch.py @@ -45,8 +45,8 @@ def __init__( self.text = text - # Set a dummy handler before installing the actual on_change, because we do not want - # on_change triggered by the initial value being set + # Set a dummy handler before installing the actual on_change, because we do not + # want on_change triggered by the initial value being set self.on_change = None self.value = value diff --git a/core/src/toga/window.py b/core/src/toga/window.py index 9a443ed9f1..b4f8efbd13 100644 --- a/core/src/toga/window.py +++ b/core/src/toga/window.py @@ -94,7 +94,8 @@ class OnCloseHandler(Protocol): def __call__(self, window: Window, /, **kwargs: Any) -> bool: """A handler to invoke when a window is about to close. - The return value of this callback controls whether the window is allowed to close. + The return value of this callback controls whether the window + is allowed to close. This can be used to prevent a window closing with unsaved changes, etc. :param window: The window instance that is closing. @@ -561,7 +562,8 @@ def question_dialog( # 2024-06: Backwards compatibility ###################################################################### warnings.warn( - "question_dialog(...) has been deprecated; use dialog(toga.QuestionDialog(...))", + "question_dialog(...) has been deprecated; " + "use dialog(toga.QuestionDialog(...))", DeprecationWarning, ) ###################################################################### @@ -587,7 +589,8 @@ def confirm_dialog( # 2024-06: Backwards compatibility ###################################################################### warnings.warn( - "confirm_dialog(...) has been deprecated; use dialog(toga.ConfirmDialog(...))", + "confirm_dialog(...) has been deprecated; " + "use dialog(toga.ConfirmDialog(...))", DeprecationWarning, ) ###################################################################### @@ -641,7 +644,8 @@ def stack_trace_dialog( # 2024-06: Backwards compatibility ###################################################################### warnings.warn( - "stack_trace_dialog(...) has been deprecated; use dialog(toga.StackTraceDialog(...))", + "stack_trace_dialog(...) has been deprecated; " + "use dialog(toga.StackTraceDialog(...))", DeprecationWarning, ) ###################################################################### @@ -673,7 +677,8 @@ def save_file_dialog( # 2024-06: Backwards compatibility ###################################################################### warnings.warn( - "save_file_dialog(...) has been deprecated; use dialog(toga.SaveFileDialog(...))", + "save_file_dialog(...) has been deprecated; " + "use dialog(toga.SaveFileDialog(...))", DeprecationWarning, ) ###################################################################### @@ -710,7 +715,8 @@ def open_file_dialog( # 2024-06: Backwards compatibility ###################################################################### warnings.warn( - "open_file_dialog(...) has been deprecated; use dialog(toga.OpenFileDialog(...))", + "open_file_dialog(...) has been deprecated; " + "use dialog(toga.OpenFileDialog(...))", DeprecationWarning, ) ###################################################################### @@ -761,7 +767,8 @@ def select_folder_dialog( # 2024-06: Backwards compatibility ###################################################################### warnings.warn( - "select_folder_dialog(...) has been deprecated; use dialog(toga.SelectFolderDialog(...))", + "select_folder_dialog(...) has been deprecated; " + "use dialog(toga.SelectFolderDialog(...))", DeprecationWarning, ) ###################################################################### diff --git a/core/tests/app/test_app.py b/core/tests/app/test_app.py index 6ad1e23aac..1d1d953560 100644 --- a/core/tests/app/test_app.py +++ b/core/tests/app/test_app.py @@ -92,7 +92,8 @@ "org.beeware.explicit-app", "override-app", ), - # Explicit app properties, but implied distribution name from app_id, no metadata + # Explicit app properties, + # but implied distribution name from app_id, no metadata ( EXPLICIT_MIN_APP_KWARGS, None, @@ -172,7 +173,8 @@ "org.beeware.explicit-app", "override-app", ), - # Explicit app properties, but implied distribution name from app_id, no metadata + # Explicit app properties, + # but implied distribution name from app_id, no metadata ( EXPLICIT_MIN_APP_KWARGS, None, @@ -411,8 +413,8 @@ def test_current_window(app): def test_no_current_window(app): """If there's no current window, current_window reflects this.""" - # If all the windows are deleted, and there's no main window (e.g., if it's a document app) - # there might be no current window. + # If all the windows are deleted, and there's no main window + # (e.g., if it's a document app) there might be no current window. app._main_window = None # The current window evaluates as None @@ -449,7 +451,8 @@ def test_change_invalid_main_window(app): def test_change_invalid_creation_main_window(event_loop): - """If the new main window value provided at creation isn't valid, an exception is raised.""" + """If the new main window value provided at creation isn't valid, + an exception is raised.""" class BadMainWindowApp(toga.App): def startup(self): diff --git a/core/tests/app/test_document_app.py b/core/tests/app/test_document_app.py index d05ba49e8f..687ba96862 100644 --- a/core/tests/app/test_document_app.py +++ b/core/tests/app/test_document_app.py @@ -29,8 +29,8 @@ def read(self): # If the object has a "read_error" attribute, raise that exception raise self.read_error else: - # We don't actually care about the file or it's contents, but it needs to exist; - # so we open it to verify that behavior. + # We don't actually care about the file or it's contents, but it + # needs to exist; so we open it to verify that behavior. with self.path.open(): self._mock_read(self.path) @@ -255,7 +255,8 @@ def test_create_with_cmdline(monkeypatch, example_file): def test_create_with_unknown_document_type(monkeypatch, capsys): - """If the document specified at the command line is an unknown type, it is ignored.""" + """If the document specified at the command line is an unknown type, + it is ignored.""" monkeypatch.setattr(sys, "argv", ["app-exe", "/path/to/filename.unknown"]) app = ExampleDocumentApp( @@ -511,7 +512,8 @@ def test_open_bad_file(monkeypatch, doc_app, other_file): def test_open_existing_file(doc_app, example_file, other_file): - """If a document is already open, the existing document instance is returned and focused.""" + """If a document is already open, the existing document instance + is returned and focused.""" # Only the original document and window exists assert len(doc_app.documents) == 1 assert len(doc_app.windows) == 1 @@ -784,7 +786,8 @@ def test_open_menu_read_fail(monkeypatch, doc_app, example_file, other_file): def test_open_non_document_window(doc_app, example_file, other_file): - """If the current window isn't a document window, commit/cleanup behavior isn't used.""" + """If the current window isn't a document window, + commit/cleanup behavior isn't used.""" # Make a non-document window current. non_doc_window = toga.Window(title="Not a Document", content=toga.Box()) non_doc_window.show() diff --git a/core/tests/command/test_command.py b/core/tests/command/test_command.py index 32b399ea03..ee8d09126d 100644 --- a/core/tests/command/test_command.py +++ b/core/tests/command/test_command.py @@ -58,8 +58,8 @@ def test_create(): assert cmd.action._raw is None assert ( - repr(cmd) - == " section=0 order=0>" + repr(cmd) == " section=0 order=0>" ) @@ -153,8 +153,8 @@ def test_create_explicit(app): assert cmd.action._raw == handler assert ( - repr(cmd) - == " section=3 order=4>" + repr(cmd) == " section=3 order=4>" ) diff --git a/core/tests/command/test_group.py b/core/tests/command/test_group.py index 0aad412211..2dccc1060f 100644 --- a/core/tests/command/test_group.py +++ b/core/tests/command/test_group.py @@ -25,8 +25,8 @@ def test_create_with_params(): assert grp.parent == parent assert ( - repr(grp) - == " section=3>" + repr(grp) == " section=3>" ) diff --git a/core/tests/hardware/test_location.py b/core/tests/hardware/test_location.py index 5d12107f31..e714952de3 100644 --- a/core/tests/hardware/test_location.py +++ b/core/tests/hardware/test_location.py @@ -13,8 +13,8 @@ def test_no_location(monkeypatch, app): - """If there's no location service, and no factory implementation, accessing camera raises an - exception.""" + """If there's no location service, and no factory implementation, + accessing camera raises an exception.""" try: monkeypatch.delattr(app, "_location") except AttributeError: @@ -148,7 +148,8 @@ def test_request_background_permission_sync(app): def test_current_location_prior_permission(app): - """If permission has been previously requested, the current location can be determined.""" + """If permission has been previously requested, + the current location can be determined.""" # Set permission app.location._impl._has_permission = 1 diff --git a/core/tests/sources/test_list_source.py b/core/tests/sources/test_list_source.py index 84bed7ecd4..9d69bc8c35 100644 --- a/core/tests/sources/test_list_source.py +++ b/core/tests/sources/test_list_source.py @@ -415,6 +415,7 @@ def test_find(source): # An overspecified search will fail with pytest.raises( ValueError, - match=r"No row matching {'val1': 'first', 'val2': 111, 'value': 'overspecified'} in data", + match=r"No row matching " + r"{'val1': 'first', 'val2': 111, 'value': 'overspecified'} in data", ): source.find(dict(val1="first", val2=111, value="overspecified")) diff --git a/core/tests/style/pack/test_css.py b/core/tests/style/pack/test_css.py index b3f924e256..fa15a19b67 100644 --- a/core/tests/style/pack/test_css.py +++ b/core/tests/style/pack/test_css.py @@ -363,7 +363,8 @@ # Background Color pytest.param( Pack(background_color=REBECCAPURPLE), - "flex-direction: row; flex: 0.0 0 auto; background-color: rgb(102, 51, 153);", + "flex-direction: row; flex: " + "0.0 0 auto; background-color: rgb(102, 51, 153);", id="background-color", ), # Text Alignment diff --git a/core/tests/style/pack/utils.py b/core/tests/style/pack/utils.py index dd55f2dbc5..bf9e5c315c 100644 --- a/core/tests/style/pack/utils.py +++ b/core/tests/style/pack/utils.py @@ -81,13 +81,15 @@ def _assert_layout(node, expected_layout): node.layout.absolute_content_left, node.layout.absolute_content_top, ) == expected_layout["origin"], ( - f"origin of {node} ({node.layout.absolute_content_left}, {node.layout.absolute_content_top}) " + f"origin of {node} ({node.layout.absolute_content_left}, " + f"{node.layout.absolute_content_top}) " f"doesn't match expected {expected_layout['origin']}" ) assert (node.layout.content_width, node.layout.content_height) == expected_layout[ "content" ], ( - f"content size of {node} ({node.layout.content_width}, {node.layout.content_height}) " + f"content size of " + f"{node} ({node.layout.content_width}, {node.layout.content_height}) " f"doesn't match expected {expected_layout['content']}" ) diff --git a/core/tests/test_handlers.py b/core/tests/test_handlers.py index 682ab07488..aad58f6d00 100644 --- a/core/tests/test_handlers.py +++ b/core/tests/test_handlers.py @@ -55,8 +55,8 @@ def test_noop_handler_with_cleanup_error(capsys): # Evidence of the handler cleanup error is in the log. assert ( - "Error in handler cleanup: Problem in cleanup\nTraceback (most recent call last):\n" - in capsys.readouterr().err + "Error in handler cleanup: Problem in cleanup\n" + "Traceback (most recent call last):\n" in capsys.readouterr().err ) @@ -174,8 +174,8 @@ def handler(*args, **kwargs): # Evidence of the handler cleanup error is in the log. assert ( - "Error in handler cleanup: Problem in cleanup\nTraceback (most recent call last):\n" - in capsys.readouterr().err + "Error in handler cleanup: Problem in cleanup\n" + "Traceback (most recent call last):\n" in capsys.readouterr().err ) @@ -242,8 +242,8 @@ def handler(*args, **kwargs): # Evidence of the handler cleanup error is in the log. assert ( - "Error in long running handler: Problem in handler\nTraceback (most recent call last):\n" - in capsys.readouterr().err + "Error in long running handler: Problem in handler\n" + "Traceback (most recent call last):\n" in capsys.readouterr().err ) @@ -322,8 +322,8 @@ def handler(*args, **kwargs): # Evidence of the handler cleanup error is in the log. assert ( - "Error in long running handler cleanup: Problem in cleanup\nTraceback (most recent call last):\n" - in capsys.readouterr().err + "Error in long running handler cleanup: Problem in cleanup\n" + "Traceback (most recent call last):\n" in capsys.readouterr().err ) @@ -387,8 +387,8 @@ async def handler(*args, **kwargs): # Evidence of the handler cleanup error is in the log. assert ( - "Error in async handler: Problem in handler\nTraceback (most recent call last):\n" - in capsys.readouterr().err + "Error in async handler: Problem in handler\n" + "Traceback (most recent call last):\n" in capsys.readouterr().err ) @@ -461,8 +461,8 @@ async def handler(*args, **kwargs): # Evidence of the handler cleanup error is in the log. assert ( - "Error in async handler cleanup: Problem in cleanup\nTraceback (most recent call last):\n" - in capsys.readouterr().err + "Error in async handler cleanup: Problem in cleanup\n" + "Traceback (most recent call last):\n" in capsys.readouterr().err ) diff --git a/core/tests/test_icons.py b/core/tests/test_icons.py index d5095ad366..d8aa5aa5a3 100644 --- a/core/tests/test_icons.py +++ b/core/tests/test_icons.py @@ -216,7 +216,8 @@ def test_create_app_icon_non_script(monkeypatch, app, capsys): def test_create_app_icon_missing_non_script(monkeypatch, app, capsys): - """If the icon from binary executable cannot be found, the app icon is reset to the default""" + """If the icon from binary executable cannot be found, + the app icon is reset to the default""" # Prime the dummy so the app icon cannot be found monkeypatch.setattr( DummyIcon, diff --git a/core/tests/test_paths.py b/core/tests/test_paths.py index 30f23b7d66..1931a10e90 100644 --- a/core/tests/test_paths.py +++ b/core/tests/test_paths.py @@ -39,20 +39,21 @@ def assert_paths(output, app_path, app_name): results = output.splitlines() assert f"app.paths.app={app_path.resolve()}" in results assert ( - f"app.paths.config={(Path.home() / 'config' / f'org.testbed.{app_name}').resolve()}" - in results + f"app.paths.config=" + f"{(Path.home() / 'config' / f'org.testbed.{app_name}').resolve()}" in results ) assert ( - f"app.paths.data={(Path.home() / 'user_data' / f'org.testbed.{app_name}').resolve()}" + f"app.paths.data=" + f"{(Path.home() / 'user_data' / f'org.testbed.{app_name}').resolve()}" in results ) assert ( - f"app.paths.cache={(Path.home() / 'cache' / f'org.testbed.{app_name}').resolve()}" - in results + f"app.paths.cache=" + f"{(Path.home() / 'cache' / f'org.testbed.{app_name}').resolve()}" in results ) assert ( - f"app.paths.logs={(Path.home() / 'logs' / f'org.testbed.{app_name}').resolve()}" - in results + f"app.paths.logs=" + f"{(Path.home() / 'logs' / f'org.testbed.{app_name}').resolve()}" in results ) assert f"app.paths.toga={Path(toga.__file__).parent.resolve()}" in results diff --git a/core/tests/test_platform.py b/core/tests/test_platform.py index 423f97c868..fff64c76c3 100644 --- a/core/tests/test_platform.py +++ b/core/tests/test_platform.py @@ -199,6 +199,7 @@ def test_environment_variable_fail(monkeypatch): monkeypatch.setenv("TOGA_BACKEND", "fake_platform_module") with pytest.raises( RuntimeError, - match=r"The backend specified by TOGA_BACKEND \('fake_platform_module'\) could not be loaded.", + match=r"The backend specified by TOGA_BACKEND " + r"\('fake_platform_module'\) could not be loaded.", ): _get_platform_factory() diff --git a/core/tests/widgets/canvas/test_canvas.py b/core/tests/widgets/canvas/test_canvas.py index 8fe1f432b5..2afbb5c3c3 100644 --- a/core/tests/widgets/canvas/test_canvas.py +++ b/core/tests/widgets/canvas/test_canvas.py @@ -165,31 +165,36 @@ def test_deprecated_drawing_operations(widget): with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; use context.begin_path()", + match=r"Direct canvas operations have been deprecated; " + r"use context.begin_path()", ): widget.new_path() with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; use context.move_to()", + match=r"Direct canvas operations have been deprecated; " + r"use context.move_to()", ): widget.move_to(10, 20) with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; use context.line_to()", + match=r"Direct canvas operations have been deprecated; " + r"use context.line_to()", ): widget.line_to(10, 20) with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; use context.bezier_curve_to()", + match=r"Direct canvas operations have been deprecated; " + r"use context.bezier_curve_to()", ): widget.bezier_curve_to(1, 2, 3, 4, 10, 20) with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; use context.quadratic_curve_to()", + match=r"Direct canvas operations have been deprecated; " + r"use context.quadratic_curve_to()", ): widget.quadratic_curve_to(1, 2, 10, 20) @@ -213,7 +218,8 @@ def test_deprecated_drawing_operations(widget): with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; use context.write_text()", + match=r"Direct canvas operations have been deprecated; " + r"use context.write_text()", ): widget.write_text("Hello World", 10, 20, Font("Cutive", 37)) @@ -237,7 +243,8 @@ def test_deprecated_drawing_operations(widget): with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; use context.reset_transform()", + match=r"Direct canvas operations have been deprecated; " + r"use context.reset_transform()", ): widget.reset_transform() diff --git a/core/tests/widgets/canvas/test_context_objects.py b/core/tests/widgets/canvas/test_context_objects.py index a4228447e8..a9e91075f9 100644 --- a/core/tests/widgets/canvas/test_context_objects.py +++ b/core/tests/widgets/canvas/test_context_objects.py @@ -272,7 +272,8 @@ def test_fill(widget, kwargs, args_repr, has_move, properties): # Color ( {"color": REBECCAPURPLE}, - f"x=None, y=None, color={REBECCA_PURPLE_COLOR}, line_width=2.0, line_dash=None", + f"x=None, y=None, color={REBECCA_PURPLE_COLOR}, " + f"line_width=2.0, line_dash=None", False, { "x": None, @@ -330,7 +331,8 @@ def test_fill(widget, kwargs, args_repr, has_move, properties): "line_width": 4.5, "line_dash": [2, 7], }, - f"x=10, y=20, color={REBECCA_PURPLE_COLOR}, line_width=4.5, line_dash=[2, 7]", + f"x=10, y=20, color={REBECCA_PURPLE_COLOR}, " + f"line_width=4.5, line_dash=[2, 7]", True, { "x": 10, diff --git a/core/tests/widgets/canvas/test_draw_operations.py b/core/tests/widgets/canvas/test_draw_operations.py index fc85bcfb98..069d286533 100644 --- a/core/tests/widgets/canvas/test_draw_operations.py +++ b/core/tests/widgets/canvas/test_draw_operations.py @@ -262,7 +262,8 @@ def test_quadratic_curve_to(widget): # Defaults ( {"x": 10, "y": 20, "radius": 30}, - "x=10, y=20, radius=30, startangle=0.000, endangle=6.283, anticlockwise=False", + "x=10, y=20, radius=30, startangle=0.000, " + "endangle=6.283, anticlockwise=False", { "x": 10, "y": 20, @@ -275,7 +276,8 @@ def test_quadratic_curve_to(widget): # Start angle ( {"x": 10, "y": 20, "radius": 30, "startangle": 1.234}, - "x=10, y=20, radius=30, startangle=1.234, endangle=6.283, anticlockwise=False", + "x=10, y=20, radius=30, startangle=1.234, " + "endangle=6.283, anticlockwise=False", { "x": 10, "y": 20, @@ -293,7 +295,8 @@ def test_quadratic_curve_to(widget): "radius": 30, "endangle": 2.345, }, - "x=10, y=20, radius=30, startangle=0.000, endangle=2.345, anticlockwise=False", + "x=10, y=20, radius=30, startangle=0.000, " + "endangle=2.345, anticlockwise=False", { "x": 10, "y": 20, @@ -311,7 +314,8 @@ def test_quadratic_curve_to(widget): "radius": 30, "anticlockwise": False, }, - "x=10, y=20, radius=30, startangle=0.000, endangle=6.283, anticlockwise=False", + "x=10, y=20, radius=30, startangle=0.000, " + "endangle=6.283, anticlockwise=False", { "x": 10, "y": 20, @@ -329,7 +333,8 @@ def test_quadratic_curve_to(widget): "radius": 30, "anticlockwise": True, }, - "x=10, y=20, radius=30, startangle=0.000, endangle=6.283, anticlockwise=True", + "x=10, y=20, radius=30, startangle=0.000, " + "endangle=6.283, anticlockwise=True", { "x": 10, "y": 20, @@ -349,7 +354,8 @@ def test_quadratic_curve_to(widget): "endangle": 2.345, "anticlockwise": True, }, - "x=10, y=20, radius=30, startangle=1.234, endangle=2.345, anticlockwise=True", + "x=10, y=20, radius=30, startangle=1.234, " + "endangle=2.345, anticlockwise=True", { "x": 10, "y": 20, diff --git a/core/tests/widgets/test_optioncontainer.py b/core/tests/widgets/test_optioncontainer.py index bdf83fcc4d..101d6ef8c5 100644 --- a/core/tests/widgets/test_optioncontainer.py +++ b/core/tests/widgets/test_optioncontainer.py @@ -126,7 +126,8 @@ def test_widget_create_invalid_content(value): with pytest.raises( ValueError, match=( - r"Content items must be an OptionItem instance, or tuples of \(title, widget\), " + r"Content items must be an OptionItem instance, " + r"or tuples of \(title, widget\), " r"\(title, widget, icon\), or \(title, widget, icon, enabled\)" ), ): diff --git a/core/tests/widgets/test_scrollcontainer.py b/core/tests/widgets/test_scrollcontainer.py index a17013eaaa..b0b6e6d8ad 100644 --- a/core/tests/widgets/test_scrollcontainer.py +++ b/core/tests/widgets/test_scrollcontainer.py @@ -321,7 +321,8 @@ def test_horizontal_position_when_not_horizontal(scroll_container): scroll_container.horizontal = False with pytest.raises( ValueError, - match=r"Cannot set horizontal position when horizontal scrolling is not enabled.", + match=r"Cannot set horizontal position " + r"when horizontal scrolling is not enabled.", ): scroll_container.horizontal_position = 37 diff --git a/core/tests/widgets/test_slider.py b/core/tests/widgets/test_slider.py index f5a5a0e46f..143e6502c4 100644 --- a/core/tests/widgets/test_slider.py +++ b/core/tests/widgets/test_slider.py @@ -338,8 +338,8 @@ def test_set_value_with_tick_count( slider, on_change, approx(value), tick_value=tick_value, change_count=1 ) - # Resetting the same value should round to the same result, so on_change should not be - # called. + # Resetting the same value should round to the same result, so on_change should not + # be called. on_change.reset_mock() slider.value = INITIAL_VALUE assert_value( diff --git a/core/tests/widgets/test_webview.py b/core/tests/widgets/test_webview.py index b8f1dcada8..ecbfda751e 100644 --- a/core/tests/widgets/test_webview.py +++ b/core/tests/widgets/test_webview.py @@ -193,7 +193,8 @@ def test_evaluate_javascript(widget): # Attempting to use or compare the result raises an error with pytest.raises( RuntimeError, - match=r"Can't check JavaScript result directly; use await or an on_result handler", + match=r"Can't check JavaScript result directly; " + r"use await or an on_result handler", ): result == 42 diff --git a/core/tests/window/test_document_window.py b/core/tests/window/test_document_window.py index 9c603ffda9..84f56f33b4 100644 --- a/core/tests/window/test_document_window.py +++ b/core/tests/window/test_document_window.py @@ -20,7 +20,8 @@ def read(self): # If the object has a "read_error" attribute, raise that exception raise self.read_error else: - # We don't actually care about the file or it's contents, but it needs to exist; + # We don't actually care about the file or it's contents, + # but it needs to exist; # so we open it to verify that behavior. with self.path.open(): self._mock_read(self.path) diff --git a/core/tests/window/test_filtered_widget_registry.py b/core/tests/window/test_filtered_widget_registry.py index 7cdb6662c8..d8c4af16c7 100644 --- a/core/tests/window/test_filtered_widget_registry.py +++ b/core/tests/window/test_filtered_widget_registry.py @@ -178,7 +178,8 @@ def test_reuse_id(app): assert "magic" not in win_2.widgets assert app.widgets["magic"] == first - # The second widget can't be added as content to either window, because of the ID clash. + # The second widget can't be added as content to either window, + # because of the ID clash. with pytest.raises( KeyError, match=r"There is already a widget with the id 'magic'", @@ -190,7 +191,8 @@ def test_reuse_id(app): assert "magic" not in win_2.widgets assert app.widgets["magic"] == first - # The widget can't be added to a different window, because there's still an app-level conflict. + # The widget can't be added to a different window, + # because there's still an app-level conflict. with pytest.raises( KeyError, match=r"There is already a widget with the id 'magic'", diff --git a/core/tests/window/test_window.py b/core/tests/window/test_window.py index c619577a60..dcb85eb5a8 100644 --- a/core/tests/window/test_window.py +++ b/core/tests/window/test_window.py @@ -488,7 +488,8 @@ def test_widget_id_reusablity(window, app): assert CONTENT_WIDGET_ID in app.widgets assert LABEL_WIDGET_ID in app.widgets - # CONTENT_WIDGET_ID is in use, so a widget with that ID can't be assigned to a window. + # CONTENT_WIDGET_ID is in use, so a widget with that ID can't be assigned + # to a window. with pytest.raises( KeyError, match=r"There is already a widget with the id 'sample_label'", @@ -554,7 +555,8 @@ def test_deprecated_info_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"info_dialog\(...\) has been deprecated; use dialog\(toga.InfoDialog\(...\)\)", + match=r"info_dialog\(...\) has been deprecated; " + r"use dialog\(toga.InfoDialog\(...\)\)", ): dialog = window.info_dialog("Title", "Body", on_result=on_result_handler) @@ -595,7 +597,8 @@ def test_deprecated_question_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"question_dialog\(...\) has been deprecated; use dialog\(toga.QuestionDialog\(...\)\)", + match=r"question_dialog\(...\) has been deprecated; " + r"use dialog\(toga.QuestionDialog\(...\)\)", ): dialog = window.question_dialog("Title", "Body", on_result=on_result_handler) @@ -636,7 +639,8 @@ def test_deprecated_confirm_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"confirm_dialog\(...\) has been deprecated; use dialog\(toga.ConfirmDialog\(...\)\)", + match=r"confirm_dialog\(...\) has been deprecated; " + r"use dialog\(toga.ConfirmDialog\(...\)\)", ): dialog = window.confirm_dialog("Title", "Body", on_result=on_result_handler) @@ -677,7 +681,8 @@ def test_deprecated_error_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"error_dialog\(...\) has been deprecated; use dialog\(toga.ErrorDialog\(...\)\)", + match=r"error_dialog\(...\) has been deprecated; " + r"use dialog\(toga.ErrorDialog\(...\)\)", ): dialog = window.error_dialog("Title", "Body", on_result=on_result_handler) @@ -718,7 +723,8 @@ def test_deprecated_stack_trace_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"stack_trace_dialog\(...\) has been deprecated; use dialog\(toga.StackTraceDialog\(...\)\)", + match=r"stack_trace_dialog\(...\) has been deprecated; " + r"use dialog\(toga.StackTraceDialog\(...\)\)", ): dialog = window.stack_trace_dialog( "Title", @@ -767,7 +773,8 @@ def test_deprecated_save_file_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"save_file_dialog\(...\) has been deprecated; use dialog\(toga.SaveFileDialog\(...\)\)", + match=r"save_file_dialog\(...\) has been deprecated; " + r"use dialog\(toga.SaveFileDialog\(...\)\)", ): dialog = window.save_file_dialog( "Title", @@ -815,7 +822,8 @@ def test_deprecated_save_file_dialog_default_directory(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"save_file_dialog\(...\) has been deprecated; use dialog\(toga.SaveFileDialog\(...\)\)", + match=r"save_file_dialog\(...\) has been deprecated; " + r"use dialog\(toga.SaveFileDialog\(...\)\)", ): dialog = window.save_file_dialog( "Title", @@ -864,7 +872,8 @@ def test_deprecated_open_file_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"open_file_dialog\(...\) has been deprecated; use dialog\(toga.OpenFileDialog\(...\)\)", + match=r"open_file_dialog\(...\) has been deprecated; " + r"use dialog\(toga.OpenFileDialog\(...\)\)", ): dialog = window.open_file_dialog( "Title", @@ -915,7 +924,8 @@ def test_deprecated_open_file_dialog_default_directory(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"open_file_dialog\(...\) has been deprecated; use dialog\(toga.OpenFileDialog\(...\)\)", + match=r"open_file_dialog\(...\) has been deprecated; " + r"use dialog\(toga.OpenFileDialog\(...\)\)", ): dialog = window.open_file_dialog( "Title", @@ -964,7 +974,8 @@ def test_deprecated_select_folder_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"select_folder_dialog\(...\) has been deprecated; use dialog\(toga.SelectFolderDialog\(...\)\)", + match=r"select_folder_dialog\(...\) has been deprecated; " + r"use dialog\(toga.SelectFolderDialog\(...\)\)", ): dialog = window.select_folder_dialog( "Title", @@ -1014,7 +1025,8 @@ def test_deprecated_select_folder_dialog_default_directory(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"select_folder_dialog\(...\) has been deprecated; use dialog\(toga.SelectFolderDialog\(...\)\)", + match=r"select_folder_dialog\(...\) has been deprecated; " + r"use dialog\(toga.SelectFolderDialog\(...\)\)", ): dialog = window.select_folder_dialog( "Title", @@ -1061,10 +1073,12 @@ def test_deprecated_names_open_file_dialog(window, app): match=r"open_file_dialog\(multiselect\) has been renamed multiple_select", ), pytest.warns( DeprecationWarning, - match=r"Synchronous `on_result` handlers have been deprecated; use `await` on the asynchronous result", + match=r"Synchronous `on_result` handlers have been deprecated; " + r"use `await` on the asynchronous result", ), pytest.warns( DeprecationWarning, - match=r"open_file_dialog\(...\) has been deprecated; use dialog\(toga.OpenFileDialog\(...\)\)", + match=r"open_file_dialog\(...\) has been deprecated; " + r"use dialog\(toga.OpenFileDialog\(...\)\)", ): dialog = window.open_file_dialog( "Title", @@ -1100,13 +1114,16 @@ def test_deprecated_names_select_folder_dialog(window, app): with pytest.warns( DeprecationWarning, - match=r"select_folder_dialog\(multiselect\) has been renamed multiple_select", + match=r"select_folder_dialog\(multiselect\) " + r"has been renamed multiple_select", ), pytest.warns( DeprecationWarning, - match=r"Synchronous `on_result` handlers have been deprecated; use `await` on the asynchronous result", + match=r"Synchronous `on_result` handlers have been deprecated; " + r"use `await` on the asynchronous result", ), pytest.warns( DeprecationWarning, - match=r"select_folder_dialog\(...\) has been deprecated; use dialog\(toga.SelectFolderDialog\(...\)\)", + match=r"select_folder_dialog\(...\) has been deprecated; " + r"use dialog\(toga.SelectFolderDialog\(...\)\)", ): dialog = window.select_folder_dialog( "Title", diff --git a/docs/conf.py b/docs/conf.py index 35a409a998..08c1a6a99c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -369,11 +369,13 @@ def autodoc_process_signature( # -- Options for Todos ------------------------------------------- -# If this is True, todo and todolist produce output, else they produce nothing. The default is False. +# If this is True, todo and todolist produce output, else they produce nothing. +# The default is False. todo_include_todos = True # If this is True, todo emits a warning for each TODO entries. The default is False. # todo_emit_warnings = False -# If this is True, todolist produce output without file path and line, The default is False. +# If this is True, todolist produce output without file path and line, +# The default is False. # todo_link_only = False diff --git a/examples/beeliza/beeliza/bot.py b/examples/beeliza/beeliza/bot.py index 5d587a5231..95f9fc25c0 100644 --- a/examples/beeliza/beeliza/bot.py +++ b/examples/beeliza/beeliza/bot.py @@ -323,7 +323,8 @@ class Eliza: "Tell me more about your father.", "How did your father make you feel?", "How do you feel about your father?", - "Does your relationship with your father relate to your feelings today?", + "Does your relationship with your father " + "relate to your feelings today?", "Do you have trouble showing affection with your family?", ], ], @@ -334,7 +335,8 @@ class Eliza: "What is your favorite childhood memory?", "Do you remember any dreams or nightmares from childhood?", "Did the other children sometimes tease you?", - "How do you think your childhood experiences relate to your feelings today?", + "How do you think your childhood " + "experiences relate to your feelings today?", ], ], [ diff --git a/examples/hardware/hardware/app.py b/examples/hardware/hardware/app.py index 156f508afd..6d3f3e9841 100644 --- a/examples/hardware/hardware/app.py +++ b/examples/hardware/hardware/app.py @@ -195,7 +195,8 @@ async def request_background_location(self, widget, **kwargs): await self.main_window.dialog( toga.InfoDialog( "All good!", - "Application has permission to perform background location tracking", + "Application has permission to perform background " + "location tracking", ) ) else: @@ -212,7 +213,8 @@ async def request_background_location(self, widget, **kwargs): await self.main_window.dialog( toga.InfoDialog( "Oh no!", - "You have not granted permission for background location tracking", + "You have not granted permission for background " + "location tracking", ) ) except NotImplementedError: diff --git a/examples/positron-django/src/webapp/settings.py b/examples/positron-django/src/webapp/settings.py index 53b79bdcbd..94d083379f 100644 --- a/examples/positron-django/src/webapp/settings.py +++ b/examples/positron-django/src/webapp/settings.py @@ -85,7 +85,8 @@ AUTH_PASSWORD_VALIDATORS = [ { - "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + "NAME": "django.contrib.auth.password_validation." + "UserAttributeSimilarityValidator", }, { "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", diff --git a/examples/resize/resize/app.py b/examples/resize/resize/app.py index 5017ffa89b..1ce0f98e19 100644 --- a/examples/resize/resize/app.py +++ b/examples/resize/resize/app.py @@ -95,8 +95,8 @@ def on_change_text(self, panel, width, height, flex): setattr_if_changed(self.text_label.style, "flex", flex) def on_change_style(self, panel, width, height, flex): - # Increment should be large enough that the minimum window width can be determined - # by either the buttons or the labels, depending on the labels' size. + # Increment should be large enough that the minimum window width can be + # determined by either the buttons or the labels, depending on the labels' size. INCREMENT = 70 setattr_if_changed(self.style_label.style, "width", width * INCREMENT) setattr_if_changed(self.style_label.style, "height", height * INCREMENT) diff --git a/examples/screenshot/screenshot/app.py b/examples/screenshot/screenshot/app.py index 7e6cfa7204..41700fe61e 100644 --- a/examples/screenshot/screenshot/app.py +++ b/examples/screenshot/screenshot/app.py @@ -380,7 +380,8 @@ async def sequence(self, app, **kwargs): # image = self.main_window.screen.as_image() # cropped = image.crop(... crop to window size ...) # - # TODO: Crop the desktop image, rather than use a manual screenshot + # TODO: Crop the desktop image, + # rather than use a manual screenshot await self.main_window.dialog( toga.InfoDialog( "Manual intervention", @@ -397,7 +398,8 @@ async def sequence(self, app, **kwargs): # image = self.main_window.screen.as_image() # cropped = image.crop(... crop to window size ...) # - # TODO: Crop the desktop image, rather than use a manual screenshot + # TODO: Crop the desktop image, + # rather than use a manual screenshot await self.main_window.dialog( toga.InfoDialog( "Manual intervention", @@ -413,8 +415,8 @@ async def sequence(self, app, **kwargs): content_type in {"webview", "mapview"} and toga.platform.current_platform == "macOS" ): - # Manual screenshot required on macOS because screenshots don't contain - # all the rendered content. + # Manual screenshot required on macOS because screenshots don't + # contain all the rendered content. await self.main_window.dialog( toga.InfoDialog( "Manual intervention", diff --git a/examples/selection/selection/app.py b/examples/selection/selection/app.py index 17d9f75a0e..e3dede0464 100644 --- a/examples/selection/selection/app.py +++ b/examples/selection/selection/app.py @@ -140,7 +140,8 @@ def report_selection(self, widget): print( f"Element: {self.selection.value!r}; " f"Empty: {self.empty_selection.value!r}; " - f"Source: {self.source_selection.value.name} has weight {self.source_selection.value.weight}" + f"Source: {self.source_selection.value.name} " + f"has weight {self.source_selection.value.weight}" ) diff --git a/examples/statusiconapp/statusiconapp/app.py b/examples/statusiconapp/statusiconapp/app.py index 3151e55b9b..64e93db912 100644 --- a/examples/statusiconapp/statusiconapp/app.py +++ b/examples/statusiconapp/statusiconapp/app.py @@ -35,7 +35,8 @@ def startup(self): order=1, ) - # Create a submenu on the first status menu; the status icon is the parent group. + # Create a submenu on the first status menu; the status icon + # is the parent group. sub_menu = toga.Group("Sub Menu", parent=status_1, order=3) cmd3 = toga.Command( self.do_stuff, @@ -50,7 +51,8 @@ def startup(self): group=sub_menu, ) - # Two commands for the second status icon. The status icon can be retrieved by ID, + # Two commands for the second status icon. The status + # icon can be retrieved by ID, # and by index. cmd5 = toga.Command( self.do_stuff, diff --git a/examples/webview/webview/app.py b/examples/webview/webview/app.py index e81a20025f..de4c8b75b1 100644 --- a/examples/webview/webview/app.py +++ b/examples/webview/webview/app.py @@ -9,7 +9,8 @@ async def on_do_async_js(self, widget, **kwargs): def on_good_js(self, widget, **kwargs): self.webview.evaluate_javascript( - 'document.body.innerHTML = "I can invoke JS. User agent is " + navigator.userAgent;' + "document.body.innerHTML = " + '"I can invoke JS. User agent is " + navigator.userAgent;' ) def on_bad_js(self, widget, **kwargs): @@ -36,7 +37,8 @@ def on_clear_url(self, widget, **kwargs): def on_set_content(self, widget, **kwargs): self.webview.set_content( "https://example.com", - "I'm feeling very content", + "I'm feeling very " + "content", ) def on_get_agent(self, widget, **kwargs): diff --git a/gtk/src/toga_gtk/container.py b/gtk/src/toga_gtk/container.py index 9210eb1c8a..98d58f116d 100644 --- a/gtk/src/toga_gtk/container.py +++ b/gtk/src/toga_gtk/container.py @@ -156,17 +156,20 @@ def do_size_allocate(self, allocation): computed based on this new available size, and that new geometry will be applied to all child widgets of the container. """ - # print(self._content, f"Container layout {allocation.width}x{allocation.height} @ {allocation.x}x{allocation.y}") # noqa: E501 + # print(self._content, f"Container layout " + # "{allocation.width}x{allocation.height} @ {allocation.x}x{allocation.y}") + # # noqa: E501 # The container will occupy the full space it has been allocated. resized = (allocation.width, allocation.height) != (self.width, self.height) self.set_allocation(allocation) if self._content: - # This function may be called in response to irrelevant events like button clicks, - # so only refresh if we really need to. + # This function may be called in response to irrelevant events like button + # clicks, so only refresh if we really need to. if resized or self.needs_redraw: - # Re-evaluate the layout using the allocation size as the basis for geometry + # Re-evaluate the layout using the allocation size as the basis + # for geometry # print("REFRESH LAYOUT", allocation.width, allocation.height) self._content.interface.style.layout(self._content.interface, self) @@ -180,7 +183,8 @@ def do_size_allocate(self, allocation): for widget in self.get_children(): if widget.get_visible(): # Set the size of the child widget to the computed layout size. - # print(f" allocate child {widget.interface}: {widget.interface.layout}") + # print( + # f" allocate child {widget.interface}: {widget.interface.layout}") widget_allocation = Gdk.Rectangle() widget_allocation.x = ( widget.interface.layout.absolute_content_left + allocation.x diff --git a/gtk/src/toga_gtk/dialogs.py b/gtk/src/toga_gtk/dialogs.py index 968c1d2a38..854b14a5c7 100644 --- a/gtk/src/toga_gtk/dialogs.py +++ b/gtk/src/toga_gtk/dialogs.py @@ -113,7 +113,8 @@ def build_dialog(self, message, content, retry): self.native.format_secondary_text(message) - # Create a scrolling readonly text area, in monospace font, to contain the stack trace. + # Create a scrolling readonly text area, in monospace font, + # to contain the stack trace. buffer = Gtk.TextBuffer() buffer.set_text(content) diff --git a/gtk/src/toga_gtk/icons.py b/gtk/src/toga_gtk/icons.py index 2fd41752bb..70429c0e6e 100644 --- a/gtk/src/toga_gtk/icons.py +++ b/gtk/src/toga_gtk/icons.py @@ -20,13 +20,13 @@ def __init__(self, interface, path): usr = Path(sys.executable).parent.parent path = { size: ( - usr - / f"share/icons/hicolor/{size}x{size}/apps/{toga.App.app.app_id}.png" + usr / f"share/icons/hicolor/" + f"{size}x{size}/apps/{toga.App.app.app_id}.png" ) for size in self.SIZES if ( - usr - / f"share/icons/hicolor/{size}x{size}/apps/{toga.App.app.app_id}.png" + usr / f"share/icons/hicolor/" + f"{size}x{size}/apps/{toga.App.app.app_id}.png" ).is_file() } diff --git a/gtk/src/toga_gtk/images.py b/gtk/src/toga_gtk/images.py index 2cf2b7498d..bc8fd5cd32 100644 --- a/gtk/src/toga_gtk/images.py +++ b/gtk/src/toga_gtk/images.py @@ -34,7 +34,8 @@ def get_data(self): if success: return buffer else: # pragma: nocover - # This shouldn't ever happen, and it's difficult to manufacture in test conditions + # This shouldn't ever happen, and it's difficult to manufacture + # in test conditions raise ValueError("Unable to get PNG data for image") def save(self, path): diff --git a/gtk/src/toga_gtk/libs/fontconfig.py b/gtk/src/toga_gtk/libs/fontconfig.py index c3415e1845..6c72c6ae63 100644 --- a/gtk/src/toga_gtk/libs/fontconfig.py +++ b/gtk/src/toga_gtk/libs/fontconfig.py @@ -25,7 +25,8 @@ def __init__(self): self.config = fontconfig.FcConfigGetCurrent() else: # pragma: no cover print( - "Unable to initialize FontConfig library. Is libfontconfig.so.1 on your LD_LIBRARY_PATH?" + "Unable to initialize FontConfig library. " + "Is libfontconfig.so.1 on your LD_LIBRARY_PATH?" ) self.config = None diff --git a/gtk/src/toga_gtk/libs/gtk.py b/gtk/src/toga_gtk/libs/gtk.py index a9efbbd970..3b09918a8e 100644 --- a/gtk/src/toga_gtk/libs/gtk.py +++ b/gtk/src/toga_gtk/libs/gtk.py @@ -16,7 +16,8 @@ if Gdk.Screen.get_default() is None: # pragma: no cover raise RuntimeError( - "Cannot identify an active display. Is the `DISPLAY` environment variable set correctly?" + "Cannot identify an active display. Is the `DISPLAY` " + "environment variable set correctly?" ) IS_WAYLAND = not isinstance(Gdk.Display.get_default(), GdkX11.X11Display) diff --git a/gtk/src/toga_gtk/widgets/activityindicator.py b/gtk/src/toga_gtk/widgets/activityindicator.py index 54acfd3004..017770b062 100644 --- a/gtk/src/toga_gtk/widgets/activityindicator.py +++ b/gtk/src/toga_gtk/widgets/activityindicator.py @@ -16,7 +16,8 @@ def stop(self): self.native.stop() def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) + # print("REHINT", self, self.native.get_preferred_width(), + # self.native.get_preferred_height()) width = self.native.get_preferred_width() height = self.native.get_preferred_height() diff --git a/gtk/src/toga_gtk/widgets/base.py b/gtk/src/toga_gtk/widgets/base.py index d397d25eeb..03509c1175 100644 --- a/gtk/src/toga_gtk/widgets/base.py +++ b/gtk/src/toga_gtk/widgets/base.py @@ -185,7 +185,8 @@ def refresh(self): def rehint(self): # Perform the actual GTK rehint. - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) + # print("REHINT", self, self.native.get_preferred_width(), + # self.native.get_preferred_height()) width = self.native.get_preferred_width() height = self.native.get_preferred_height() diff --git a/gtk/src/toga_gtk/widgets/button.py b/gtk/src/toga_gtk/widgets/button.py index 4b02c3090f..53118e5a7d 100644 --- a/gtk/src/toga_gtk/widgets/button.py +++ b/gtk/src/toga_gtk/widgets/button.py @@ -41,7 +41,8 @@ def set_background_color(self, color): super().set_background_color(color) def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) + # print("REHINT", self, self.native.get_preferred_width(), + # self.native.get_preferred_height()) width = self.native.get_preferred_width() height = self.native.get_preferred_height() diff --git a/gtk/src/toga_gtk/widgets/canvas.py b/gtk/src/toga_gtk/widgets/canvas.py index 534c73e4f9..275f813995 100644 --- a/gtk/src/toga_gtk/widgets/canvas.py +++ b/gtk/src/toga_gtk/widgets/canvas.py @@ -299,7 +299,8 @@ def get_image_data(self): # Rehint def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) + # print("REHINT", self, self.native.get_preferred_width(), + # self.native.get_preferred_height()) # width = self.native.get_allocation().width # height = self.native.get_allocation().height width = self.interface._MIN_WIDTH diff --git a/gtk/src/toga_gtk/widgets/detailedlist.py b/gtk/src/toga_gtk/widgets/detailedlist.py index 1884a1e495..d9466266a5 100644 --- a/gtk/src/toga_gtk/widgets/detailedlist.py +++ b/gtk/src/toga_gtk/widgets/detailedlist.py @@ -44,7 +44,8 @@ def __init__(self, dl, row): self.show_all() def update(self, dl, row): - """Update the contents of the rendered row, using data from `row`, and accessors from the detailedList""" + """Update the contents of the rendered row, using data from `row`, + and accessors from the detailedList""" # Set the title and subtitle as a block of HTML text. try: @@ -237,9 +238,10 @@ def get_selection(self): return item_impl.get_index() def scroll_to_row(self, row: int): - # Rows are equally spaced; so the top of row N of M is at N/M of the overall height. - # We set the position based on the top of the window, so aim to put the scroller - # half the widget height above the start of the selected row, clipping at 0 + # Rows are equally spaced; so the top of row N of M is at N/M of the overall + # height. We set the position based on the top of the window, so aim to put the + # scroller half the widget height above the start of the selected row, clipping + # at 0 self.native_vadj.set_value( max( row / len(self.store) * self.native_vadj.get_upper() @@ -278,7 +280,8 @@ def after_on_refresh(self, widget, result): def gtk_on_value_changed(self, adj): # The vertical scroll value has changed. - # Update the refresh button; hide the buttons on the active row (if they're active) + # Update the refresh button; hide the buttons on the active row + # (if they're active) self.update_refresh_button() self.hide_actions() diff --git a/gtk/src/toga_gtk/widgets/label.py b/gtk/src/toga_gtk/widgets/label.py index f6ca0135ef..30e46b04f6 100644 --- a/gtk/src/toga_gtk/widgets/label.py +++ b/gtk/src/toga_gtk/widgets/label.py @@ -26,7 +26,8 @@ def set_text(self, value): def rehint(self): # print("REHINT", self, # self.native.get_preferred_width(), self.native.get_preferred_height(), - # getattr(self, '_fixed_height', False), getattr(self, '_fixed_width', False) + # getattr(self, '_fixed_height', False), getattr(self, + # '_fixed_width', False) # ) width = self.native.get_preferred_width() height = self.native.get_preferred_height() diff --git a/gtk/src/toga_gtk/widgets/mapview.py b/gtk/src/toga_gtk/widgets/mapview.py index eec16a3d3b..ab480859f8 100644 --- a/gtk/src/toga_gtk/widgets/mapview.py +++ b/gtk/src/toga_gtk/widgets/mapview.py @@ -43,7 +43,7 @@ -""" +""" # noqa: E501 def pin_id(pin): @@ -72,7 +72,8 @@ def create(self): raise RuntimeError( "Unable to import WebKit2. Ensure that the system package " "providing WebKit2 and its GTK bindings have been installed. " - "See https://toga.readthedocs.io/en/stable/reference/api/widgets/mapview.html#system-requirements " + "See https://toga.readthedocs.io" + "/en/stable/reference/api/widgets/mapview.html#system-requirements " "for details." ) @@ -113,8 +114,8 @@ def _invoke(self, javascript): # A callback that will update the future when the Javascript is # complete. def js_finished(webview, result, *user_data): - """If `evaluate_javascript_finish` from GTK returns a result, unmarshal it, and - call back with the result.""" + """If `evaluate_javascript_finish` from GTK returns a result, unmarshal it, + and call back with the result.""" try: value = webview.evaluate_javascript_finish(result) if value.is_number(): diff --git a/gtk/src/toga_gtk/widgets/progressbar.py b/gtk/src/toga_gtk/widgets/progressbar.py index f44ea3b026..e3a8a405d6 100644 --- a/gtk/src/toga_gtk/widgets/progressbar.py +++ b/gtk/src/toga_gtk/widgets/progressbar.py @@ -91,7 +91,8 @@ def stop(self): self._stop_indeterminate() def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) + # print("REHINT", self, self.native.get_preferred_width(), + # self.native.get_preferred_height()) width = self.native.get_preferred_width() height = self.native.get_preferred_height() diff --git a/gtk/src/toga_gtk/widgets/scrollcontainer.py b/gtk/src/toga_gtk/widgets/scrollcontainer.py index ce13d9fa29..ef30219016 100644 --- a/gtk/src/toga_gtk/widgets/scrollcontainer.py +++ b/gtk/src/toga_gtk/widgets/scrollcontainer.py @@ -13,7 +13,8 @@ def create(self): self.native.get_vadjustment().connect("changed", self.gtk_on_changed) # Set this minimum size of scroll windows because we must reserve space for - # scrollbars when splitter resized. See, https://gitlab.gnome.org/GNOME/gtk/-/issues/210 + # scrollbars when splitter resized. See, + # https://gitlab.gnome.org/GNOME/gtk/-/issues/210 self.native.set_min_content_width(self.interface._MIN_WIDTH) self.native.set_min_content_height(self.interface._MIN_HEIGHT) diff --git a/gtk/src/toga_gtk/widgets/slider.py b/gtk/src/toga_gtk/widgets/slider.py index f5d4766372..5f5832e1ef 100644 --- a/gtk/src/toga_gtk/widgets/slider.py +++ b/gtk/src/toga_gtk/widgets/slider.py @@ -82,7 +82,8 @@ def get_tick_count(self): return self.tick_count def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) + # print("REHINT", self, self.native.get_preferred_width(), + # self.native.get_preferred_height()) height = self.native.get_preferred_height() # Set intrinsic width to at least the minimum width diff --git a/gtk/src/toga_gtk/widgets/switch.py b/gtk/src/toga_gtk/widgets/switch.py index 8c86d2bc1f..b891c07d4a 100644 --- a/gtk/src/toga_gtk/widgets/switch.py +++ b/gtk/src/toga_gtk/widgets/switch.py @@ -52,7 +52,8 @@ def set_font(self, font): self.apply_css("font", get_font_css(font), native=self.native_label) def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), self.native.get_preferred_height()) + # print("REHINT", self, self.native.get_preferred_width(), + # self.native.get_preferred_height()) label_width = self.native_label.get_preferred_width() label_height = self.native_label.get_preferred_height() diff --git a/gtk/src/toga_gtk/widgets/textinput.py b/gtk/src/toga_gtk/widgets/textinput.py index 8481b255b0..f2c04bbc2e 100644 --- a/gtk/src/toga_gtk/widgets/textinput.py +++ b/gtk/src/toga_gtk/widgets/textinput.py @@ -56,7 +56,8 @@ def set_value(self, value): def rehint(self): # print("REHINT", self, # self._impl.get_preferred_width(), self._impl.get_preferred_height(), - # getattr(self, '_fixed_height', False), getattr(self, '_fixed_width', False) + # getattr(self, '_fixed_height', False), + # getattr(self, '_fixed_width', False) # ) width = self.native.get_preferred_width() height = self.native.get_preferred_height() diff --git a/gtk/src/toga_gtk/widgets/webview.py b/gtk/src/toga_gtk/widgets/webview.py index 15ff96bd3a..5a90dabcf2 100644 --- a/gtk/src/toga_gtk/widgets/webview.py +++ b/gtk/src/toga_gtk/widgets/webview.py @@ -14,7 +14,8 @@ def create(self): raise RuntimeError( "Unable to import WebKit2. Ensure that the system package " "providing WebKit2 and its GTK bindings have been installed. " - "See https://toga.readthedocs.io/en/stable/reference/api/widgets/webview.html#system-requirements " + "See https://toga.readthedocs.io" + "/en/stable/reference/api/widgets/webview.html#system-requirements " "for details." ) @@ -82,8 +83,8 @@ def evaluate_javascript(self, javascript, on_result=None): # Define a callback that will update the future when # the Javascript is complete. def gtk_js_finished(webview, task, *user_data): - """If `evaluate_javascript_finish` from GTK returns a result, unmarshal it, and - call back with the result.""" + """If `evaluate_javascript_finish` from GTK returns a result, unmarshal it, + and call back with the result.""" try: value = webview.evaluate_javascript_finish(task) if value.is_boolean(): diff --git a/gtk/src/toga_gtk/window.py b/gtk/src/toga_gtk/window.py index dd13787267..3cc46f653f 100644 --- a/gtk/src/toga_gtk/window.py +++ b/gtk/src/toga_gtk/window.py @@ -179,7 +179,8 @@ def get_image_data(self): if success: return buffer else: # pragma: nocover - # This shouldn't ever happen, and it's difficult to manufacture in test conditions + # This shouldn't ever happen, and it's difficult to manufacture + # in test conditions raise ValueError(f"Unable to generate screenshot of {self}") @@ -201,7 +202,8 @@ def create_toolbar(self): # If there's an existing toolbar, hide it until we know we need it. self.layout.remove(self.native_toolbar) - # Deregister any toolbar buttons from their commands, and remove them from the toolbar + # Deregister any toolbar buttons from their commands, and remove them + # from the toolbar for cmd, item_impl in self.toolbar_items.items(): self.native_toolbar.remove(item_impl) cmd._impl.native.remove(item_impl) diff --git a/gtk/tests_backend/app.py b/gtk/tests_backend/app.py index dc23baf8a1..e1fef60b72 100644 --- a/gtk/tests_backend/app.py +++ b/gtk/tests_backend/app.py @@ -57,13 +57,13 @@ def content_size(self, window): def assert_app_icon(self, icon): for window in self.app.windows: - # We have no real way to check we've got the right icon; use pixel peeping as a - # guess. Construct a PIL image from the current icon. + # We have no real way to check we've got the right icon; use pixel peeping + # as a guess. Construct a PIL image from the current icon. img = toga.Image(window._impl.native.get_icon()).as_format(PIL.Image.Image) if icon: - # The explicit alt icon has blue background, with green at a point 1/3 into - # the image + # The explicit alt icon has blue background, with green at a point 1/3 + # into the image assert img.getpixel((5, 5)) == (211, 230, 245) mid_color = img.getpixel((img.size[0] // 3, img.size[1] // 3)) assert mid_color == (0, 204, 9) diff --git a/gtk/tests_backend/dialogs.py b/gtk/tests_backend/dialogs.py index cf0c7df61f..3d90501dde 100644 --- a/gtk/tests_backend/dialogs.py +++ b/gtk/tests_backend/dialogs.py @@ -102,9 +102,9 @@ def close_handler(dialog, gtk_result): if result is not None: if multiple_select: if result: - # Since we are mocking selected_path(), it's never actually invoked - # under test conditions. Call it just to confirm that it returns the - # type we think it does. + # Since we are mocking selected_path(), it's never actually + # invoked under test conditions. Call it just to confirm that + # it returns the type we think it does. assert isinstance(dialog._impl.selected_paths(), list) dialog._impl.selected_paths = Mock( @@ -144,9 +144,9 @@ def close_handler(dialog, gtk_result): if result is not None: if multiple_select: if result: - # Since we are mocking selected_path(), it's never actually invoked - # under test conditions. Call it just to confirm that it returns the - # type we think it does. + # Since we are mocking selected_path(), it's never actually + # invoked under test conditions. Call it just to confirm that + # it returns the type we think it does. assert isinstance(dialog._impl.selected_paths(), list) dialog._impl.selected_paths = Mock( @@ -155,11 +155,11 @@ def close_handler(dialog, gtk_result): else: dialog._impl.selected_path = Mock(return_value=str(result)) - # GTK's file dialog might open on default location that doesn't have anything - # that can be selected, which alters closing behavior. To provide consistent - # test conditions, select an arbitrary folder that we know has subfolders. We - # don't care which folder it is, as we're mocking the return value of the - # dialog. + # GTK's file dialog might open on default location that doesn't have + # anything that can be selected, which alters closing behavior. To provide + # consistent test conditions, select an arbitrary folder that we know has + # subfolders. We don't care which folder it is, as we're mocking the return + # value of the dialog. self._wait_for_dialog("Wait for dialog to appear") if result: folder = str(Path(__file__).parent.parent) diff --git a/gtk/tests_backend/widgets/switch.py b/gtk/tests_backend/widgets/switch.py index 4a87668992..0c85054152 100644 --- a/gtk/tests_backend/widgets/switch.py +++ b/gtk/tests_backend/widgets/switch.py @@ -44,7 +44,8 @@ def assert_width(self, min_width, max_width): (min_width - MAX_SWITCH_WIDTH) <= label_width <= (max_width - MAX_SWITCH_WIDTH) - ), f"Label width ({label_width}) not in range ({min_width - MAX_SWITCH_WIDTH}, {max_width - MAX_SWITCH_WIDTH})" + ), f"Label width ({label_width}) not in range " + f"({min_width - MAX_SWITCH_WIDTH}, {max_width - MAX_SWITCH_WIDTH})" assert ( 0 <= switch_width <= MAX_SWITCH_WIDTH ), f"Switch width ({switch_width}) not in range (0-60)" diff --git a/gtk/tests_backend/window.py b/gtk/tests_backend/window.py index ae6f6f0a07..eb569030ab 100644 --- a/gtk/tests_backend/window.py +++ b/gtk/tests_backend/window.py @@ -5,8 +5,9 @@ class WindowProbe(BaseProbe, DialogsMixin): - # GTK defers a lot of window behavior to the window manager, which means some features - # either don't exist, or we can't guarantee they behave the way Toga would like. + # GTK defers a lot of window behavior to the window manager, which means some + # features either don't exist, or we can't guarantee they behave the way Toga would + # like. supports_closable = True supports_minimizable = False supports_move_while_hidden = False @@ -72,7 +73,8 @@ def assert_toolbar_item(self, index, label, tooltip, has_icon, enabled): # FIXME: get_tooltip_text() doesn't work. The tooltip can be set, but the # API to return the value just doesn't work. If it is ever fixed, this # is the test for it: - # assert (None if item.get_tooltip_text() is None else item.get_tooltip_text()) == tooltip + # assert (None if item.get_tooltip_text() is None + # else item.get_tooltip_text()) == tooltip assert (item.get_icon_widget() is not None) == has_icon assert item.get_sensitive() == enabled diff --git a/iOS/src/toga_iOS/constraints.py b/iOS/src/toga_iOS/constraints.py index dc3e4df076..80c494c4c9 100644 --- a/iOS/src/toga_iOS/constraints.py +++ b/iOS/src/toga_iOS/constraints.py @@ -50,13 +50,14 @@ def container(self): @container.setter def container(self, value): - # This will *always* remove and then add constraints. It relies on the base widget to - # *not* invoke this setter unless the container is actually changing. + # This will *always* remove and then add constraints. It relies on the base + # widget to *not* invoke this setter unless the container is actually changing. self._remove_constraints() self._container = value if value is not None: - # print(f"Add constraints for {self.widget} in {self.container} {self.widget.interface.layout}") + # print(f"Add constraints for {self.widget} in {self.container} + # {self.widget.interface.layout}") self.left_constraint = NSLayoutConstraint.constraintWithItem( self.widget.native, attribute__1=NSLayoutAttributeLeft, @@ -102,7 +103,8 @@ def container(self, value): self.container.native.addConstraint(self.height_constraint) def update(self, x, y, width, height): - # print(f"UPDATE CONSTRAINTS {self.widget} in {self.container} {width}x{height}@{x},{y}") + # print(f"UPDATE CONSTRAINTS {self.widget} in {self.container} + # {width}x{height}@{x},{y}") self.left_constraint.constant = x self.top_constraint.constant = y diff --git a/iOS/src/toga_iOS/dialogs.py b/iOS/src/toga_iOS/dialogs.py index c2c97d6af3..b629f9352e 100644 --- a/iOS/src/toga_iOS/dialogs.py +++ b/iOS/src/toga_iOS/dialogs.py @@ -17,7 +17,7 @@ def show(self, host_window, future): if self.native: # Don't differentiate between app and window-modal dialogs. - toga.App.app.current_window._impl.native.rootViewController.presentViewController( + toga.App.app.current_window._impl.native.rootViewController.presentViewController( # noqa: E501 self.native, animated=False, completion=None, diff --git a/iOS/src/toga_iOS/hardware/camera.py b/iOS/src/toga_iOS/hardware/camera.py index 10987c5d06..6a29431836 100644 --- a/iOS/src/toga_iOS/hardware/camera.py +++ b/iOS/src/toga_iOS/hardware/camera.py @@ -83,7 +83,8 @@ def __init__(self, interface): # `permission.camera` in Briefcase). No-cover because we can't manufacture # this condition in testing. raise RuntimeError( - "Application metadata does not declare that the app will use the camera." + "Application metadata does not declare that the " + "app will use the camera." ) def has_permission(self, allow_unknown=False): @@ -160,7 +161,7 @@ def take_photo(self, result, device, flash): self.native.delegate.result = result # Show the pane - toga.App.app.current_window._impl.native.rootViewController.presentViewController( + toga.App.app.current_window._impl.native.rootViewController.presentViewController( # noqa: E501 self.native, animated=True, completion=None ) else: diff --git a/iOS/src/toga_iOS/hardware/location.py b/iOS/src/toga_iOS/hardware/location.py index 26058170a3..bdf94500de 100644 --- a/iOS/src/toga_iOS/hardware/location.py +++ b/iOS/src/toga_iOS/hardware/location.py @@ -82,7 +82,8 @@ def __init__(self, interface): # via `permission.*_location` in Briefcase). No-cover because we can't # manufacture this condition in testing. raise RuntimeError( - "Application metadata does not declare that the app will use the camera." + "Application metadata does not declare that " + "the app will use the camera." ) # Tracking of futures associated with specific requests. @@ -118,7 +119,8 @@ def request_background_permission(self, future): # because we can't manufacture this condition in testing. future.set_exception( RuntimeError( - "Application metadata does not declare that the app will use the camera." + "Application metadata does not declare that " + "the app will use the camera." ) ) diff --git a/iOS/src/toga_iOS/libs/uikit.py b/iOS/src/toga_iOS/libs/uikit.py index 818900ce7c..7fbe3af6ec 100644 --- a/iOS/src/toga_iOS/libs/uikit.py +++ b/iOS/src/toga_iOS/libs/uikit.py @@ -297,7 +297,8 @@ class UIContextualActionStyle(Enum): # Camera UIImagePickerController = ObjCClass("UIImagePickerController") -# PhotoLibrary and SavedPhotosAlbumn constants also exist, but they're marked as deprecated +# PhotoLibrary and SavedPhotosAlbumn constants also exist, but they're +# marked as deprecated UIImagePickerControllerSourceTypeCamera = 1 diff --git a/iOS/src/toga_iOS/widgets/label.py b/iOS/src/toga_iOS/widgets/label.py index 72cfb6579e..7eb18b5096 100644 --- a/iOS/src/toga_iOS/widgets/label.py +++ b/iOS/src/toga_iOS/widgets/label.py @@ -77,6 +77,7 @@ def rehint(self): limitedToNumberOfLines=len(self.interface.text.split("\n")), ).size - # print(f"REHINT label {self} {self.get_text()!r} {fitting_size.width} {fitting_size.height}") + # print(f"REHINT label {self} {self.get_text()!r} + # {fitting_size.width} {fitting_size.height}") self.interface.intrinsic.width = at_least(ceil(fitting_size.width)) self.interface.intrinsic.height = ceil(fitting_size.height) diff --git a/iOS/src/toga_iOS/widgets/mapview.py b/iOS/src/toga_iOS/widgets/mapview.py index 034f4e032b..e16577d619 100644 --- a/iOS/src/toga_iOS/widgets/mapview.py +++ b/iOS/src/toga_iOS/widgets/mapview.py @@ -131,9 +131,9 @@ def get_zoom(self): def set_zoom(self, zoom): if self.backlog is None: - # The zoom level indicates how many degrees of longitude will be displayed in a - # 256 pixel horizontal range. Determine how many degrees of longitude that is, - # and scale to the size of the visible horizontal space. + # The zoom level indicates how many degrees of longitude will be displayed + # in a 56 pixel horizontal range. Determine how many degrees of longitude + # that is, and scale to the size of the visible horizontal space. # The horizontal axis can't show more than 360 degrees of longitude, so clip # the range to that value. The OSM zoom level is based on 360 degrees of @@ -144,8 +144,8 @@ def set_zoom(self, zoom): ) # If we're currently panning to a new location, use the desired *future* - # location as the center of the zoom region. Otherwise use the current center - # coordinate. + # location as the center of the zoom region. Otherwise use the current + # center coordinate. center = ( self.future_location if self.future_location is not None diff --git a/iOS/src/toga_iOS/window.py b/iOS/src/toga_iOS/window.py index 5fe3736dda..c05e0639b3 100644 --- a/iOS/src/toga_iOS/window.py +++ b/iOS/src/toga_iOS/window.py @@ -91,7 +91,8 @@ def content_refreshed(self, container): if self.container.width < min_width or self.container.height < min_height: print( f"Warning: Window content {(min_width, min_height)} " - f"exceeds available space {(self.container.width, self.container.height)}" + f"exceeds available space " + f"{(self.container.width, self.container.height)}" ) def set_content(self, widget): @@ -196,7 +197,8 @@ def render(context): renderer.PNGDataWithActions(Block(render, None, objc_id)) ) - # Get the size of the actual content (offsetting for the header) in raw coordinates. + # Get the size of the actual content (offsetting for the header) + # in raw coordinates. container_bounds = self.container.content.native.bounds image_bounds = NSRect( NSPoint( diff --git a/iOS/tests_backend/widgets/detailedlist.py b/iOS/tests_backend/widgets/detailedlist.py index b1ebf9e648..1485dd6ca4 100644 --- a/iOS/tests_backend/widgets/detailedlist.py +++ b/iOS/tests_backend/widgets/detailedlist.py @@ -140,7 +140,7 @@ async def perform_primary_action(self, row, active=True): path = NSIndexPath.indexPathForRow(row, inSection=0) # Need to use the long form of this method because the first argument when used # as a selector is ambiguous with a property of the same name on the object. - config = self.native.delegate.tableView_trailingSwipeActionsConfigurationForRowAtIndexPath_( + config = self.native.delegate.tableView_trailingSwipeActionsConfigurationForRowAtIndexPath_( # noqa: E501 self.native, path ) @@ -159,7 +159,7 @@ async def perform_secondary_action(self, row, active=True): path = NSIndexPath.indexPathForRow(row, inSection=0) # Need to use the long form of this method because the first argument when used # as a selector is ambiguous with a property of the same name on the object. - config = self.native.delegate.tableView_leadingSwipeActionsConfigurationForRowAtIndexPath_( + config = self.native.delegate.tableView_leadingSwipeActionsConfigurationForRowAtIndexPath_( # noqa: E501 self.native, path ) diff --git a/iOS/tests_backend/widgets/mapview.py b/iOS/tests_backend/widgets/mapview.py index f69a96c4cf..37002f73b0 100644 --- a/iOS/tests_backend/widgets/mapview.py +++ b/iOS/tests_backend/widgets/mapview.py @@ -19,7 +19,8 @@ async def tile_longitude_span(self): # MKCoordinateRegion assert re.match( ( - r", " + r", " r"span=\)>" ), repr(self.native.region), diff --git a/iOS/tests_backend/widgets/optioncontainer.py b/iOS/tests_backend/widgets/optioncontainer.py index d74a7f7fe9..bce195a6ed 100644 --- a/iOS/tests_backend/widgets/optioncontainer.py +++ b/iOS/tests_backend/widgets/optioncontainer.py @@ -29,7 +29,8 @@ def select_tab(self, index): self.impl.native_controller.selectedIndex = index - n_disabled if self.impl.native_controller.selectedIndex <= 4: - # Programmatically selecting a tab doesn't trigger the didSelectItem event. + # Programmatically selecting a tab doesn't trigger the didSelectItem + # event. self.impl.native_controller.tabBar_didSelectItem_( self.impl.native_controller.tabBar, index - n_disabled, diff --git a/iOS/tests_backend/widgets/switch.py b/iOS/tests_backend/widgets/switch.py index 1f2523e8e0..de2fc8f654 100644 --- a/iOS/tests_backend/widgets/switch.py +++ b/iOS/tests_backend/widgets/switch.py @@ -42,7 +42,8 @@ def assert_width(self, min_width, max_width): (min_width - MAX_SWITCH_WIDTH) <= label_width <= (max_width - MAX_SWITCH_WIDTH) - ), f"Label width ({label_width}) not in range ({min_width - MAX_SWITCH_WIDTH}, {max_width - MAX_SWITCH_WIDTH})" + ), f"Label width ({label_width}) not in range " + f"({min_width - MAX_SWITCH_WIDTH}, {max_width - MAX_SWITCH_WIDTH})" assert ( 0 <= switch_width <= MAX_SWITCH_WIDTH ), f"Switch width ({switch_width}) not in range (0-60)" diff --git a/testbed/src/testbed/app.py b/testbed/src/testbed/app.py index f28291791d..2714e4f79f 100644 --- a/testbed/src/testbed/app.py +++ b/testbed/src/testbed/app.py @@ -174,7 +174,8 @@ def task_factory(loop, coro, context=None): tooltip="Perform action 2", ) - # Create a submenu on the first status menu; the status icon is the parent group. + # Create a submenu on the first status menu; + # the status icon is the parent group. self.status1_sub_menu = toga.Group("Sub Menu", parent=self.status1, order=3) self.status_cmd3 = toga.Command( self.cmd_action, diff --git a/testbed/tests/app/test_document_app.py b/testbed/tests/app/test_document_app.py index ddb6ac56af..cac8a5ca0e 100644 --- a/testbed/tests/app/test_document_app.py +++ b/testbed/tests/app/test_document_app.py @@ -90,7 +90,8 @@ async def test_open_initial_document(monkeypatch, app, app_probe): async def test_open_document_by_drag(app, app_probe): - """A file can be If an attempt is made to open a file by dragging, an error is raised.""" + """A file can be If an attempt is made to open a file by dragging, + an error is raised.""" document_path = Path(__file__).parent / "docs/example.testbed" app_probe.open_document_by_drag(document_path) diff --git a/testbed/tests/conftest.py b/testbed/tests/conftest.py index 78e0d14c21..8aca92bac1 100644 --- a/testbed/tests/conftest.py +++ b/testbed/tests/conftest.py @@ -17,16 +17,16 @@ register_assert_rewrite("tests_backend") -# Use this for widgets or tests which are not supported on some platforms, but could be -# supported in the future. +# Use this for widgets or tests which are not supported on some platforms, +# but could be supported in the future. def skip_on_platforms(*platforms, reason=None): current_platform = toga.platform.current_platform if current_platform in platforms: skip(reason or f"not yet implemented on {current_platform}") -# Use this for widgets or tests which are not supported on some platforms, and will not -# be supported in the foreseeable future. +# Use this for widgets or tests which are not supported on some platforms, +# and will not be supported in the foreseeable future. def xfail_on_platforms(*platforms, reason=None): current_platform = toga.platform.current_platform if current_platform in platforms: @@ -39,7 +39,8 @@ def skip_if_unbundled_app(reason=None): if not toga.App.app.is_bundled: skip( reason - or "test requires a full application, use 'briefcase run' instead of 'briefcase dev'" + or "test requires a full application, " + "use 'briefcase run' instead of 'briefcase dev'" ) diff --git a/testbed/tests/hardware/test_camera.py b/testbed/tests/hardware/test_camera.py index b8175353d5..73f7ec8141 100644 --- a/testbed/tests/hardware/test_camera.py +++ b/testbed/tests/hardware/test_camera.py @@ -43,7 +43,8 @@ async def test_grant_permission(app, camera_probe): async def test_deny_permission(app, camera_probe): """A user can deny permission to use the camera""" - # Initiate the permission request. As permissions are not primed, they will be denied. + # Initiate the permission request. As permissions are not primed, + # they will be denied. assert not await app.camera.request_permission() # Permission has been denied @@ -93,7 +94,8 @@ async def test_flash_mode(app, camera_probe): async def test_take_photo_unknown_permission(app, camera_probe): - """If a user hasn't explicitly granted permissions, they can take a photo with the camera""" + """If a user hasn't explicitly granted permissions, + they can take a photo with the camera""" if not camera_probe.request_permission_on_first_use: pytest.xfail("Platform does not request permission on first use") diff --git a/testbed/tests/hardware/test_location.py b/testbed/tests/hardware/test_location.py index bcdaa61a28..1131676c52 100644 --- a/testbed/tests/hardware/test_location.py +++ b/testbed/tests/hardware/test_location.py @@ -38,7 +38,8 @@ async def test_grant_permission(app, location_probe): async def test_deny_permission(app, location_probe): """A user can deny permission to use location.""" - # Initiate the permission request. As permissions are not primed, they will be denied. + # Initiate the permission request. As permissions are not primed, + # they will be denied. assert not await app.location.request_permission() # Permission has been denied diff --git a/testbed/tests/test_fonts.py b/testbed/tests/test_fonts.py index 5afef3623d..2cba23b5df 100644 --- a/testbed/tests/test_fonts.py +++ b/testbed/tests/test_fonts.py @@ -63,7 +63,8 @@ async def test_font_options(widget: toga.Label, font_probe): widget.style.font_variant = font_variant widget.style.font_weight = font_weight await font_probe.redraw( - f"Using a {font_family} {font_size} {font_weight} {font_style} {font_variant} font" + f"Using a {font_family} {font_size} {font_weight} " + f"{font_style} {font_variant} font" ) font_probe.assert_font_family(font_family) diff --git a/testbed/tests/test_icons.py b/testbed/tests/test_icons.py index b0754cba1b..feadc3969f 100644 --- a/testbed/tests/test_icons.py +++ b/testbed/tests/test_icons.py @@ -47,6 +47,7 @@ async def test_bad_icon_file(app): "If a file isn't a loadable icon, an error is raised" with pytest.raises( ValueError, - match=rf"Unable to load icon from {re.escape(str(app.paths.app / 'resources' / 'icons' / 'bad'))}", + match=rf"Unable to load icon from " + rf"{re.escape(str(app.paths.app / 'resources' / 'icons' / 'bad'))}", ): toga.Icon("resources/icons/bad") diff --git a/testbed/tests/test_images.py b/testbed/tests/test_images.py index 57ff54a2b4..3a70268987 100644 --- a/testbed/tests/test_images.py +++ b/testbed/tests/test_images.py @@ -59,7 +59,8 @@ async def test_buffer_image(app): async def test_pil_raw_and_data_image(app): - "An image can be created from PIL, platform's raw representation and `toga.Image` data" + "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) diff --git a/testbed/tests/test_statusicons.py b/testbed/tests/test_statusicons.py index 6241e60d90..7c65307431 100644 --- a/testbed/tests/test_statusicons.py +++ b/testbed/tests/test_statusicons.py @@ -109,7 +109,8 @@ async def test_unknown_status_icon(app, app_probe): try: with pytest.raises( ValueError, - match=r"Command 'Bad Action' does not belong to a current status icon group.", + match=r"Command 'Bad Action' " + "does not belong to a current status icon group.", ): app.status_icons.commands.add(bad_cmd) finally: diff --git a/testbed/tests/testbed.py b/testbed/tests/testbed.py index 94f654e34d..850a29dff5 100644 --- a/testbed/tests/testbed.py +++ b/testbed/tests/testbed.py @@ -15,8 +15,8 @@ def run_tests(app, cov, args, report_coverage, run_slow, running_in_ci): try: - # Wait for the app's main window to be visible. Retrieving the actual main window - # will raise an exception until the app is actually initialized. + # Wait for the app's main window to be visible. Retrieving the actual + # main window will raise an exception until the app is actually initialized. print("Waiting for app to be ready for testing... ", end="", flush=True) i = 0 ready = False @@ -152,7 +152,8 @@ def run_tests(app, cov, args, report_coverage, run_slow, running_in_ci): "coverage_conditional_plugin:rules", { "no-cover-if-linux-wayland": "os_environ.get('WAYLAND_DISPLAY', '') != ''", - "no-cover-if-linux-x": "os_environ.get('WAYLAND_DISPLAY', 'not-set') == 'not-set'", + "no-cover-if-linux-x": "os_environ.get" + "('WAYLAND_DISPLAY', 'not-set') == 'not-set'", }, ) cov.start() diff --git a/testbed/tests/widgets/properties.py b/testbed/tests/widgets/properties.py index 0b376e7862..13cc753e07 100644 --- a/testbed/tests/widgets/properties.py +++ b/testbed/tests/widgets/properties.py @@ -547,7 +547,8 @@ async def test_flex_horizontal_widget_size(widget, probe): # Widget is still the width of the screen # and the height hasn't changed await probe.redraw( - message="Widget width should be still the width of the screen without height change" + message="Widget width should be still the width of the screen" + "without height change" ) assert probe.width > 350 probe.assert_width(350, MAX_WIDTH) diff --git a/testbed/tests/widgets/test_canvas.py b/testbed/tests/widgets/test_canvas.py index aa967e4618..40c5637d3b 100644 --- a/testbed/tests/widgets/test_canvas.py +++ b/testbed/tests/widgets/test_canvas.py @@ -244,7 +244,8 @@ async def test_image_data(canvas, probe): def assert_reference(probe, reference, threshold=0.0): - """Assert that the canvas currently matches a reference image, within an RMS threshold""" + """Assert that the canvas currently matches a reference image, within an + RMS threshold""" # Get the canvas image. image = probe.get_image() scaled_image = image.resize((200, 200)) diff --git a/testbed/tests/widgets/test_imageview.py b/testbed/tests/widgets/test_imageview.py index fda5e8f089..31e2c209ca 100644 --- a/testbed/tests/widgets/test_imageview.py +++ b/testbed/tests/widgets/test_imageview.py @@ -71,7 +71,8 @@ async def test_implicit_size(widget, probe, container_probe): async def test_explicit_width(widget, probe, container_probe): - """If the image width is explicit, the image view will resize preserving aspect ratio.""" + """If the image width is explicit, the image view will resize preserving + aspect ratio.""" # Explicitly set width; height follows aspect raio widget.style.width = 200 @@ -113,7 +114,8 @@ async def test_explicit_width(widget, probe, container_probe): async def test_explicit_height(widget, probe, container_probe): - """If the image height is explicit, the image view will resize preserving aspect ratio.""" + """If the image height is explicit, the image view will resize preserving + aspect ratio.""" # Explicitly set height; width follows aspect raio widget.style.height = 150 diff --git a/testbed/tests/widgets/test_slider.py b/testbed/tests/widgets/test_slider.py index d8cecda2b7..6b8eabf993 100644 --- a/testbed/tests/widgets/test_slider.py +++ b/testbed/tests/widgets/test_slider.py @@ -23,8 +23,8 @@ # To ensure less than 1 pixel of error, the slider must be able to distinguish at least # 10,000 positions in continuous mode. # -# Pi is irrational, which helps test things which should be accurate to within the limits -# of a Python float, e.g. setting a value and then immediately getting it. +# Pi is irrational, which helps test things which should be accurate to within the +# limits of a Python float, e.g. setting a value and then immediately getting it. ACCURACY = 0.0001 POSITIONS = [0, 0.0001, 1 / pi, 0.5, 0.9, 0.9999, 1] SCALES = [0.0001, 0.1, 1, pi, 10000] diff --git a/testbed/tests/window/test_window.py b/testbed/tests/window/test_window.py index cf284945bf..2684737105 100644 --- a/testbed/tests/window/test_window.py +++ b/testbed/tests/window/test_window.py @@ -45,7 +45,8 @@ async def test_title(main_window, main_window_probe): await main_window_probe.wait_for_window("Window title can be reverted") -# Mobile platforms have different windowing characteristics, so they have different tests. +# Mobile platforms have different windowing characteristics, +# so they have different tests. if toga.platform.current_platform in {"iOS", "android"}: #################################################################################### # Mobile platform tests @@ -147,7 +148,8 @@ async def test_full_screen(main_window, main_window_probe): await main_window_probe.wait_for_window("Full screen is a no-op") async def test_screen(main_window, main_window_probe): - """The window can be relocated to another screen, using both absolute and relative screen positions.""" + """The window can be relocated to another screen, using both absolute and + relative screen positions.""" assert main_window.screen.origin == (0, 0) initial_size = main_window.size main_window.position = (150, 50) @@ -462,7 +464,8 @@ async def test_visibility(app, second_window, second_window_probe): async def test_move_and_resize(second_window, second_window_probe): """A window can be moved and resized.""" - # Determine the extra width consumed by window chrome (e.g., title bars, borders etc) + # Determine the extra width consumed by window chrome + # (e.g., title bars, borders etc) extra_width = second_window.size[0] - second_window_probe.content_size[0] extra_height = second_window.size[1] - second_window_probe.content_size[1] @@ -567,7 +570,8 @@ async def test_full_screen(second_window, second_window_probe): ], ) async def test_screen(second_window, second_window_probe): - """The window can be relocated to another screen, using both absolute and relative screen positions.""" + """The window can be relocated to another screen, using both absolute and + relative screen positions.""" initial_position = second_window.position @@ -577,7 +581,8 @@ async def test_screen(second_window, second_window_probe): if second_window_probe.supports_placement: assert second_window.position != initial_position - # `position` and `screen_position` will be same as the window will be in primary screen. + # `position` and `screen_position` will be same as the window will be in + # primary screen. if second_window_probe.supports_placement: assert second_window.position == (200, 200) assert second_window.screen_position == (200, 200) diff --git a/textual/src/toga_textual/dialogs.py b/textual/src/toga_textual/dialogs.py index 5e1a7e42b3..c8064f0bfc 100644 --- a/textual/src/toga_textual/dialogs.py +++ b/textual/src/toga_textual/dialogs.py @@ -152,7 +152,8 @@ def create_buttons(self): ] def style_content(self, dialog): - # Textual apps must have a current window, so we can style relative to that window. + # Textual apps must have a current window, so we can style + # relative to that window. dialog.content.styles.margin = 1 dialog.content.styles.height = toga.App.app.current_window.size[1] - 18 @@ -259,7 +260,8 @@ def create_buttons(self): ] def style_content(self, dialog): - # Textual apps must have a current window, so we can style relative to that window. + # Textual apps must have a current window, so we can style + # relative to that window. dialog.content.styles.margin = 1 dialog.content.styles.height = toga.App.app.current_window.size[1] - 18 @@ -318,7 +320,8 @@ def create_buttons(self): ] def style_content(self, dialog): - # Textual apps must have a current window, so we can style relative to that window. + # Textual apps must have a current window, so we can style + # relative to that window. dialog.content.styles.margin = 1 dialog.content.styles.height = toga.App.app.current_window.size[1] - 18 @@ -372,7 +375,8 @@ def create_buttons(self): ] def style_content(self, dialog): - # Textual apps must have a current window, so we can style relative to that window. + # Textual apps must have a current window, so we can style + # relative to that window. dialog.content.styles.margin = 1 dialog.content.styles.height = toga.App.app.current_window.size[1] - 19 diff --git a/winforms/src/toga_winforms/fonts.py b/winforms/src/toga_winforms/fonts.py index 2aea10641e..e4bd651546 100644 --- a/winforms/src/toga_winforms/fonts.py +++ b/winforms/src/toga_winforms/fonts.py @@ -30,7 +30,8 @@ class Font: def __init__(self, interface): - self._pfc = None # this needs to be an instance variable, otherwise we might get Winforms exceptions later + self._pfc = None # this needs to be an instance variable, otherwise we might + # get Winforms exceptions later self.interface = interface try: font = _FONT_CACHE[self.interface] diff --git a/winforms/src/toga_winforms/widgets/mapview.py b/winforms/src/toga_winforms/widgets/mapview.py index 31a3d9c3fb..f438e26413 100644 --- a/winforms/src/toga_winforms/widgets/mapview.py +++ b/winforms/src/toga_winforms/widgets/mapview.py @@ -54,7 +54,7 @@ -""" +""" # noqa: E501 def pin_id(pin): @@ -141,7 +141,8 @@ def winforms_initialization_completed(self, sender, args): WinForms.MessageBoxIcon.Error, ) webbrowser.open( - "https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download" + "https://developer.microsoft.com" + "/en-us/microsoft-edge/webview2/#download" ) else: # pragma: nocover diff --git a/winforms/src/toga_winforms/widgets/table.py b/winforms/src/toga_winforms/widgets/table.py index 942c3eca78..a3a41964b8 100644 --- a/winforms/src/toga_winforms/widgets/table.py +++ b/winforms/src/toga_winforms/widgets/table.py @@ -82,7 +82,8 @@ def set_bounds(self, x, y, width, height): def winforms_retrieve_virtual_item(self, sender, e): # Because ListView is in VirtualMode, it's necessary implement - # VirtualItemsSelectionRangeChanged event to create ListViewItem when it's needed + # VirtualItemsSelectionRangeChanged event to create ListViewItem + # when it's needed if ( self._cache and e.ItemIndex >= self._first_item @@ -208,8 +209,8 @@ def icon(attr): # If the table has accessors, populate the icons for the table. if self._accessors: - # TODO: ListView only has built-in support for one icon per row. One possible - # workaround is in https://stackoverflow.com/a/46128593. + # TODO: ListView only has built-in support for one icon per row. One + # possible workaround is in https://stackoverflow.com/a/46128593. icon = icon(self._accessors[0]) if icon is not None: lvi.ImageIndex = self._image_index(icon) diff --git a/winforms/src/toga_winforms/widgets/webview.py b/winforms/src/toga_winforms/widgets/webview.py index 7756f5e776..a9b00e8705 100644 --- a/winforms/src/toga_winforms/widgets/webview.py +++ b/winforms/src/toga_winforms/widgets/webview.py @@ -110,7 +110,8 @@ def winforms_initialization_completed(self, sender, args): WinForms.MessageBoxIcon.Error, ) webbrowser.open( - "https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download" + "https://developer.microsoft.com" + "/en-us/microsoft-edge/webview2/#download" ) else: # pragma: nocover diff --git a/winforms/tests_backend/app.py b/winforms/tests_backend/app.py index c24ade1f39..b746422ae3 100644 --- a/winforms/tests_backend/app.py +++ b/winforms/tests_backend/app.py @@ -109,15 +109,15 @@ def content_size(self, window): def assert_app_icon(self, icon): for window in self.app.windows: - # We have no real way to check we've got the right icon; use pixel peeping as a - # guess. Construct a PIL image from the current icon. + # We have no real way to check we've got the right icon; use pixel peeping + # as a guess. Construct a PIL image from the current icon. img = toga.Image( Bitmap.FromHicon(window._impl.native.Icon.Handle) ).as_format(PIL.Image.Image) if icon: - # The explicit alt icon has blue background, with green at a point 1/3 into - # the image + # The explicit alt icon has blue background, with green at a point 1/3 + # into the image assert img.getpixel((5, 5)) == (211, 230, 245, 255) mid_color = img.getpixel((img.size[0] // 3, img.size[1] // 3)) assert mid_color == (0, 204, 9, 255) diff --git a/winforms/tests_backend/dialogs.py b/winforms/tests_backend/dialogs.py index 072be6ba2f..f3b8c52807 100644 --- a/winforms/tests_backend/dialogs.py +++ b/winforms/tests_backend/dialogs.py @@ -16,8 +16,9 @@ def automated_show(host_window, future): orig_show(host_window, future) async def _close_dialog(): - # Give the inner event loop a chance to start. The MessageBox dialogs work with - # sleep(0), but the file dialogs require it to be positive for some reason. + # Give the inner event loop a chance to start. The MessageBox dialogs + # work with sleep(0), but the file dialogs require it to be positive + # for some reason. await asyncio.sleep(0.001) try: diff --git a/winforms/tests_backend/widgets/progressbar.py b/winforms/tests_backend/widgets/progressbar.py index 76b43be525..d4936e65b1 100644 --- a/winforms/tests_backend/widgets/progressbar.py +++ b/winforms/tests_backend/widgets/progressbar.py @@ -22,5 +22,6 @@ def position(self): return self.native.Value / self.native.Maximum async def wait_for_animation(self): - # WinForms ProgressBar has internal animation handling; no special handling required. + # WinForms ProgressBar has internal animation handling; + # no special handling required. pass From f90ad2544f4ae3b3311e270337e3dcac8018d8df Mon Sep 17 00:00:00 2001 From: Marc Bradshaw Date: Mon, 25 Nov 2024 18:10:53 +1100 Subject: [PATCH 03/10] Add a changes file for change 2975 --- changes/2975.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/2975.misc.rst diff --git a/changes/2975.misc.rst b/changes/2975.misc.rst new file mode 100644 index 0000000000..93c0e0aa58 --- /dev/null +++ b/changes/2975.misc.rst @@ -0,0 +1 @@ +Update the flake8 line limit to 88 to match limit for Black, and shorten longer lines. From 843d867d22d1c4bcb554005cf4ef279e0d6b19f6 Mon Sep 17 00:00:00 2001 From: Marc Bradshaw Date: Tue, 26 Nov 2024 09:05:56 +1100 Subject: [PATCH 04/10] Shorten line based on example in 7654820 --- core/src/toga/app.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/toga/app.py b/core/src/toga/app.py index d7e732af73..0023ea4ada 100644 --- a/core/src/toga/app.py +++ b/core/src/toga/app.py @@ -106,7 +106,11 @@ def __iter__(self) -> Iterator[Widget]: return self.values() def __repr__(self) -> str: - return f"{{{', '.join(f'{k!r}: {v!r}' for k, v in sorted(self._registry.items()))}}}" # noqa: E501 + return ( + "{" + + ", ".join(f"{k!r}: {v!r}" for k, v in sorted(self._registry.items())) + + "}" + ) def items(self) -> Iterator[tuple[str, Widget]]: return self._registry.items() From c99058fea092fdd35870c21154d89479a96f00f9 Mon Sep 17 00:00:00 2001 From: Marc Bradshaw Date: Tue, 26 Nov 2024 09:08:42 +1100 Subject: [PATCH 05/10] Remove existing, now unrequired noqa comment --- gtk/src/toga_gtk/container.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gtk/src/toga_gtk/container.py b/gtk/src/toga_gtk/container.py index 98d58f116d..de68ab6092 100644 --- a/gtk/src/toga_gtk/container.py +++ b/gtk/src/toga_gtk/container.py @@ -158,7 +158,6 @@ def do_size_allocate(self, allocation): """ # print(self._content, f"Container layout " # "{allocation.width}x{allocation.height} @ {allocation.x}x{allocation.y}") - # # noqa: E501 # The container will occupy the full space it has been allocated. resized = (allocation.width, allocation.height) != (self.width, self.height) From 8feb63e302cf8d22b6c2306632cca3548264dabf Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 26 Nov 2024 16:59:12 +1100 Subject: [PATCH 06/10] Small cleanups for style consistency. --- android/src/toga_android/app.py | 2 +- android/src/toga_android/keys.py | 11 +- android/src/toga_android/libs/events.py | 49 ++---- .../src/toga_android/widgets/detailedlist.py | 8 +- android/tests_backend/widgets/progressbar.py | 2 +- cocoa/src/toga_cocoa/constraints.py | 2 +- cocoa/src/toga_cocoa/hardware/camera.py | 17 +- cocoa/src/toga_cocoa/widgets/numberinput.py | 84 +++++----- cocoa/src/toga_cocoa/widgets/table.py | 5 +- cocoa/src/toga_cocoa/widgets/textinput.py | 2 +- core/src/toga/handlers.py | 2 +- core/src/toga/platform.py | 4 +- core/src/toga/sources/base.py | 8 +- core/src/toga/validators.py | 150 ++++++++---------- core/src/toga/widgets/base.py | 4 +- core/tests/command/test_command.py | 8 +- core/tests/command/test_group.py | 4 +- core/tests/sources/test_list_source.py | 6 +- core/tests/style/pack/test_css.py | 6 +- core/tests/style/pack/utils.py | 8 +- core/tests/test_icons.py | 4 +- core/tests/test_paths.py | 23 ++- core/tests/widgets/canvas/test_canvas.py | 36 +++-- .../widgets/canvas/test_context_objects.py | 12 +- .../widgets/canvas/test_draw_operations.py | 36 +++-- core/tests/widgets/test_webview.py | 6 +- core/tests/window/test_window.py | 95 +++++++---- examples/beeliza/beeliza/bot.py | 12 +- examples/hardware/hardware/app.py | 12 +- .../positron-django/src/webapp/settings.py | 6 +- examples/webview/webview/app.py | 10 +- gtk/src/toga_gtk/icons.py | 12 +- gtk/src/toga_gtk/widgets/scrollcontainer.py | 2 +- gtk/tests_backend/widgets/switch.py | 6 +- iOS/src/toga_iOS/dialogs.py | 4 +- iOS/src/toga_iOS/hardware/camera.py | 6 +- iOS/tests_backend/widgets/detailedlist.py | 18 +-- iOS/tests_backend/widgets/switch.py | 6 +- testbed/tests/conftest.py | 6 +- testbed/tests/test_icons.py | 6 +- testbed/tests/test_statusicons.py | 6 +- testbed/tests/testbed.py | 5 +- testbed/tests/widgets/properties.py | 6 +- winforms/src/toga_winforms/fonts.py | 5 +- 44 files changed, 383 insertions(+), 339 deletions(-) diff --git a/android/src/toga_android/app.py b/android/src/toga_android/app.py index 6abc65d76c..e9d99e623f 100644 --- a/android/src/toga_android/app.py +++ b/android/src/toga_android/app.py @@ -68,7 +68,7 @@ def onActivityResult(self, requestCode, resultCode, resultData): def onRequestPermissionsResult(self, requestCode, permissions, grantResults): print( - f"Toga app: onRequestPermissionsResult " + "Toga app: onRequestPermissionsResult " f"{requestCode=} {permissions=} {grantResults=}" ) try: diff --git a/android/src/toga_android/keys.py b/android/src/toga_android/keys.py index 71d60abd09..22339ee357 100644 --- a/android/src/toga_android/keys.py +++ b/android/src/toga_android/keys.py @@ -16,7 +16,8 @@ KeyEvent.KEYCODE_F10: Key.F10, KeyEvent.KEYCODE_F11: Key.F11, KeyEvent.KEYCODE_F12: Key.F12, - # KeyEvent.KEY_quoteleft: Key.BACK_QUOTE, TODO Find matching key + # TODO Find matching key + # KeyEvent.KEY_quoteleft: Key.BACK_QUOTE, KeyEvent.KEYCODE_1: Key._1, KeyEvent.KEYCODE_2: Key._2, KeyEvent.KEYCODE_3: Key._3, @@ -27,7 +28,8 @@ KeyEvent.KEYCODE_8: Key._8, KeyEvent.KEYCODE_9: Key._9, KeyEvent.KEYCODE_0: Key._0, - # KeyEvent.KEYCODE_MINUS: Key.MINUS, TODO Create handling for num row special keys + # TODO Create handling for num row special keys + # KeyEvent.KEYCODE_MINUS: Key.MINUS, # KeyEvent.KEYCODE_EQUALS: Key.EQUAL, # KeyEvent.KEYCODE_DEL: Key.BACKSPACE, # KeyEvent.KEY_asciitilde: Key.TILDE, @@ -70,8 +72,8 @@ KeyEvent.KEYCODE_Y: Key.Y, KeyEvent.KEYCODE_Z: Key.Z, KeyEvent.KEYCODE_TAB: Key.TAB, + # TODO Create handling for num row special keys # KeyEvent.KEYCODE_LEFT_BRACKET: Key.OPEN_BRACKET, - # TODO Create handling for num row special keys # KeyEvent.KEYCODE_RIGHT_BRACKET: Key.CLOSE_BRACKET, # KeyEvent.KEYCODE_BACKSLASH: Key.BACKSLASH, # KeyEvent.KEY_braceleft: Key.OPEN_BRACE, @@ -80,7 +82,8 @@ # KeyEvent.KEY_semicolon: Key.SEMICOLON, # KeyEvent.KEY_apostrophe: Key.QUOTE, KeyEvent.KEYCODE_ENTER: Key.ENTER, - # KeyEvent.KEY_colon: Key.COLON, TODO Create handling for num row special keys + # TODO Create handling for num row special keys + # KeyEvent.KEY_colon: Key.COLON, # KeyEvent.KEY_quotedbl: Key.DOUBLE_QUOTE, # KeyEvent.KEY_comma: Key.COMMA, # KeyEvent.KEY_period: Key.FULL_STOP, diff --git a/android/src/toga_android/libs/events.py b/android/src/toga_android/libs/events.py index 5eeaa95532..c7c148bd03 100644 --- a/android/src/toga_android/libs/events.py +++ b/android/src/toga_android/libs/events.py @@ -233,10 +233,9 @@ class AndroidInterop: """Encapsulate details of Android event loop cooperation.""" def __init__(self): - # `_runnable_by_fn` is a one-to-one mapping from Python callables to - # Java Runnables. - # This allows us to avoid creating more than one Java object per Python - # callable, which would prevent removeCallbacks from working. + # `_runnable_by_fn` is a one-to-one mapping from Python callables to Java + # Runnables. This allows us to avoid creating more than one Java object per + # Python callable, which would prevent removeCallbacks from working. self._runnable_by_fn = {} # The handler must be created on the Android UI thread. self.handler = Handler() @@ -249,8 +248,8 @@ def get_or_create_runnable(self, fn): return self._runnable_by_fn[fn] def call_later(self, fn, timeout_millis): - """Enqueue a Python callable `fn` to be run after - `timeout_millis` milliseconds.""" + """Enqueue a Python callable `fn` to be run after `timeout_millis` + milliseconds.""" runnable = self.get_or_create_runnable(fn) self.handler.removeCallbacks(runnable) self.handler.postDelayed(runnable, int(timeout_millis)) @@ -304,11 +303,7 @@ def message_queue(self): def register(self, fileobj, events, data=None): if self._debug: # pragma: no cover - print( - "register() fileobj={fileobj} events={events} data={data}".format( - fileobj=fileobj, events=events, data=data - ) - ) + print(f"register() fileobj={fileobj} events={events} data={data}") ret = super().register(fileobj, events, data=data) self.register_with_android(fileobj, events) return ret @@ -330,11 +325,7 @@ def _reregister(): ) return if self._debug: # pragma: no cover - print( - "reregister_with_android_soon reregistering key={key}".format( - key=key - ) - ) + print(f"reregister_with_android_soon reregistering key={key}") self.register_with_android(key.fd, key.events) # Use `call_later(0, fn)` to ensure the Python event loop runs to @@ -343,11 +334,7 @@ def _reregister(): def register_with_android(self, fileobj, events): if self._debug: # pragma: no cover - print( - "register_with_android() fileobj={fileobj} events={events}".format( - fileobj=fileobj, events=events - ) - ) + print(f"register_with_android() fileobj={fileobj} events={events}") # `events` is a bitset comprised of `selectors.EVENT_READ` and # `selectors.EVENT_WRITE`. # Register this FD for read and/or write events from Android. @@ -365,11 +352,7 @@ def handle_fd_wakeup(self, fd, events): key = self._fd_to_key.get(fd) if key is None: # pragma: no cover - print( - "Warning: handle_fd_wakeup: wakeup for unregistered fd={fd}".format( - fd=fd - ) - ) + print(f"Warning: handle_fd_wakeup: wakeup for unregistered fd={fd}") return key_event_pairs = [] @@ -380,18 +363,14 @@ def handle_fd_wakeup(self, fd, events): if self._debug: # pragma: no cover print( "handle_fd_wakeup() calling parent for " - "key_event_pairs={key_event_pairs}".format( - key_event_pairs=key_event_pairs - ) + f"key_event_pairs={key_event_pairs}" ) # Call superclass private method to notify. self.loop._process_events(key_event_pairs) else: # pragma: no cover print( "Warning: handle_fd_wakeup(): unnecessary wakeup " - "fd={fd} events={events} key={key}".format( - fd=fd, events=events, key=key - ) + f"fd={fd} events={events} key={key}" ) # This class declines to implement the `select()` method, purely as @@ -430,11 +409,7 @@ def onFileDescriptorEvents(self, fd_obj, events): # to Python. fd = getattr(fd_obj, "getInt$")() if self._debug: # pragma: no cover - print( - "onFileDescriptorEvents woke up for fd={fd} events={events}".format( - fd=fd, events=events - ) - ) + print(f"onFileDescriptorEvents woke up for fd={fd} events={events}") # Tell the Python event loop that the FD is ready for read and/or write. self.android_selector.handle_fd_wakeup(fd, events) # Tell Android we don't want any more wake-ups from this FD until the event diff --git a/android/src/toga_android/widgets/detailedlist.py b/android/src/toga_android/widgets/detailedlist.py index 6d1520d3c5..71a99b473f 100644 --- a/android/src/toga_android/widgets/detailedlist.py +++ b/android/src/toga_android/widgets/detailedlist.py @@ -100,10 +100,10 @@ class DetailedList(Widget): def create(self): if SwipeRefreshLayout is None: # pragma: no cover raise RuntimeError( - "Unable to import SwipeRefreshLayout. " - "Ensure that the AndroidX Swipe Refresh Layout " - "widget package (androidx.swiperefreshlayout:swiperefreshlayout:1.1.0) " - "is listed in your app's dependencies." + "Unable to import SwipeRefreshLayout. Ensure that the AndroidX Swipe " + "Refresh Layout widget package " + "(androidx.swiperefreshlayout:swiperefreshlayout:1.1.0) is listed in " + "your app's dependencies." ) # get the selection color from the current theme attrs = [R.attr.colorBackground, R.attr.colorControlHighlight] diff --git a/android/tests_backend/widgets/progressbar.py b/android/tests_backend/widgets/progressbar.py index 10aac855b3..85f52e4c79 100644 --- a/android/tests_backend/widgets/progressbar.py +++ b/android/tests_backend/widgets/progressbar.py @@ -21,5 +21,5 @@ def position(self): async def wait_for_animation(self): # Android ProgressBar has internal animation handling; - # no special handling required. + # no special handling required. pass diff --git a/cocoa/src/toga_cocoa/constraints.py b/cocoa/src/toga_cocoa/constraints.py index 6cd40e0177..52cbaea791 100644 --- a/cocoa/src/toga_cocoa/constraints.py +++ b/cocoa/src/toga_cocoa/constraints.py @@ -62,7 +62,7 @@ def container(self, value): self._container = value if value is not None: # print(f"Add constraints for {self.widget} in {self.container} - # {self.widget.interface.layout}) + # {self.widget.interface.layout}") self.left_constraint = NSLayoutConstraint.constraintWithItem( self.widget.native, attribute__1=NSLayoutAttributeLeft, diff --git a/cocoa/src/toga_cocoa/hardware/camera.py b/cocoa/src/toga_cocoa/hardware/camera.py index 005ce276b8..2fae6d5c6a 100644 --- a/cocoa/src/toga_cocoa/hardware/camera.py +++ b/cocoa/src/toga_cocoa/hardware/camera.py @@ -274,18 +274,17 @@ def __init__(self, interface): def has_permission(self, allow_unknown=False): # To reset permissions to "factory" status, run: - # tccutil reset Camera + # tccutil reset Camera # # To reset a single app: - # tccutil reset Camera + # tccutil reset Camera # - # e.g. - # tccutil reset Camera org.beeware.appname - # # for a bundled app - # tccutil reset Camera com.microsoft.VSCode - # # for code running in Visual Studio - # tccutil reset Camera com.apple.Terminal - # # for code running in the Apple terminal + # e.g. For a bundled app: + # tccutil reset Camera org.beeware.appname + # For code running in Visual Studio: + # tccutil reset Camera com.microsoft.VSCode + # For code running in the Apple terminal: + # tccutil reset Camera com.apple.Terminal if allow_unknown: valid_values = { diff --git a/cocoa/src/toga_cocoa/widgets/numberinput.py b/cocoa/src/toga_cocoa/widgets/numberinput.py index d475581ea8..d594ffdb95 100644 --- a/cocoa/src/toga_cocoa/widgets/numberinput.py +++ b/cocoa/src/toga_cocoa/widgets/numberinput.py @@ -93,75 +93,75 @@ def create(self): # Add constraints to lay out the input and stepper. # Stepper is always top right corner. self.native.addConstraint( - NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501 + NSLayoutConstraint.constraintWithItem( self.native, - NSLayoutAttributeTop, - NSLayoutRelationEqual, - self.native_stepper, - NSLayoutAttributeTop, - 1.0, - 0, + attribute__from=NSLayoutAttributeTop, + relatedBy=NSLayoutRelationEqual, + toItem=self.native_stepper, + attribute__to=NSLayoutAttributeTop, + multiplier=1.0, + _constant=0, ) ) self.native.addConstraint( - NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501 + NSLayoutConstraint.constraintWithItem( self.native, - NSLayoutAttributeRight, - NSLayoutRelationEqual, - self.native_stepper, - NSLayoutAttributeRight, - 1.0, - 0, + attribute__from=NSLayoutAttributeRight, + relatedBy=NSLayoutRelationEqual, + toItem=self.native_stepper, + attribute__to=NSLayoutAttributeRight, + multiplier=1.0, + _constant=0, ) ) # Stepper height matches container box height self.native.addConstraint( - NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501 + NSLayoutConstraint.constraintWithItem( self.native, - NSLayoutAttributeBottom, - NSLayoutRelationEqual, - self.native_stepper, - NSLayoutAttributeBottom, - 1.0, - 0, + attribute__from=NSLayoutAttributeBottom, + relatedBy=NSLayoutRelationEqual, + toItem=self.native_stepper, + attribute__to=NSLayoutAttributeBottom, + multiplier=1.0, + _constant=0, ) ) # Input is always left, centred vertically on the stepper self.native.addConstraint( - NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501 + NSLayoutConstraint.constraintWithItem( self.native_stepper, - NSLayoutAttributeCenterY, - NSLayoutRelationEqual, - self.native_input, - NSLayoutAttributeCenterY, - 1.0, - 0, + attribute__from=NSLayoutAttributeCenterY, + relatedBy=NSLayoutRelationEqual, + toItem=self.native_input, + attribute__to=NSLayoutAttributeCenterY, + multiplier=1.0, + _constant=0, ) ) self.native.addConstraint( - NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501 + NSLayoutConstraint.constraintWithItem( self.native, - NSLayoutAttributeLeft, - NSLayoutRelationEqual, - self.native_input, - NSLayoutAttributeLeft, - 1.0, - 0, + attribute__from=NSLayoutAttributeLeft, + relatedBy=NSLayoutRelationEqual, + toItem=self.native_input, + attribute__to=NSLayoutAttributeLeft, + multiplier=1.0, + _constant=0, ) ) # Stepper and input meet in the middle with a small gap self.native.addConstraint( - NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_( # noqa: E501 + NSLayoutConstraint.constraintWithItem( self.native_stepper, - NSLayoutAttributeLeft, - NSLayoutRelationEqual, - self.native_input, - NSLayoutAttributeRight, - 1.0, - 2, + attribute__from=NSLayoutAttributeLeft, + relatedBy=NSLayoutRelationEqual, + toItem=self.native_input, + attribute__to=NSLayoutAttributeRight, + multiplier=1.0, + _constant=2, ) ) diff --git a/cocoa/src/toga_cocoa/widgets/table.py b/cocoa/src/toga_cocoa/widgets/table.py index d628c919c4..1f240bd89d 100644 --- a/cocoa/src/toga_cocoa/widgets/table.py +++ b/cocoa/src/toga_cocoa/widgets/table.py @@ -119,8 +119,9 @@ def tableViewSelectionDidChange_(self, notification) -> None: # value = getattr(data_row, col_identifier, None) # if isinstance(value, toga.Widget): # # if the cell value is a widget, use its height - # heights.append(value._impl.native.intrinsicContentSize().height - # + margin) + # heights.append( + # value._impl.native.intrinsicContentSize().height + margin + # ) # # return max(heights) diff --git a/cocoa/src/toga_cocoa/widgets/textinput.py b/cocoa/src/toga_cocoa/widgets/textinput.py index 8eb0f1e05a..0ea3bf22ab 100644 --- a/cocoa/src/toga_cocoa/widgets/textinput.py +++ b/cocoa/src/toga_cocoa/widgets/textinput.py @@ -221,7 +221,7 @@ def rehint(self): # Width must be > 100 # print("REHINT TextInput", self, # self._impl.intrinsicContentSize().width, - # self._impl.intrinsicContentSize().height + # self._impl.intrinsicContentSize().height, # ) self.interface.intrinsic.width = at_least(self.interface._MIN_WIDTH) self.interface.intrinsic.height = self.native.intrinsicContentSize().height diff --git a/core/src/toga/handlers.py b/core/src/toga/handlers.py index b377d99858..ee1fcdfd26 100644 --- a/core/src/toga/handlers.py +++ b/core/src/toga/handlers.py @@ -260,7 +260,7 @@ def __await__(self) -> Generator[Any, None, Any]: def __bool__(self, other: object) -> NoReturn: raise RuntimeError( f"Can't check {self.RESULT_TYPE} result directly; " - f"use await or an on_result handler" + "use await or an on_result handler" ) __lt__ = __bool__ diff --git a/core/src/toga/platform.py b/core/src/toga/platform.py index 2b06436fd8..708fe50865 100644 --- a/core/src/toga/platform.py +++ b/core/src/toga/platform.py @@ -95,7 +95,7 @@ def get_platform_factory() -> ModuleType: ) raise RuntimeError( f"Multiple Toga backends are installed ({toga_backends_string}), " - f"but none of them match your current platform " + "but none of them match your current platform " f"({current_platform!r}). " "Install a backend for your current platform, or use " "TOGA_BACKEND to specify a backend." @@ -108,7 +108,7 @@ def get_platform_factory() -> ModuleType: ] ) raise RuntimeError( - f"Multiple candidate toga backends found: " + "Multiple candidate toga backends found: " f"({toga_backends_string}). " "Uninstall the backends you don't require, or use " "TOGA_BACKEND to specify a backend." diff --git a/core/src/toga/sources/base.py b/core/src/toga/sources/base.py index 3b20abd5ed..dc995f1ae2 100644 --- a/core/src/toga/sources/base.py +++ b/core/src/toga/sources/base.py @@ -33,8 +33,8 @@ def clear(self) -> object: class Source: - """A base class for data sources, - providing an implementation of data notifications.""" + """A base class for data sources, providing an implementation of data + notifications.""" def __init__(self) -> None: self._listeners: list[Listener] = [] @@ -50,8 +50,8 @@ def listeners(self) -> list[Listener]: def add_listener(self, listener: Listener) -> None: """Add a new listener to this data source. - If the listener is already registered on this data source, the - request to add is ignored. + If the listener is already registered on this data source, the request to add is + ignored. :param listener: The listener to add """ diff --git a/core/src/toga/validators.py b/core/src/toga/validators.py index c9850c67d7..0c1896d58c 100644 --- a/core/src/toga/validators.py +++ b/core/src/toga/validators.py @@ -10,10 +10,9 @@ def __init__(self, error_message: str, allow_empty: bool = True): Subclasses should implement the ``is_valid()`` method - :param error_message: The error to display to the user when the input - isn't valid. - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param error_message: The error to display to the user when the input isn't + valid. + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ self.error_message = error_message self.allow_empty = allow_empty @@ -44,18 +43,17 @@ def __init__( """An abstract base class for validators that are based on counting instances of some content in the overall content. - Subclasses should implement the ``count()`` method to identify the - content of interest. + Subclasses should implement the ``count()`` method to identify the content of + interest. :param count: Optional; The expected count. :param expected_existence_message: The error message to show if matches are expected, but were not found. :param expected_non_existence_message: The error message to show if matches were not expected, but were found. - :param expected_count_message: The error message to show if matches - were expected, but a different number were found. - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param expected_count_message: The error message to show if matches were + expected, but a different number were found. + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ self.expected_count = count self.expected_existence_message = expected_existence_message @@ -97,10 +95,9 @@ def __init__( :param min_length: The minimum length of the string (inclusive). :param max_length: The maximum length of the string (inclusive). - :param error_message: Optional; the error message to display when the - length isn't in the given range. - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param error_message: Optional; the error message to display when the length + isn't in the given range. + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is None: error_message = ( @@ -138,10 +135,9 @@ def __init__( """A validator confirming that the length of input exceeds a minimum size. :param length: The minimum length of the string (inclusive). - :param error_message: Optional; the error message to display when the - string isn't long enough. - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param error_message: Optional; the error message to display when the string + isn't long enough. + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is None: error_message = f"Input is too short (length should be at least {length})" @@ -159,12 +155,12 @@ def __init__( length: int, error_message: str | None = None, ): - """A validator confirming that the length of - input does not exceed a maximum size. + """A validator confirming that the length of input does not exceed a maximum + size. :param length: The maximum length of the string (inclusive). - :param error_message: Optional; the error message to display when the - string is too long. + :param error_message: Optional; the error message to display when the string is + too long. """ if error_message is None: error_message = f"Input is too long (length should be at most {length})" @@ -185,10 +181,9 @@ def __init__( """A validator confirming that the input starts with a given substring. :param substring: The substring that the input must start with. - :param error_message: Optional; the error message to display when the - string doesn't start with the given substring. - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param error_message: Optional; the error message to display when the string + doesn't start with the given substring. + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is None: error_message = f"Input should start with {substring!r}" @@ -210,10 +205,9 @@ def __init__( """A validator confirming that the string ends with a given substring. :param substring: The substring that the input must end with. - :param error_message: Optional; the error message to display when the - string doesn't end with the given substring. - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param error_message: Optional; the error message to display when the string + doesn't end with the given substring. + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is None: error_message = f"Input should end with '{substring}'" @@ -238,10 +232,9 @@ def __init__( :param substring: The substring that must exist in the input. :param count: Optional; The exact number of matches that are expected. - :param error_message: Optional; the error message to display when the - input doesn't contain the substring (or the requested count of substrings). - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param error_message: Optional; the error message to display when the input + doesn't contain the substring (or the requested count of substrings). + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is not None: expected_non_existence_message = error_message @@ -276,8 +269,8 @@ def __init__( """A validator confirming that the string does not contain a substring. :param substring: A substring that must not exist in the input. - :param error_message: Optional; the error message to display when the - input contains the provided substring. + :param error_message: Optional; the error message to display when the input + contains the provided substring. """ super().__init__( substring, @@ -296,10 +289,9 @@ def __init__( """A validator confirming that the string matches a given regular expression. :param regex_string: A regular expression that the input must match. - :param error_message: Optional; the error message to display when the - input doesn't match the provided regular expression. - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param error_message: Optional; the error message to display when the input + doesn't match the provided regular expression. + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is None: error_message = f"Input should match regex: {regex_string!r}" @@ -320,14 +312,13 @@ def __init__( ): """A validator confirming that the string contains upper case letters. - :param count: Optional; if provided, the exact count of upper - case letters that must exist. If not provided, the existence of any - upper case letter will make the string valid. - :param error_message: Optional; the error message to display when the - input doesn't contain upper case letters (or the requested count of - upper case letters). - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param count: Optional; if provided, the exact count of upper case letters that + must exist. If not provided, the existence of any upper case letter will + make the string valid. + :param error_message: Optional; the error message to display when the input + doesn't contain upper case letters (or the requested count of upper case + letters). + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is not None: expected_non_existence_message = error_message @@ -365,14 +356,13 @@ def __init__( ): """A validator confirming that the string contains lower case letters. - :param count: Optional; if provided, the exact count of lower - case letters that must exist. If not provided, the existence of any - lower case letter will make the string valid. - :param error_message: Optional; the error message to display when the - input doesn't contain lower case letters (or the requested count of - lower case letters). - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param count: Optional; if provided, the exact count of lower case letters that + must exist. If not provided, the existence of any lower case letter will + make the string valid. + :param error_message: Optional; the error message to display when the input + doesn't contain lower case letters (or the requested count of lower case + letters). + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is not None: expected_non_existence_message = error_message @@ -410,13 +400,11 @@ def __init__( ): """A validator confirming that the string contains digits. - :param count: Optional; if provided, the exact count of digits - that must exist. If not provided, the existence of any digit will - make the string valid. - :param error_message: Optional; the error message to display when the - input doesn't contain digits (or the requested count of digits). - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param count: Optional; if provided, the exact count of digits that must exist. + If not provided, the existence of any digit will make the string valid. + :param error_message: Optional; the error message to display when the input + doesn't contain digits (or the requested count of digits). + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is not None: expected_non_existence_message = error_message @@ -449,14 +437,13 @@ def __init__( """A validator confirming that the string contains "special" (i.e., non-alphanumeric) characters. - :param count: Optional; if provided, the exact count of special - characters that must exist. If not provided, the existence of any - special character will make the string valid. - :param error_message: Optional; the error message to display when the - input doesn't contain special characters (or the requested count of - special characters). - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param count: Optional; if provided, the exact count of special characters that + must exist. If not provided, the existence of any special character will + make the string valid. + :param error_message: Optional; the error message to display when the input + doesn't contain special characters (or the requested count of special + characters). + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is not None: expected_non_existence_message = error_message @@ -499,10 +486,9 @@ def __init__( ): """A validator confirming that the string is an integer. - :param error_message: Optional; the error message to display when the - input isn't an integer. - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param error_message: Optional; the error message to display when the input + isn't an integer. + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is None: error_message = "Input should be an integer" @@ -524,10 +510,9 @@ def __init__( ): """A validator confirming that the string is a number. - :param error_message: Optional; the error message to display when the - input isn't a number. - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param error_message: Optional; the error message to display when the input + isn't a number. + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is None: error_message = "Input should be a number" @@ -560,10 +545,9 @@ def __init__( some email addresses that aren't *technically* valid. However, it shouldn't *exclude* any valid email addresses. - :param error_message: Optional; the error message to display when the - input isn't a number. - :param allow_empty: Optional; Is no input considered valid? Defaults to - ``True`` + :param error_message: Optional; the error message to display when the input + isn't a number. + :param allow_empty: Optional; Is no input considered valid? Defaults to ``True`` """ if error_message is None: error_message = "Input should be a valid email address" diff --git a/core/src/toga/widgets/base.py b/core/src/toga/widgets/base.py index a3e4f9db17..61d135cb9f 100644 --- a/core/src/toga/widgets/base.py +++ b/core/src/toga/widgets/base.py @@ -258,8 +258,8 @@ def window(self, window: Window | None) -> None: @property def enabled(self) -> bool: - """Is the widget currently enabled? - i.e., can the user interact with the widget?""" + """Is the widget currently enabled? i.e., can the user interact with the + widget?""" return self._impl.get_enabled() @enabled.setter diff --git a/core/tests/command/test_command.py b/core/tests/command/test_command.py index ee8d09126d..6a170a7adb 100644 --- a/core/tests/command/test_command.py +++ b/core/tests/command/test_command.py @@ -57,8 +57,8 @@ def test_create(): assert cmd.order == 0 assert cmd.action._raw is None - assert ( - repr(cmd) == " section=0 order=0>" ) @@ -152,8 +152,8 @@ def test_create_explicit(app): assert cmd.action._raw == handler - assert ( - repr(cmd) == " section=3 order=4>" ) diff --git a/core/tests/command/test_group.py b/core/tests/command/test_group.py index 2dccc1060f..ad0239ea47 100644 --- a/core/tests/command/test_group.py +++ b/core/tests/command/test_group.py @@ -24,8 +24,8 @@ def test_create_with_params(): assert grp.section == 3 assert grp.parent == parent - assert ( - repr(grp) == " section=3>" ) diff --git a/core/tests/sources/test_list_source.py b/core/tests/sources/test_list_source.py index 9d69bc8c35..3a6ba6d524 100644 --- a/core/tests/sources/test_list_source.py +++ b/core/tests/sources/test_list_source.py @@ -415,7 +415,9 @@ def test_find(source): # An overspecified search will fail with pytest.raises( ValueError, - match=r"No row matching " - r"{'val1': 'first', 'val2': 111, 'value': 'overspecified'} in data", + match=( + r"No row matching " + r"{'val1': 'first', 'val2': 111, 'value': 'overspecified'} in data" + ), ): source.find(dict(val1="first", val2=111, value="overspecified")) diff --git a/core/tests/style/pack/test_css.py b/core/tests/style/pack/test_css.py index fa15a19b67..b0cff044d4 100644 --- a/core/tests/style/pack/test_css.py +++ b/core/tests/style/pack/test_css.py @@ -363,8 +363,10 @@ # Background Color pytest.param( Pack(background_color=REBECCAPURPLE), - "flex-direction: row; flex: " - "0.0 0 auto; background-color: rgb(102, 51, 153);", + ( + "flex-direction: row; flex: " + "0.0 0 auto; background-color: rgb(102, 51, 153);" + ), id="background-color", ), # Text Alignment diff --git a/core/tests/style/pack/utils.py b/core/tests/style/pack/utils.py index bf9e5c315c..185f2e132f 100644 --- a/core/tests/style/pack/utils.py +++ b/core/tests/style/pack/utils.py @@ -81,15 +81,15 @@ def _assert_layout(node, expected_layout): node.layout.absolute_content_left, node.layout.absolute_content_top, ) == expected_layout["origin"], ( - f"origin of {node} ({node.layout.absolute_content_left}, " - f"{node.layout.absolute_content_top}) " + f"origin of {node} " + f"({node.layout.absolute_content_left}, {node.layout.absolute_content_top}) " f"doesn't match expected {expected_layout['origin']}" ) assert (node.layout.content_width, node.layout.content_height) == expected_layout[ "content" ], ( - f"content size of " - f"{node} ({node.layout.content_width}, {node.layout.content_height}) " + f"content size of {node} " + f"({node.layout.content_width}, {node.layout.content_height}) " f"doesn't match expected {expected_layout['content']}" ) diff --git a/core/tests/test_icons.py b/core/tests/test_icons.py index d8aa5aa5a3..01fb6c561f 100644 --- a/core/tests/test_icons.py +++ b/core/tests/test_icons.py @@ -216,8 +216,8 @@ def test_create_app_icon_non_script(monkeypatch, app, capsys): def test_create_app_icon_missing_non_script(monkeypatch, app, capsys): - """If the icon from binary executable cannot be found, - the app icon is reset to the default""" + """If the icon from binary executable cannot be found, the app icon is reset to the + default.""" # Prime the dummy so the app icon cannot be found monkeypatch.setattr( DummyIcon, diff --git a/core/tests/test_paths.py b/core/tests/test_paths.py index 1931a10e90..3dfe9e7372 100644 --- a/core/tests/test_paths.py +++ b/core/tests/test_paths.py @@ -39,22 +39,21 @@ def assert_paths(output, app_path, app_name): results = output.splitlines() assert f"app.paths.app={app_path.resolve()}" in results assert ( - f"app.paths.config=" - f"{(Path.home() / 'config' / f'org.testbed.{app_name}').resolve()}" in results - ) + "app.paths.config=" + f"{(Path.home() / 'config' / f'org.testbed.{app_name}').resolve()}" + ) in results assert ( - f"app.paths.data=" + "app.paths.data=" f"{(Path.home() / 'user_data' / f'org.testbed.{app_name}').resolve()}" - in results - ) + ) in results assert ( - f"app.paths.cache=" - f"{(Path.home() / 'cache' / f'org.testbed.{app_name}').resolve()}" in results - ) + "app.paths.cache=" + f"{(Path.home() / 'cache' / f'org.testbed.{app_name}').resolve()}" + ) in results assert ( - f"app.paths.logs=" - f"{(Path.home() / 'logs' / f'org.testbed.{app_name}').resolve()}" in results - ) + "app.paths.logs=" + f"{(Path.home() / 'logs' / f'org.testbed.{app_name}').resolve()}" + ) in results assert f"app.paths.toga={Path(toga.__file__).parent.resolve()}" in results diff --git a/core/tests/widgets/canvas/test_canvas.py b/core/tests/widgets/canvas/test_canvas.py index 2afbb5c3c3..c1e4d4a553 100644 --- a/core/tests/widgets/canvas/test_canvas.py +++ b/core/tests/widgets/canvas/test_canvas.py @@ -165,36 +165,40 @@ def test_deprecated_drawing_operations(widget): with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; " - r"use context.begin_path()", + match=( + r"Direct canvas operations have been deprecated; " + r"use context.begin_path()" + ), ): widget.new_path() with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; " - r"use context.move_to()", + match=r"Direct canvas operations have been deprecated; use context.move_to()", ): widget.move_to(10, 20) with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; " - r"use context.line_to()", + match=r"Direct canvas operations have been deprecated; use context.line_to()", ): widget.line_to(10, 20) with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; " - r"use context.bezier_curve_to()", + match=( + r"Direct canvas operations have been deprecated; " + r"use context.bezier_curve_to()" + ), ): widget.bezier_curve_to(1, 2, 3, 4, 10, 20) with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; " - r"use context.quadratic_curve_to()", + match=( + r"Direct canvas operations have been deprecated; " + r"use context.quadratic_curve_to()" + ), ): widget.quadratic_curve_to(1, 2, 10, 20) @@ -218,8 +222,10 @@ def test_deprecated_drawing_operations(widget): with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; " - r"use context.write_text()", + match=( + r"Direct canvas operations have been deprecated; " + r"use context.write_text()" + ), ): widget.write_text("Hello World", 10, 20, Font("Cutive", 37)) @@ -243,8 +249,10 @@ def test_deprecated_drawing_operations(widget): with pytest.warns( DeprecationWarning, - match=r"Direct canvas operations have been deprecated; " - r"use context.reset_transform()", + match=( + r"Direct canvas operations have been deprecated; " + r"use context.reset_transform()" + ), ): widget.reset_transform() diff --git a/core/tests/widgets/canvas/test_context_objects.py b/core/tests/widgets/canvas/test_context_objects.py index a9e91075f9..79171565b6 100644 --- a/core/tests/widgets/canvas/test_context_objects.py +++ b/core/tests/widgets/canvas/test_context_objects.py @@ -272,8 +272,10 @@ def test_fill(widget, kwargs, args_repr, has_move, properties): # Color ( {"color": REBECCAPURPLE}, - f"x=None, y=None, color={REBECCA_PURPLE_COLOR}, " - f"line_width=2.0, line_dash=None", + ( + f"x=None, y=None, color={REBECCA_PURPLE_COLOR}, " + f"line_width=2.0, line_dash=None" + ), False, { "x": None, @@ -331,8 +333,10 @@ def test_fill(widget, kwargs, args_repr, has_move, properties): "line_width": 4.5, "line_dash": [2, 7], }, - f"x=10, y=20, color={REBECCA_PURPLE_COLOR}, " - f"line_width=4.5, line_dash=[2, 7]", + ( + f"x=10, y=20, color={REBECCA_PURPLE_COLOR}, " + f"line_width=4.5, line_dash=[2, 7]" + ), True, { "x": 10, diff --git a/core/tests/widgets/canvas/test_draw_operations.py b/core/tests/widgets/canvas/test_draw_operations.py index 069d286533..6f1eff52ef 100644 --- a/core/tests/widgets/canvas/test_draw_operations.py +++ b/core/tests/widgets/canvas/test_draw_operations.py @@ -262,8 +262,10 @@ def test_quadratic_curve_to(widget): # Defaults ( {"x": 10, "y": 20, "radius": 30}, - "x=10, y=20, radius=30, startangle=0.000, " - "endangle=6.283, anticlockwise=False", + ( + "x=10, y=20, radius=30, startangle=0.000, " + "endangle=6.283, anticlockwise=False" + ), { "x": 10, "y": 20, @@ -276,8 +278,10 @@ def test_quadratic_curve_to(widget): # Start angle ( {"x": 10, "y": 20, "radius": 30, "startangle": 1.234}, - "x=10, y=20, radius=30, startangle=1.234, " - "endangle=6.283, anticlockwise=False", + ( + "x=10, y=20, radius=30, startangle=1.234, " + "endangle=6.283, anticlockwise=False" + ), { "x": 10, "y": 20, @@ -295,8 +299,10 @@ def test_quadratic_curve_to(widget): "radius": 30, "endangle": 2.345, }, - "x=10, y=20, radius=30, startangle=0.000, " - "endangle=2.345, anticlockwise=False", + ( + "x=10, y=20, radius=30, startangle=0.000, " + "endangle=2.345, anticlockwise=False" + ), { "x": 10, "y": 20, @@ -314,8 +320,10 @@ def test_quadratic_curve_to(widget): "radius": 30, "anticlockwise": False, }, - "x=10, y=20, radius=30, startangle=0.000, " - "endangle=6.283, anticlockwise=False", + ( + "x=10, y=20, radius=30, startangle=0.000, " + "endangle=6.283, anticlockwise=False" + ), { "x": 10, "y": 20, @@ -333,8 +341,10 @@ def test_quadratic_curve_to(widget): "radius": 30, "anticlockwise": True, }, - "x=10, y=20, radius=30, startangle=0.000, " - "endangle=6.283, anticlockwise=True", + ( + "x=10, y=20, radius=30, startangle=0.000, " + "endangle=6.283, anticlockwise=True" + ), { "x": 10, "y": 20, @@ -354,8 +364,10 @@ def test_quadratic_curve_to(widget): "endangle": 2.345, "anticlockwise": True, }, - "x=10, y=20, radius=30, startangle=1.234, " - "endangle=2.345, anticlockwise=True", + ( + "x=10, y=20, radius=30, startangle=1.234, " + "endangle=2.345, anticlockwise=True" + ), { "x": 10, "y": 20, diff --git a/core/tests/widgets/test_webview.py b/core/tests/widgets/test_webview.py index ecbfda751e..07a6594185 100644 --- a/core/tests/widgets/test_webview.py +++ b/core/tests/widgets/test_webview.py @@ -193,8 +193,10 @@ def test_evaluate_javascript(widget): # Attempting to use or compare the result raises an error with pytest.raises( RuntimeError, - match=r"Can't check JavaScript result directly; " - r"use await or an on_result handler", + match=( + r"Can't check JavaScript result directly; " + r"use await or an on_result handler" + ), ): result == 42 diff --git a/core/tests/window/test_window.py b/core/tests/window/test_window.py index dcb85eb5a8..19088f95d5 100644 --- a/core/tests/window/test_window.py +++ b/core/tests/window/test_window.py @@ -555,8 +555,10 @@ def test_deprecated_info_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"info_dialog\(...\) has been deprecated; " - r"use dialog\(toga.InfoDialog\(...\)\)", + match=( + r"info_dialog\(...\) has been deprecated; " + r"use dialog\(toga.InfoDialog\(...\)\)" + ), ): dialog = window.info_dialog("Title", "Body", on_result=on_result_handler) @@ -597,8 +599,10 @@ def test_deprecated_question_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"question_dialog\(...\) has been deprecated; " - r"use dialog\(toga.QuestionDialog\(...\)\)", + match=( + r"question_dialog\(...\) has been deprecated; " + r"use dialog\(toga.QuestionDialog\(...\)\)" + ), ): dialog = window.question_dialog("Title", "Body", on_result=on_result_handler) @@ -639,8 +643,10 @@ def test_deprecated_confirm_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"confirm_dialog\(...\) has been deprecated; " - r"use dialog\(toga.ConfirmDialog\(...\)\)", + match=( + r"confirm_dialog\(...\) has been deprecated; " + r"use dialog\(toga.ConfirmDialog\(...\)\)" + ), ): dialog = window.confirm_dialog("Title", "Body", on_result=on_result_handler) @@ -681,8 +687,10 @@ def test_deprecated_error_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"error_dialog\(...\) has been deprecated; " - r"use dialog\(toga.ErrorDialog\(...\)\)", + match=( + r"error_dialog\(...\) has been deprecated; " + r"use dialog\(toga.ErrorDialog\(...\)\)" + ), ): dialog = window.error_dialog("Title", "Body", on_result=on_result_handler) @@ -723,8 +731,10 @@ def test_deprecated_stack_trace_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"stack_trace_dialog\(...\) has been deprecated; " - r"use dialog\(toga.StackTraceDialog\(...\)\)", + match=( + r"stack_trace_dialog\(...\) has been deprecated; " + r"use dialog\(toga.StackTraceDialog\(...\)\)" + ), ): dialog = window.stack_trace_dialog( "Title", @@ -773,8 +783,10 @@ def test_deprecated_save_file_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"save_file_dialog\(...\) has been deprecated; " - r"use dialog\(toga.SaveFileDialog\(...\)\)", + match=( + r"save_file_dialog\(...\) has been deprecated; " + r"use dialog\(toga.SaveFileDialog\(...\)\)" + ), ): dialog = window.save_file_dialog( "Title", @@ -822,8 +834,10 @@ def test_deprecated_save_file_dialog_default_directory(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"save_file_dialog\(...\) has been deprecated; " - r"use dialog\(toga.SaveFileDialog\(...\)\)", + match=( + r"save_file_dialog\(...\) has been deprecated; " + r"use dialog\(toga.SaveFileDialog\(...\)\)" + ), ): dialog = window.save_file_dialog( "Title", @@ -872,8 +886,10 @@ def test_deprecated_open_file_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"open_file_dialog\(...\) has been deprecated; " - r"use dialog\(toga.OpenFileDialog\(...\)\)", + match=( + r"open_file_dialog\(...\) has been deprecated; " + r"use dialog\(toga.OpenFileDialog\(...\)\)" + ), ): dialog = window.open_file_dialog( "Title", @@ -924,8 +940,10 @@ def test_deprecated_open_file_dialog_default_directory(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"open_file_dialog\(...\) has been deprecated; " - r"use dialog\(toga.OpenFileDialog\(...\)\)", + match=( + r"open_file_dialog\(...\) has been deprecated; " + r"use dialog\(toga.OpenFileDialog\(...\)\)" + ), ): dialog = window.open_file_dialog( "Title", @@ -974,8 +992,10 @@ def test_deprecated_select_folder_dialog(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"select_folder_dialog\(...\) has been deprecated; " - r"use dialog\(toga.SelectFolderDialog\(...\)\)", + match=( + r"select_folder_dialog\(...\) has been deprecated; " + r"use dialog\(toga.SelectFolderDialog\(...\)\)" + ), ): dialog = window.select_folder_dialog( "Title", @@ -1025,8 +1045,10 @@ def test_deprecated_select_folder_dialog_default_directory(window, app): match=r"Synchronous `on_result` handlers have been deprecated;", ), pytest.warns( DeprecationWarning, - match=r"select_folder_dialog\(...\) has been deprecated; " - r"use dialog\(toga.SelectFolderDialog\(...\)\)", + match=( + r"select_folder_dialog\(...\) has been deprecated; " + r"use dialog\(toga.SelectFolderDialog\(...\)\)" + ), ): dialog = window.select_folder_dialog( "Title", @@ -1073,12 +1095,16 @@ def test_deprecated_names_open_file_dialog(window, app): match=r"open_file_dialog\(multiselect\) has been renamed multiple_select", ), pytest.warns( DeprecationWarning, - match=r"Synchronous `on_result` handlers have been deprecated; " - r"use `await` on the asynchronous result", + match=( + r"Synchronous `on_result` handlers have been deprecated; " + r"use `await` on the asynchronous result" + ), ), pytest.warns( DeprecationWarning, - match=r"open_file_dialog\(...\) has been deprecated; " - r"use dialog\(toga.OpenFileDialog\(...\)\)", + match=( + r"open_file_dialog\(...\) has been deprecated; " + r"use dialog\(toga.OpenFileDialog\(...\)\)" + ), ): dialog = window.open_file_dialog( "Title", @@ -1114,16 +1140,21 @@ def test_deprecated_names_select_folder_dialog(window, app): with pytest.warns( DeprecationWarning, - match=r"select_folder_dialog\(multiselect\) " - r"has been renamed multiple_select", + match=( + r"select_folder_dialog\(multiselect\) " r"has been renamed multiple_select" + ), ), pytest.warns( DeprecationWarning, - match=r"Synchronous `on_result` handlers have been deprecated; " - r"use `await` on the asynchronous result", + match=( + r"Synchronous `on_result` handlers have been deprecated; " + r"use `await` on the asynchronous result" + ), ), pytest.warns( DeprecationWarning, - match=r"select_folder_dialog\(...\) has been deprecated; " - r"use dialog\(toga.SelectFolderDialog\(...\)\)", + match=( + r"select_folder_dialog\(...\) has been deprecated; " + r"use dialog\(toga.SelectFolderDialog\(...\)\)" + ), ): dialog = window.select_folder_dialog( "Title", diff --git a/examples/beeliza/beeliza/bot.py b/examples/beeliza/beeliza/bot.py index 95f9fc25c0..c55e3ba904 100644 --- a/examples/beeliza/beeliza/bot.py +++ b/examples/beeliza/beeliza/bot.py @@ -323,8 +323,10 @@ class Eliza: "Tell me more about your father.", "How did your father make you feel?", "How do you feel about your father?", - "Does your relationship with your father " - "relate to your feelings today?", + ( + "Does your relationship with your father " + "relate to your feelings today?" + ), "Do you have trouble showing affection with your family?", ], ], @@ -335,8 +337,10 @@ class Eliza: "What is your favorite childhood memory?", "Do you remember any dreams or nightmares from childhood?", "Did the other children sometimes tease you?", - "How do you think your childhood " - "experiences relate to your feelings today?", + ( + "How do you think your childhood " + "experiences relate to your feelings today?" + ), ], ], [ diff --git a/examples/hardware/hardware/app.py b/examples/hardware/hardware/app.py index 6d3f3e9841..4e8790ce7d 100644 --- a/examples/hardware/hardware/app.py +++ b/examples/hardware/hardware/app.py @@ -195,8 +195,10 @@ async def request_background_location(self, widget, **kwargs): await self.main_window.dialog( toga.InfoDialog( "All good!", - "Application has permission to perform background " - "location tracking", + ( + "Application has permission to perform background " + "location tracking" + ), ) ) else: @@ -213,8 +215,10 @@ async def request_background_location(self, widget, **kwargs): await self.main_window.dialog( toga.InfoDialog( "Oh no!", - "You have not granted permission for background " - "location tracking", + ( + "You have not granted permission for background " + "location tracking" + ), ) ) except NotImplementedError: diff --git a/examples/positron-django/src/webapp/settings.py b/examples/positron-django/src/webapp/settings.py index 94d083379f..52a6fd56c2 100644 --- a/examples/positron-django/src/webapp/settings.py +++ b/examples/positron-django/src/webapp/settings.py @@ -85,8 +85,10 @@ AUTH_PASSWORD_VALIDATORS = [ { - "NAME": "django.contrib.auth.password_validation." - "UserAttributeSimilarityValidator", + "NAME": ( + "django.contrib.auth.password_validation." + "UserAttributeSimilarityValidator" + ), }, { "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", diff --git a/examples/webview/webview/app.py b/examples/webview/webview/app.py index de4c8b75b1..454371c523 100644 --- a/examples/webview/webview/app.py +++ b/examples/webview/webview/app.py @@ -9,8 +9,8 @@ async def on_do_async_js(self, widget, **kwargs): def on_good_js(self, widget, **kwargs): self.webview.evaluate_javascript( - "document.body.innerHTML = " - '"I can invoke JS. User agent is " + navigator.userAgent;' + 'document.body.innerHTML = "I can invoke JS. User agent is "' + "+ navigator.userAgent;" ) def on_bad_js(self, widget, **kwargs): @@ -37,8 +37,10 @@ def on_clear_url(self, widget, **kwargs): def on_set_content(self, widget, **kwargs): self.webview.set_content( "https://example.com", - "I'm feeling very " - "content", + ( + "I'm feeling very " + "content" + ), ) def on_get_agent(self, widget, **kwargs): diff --git a/gtk/src/toga_gtk/icons.py b/gtk/src/toga_gtk/icons.py index 70429c0e6e..c0382cedb1 100644 --- a/gtk/src/toga_gtk/icons.py +++ b/gtk/src/toga_gtk/icons.py @@ -17,17 +17,11 @@ def __init__(self, interface, path): if path is None: # Use the executable location to find the share folder; look for icons # matching the app bundle in that location. - usr = Path(sys.executable).parent.parent + hicolor = Path(sys.executable).parent.parent / "share/icons/hicolor" path = { - size: ( - usr / f"share/icons/hicolor/" - f"{size}x{size}/apps/{toga.App.app.app_id}.png" - ) + size: hicolor / f"{size}x{size}/apps/{toga.App.app.app_id}.png" for size in self.SIZES - if ( - usr / f"share/icons/hicolor/" - f"{size}x{size}/apps/{toga.App.app.app_id}.png" - ).is_file() + if (hicolor / f"{size}x{size}/apps/{toga.App.app.app_id}.png").is_file() } self.paths = path diff --git a/gtk/src/toga_gtk/widgets/scrollcontainer.py b/gtk/src/toga_gtk/widgets/scrollcontainer.py index ef30219016..33cebbb1fc 100644 --- a/gtk/src/toga_gtk/widgets/scrollcontainer.py +++ b/gtk/src/toga_gtk/widgets/scrollcontainer.py @@ -13,7 +13,7 @@ def create(self): self.native.get_vadjustment().connect("changed", self.gtk_on_changed) # Set this minimum size of scroll windows because we must reserve space for - # scrollbars when splitter resized. See, + # scrollbars when splitter resized. See # https://gitlab.gnome.org/GNOME/gtk/-/issues/210 self.native.set_min_content_width(self.interface._MIN_WIDTH) self.native.set_min_content_height(self.interface._MIN_HEIGHT) diff --git a/gtk/tests_backend/widgets/switch.py b/gtk/tests_backend/widgets/switch.py index 0c85054152..5254ccf87f 100644 --- a/gtk/tests_backend/widgets/switch.py +++ b/gtk/tests_backend/widgets/switch.py @@ -44,8 +44,10 @@ def assert_width(self, min_width, max_width): (min_width - MAX_SWITCH_WIDTH) <= label_width <= (max_width - MAX_SWITCH_WIDTH) - ), f"Label width ({label_width}) not in range " - f"({min_width - MAX_SWITCH_WIDTH}, {max_width - MAX_SWITCH_WIDTH})" + ), ( + f"Label width ({label_width}) not in range " + f"({min_width - MAX_SWITCH_WIDTH}, {max_width - MAX_SWITCH_WIDTH})" + ) assert ( 0 <= switch_width <= MAX_SWITCH_WIDTH ), f"Switch width ({switch_width}) not in range (0-60)" diff --git a/iOS/src/toga_iOS/dialogs.py b/iOS/src/toga_iOS/dialogs.py index b629f9352e..8c93a0b579 100644 --- a/iOS/src/toga_iOS/dialogs.py +++ b/iOS/src/toga_iOS/dialogs.py @@ -17,7 +17,9 @@ def show(self, host_window, future): if self.native: # Don't differentiate between app and window-modal dialogs. - toga.App.app.current_window._impl.native.rootViewController.presentViewController( # noqa: E501 + ( + toga.App.app.current_window._impl.native.rootViewController + ).presentViewController( self.native, animated=False, completion=None, diff --git a/iOS/src/toga_iOS/hardware/camera.py b/iOS/src/toga_iOS/hardware/camera.py index 6a29431836..d911f8806d 100644 --- a/iOS/src/toga_iOS/hardware/camera.py +++ b/iOS/src/toga_iOS/hardware/camera.py @@ -161,8 +161,8 @@ def take_photo(self, result, device, flash): self.native.delegate.result = result # Show the pane - toga.App.app.current_window._impl.native.rootViewController.presentViewController( # noqa: E501 - self.native, animated=True, completion=None - ) + ( + toga.App.app.current_window._impl.native.rootViewController + ).presentViewController(self.native, animated=True, completion=None) else: raise PermissionError("App does not have permission to take photos") diff --git a/iOS/tests_backend/widgets/detailedlist.py b/iOS/tests_backend/widgets/detailedlist.py index 1485dd6ca4..e87feb27b8 100644 --- a/iOS/tests_backend/widgets/detailedlist.py +++ b/iOS/tests_backend/widgets/detailedlist.py @@ -30,16 +30,14 @@ def __init__(self, widget): def row_count(self): # Need to use the long form of this method because the first argument when used # as a selector is ambiguous with a property of the same name on the object. - return int( - self.native.delegate.tableView_numberOfRowsInSection_(self.native, 0) - ) + return int(self.native.delegate.tableView(self.native, numberOfRowsInSection=0)) def assert_cell_content(self, row, title, subtitle, icon=None): # Need to use the long form of this method because the first argument when used # as a selector is ambiguous with a property of the same name on the object. - cell = self.native.delegate.tableView_cellForRowAtIndexPath_( + cell = self.native.delegate.tableView( self.native, - NSIndexPath.indexPathForRow(row, inSection=0), + cellForRowAtIndexPath=NSIndexPath.indexPathForRow(row, inSection=0), ) assert str(cell.textLabel.text) == title assert str(cell.detailTextLabel.text) == subtitle @@ -140,8 +138,9 @@ async def perform_primary_action(self, row, active=True): path = NSIndexPath.indexPathForRow(row, inSection=0) # Need to use the long form of this method because the first argument when used # as a selector is ambiguous with a property of the same name on the object. - config = self.native.delegate.tableView_trailingSwipeActionsConfigurationForRowAtIndexPath_( # noqa: E501 - self.native, path + config = self.native.delegate.tableView( + self.native, + trailingSwipeActionsConfigurationForRowAtIndexPath=path, ) if active: @@ -159,8 +158,9 @@ async def perform_secondary_action(self, row, active=True): path = NSIndexPath.indexPathForRow(row, inSection=0) # Need to use the long form of this method because the first argument when used # as a selector is ambiguous with a property of the same name on the object. - config = self.native.delegate.tableView_leadingSwipeActionsConfigurationForRowAtIndexPath_( # noqa: E501 - self.native, path + config = self.native.delegate.tableView( + self.native, + leadingSwipeActionsConfigurationForRowAtIndexPath=path, ) if active: diff --git a/iOS/tests_backend/widgets/switch.py b/iOS/tests_backend/widgets/switch.py index de2fc8f654..a871139484 100644 --- a/iOS/tests_backend/widgets/switch.py +++ b/iOS/tests_backend/widgets/switch.py @@ -42,8 +42,10 @@ def assert_width(self, min_width, max_width): (min_width - MAX_SWITCH_WIDTH) <= label_width <= (max_width - MAX_SWITCH_WIDTH) - ), f"Label width ({label_width}) not in range " - f"({min_width - MAX_SWITCH_WIDTH}, {max_width - MAX_SWITCH_WIDTH})" + ), ( + f"Label width ({label_width}) not in range " + f"({min_width - MAX_SWITCH_WIDTH}, {max_width - MAX_SWITCH_WIDTH})" + ) assert ( 0 <= switch_width <= MAX_SWITCH_WIDTH ), f"Switch width ({switch_width}) not in range (0-60)" diff --git a/testbed/tests/conftest.py b/testbed/tests/conftest.py index 8aca92bac1..e86e015e7c 100644 --- a/testbed/tests/conftest.py +++ b/testbed/tests/conftest.py @@ -39,8 +39,10 @@ def skip_if_unbundled_app(reason=None): if not toga.App.app.is_bundled: skip( reason - or "test requires a full application, " - "use 'briefcase run' instead of 'briefcase dev'" + or ( + "test requires a full application, " + "use 'briefcase run' instead of 'briefcase dev'" + ) ) diff --git a/testbed/tests/test_icons.py b/testbed/tests/test_icons.py index feadc3969f..499fe35df9 100644 --- a/testbed/tests/test_icons.py +++ b/testbed/tests/test_icons.py @@ -47,7 +47,9 @@ async def test_bad_icon_file(app): "If a file isn't a loadable icon, an error is raised" with pytest.raises( ValueError, - match=rf"Unable to load icon from " - rf"{re.escape(str(app.paths.app / 'resources' / 'icons' / 'bad'))}", + match=( + rf"Unable to load icon from " + rf"{re.escape(str(app.paths.app / 'resources' / 'icons' / 'bad'))}" + ), ): toga.Icon("resources/icons/bad") diff --git a/testbed/tests/test_statusicons.py b/testbed/tests/test_statusicons.py index 7c65307431..0e64b8393c 100644 --- a/testbed/tests/test_statusicons.py +++ b/testbed/tests/test_statusicons.py @@ -109,8 +109,10 @@ async def test_unknown_status_icon(app, app_probe): try: with pytest.raises( ValueError, - match=r"Command 'Bad Action' " - "does not belong to a current status icon group.", + match=( + r"Command 'Bad Action' " + r"does not belong to a current status icon group." + ), ): app.status_icons.commands.add(bad_cmd) finally: diff --git a/testbed/tests/testbed.py b/testbed/tests/testbed.py index 850a29dff5..857eaaf05a 100644 --- a/testbed/tests/testbed.py +++ b/testbed/tests/testbed.py @@ -152,8 +152,9 @@ def run_tests(app, cov, args, report_coverage, run_slow, running_in_ci): "coverage_conditional_plugin:rules", { "no-cover-if-linux-wayland": "os_environ.get('WAYLAND_DISPLAY', '') != ''", - "no-cover-if-linux-x": "os_environ.get" - "('WAYLAND_DISPLAY', 'not-set') == 'not-set'", + "no-cover-if-linux-x": ( + "os_environ.get('WAYLAND_DISPLAY', 'not-set') == 'not-set'" + ), }, ) cov.start() diff --git a/testbed/tests/widgets/properties.py b/testbed/tests/widgets/properties.py index 13cc753e07..0870c09567 100644 --- a/testbed/tests/widgets/properties.py +++ b/testbed/tests/widgets/properties.py @@ -547,8 +547,10 @@ async def test_flex_horizontal_widget_size(widget, probe): # Widget is still the width of the screen # and the height hasn't changed await probe.redraw( - message="Widget width should be still the width of the screen" - "without height change" + message=( + "Widget width should be still the width of the screen" + "without height change" + ) ) assert probe.width > 350 probe.assert_width(350, MAX_WIDTH) diff --git a/winforms/src/toga_winforms/fonts.py b/winforms/src/toga_winforms/fonts.py index e4bd651546..96985872e3 100644 --- a/winforms/src/toga_winforms/fonts.py +++ b/winforms/src/toga_winforms/fonts.py @@ -30,8 +30,9 @@ class Font: def __init__(self, interface): - self._pfc = None # this needs to be an instance variable, otherwise we might - # get Winforms exceptions later + # this needs to be an instance variable, otherwise we might get Winforms + # exceptions later + self._pfc = None self.interface = interface try: font = _FONT_CACHE[self.interface] From 925c0d790dc8748c886f471f0cd293e5ea269eb8 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 27 Nov 2024 14:43:18 +0800 Subject: [PATCH 07/10] More tweaks and fixes. --- android/src/toga_android/app.py | 11 +-- android/src/toga_android/libs/events.py | 99 +++++++++---------- cocoa/src/toga_cocoa/widgets/numberinput.py | 12 +-- cocoa/src/toga_cocoa/window.py | 4 +- gtk/src/toga_gtk/widgets/activityindicator.py | 8 +- iOS/src/toga_iOS/widgets/mapview.py | 2 +- iOS/tests_backend/widgets/detailedlist.py | 20 ++-- 7 files changed, 81 insertions(+), 75 deletions(-) diff --git a/android/src/toga_android/app.py b/android/src/toga_android/app.py index e9d99e623f..c3c56ffd30 100644 --- a/android/src/toga_android/app.py +++ b/android/src/toga_android/app.py @@ -68,7 +68,7 @@ def onActivityResult(self, requestCode, resultCode, resultData): def onRequestPermissionsResult(self, requestCode, permissions, grantResults): print( - "Toga app: onRequestPermissionsResult " + f"Toga app: onRequestPermissionsResult " f"{requestCode=} {permissions=} {grantResults=}" ) try: @@ -228,13 +228,12 @@ def exit(self): pass # pragma: no cover def main_loop(self): - # In order to support user asyncio code, start the Python/Android - # cooperative event loop. + # In order to support user asyncio code, start the Python/Android cooperative + # event loop. self.loop.run_forever_cooperatively() - # On Android, Toga UI integrates automatically into the main Android event - # loop by virtue - # of the Android Activity system. + # On Android, Toga UI integrates automatically into the main Android event loop + # by virtue of the Android Activity system. self.create() def set_icon(self, icon): diff --git a/android/src/toga_android/libs/events.py b/android/src/toga_android/libs/events.py index c7c148bd03..f191d65c19 100644 --- a/android/src/toga_android/libs/events.py +++ b/android/src/toga_android/libs/events.py @@ -12,21 +12,21 @@ from java.io import FileDescriptor from java.lang import Runnable -# Some methods in this file are based on CPython's implementation. -# Per https://github.com/python/cpython/blob/master/LICENSE , re-use is permitted -# via the Python Software Foundation License Version 2, which includes inclusion -# into this project under its BSD license terms so long as we retain this copyright -# notice: +# Some methods in this file are based on CPython's implementation. Per +# https://github.com/python/cpython/blob/master/LICENSE , re-use is permitted via the +# Python Software Foundation License Version 2, which includes inclusion into this +# project under its BSD license terms so long as we retain this copyright notice: +# # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, -# 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation; -# All Rights Reserved. +# 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Python Software Foundation; All Rights +# Reserved. class AndroidEventLoop(asyncio.SelectorEventLoop): # `AndroidEventLoop` exists to support starting the Python event loop cooperatively - # with the built-in Android event loop. Since it's cooperative, - # it has a `run_forever_cooperatively()` method which returns immediately. - # This is is different from the parent class's `run_forever()`, which blocks. + # with the built-in Android event loop. Since it's cooperative, it has a + # `run_forever_cooperatively()` method which returns immediately. This is is + # different from the parent class's `run_forever()`, which blocks. # # In some cases, for simplicity of implementation, this class reaches into the # internals of the parent and grandparent classes. @@ -36,17 +36,17 @@ class AndroidEventLoop(asyncio.SelectorEventLoop): # descriptors are ready for I/O. # # `SelectorEventLoop` uses an approach we **cannot** use: it calls the `select()` - # method to block waiting for specific file descriptors to be come ready for I/O, - # or a timeout corresponding to the soonest delayed task, whichever occurs sooner. + # method to block waiting for specific file descriptors to be come ready for I/O, or + # a timeout corresponding to the soonest delayed task, whichever occurs sooner. # - # To handle delayed tasks, `AndroidEventLoop` asks the Android event loop to wake - # it up when its soonest delayed task is ready. To accomplish this, - # it relies on a `SelectorEventLoop` implementation detail: `_scheduled` is a - # collection of tasks sorted by soonest wakeup time. + # To handle delayed tasks, `AndroidEventLoop` asks the Android event loop to wake it + # up when its soonest delayed task is ready. To accomplish this, it relies on a + # `SelectorEventLoop` implementation detail: `_scheduled` is a collection of tasks + # sorted by soonest wakeup time. # - # To handle waking up when it's possible to do I/O, `AndroidEventLoop` will - # register file descriptors with the Android event loop so the platform can wake it - # up accordingly. It does not do this yet. + # To handle waking up when it's possible to do I/O, `AndroidEventLoop` will register + # file descriptors with the Android event loop so the platform can wake it up + # accordingly. It does not do this yet. def __init__(self): # Tell the parent constructor to use our custom Selector. selector = AndroidSelector(self) @@ -184,9 +184,8 @@ def run_delayed_tasks(self): check if there are more delayed tasks to execute in the future; if so, schedule the next wakeup. """ - # Based heavily on `BaseEventLoop._run_once()` from CPython -- specifically, - # the part after blocking on `select()`. - # Handle 'later' callbacks that are ready. + # Based heavily on `BaseEventLoop._run_once()` from CPython -- specifically, the + # part after blocking on `select()`. Handle 'later' callbacks that are ready. end_time = self.time() + self._clock_resolution while self._scheduled: handle = self._scheduled[0] @@ -196,12 +195,11 @@ def run_delayed_tasks(self): handle._scheduled = False self._ready.append(handle) - # This is the only place where callbacks are actually *called*. - # All other places just add them to ready. - # Note: We run all currently scheduled callbacks, but not any - # callbacks scheduled by callbacks run this time around -- - # they will be run the next time (after another I/O poll). - # Use an idiom that is thread-safe without using locks. + # This is the only place where callbacks are actually *called*. All other places + # just add them to ready. Note: We run all currently scheduled callbacks, but + # not any callbacks scheduled by callbacks run this time around -- they will be + # run the next time (after another I/O poll). Use an idiom that is thread-safe + # without using locks. ntodo = len(self._ready) for i in range(ntodo): handle = self._ready.popleft() @@ -296,10 +294,10 @@ def file_descriptor_event_listener(self): def message_queue(self): return Looper.getMainLooper().getQueue() - # File descriptors can be registered and unregistered by the event loop. - # The events for which we listen can be modified. For register & unregister, - # we mostly rely on the parent class. For modify(), the parent class calls - # unregister() and register(), so we rely on that as well. + # File descriptors can be registered and unregistered by the event loop. The events + # for which we listen can be modified. For register & unregister, we mostly rely on + # the parent class. For modify(), the parent class calls unregister() and + # register(), so we rely on that as well. def register(self, fileobj, events, data=None): if self._debug: # pragma: no cover @@ -336,12 +334,13 @@ def register_with_android(self, fileobj, events): if self._debug: # pragma: no cover print(f"register_with_android() fileobj={fileobj} events={events}") # `events` is a bitset comprised of `selectors.EVENT_READ` and - # `selectors.EVENT_WRITE`. - # Register this FD for read and/or write events from Android. + # `selectors.EVENT_WRITE`. Register this FD for read and/or write events from + # Android. self.message_queue.addOnFileDescriptorEventListener( _create_java_fd(fileobj), - events, # Passing `events` as-is because Android and Python use - # the same values for read & write events. + # Passing `events` as-is because Android and Python use the same values for + # read & write events. + events, self.file_descriptor_event_listener, ) @@ -373,13 +372,13 @@ def handle_fd_wakeup(self, fd, events): f"fd={fd} events={events} key={key}" ) - # This class declines to implement the `select()` method, purely as - # a safety mechanism. On Android, this would be an error -- it would result - # in the app freezing, triggering an App Not Responding pop-up from the - # platform, and the user killing the app. + # This class declines to implement the `select()` method, purely as a safety + # mechanism. On Android, this would be an error -- it would result in the app + # freezing, triggering an App Not Responding pop-up from the platform, and the user + # killing the app. # - # Instead, the AndroidEventLoop cooperates with the native Android event - # loop to be woken up to get work done as needed. + # Instead, the AndroidEventLoop cooperates with the native Android event loop to be + # woken up to get work done as needed. def select(self, *args, **kwargs): raise NotImplementedError("AndroidSelector refuses to select(); see comments.") @@ -387,8 +386,8 @@ def select(self, *args, **kwargs): class AndroidSelectorFileDescriptorEventsListener( dynamic_proxy(MessageQueue.OnFileDescriptorEventListener) ): - """Notify an `AndroidSelector` instance when file descriptors - become readable/writable.""" + """Notify an `AndroidSelector` instance when file descriptors become + readable/writable.""" def __init__(self, android_selector): super().__init__() @@ -399,12 +398,12 @@ def __init__(self, android_selector): def onFileDescriptorEvents(self, fd_obj, events): """Receive a Java FileDescriptor object and notify the Python event loop that - the FD - is ready for read and/or write. + the FD is ready for read and/or write. As an implementation detail, this relies on the fact that Android EVENT_INPUT and Python selectors.EVENT_READ have the same value (1) and Android EVENT_OUTPUT - and Python selectors.EVENT_WRITE have the same value (2).""" + and Python selectors.EVENT_WRITE have the same value (2). + """ # Call hidden (non-private) method to get the numeric FD, so we can pass that # to Python. fd = getattr(fd_obj, "getInt$")() @@ -424,10 +423,8 @@ def _create_java_fd(int_fd): """Given a numeric file descriptor, create a `java.io.FileDescriptor` object.""" # On Android, the class exposes hidden (non-private) methods `getInt$()` and # `setInt$()`. Because they aren't valid Python identifier names, we need to use - # `getattr()` to grab them. - # See e.g. https://android.googlesource.com - # /platform/prebuilts/fullsdk/sources/android-28/+/refs/heads/master - # /java/io/FileDescriptor.java#149 + # `getattr()` to grab them. See e.g. + # https://android.googlesource.com/platform/prebuilts/fullsdk/sources/android-28/+/refs/heads/master/java/io/FileDescriptor.java#149 # noqa: E501 java_fd = FileDescriptor() getattr(java_fd, "setInt$")(int_fd) return java_fd diff --git a/cocoa/src/toga_cocoa/widgets/numberinput.py b/cocoa/src/toga_cocoa/widgets/numberinput.py index d594ffdb95..9bbb6e73f7 100644 --- a/cocoa/src/toga_cocoa/widgets/numberinput.py +++ b/cocoa/src/toga_cocoa/widgets/numberinput.py @@ -100,7 +100,7 @@ def create(self): toItem=self.native_stepper, attribute__to=NSLayoutAttributeTop, multiplier=1.0, - _constant=0, + constant=0, ) ) self.native.addConstraint( @@ -111,7 +111,7 @@ def create(self): toItem=self.native_stepper, attribute__to=NSLayoutAttributeRight, multiplier=1.0, - _constant=0, + constant=0, ) ) @@ -124,7 +124,7 @@ def create(self): toItem=self.native_stepper, attribute__to=NSLayoutAttributeBottom, multiplier=1.0, - _constant=0, + constant=0, ) ) @@ -137,7 +137,7 @@ def create(self): toItem=self.native_input, attribute__to=NSLayoutAttributeCenterY, multiplier=1.0, - _constant=0, + constant=0, ) ) self.native.addConstraint( @@ -148,7 +148,7 @@ def create(self): toItem=self.native_input, attribute__to=NSLayoutAttributeLeft, multiplier=1.0, - _constant=0, + constant=0, ) ) @@ -161,7 +161,7 @@ def create(self): toItem=self.native_input, attribute__to=NSLayoutAttributeRight, multiplier=1.0, - _constant=2, + constant=2, ) ) diff --git a/cocoa/src/toga_cocoa/window.py b/cocoa/src/toga_cocoa/window.py index 854104630c..c4802db5b9 100644 --- a/cocoa/src/toga_cocoa/window.py +++ b/cocoa/src/toga_cocoa/window.py @@ -175,8 +175,8 @@ def __init__(self, interface, title, position, size): self.container = Container(on_refresh=self.content_refreshed) self.native.contentView = self.container.native - # Ensure that the container renders it's background in the - # same color as the window. + # Ensure that the container renders it's background in the same color as the + # window. self.native.wantsLayer = True self.container.native.backgroundColor = self.native.backgroundColor diff --git a/gtk/src/toga_gtk/widgets/activityindicator.py b/gtk/src/toga_gtk/widgets/activityindicator.py index 017770b062..523f7d2d0f 100644 --- a/gtk/src/toga_gtk/widgets/activityindicator.py +++ b/gtk/src/toga_gtk/widgets/activityindicator.py @@ -16,8 +16,12 @@ def stop(self): self.native.stop() def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), - # self.native.get_preferred_height()) + # print( + # "REHINT", + # self, + # self.native.get_preferred_width(), + # self.native.get_preferred_height(), + # ) width = self.native.get_preferred_width() height = self.native.get_preferred_height() diff --git a/iOS/src/toga_iOS/widgets/mapview.py b/iOS/src/toga_iOS/widgets/mapview.py index e16577d619..2dd8470240 100644 --- a/iOS/src/toga_iOS/widgets/mapview.py +++ b/iOS/src/toga_iOS/widgets/mapview.py @@ -132,7 +132,7 @@ def get_zoom(self): def set_zoom(self, zoom): if self.backlog is None: # The zoom level indicates how many degrees of longitude will be displayed - # in a 56 pixel horizontal range. Determine how many degrees of longitude + # in a 256 pixel horizontal range. Determine how many degrees of longitude # that is, and scale to the size of the visible horizontal space. # The horizontal axis can't show more than 360 degrees of longitude, so clip diff --git a/iOS/tests_backend/widgets/detailedlist.py b/iOS/tests_backend/widgets/detailedlist.py index e87feb27b8..79d554078d 100644 --- a/iOS/tests_backend/widgets/detailedlist.py +++ b/iOS/tests_backend/widgets/detailedlist.py @@ -30,14 +30,16 @@ def __init__(self, widget): def row_count(self): # Need to use the long form of this method because the first argument when used # as a selector is ambiguous with a property of the same name on the object. - return int(self.native.delegate.tableView(self.native, numberOfRowsInSection=0)) + return int( + self.native.delegate.tableView_numberOfRowsInSection_(self.native, 0) + ) def assert_cell_content(self, row, title, subtitle, icon=None): # Need to use the long form of this method because the first argument when used # as a selector is ambiguous with a property of the same name on the object. - cell = self.native.delegate.tableView( + cell = self.native.delegate.tableView_cellForRowAtIndexPath_( self.native, - cellForRowAtIndexPath=NSIndexPath.indexPathForRow(row, inSection=0), + NSIndexPath.indexPathForRow(row, inSection=0), ) assert str(cell.textLabel.text) == title assert str(cell.detailTextLabel.text) == subtitle @@ -138,9 +140,11 @@ async def perform_primary_action(self, row, active=True): path = NSIndexPath.indexPathForRow(row, inSection=0) # Need to use the long form of this method because the first argument when used # as a selector is ambiguous with a property of the same name on the object. - config = self.native.delegate.tableView( + config = ( + self.native.delegate + ).tableView_trailingSwipeActionsConfigurationForRowAtIndexPath_( self.native, - trailingSwipeActionsConfigurationForRowAtIndexPath=path, + path, ) if active: @@ -158,9 +162,11 @@ async def perform_secondary_action(self, row, active=True): path = NSIndexPath.indexPathForRow(row, inSection=0) # Need to use the long form of this method because the first argument when used # as a selector is ambiguous with a property of the same name on the object. - config = self.native.delegate.tableView( + config = ( + self.native.delegate + ).tableView_leadingSwipeActionsConfigurationForRowAtIndexPath_( self.native, - leadingSwipeActionsConfigurationForRowAtIndexPath=path, + path, ) if active: From 64bf45281c9b7526960026d98d83e50b87030313 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Wed, 27 Nov 2024 15:39:33 +0800 Subject: [PATCH 08/10] One more pass of cleanups. --- changes/2975.misc.rst | 2 +- cocoa/src/toga_cocoa/constraints.py | 12 ++++++---- cocoa/src/toga_cocoa/hardware/camera.py | 4 ++-- .../toga_cocoa/widgets/internal/refresh.py | 3 +-- cocoa/src/toga_cocoa/widgets/tree.py | 10 +++++---- core/src/toga/documents.py | 6 +++-- core/src/toga/platform.py | 22 +++++++++++-------- core/src/toga/style/pack.py | 10 +++++---- core/tests/widgets/test_scrollcontainer.py | 6 +++-- gtk/src/toga_gtk/container.py | 11 +++++++--- gtk/src/toga_gtk/widgets/base.py | 8 +++++-- gtk/src/toga_gtk/widgets/button.py | 8 +++++-- gtk/src/toga_gtk/widgets/canvas.py | 8 +++++-- gtk/src/toga_gtk/widgets/label.py | 11 ++++++---- gtk/src/toga_gtk/widgets/progressbar.py | 8 +++++-- gtk/src/toga_gtk/widgets/slider.py | 8 +++++-- gtk/src/toga_gtk/widgets/switch.py | 8 +++++-- gtk/src/toga_gtk/widgets/textinput.py | 11 ++++++---- gtk/tests_backend/window.py | 5 +++-- iOS/src/toga_iOS/constraints.py | 12 ++++++---- iOS/src/toga_iOS/widgets/label.py | 6 +++-- testbed/tests/test_images.py | 4 ++-- 22 files changed, 120 insertions(+), 63 deletions(-) diff --git a/changes/2975.misc.rst b/changes/2975.misc.rst index 93c0e0aa58..187957bbe0 100644 --- a/changes/2975.misc.rst +++ b/changes/2975.misc.rst @@ -1 +1 @@ -Update the flake8 line limit to 88 to match limit for Black, and shorten longer lines. +The flake8 line limit was adjusted to 88 to match limit for Black. diff --git a/cocoa/src/toga_cocoa/constraints.py b/cocoa/src/toga_cocoa/constraints.py index 52cbaea791..790cd5d38a 100644 --- a/cocoa/src/toga_cocoa/constraints.py +++ b/cocoa/src/toga_cocoa/constraints.py @@ -61,8 +61,10 @@ def container(self, value): self._remove_constraints() self._container = value if value is not None: - # print(f"Add constraints for {self.widget} in {self.container} - # {self.widget.interface.layout}") + # print( + # f"Add constraints for {self.widget} in {self.container} " + # f"{self.widget.interface.layout}" + # ) self.left_constraint = NSLayoutConstraint.constraintWithItem( self.widget.native, attribute__1=NSLayoutAttributeLeft, @@ -108,8 +110,10 @@ def container(self, value): self.container.native.addConstraint(self.height_constraint) def update(self, x, y, width, height): - # print(f"UPDATE CONSTRAINTS {self.widget} in {self.container} - # {width}x{height}@{x},{y}") + # print( + # f"UPDATE CONSTRAINTS {self.widget} in {self.container} " + # f"{width}x{height}@{x},{y}" + # ) self.left_constraint.constant = x self.top_constraint.constant = y diff --git a/cocoa/src/toga_cocoa/hardware/camera.py b/cocoa/src/toga_cocoa/hardware/camera.py index 2fae6d5c6a..38b608730f 100644 --- a/cocoa/src/toga_cocoa/hardware/camera.py +++ b/cocoa/src/toga_cocoa/hardware/camera.py @@ -88,8 +88,8 @@ def create_preview_window(self): style=Pack(width=200), ) - # The shutter button. Initially disabled until we know we - # have a camera available + # The shutter button. Initially disabled until we know we have a camera + # available self.shutter_button = toga.Button( icon=toga.Icon("camera", system=True), on_press=self.take_photo, diff --git a/cocoa/src/toga_cocoa/widgets/internal/refresh.py b/cocoa/src/toga_cocoa/widgets/internal/refresh.py index 83f74e0b22..4bd5777079 100644 --- a/cocoa/src/toga_cocoa/widgets/internal/refresh.py +++ b/cocoa/src/toga_cocoa/widgets/internal/refresh.py @@ -32,8 +32,7 @@ ######################################################################################## # This is broadly derived from Alex Zielenski's ScrollToRefresh implementation: -# https://github.com/ -# alexzielenski/ScrollToRefresh/blob/master/ScrollToRefresh/src/EQSTRScrollView.m +# https://github.com/alexzielenski/ScrollToRefresh/blob/master/ScrollToRefresh/src/EQSTRScrollView.m # noqa: E501 # ====================================================================================== # ScrollToRefresh # diff --git a/cocoa/src/toga_cocoa/widgets/tree.py b/cocoa/src/toga_cocoa/widgets/tree.py index f546603833..834096bab2 100644 --- a/cocoa/src/toga_cocoa/widgets/tree.py +++ b/cocoa/src/toga_cocoa/widgets/tree.py @@ -95,8 +95,9 @@ def outlineView_viewForTableColumn_item_(self, tree, column, item): tcv = self.makeViewWithIdentifier(identifier, owner=self) if not tcv: # there is no existing view to reuse so create a new one - # tcv = TogaIconView.alloc().initWithFrame(CGRectMake( - # 0, 0, column.width, 16)) + # tcv = TogaIconView.alloc().initWithFrame( + # CGRectMake(0, 0, column.width, 16) + # ) tcv = TogaIconView.alloc().init() tcv.identifier = identifier @@ -146,8 +147,9 @@ def outlineView_pasteboardWriterForItem_( return None # @objc_method - # def outlineView_sortDescriptorsDidChange_(self, - # tableView, oldDescriptors) -> None: + # def outlineView_sortDescriptorsDidChange_( + # self, tableView, oldDescriptors + # ) -> None: # # for descriptor in self.sortDescriptors[::-1]: # accessor = descriptor.key diff --git a/core/src/toga/documents.py b/core/src/toga/documents.py index 8fb2882ca7..701c4e142c 100644 --- a/core/src/toga/documents.py +++ b/core/src/toga/documents.py @@ -428,8 +428,10 @@ async def _confirm_close(self, window, **kwargs): if await self.dialog( toga.QuestionDialog( "Save changes?", - "This document has unsaved changes. " - "Do you want to save these changes?", + ( + "This document has unsaved changes. " + "Do you want to save these changes?" + ), ) ): return await self.save() diff --git a/core/src/toga/platform.py b/core/src/toga/platform.py index 708fe50865..038a3b356d 100644 --- a/core/src/toga/platform.py +++ b/core/src/toga/platform.py @@ -73,10 +73,12 @@ def get_platform_factory() -> ModuleType: # (https://github.com/chaquo/chaquopy/issues/890), so include the original # exception message in case the backend does exist but throws a # ModuleNotFoundError from one of its internal imports. - raise RuntimeError( + msg = ( f"The backend specified by TOGA_BACKEND ({backend_value!r}) could " f"not be loaded ({e}). It should be one of: {toga_backends_values}." ) + raise RuntimeError(msg) + else: toga_backends = find_backends() if len(toga_backends) == 0: @@ -93,13 +95,14 @@ def get_platform_factory() -> ModuleType: toga_backends_string = ", ".join( [f"{backend.value!r} ({backend.name})" for backend in toga_backends] ) - raise RuntimeError( + msg = ( f"Multiple Toga backends are installed ({toga_backends_string}), " - "but none of them match your current platform " + f"but none of them match your current platform " f"({current_platform!r}). " - "Install a backend for your current platform, or use " - "TOGA_BACKEND to specify a backend." + f"Install a backend for your current platform, or use " + f"TOGA_BACKEND to specify a backend." ) + raise RuntimeError(msg) if len(matching_backends) > 1: toga_backends_string = ", ".join( [ @@ -107,12 +110,13 @@ def get_platform_factory() -> ModuleType: for backend in matching_backends ] ) - raise RuntimeError( - "Multiple candidate toga backends found: " + msg = ( + f"Multiple candidate toga backends found: " f"({toga_backends_string}). " - "Uninstall the backends you don't require, or use " - "TOGA_BACKEND to specify a backend." + f"Uninstall the backends you don't require, or use " + f"TOGA_BACKEND to specify a backend." ) + raise RuntimeError(msg) backend = matching_backends[0] factory = importlib.import_module(f"{backend.value}.factory") return factory diff --git a/core/src/toga/style/pack.py b/core/src/toga/style/pack.py index a51c2d26a8..57db86b12a 100644 --- a/core/src/toga/style/pack.py +++ b/core/src/toga/style/pack.py @@ -143,8 +143,9 @@ def apply(self, prop: str, value: object) -> None: def layout(self, node: Node, viewport: Any) -> None: # self._debug("=" * 80) - # self._debug(f"Layout root {node}, - # available {viewport.width}x{viewport.height}") + # self._debug( + # f"Layout root {node}, available {viewport.width}x{viewport.height}" + # ) self.__class__._depth = -1 self._layout_node( @@ -591,8 +592,9 @@ def _layout_column_children( elif child.intrinsic.height is not None: if hasattr(child.intrinsic.height, "value"): if child.style.flex: - # self._debug(f"- intrinsic flex height " - # f"{child.intrinsic.height}") + # self._debug( + # f"- intrinsic flex height {child.intrinsic.height}" + # ) flex_total += child.style.flex # Final child content size will be computed in pass 2, after the # amount of flexible space is known. For now, set an initial diff --git a/core/tests/widgets/test_scrollcontainer.py b/core/tests/widgets/test_scrollcontainer.py index b0b6e6d8ad..32caa1054c 100644 --- a/core/tests/widgets/test_scrollcontainer.py +++ b/core/tests/widgets/test_scrollcontainer.py @@ -321,8 +321,10 @@ def test_horizontal_position_when_not_horizontal(scroll_container): scroll_container.horizontal = False with pytest.raises( ValueError, - match=r"Cannot set horizontal position " - r"when horizontal scrolling is not enabled.", + match=( + r"Cannot set horizontal position " + r"when horizontal scrolling is not enabled." + ), ): scroll_container.horizontal_position = 37 diff --git a/gtk/src/toga_gtk/container.py b/gtk/src/toga_gtk/container.py index de68ab6092..37ab26dbda 100644 --- a/gtk/src/toga_gtk/container.py +++ b/gtk/src/toga_gtk/container.py @@ -156,8 +156,11 @@ def do_size_allocate(self, allocation): computed based on this new available size, and that new geometry will be applied to all child widgets of the container. """ - # print(self._content, f"Container layout " - # "{allocation.width}x{allocation.height} @ {allocation.x}x{allocation.y}") + # print( + # self._content, + # f"Container layout {allocation.width}x{allocation.height} " + # f"@ {allocation.x}x{allocation.y}", + # ) # The container will occupy the full space it has been allocated. resized = (allocation.width, allocation.height) != (self.width, self.height) @@ -183,7 +186,9 @@ def do_size_allocate(self, allocation): if widget.get_visible(): # Set the size of the child widget to the computed layout size. # print( - # f" allocate child {widget.interface}: {widget.interface.layout}") + # f" allocate child {widget.interface}: " + # f"{widget.interface.layout}" + # ) widget_allocation = Gdk.Rectangle() widget_allocation.x = ( widget.interface.layout.absolute_content_left + allocation.x diff --git a/gtk/src/toga_gtk/widgets/base.py b/gtk/src/toga_gtk/widgets/base.py index 03509c1175..c1868f1aa2 100644 --- a/gtk/src/toga_gtk/widgets/base.py +++ b/gtk/src/toga_gtk/widgets/base.py @@ -185,8 +185,12 @@ def refresh(self): def rehint(self): # Perform the actual GTK rehint. - # print("REHINT", self, self.native.get_preferred_width(), - # self.native.get_preferred_height()) + # print( + # "REHINT", + # self, + # self.native.get_preferred_width(), + # self.native.get_preferred_height(), + # ) width = self.native.get_preferred_width() height = self.native.get_preferred_height() diff --git a/gtk/src/toga_gtk/widgets/button.py b/gtk/src/toga_gtk/widgets/button.py index 53118e5a7d..48f9b323ed 100644 --- a/gtk/src/toga_gtk/widgets/button.py +++ b/gtk/src/toga_gtk/widgets/button.py @@ -41,8 +41,12 @@ def set_background_color(self, color): super().set_background_color(color) def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), - # self.native.get_preferred_height()) + # print( + # "REHINT", + # self, + # self.native.get_preferred_width(), + # self.native.get_preferred_height(), + # ) width = self.native.get_preferred_width() height = self.native.get_preferred_height() diff --git a/gtk/src/toga_gtk/widgets/canvas.py b/gtk/src/toga_gtk/widgets/canvas.py index 275f813995..fe05c28e13 100644 --- a/gtk/src/toga_gtk/widgets/canvas.py +++ b/gtk/src/toga_gtk/widgets/canvas.py @@ -299,8 +299,12 @@ def get_image_data(self): # Rehint def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), - # self.native.get_preferred_height()) + # print( + # "REHINT", + # self, + # self.native.get_preferred_width(), + # self.native.get_preferred_height(), + # ) # width = self.native.get_allocation().width # height = self.native.get_allocation().height width = self.interface._MIN_WIDTH diff --git a/gtk/src/toga_gtk/widgets/label.py b/gtk/src/toga_gtk/widgets/label.py index 30e46b04f6..c79a28856f 100644 --- a/gtk/src/toga_gtk/widgets/label.py +++ b/gtk/src/toga_gtk/widgets/label.py @@ -24,10 +24,13 @@ def set_text(self, value): self.native.set_text(value) def rehint(self): - # print("REHINT", self, - # self.native.get_preferred_width(), self.native.get_preferred_height(), - # getattr(self, '_fixed_height', False), getattr(self, - # '_fixed_width', False) + # print( + # "REHINT", + # self, + # self.native.get_preferred_width(), + # self.native.get_preferred_height(), + # getattr(self, "_fixed_height", False), + # getattr(self, "_fixed_width", False), # ) width = self.native.get_preferred_width() height = self.native.get_preferred_height() diff --git a/gtk/src/toga_gtk/widgets/progressbar.py b/gtk/src/toga_gtk/widgets/progressbar.py index e3a8a405d6..a44fa71db2 100644 --- a/gtk/src/toga_gtk/widgets/progressbar.py +++ b/gtk/src/toga_gtk/widgets/progressbar.py @@ -91,8 +91,12 @@ def stop(self): self._stop_indeterminate() def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), - # self.native.get_preferred_height()) + # print( + # "REHINT", + # self, + # self.native.get_preferred_width(), + # self.native.get_preferred_height(), + # ) width = self.native.get_preferred_width() height = self.native.get_preferred_height() diff --git a/gtk/src/toga_gtk/widgets/slider.py b/gtk/src/toga_gtk/widgets/slider.py index 5f5832e1ef..33e78b5037 100644 --- a/gtk/src/toga_gtk/widgets/slider.py +++ b/gtk/src/toga_gtk/widgets/slider.py @@ -82,8 +82,12 @@ def get_tick_count(self): return self.tick_count def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), - # self.native.get_preferred_height()) + # print( + # "REHINT", + # self, + # self.native.get_preferred_width(), + # self.native.get_preferred_height(), + # ) height = self.native.get_preferred_height() # Set intrinsic width to at least the minimum width diff --git a/gtk/src/toga_gtk/widgets/switch.py b/gtk/src/toga_gtk/widgets/switch.py index b891c07d4a..6518f4ae1d 100644 --- a/gtk/src/toga_gtk/widgets/switch.py +++ b/gtk/src/toga_gtk/widgets/switch.py @@ -52,8 +52,12 @@ def set_font(self, font): self.apply_css("font", get_font_css(font), native=self.native_label) def rehint(self): - # print("REHINT", self, self.native.get_preferred_width(), - # self.native.get_preferred_height()) + # print( + # "REHINT", + # self, + # self.native.get_preferred_width(), + # self.native.get_preferred_height(), + # ) label_width = self.native_label.get_preferred_width() label_height = self.native_label.get_preferred_height() diff --git a/gtk/src/toga_gtk/widgets/textinput.py b/gtk/src/toga_gtk/widgets/textinput.py index f2c04bbc2e..75d9067b1d 100644 --- a/gtk/src/toga_gtk/widgets/textinput.py +++ b/gtk/src/toga_gtk/widgets/textinput.py @@ -54,10 +54,13 @@ def set_value(self, value): self.native.set_text(value) def rehint(self): - # print("REHINT", self, - # self._impl.get_preferred_width(), self._impl.get_preferred_height(), - # getattr(self, '_fixed_height', False), - # getattr(self, '_fixed_width', False) + # print( + # "REHINT", + # self, + # self._impl.get_preferred_width(), + # self._impl.get_preferred_height(), + # getattr(self, "_fixed_height", False), + # getattr(self, "_fixed_width", False), # ) width = self.native.get_preferred_width() height = self.native.get_preferred_height() diff --git a/gtk/tests_backend/window.py b/gtk/tests_backend/window.py index eb569030ab..4118058388 100644 --- a/gtk/tests_backend/window.py +++ b/gtk/tests_backend/window.py @@ -73,8 +73,9 @@ def assert_toolbar_item(self, index, label, tooltip, has_icon, enabled): # FIXME: get_tooltip_text() doesn't work. The tooltip can be set, but the # API to return the value just doesn't work. If it is ever fixed, this # is the test for it: - # assert (None if item.get_tooltip_text() is None - # else item.get_tooltip_text()) == tooltip + # assert ( + # None if item.get_tooltip_text() is None else item.get_tooltip_text() + # ) == tooltip assert (item.get_icon_widget() is not None) == has_icon assert item.get_sensitive() == enabled diff --git a/iOS/src/toga_iOS/constraints.py b/iOS/src/toga_iOS/constraints.py index 80c494c4c9..98cb2df838 100644 --- a/iOS/src/toga_iOS/constraints.py +++ b/iOS/src/toga_iOS/constraints.py @@ -56,8 +56,10 @@ def container(self, value): self._remove_constraints() self._container = value if value is not None: - # print(f"Add constraints for {self.widget} in {self.container} - # {self.widget.interface.layout}") + # print( + # f"Add constraints for {self.widget} in {self.container}" + # f"{self.widget.interface.layout}" + # ) self.left_constraint = NSLayoutConstraint.constraintWithItem( self.widget.native, attribute__1=NSLayoutAttributeLeft, @@ -103,8 +105,10 @@ def container(self, value): self.container.native.addConstraint(self.height_constraint) def update(self, x, y, width, height): - # print(f"UPDATE CONSTRAINTS {self.widget} in {self.container} - # {width}x{height}@{x},{y}") + # print( + # f"UPDATE CONSTRAINTS {self.widget} in {self.container} " + # f"{width}x{height}@{x},{y}" + # ) self.left_constraint.constant = x self.top_constraint.constant = y diff --git a/iOS/src/toga_iOS/widgets/label.py b/iOS/src/toga_iOS/widgets/label.py index 7eb18b5096..0426fc3cc8 100644 --- a/iOS/src/toga_iOS/widgets/label.py +++ b/iOS/src/toga_iOS/widgets/label.py @@ -77,7 +77,9 @@ def rehint(self): limitedToNumberOfLines=len(self.interface.text.split("\n")), ).size - # print(f"REHINT label {self} {self.get_text()!r} - # {fitting_size.width} {fitting_size.height}") + # print( + # f"REHINT label {self} {self.get_text()!r} " + # f"{fitting_size.width} {fitting_size.height}" + # ) self.interface.intrinsic.width = at_least(ceil(fitting_size.width)) self.interface.intrinsic.height = ceil(fitting_size.height) diff --git a/testbed/tests/test_images.py b/testbed/tests/test_images.py index 3a70268987..91bc16b8a4 100644 --- a/testbed/tests/test_images.py +++ b/testbed/tests/test_images.py @@ -59,8 +59,8 @@ async def test_buffer_image(app): async def test_pil_raw_and_data_image(app): - "An image can be created from PIL," - "platform's raw representation and `toga.Image` data" + """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) From 412059f9acc48adfd9e00628fe1c8dee5ff509dd Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Thu, 28 Nov 2024 06:13:44 +0800 Subject: [PATCH 09/10] More fixes from code review. --- android/src/toga_android/libs/events.py | 4 ++-- cocoa/src/toga_cocoa/hardware/camera.py | 3 +-- core/tests/style/pack/test_css.py | 3 ++- core/tests/test_paths.py | 8 ++++---- examples/statusiconapp/statusiconapp/app.py | 5 ++--- gtk/src/toga_gtk/widgets/mapview.py | 7 +++---- gtk/src/toga_gtk/widgets/webview.py | 7 +++---- testbed/tests/app/test_document_app.py | 3 +-- winforms/src/toga_winforms/widgets/mapview.py | 3 +-- winforms/src/toga_winforms/widgets/webview.py | 3 +-- 10 files changed, 20 insertions(+), 26 deletions(-) diff --git a/android/src/toga_android/libs/events.py b/android/src/toga_android/libs/events.py index f191d65c19..8a97ca4364 100644 --- a/android/src/toga_android/libs/events.py +++ b/android/src/toga_android/libs/events.py @@ -361,14 +361,14 @@ def handle_fd_wakeup(self, fd, events): if key_event_pairs: if self._debug: # pragma: no cover print( - "handle_fd_wakeup() calling parent for " + f"handle_fd_wakeup() calling parent for " f"key_event_pairs={key_event_pairs}" ) # Call superclass private method to notify. self.loop._process_events(key_event_pairs) else: # pragma: no cover print( - "Warning: handle_fd_wakeup(): unnecessary wakeup " + f"Warning: handle_fd_wakeup(): unnecessary wakeup " f"fd={fd} events={events} key={key}" ) diff --git a/cocoa/src/toga_cocoa/hardware/camera.py b/cocoa/src/toga_cocoa/hardware/camera.py index 38b608730f..9be10da170 100644 --- a/cocoa/src/toga_cocoa/hardware/camera.py +++ b/cocoa/src/toga_cocoa/hardware/camera.py @@ -262,8 +262,7 @@ def __init__(self, interface): msg = ( "Application metadata does not declare that the app will use " "the camera. See " - "https://toga.readthedocs.io" - "/en/stable/reference/api/hardware/camera.html" + "https://toga.readthedocs.io/en/stable/reference/api/hardware/camera.html" # noqa: E501 ) if self.interface.app.is_bundled: raise RuntimeError(msg) diff --git a/core/tests/style/pack/test_css.py b/core/tests/style/pack/test_css.py index b0cff044d4..3efaab5a64 100644 --- a/core/tests/style/pack/test_css.py +++ b/core/tests/style/pack/test_css.py @@ -365,7 +365,8 @@ Pack(background_color=REBECCAPURPLE), ( "flex-direction: row; flex: " - "0.0 0 auto; background-color: rgb(102, 51, 153);" + "0.0 0 auto; " + "background-color: rgb(102, 51, 153);" ), id="background-color", ), diff --git a/core/tests/test_paths.py b/core/tests/test_paths.py index 3dfe9e7372..d4b16e7602 100644 --- a/core/tests/test_paths.py +++ b/core/tests/test_paths.py @@ -39,19 +39,19 @@ def assert_paths(output, app_path, app_name): results = output.splitlines() assert f"app.paths.app={app_path.resolve()}" in results assert ( - "app.paths.config=" + f"app.paths.config=" f"{(Path.home() / 'config' / f'org.testbed.{app_name}').resolve()}" ) in results assert ( - "app.paths.data=" + f"app.paths.data=" f"{(Path.home() / 'user_data' / f'org.testbed.{app_name}').resolve()}" ) in results assert ( - "app.paths.cache=" + f"app.paths.cache=" f"{(Path.home() / 'cache' / f'org.testbed.{app_name}').resolve()}" ) in results assert ( - "app.paths.logs=" + f"app.paths.logs=" f"{(Path.home() / 'logs' / f'org.testbed.{app_name}').resolve()}" ) in results assert f"app.paths.toga={Path(toga.__file__).parent.resolve()}" in results diff --git a/examples/statusiconapp/statusiconapp/app.py b/examples/statusiconapp/statusiconapp/app.py index 64e93db912..50de49115a 100644 --- a/examples/statusiconapp/statusiconapp/app.py +++ b/examples/statusiconapp/statusiconapp/app.py @@ -51,9 +51,8 @@ def startup(self): group=sub_menu, ) - # Two commands for the second status icon. The status - # icon can be retrieved by ID, - # and by index. + # Two commands for the second status icon. The status icon can be retrieved by + # ID, and by index. cmd5 = toga.Command( self.do_stuff, text="Action 5", diff --git a/gtk/src/toga_gtk/widgets/mapview.py b/gtk/src/toga_gtk/widgets/mapview.py index ab480859f8..9b77c18076 100644 --- a/gtk/src/toga_gtk/widgets/mapview.py +++ b/gtk/src/toga_gtk/widgets/mapview.py @@ -70,10 +70,9 @@ class MapView(Widget): def create(self): if WebKit2 is None: # pragma: no cover raise RuntimeError( - "Unable to import WebKit2. Ensure that the system package " - "providing WebKit2 and its GTK bindings have been installed. " - "See https://toga.readthedocs.io" - "/en/stable/reference/api/widgets/mapview.html#system-requirements " + "Unable to import WebKit2. Ensure that the system package providing " + "WebKit2 and its GTK bindings have been installed. See " + "https://toga.readthedocs.io/en/stable/reference/api/widgets/mapview.html#system-requirements " # noqa: E501 "for details." ) diff --git a/gtk/src/toga_gtk/widgets/webview.py b/gtk/src/toga_gtk/widgets/webview.py index 5a90dabcf2..2e01b8a57b 100644 --- a/gtk/src/toga_gtk/widgets/webview.py +++ b/gtk/src/toga_gtk/widgets/webview.py @@ -12,10 +12,9 @@ class WebView(Widget): def create(self): if WebKit2 is None: # pragma: no cover raise RuntimeError( - "Unable to import WebKit2. Ensure that the system package " - "providing WebKit2 and its GTK bindings have been installed. " - "See https://toga.readthedocs.io" - "/en/stable/reference/api/widgets/webview.html#system-requirements " + "Unable to import WebKit2. Ensure that the system package providing " + "WebKit2 and its GTK bindings have been installed. See " + "https://toga.readthedocs.io/en/stable/reference/api/widgets/mapview.html#system-requirements " # noqa: E501 "for details." ) diff --git a/testbed/tests/app/test_document_app.py b/testbed/tests/app/test_document_app.py index cac8a5ca0e..7992c1748b 100644 --- a/testbed/tests/app/test_document_app.py +++ b/testbed/tests/app/test_document_app.py @@ -90,8 +90,7 @@ async def test_open_initial_document(monkeypatch, app, app_probe): async def test_open_document_by_drag(app, app_probe): - """A file can be If an attempt is made to open a file by dragging, - an error is raised.""" + """A file can be opened by dragging.""" document_path = Path(__file__).parent / "docs/example.testbed" app_probe.open_document_by_drag(document_path) diff --git a/winforms/src/toga_winforms/widgets/mapview.py b/winforms/src/toga_winforms/widgets/mapview.py index f438e26413..a770c858fe 100644 --- a/winforms/src/toga_winforms/widgets/mapview.py +++ b/winforms/src/toga_winforms/widgets/mapview.py @@ -141,8 +141,7 @@ def winforms_initialization_completed(self, sender, args): WinForms.MessageBoxIcon.Error, ) webbrowser.open( - "https://developer.microsoft.com" - "/en-us/microsoft-edge/webview2/#download" + "https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download" # noqa: E501 ) else: # pragma: nocover diff --git a/winforms/src/toga_winforms/widgets/webview.py b/winforms/src/toga_winforms/widgets/webview.py index a9b00e8705..d84b6b52aa 100644 --- a/winforms/src/toga_winforms/widgets/webview.py +++ b/winforms/src/toga_winforms/widgets/webview.py @@ -110,8 +110,7 @@ def winforms_initialization_completed(self, sender, args): WinForms.MessageBoxIcon.Error, ) webbrowser.open( - "https://developer.microsoft.com" - "/en-us/microsoft-edge/webview2/#download" + "https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download" # noqa: E501 ) else: # pragma: nocover From ec36d8c8f8d18929b9de057e4e0d7b1e27621c58 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Fri, 29 Nov 2024 05:58:20 +0800 Subject: [PATCH 10/10] One last set of updates. --- core/src/toga/platform.py | 9 +++------ core/tests/style/pack/test_css.py | 3 +-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/core/src/toga/platform.py b/core/src/toga/platform.py index 038a3b356d..ba4a686408 100644 --- a/core/src/toga/platform.py +++ b/core/src/toga/platform.py @@ -73,11 +73,10 @@ def get_platform_factory() -> ModuleType: # (https://github.com/chaquo/chaquopy/issues/890), so include the original # exception message in case the backend does exist but throws a # ModuleNotFoundError from one of its internal imports. - msg = ( + raise RuntimeError( f"The backend specified by TOGA_BACKEND ({backend_value!r}) could " f"not be loaded ({e}). It should be one of: {toga_backends_values}." ) - raise RuntimeError(msg) else: toga_backends = find_backends() @@ -95,14 +94,13 @@ def get_platform_factory() -> ModuleType: toga_backends_string = ", ".join( [f"{backend.value!r} ({backend.name})" for backend in toga_backends] ) - msg = ( + raise RuntimeError( f"Multiple Toga backends are installed ({toga_backends_string}), " f"but none of them match your current platform " f"({current_platform!r}). " f"Install a backend for your current platform, or use " f"TOGA_BACKEND to specify a backend." ) - raise RuntimeError(msg) if len(matching_backends) > 1: toga_backends_string = ", ".join( [ @@ -110,13 +108,12 @@ def get_platform_factory() -> ModuleType: for backend in matching_backends ] ) - msg = ( + raise RuntimeError( f"Multiple candidate toga backends found: " f"({toga_backends_string}). " f"Uninstall the backends you don't require, or use " f"TOGA_BACKEND to specify a backend." ) - raise RuntimeError(msg) backend = matching_backends[0] factory = importlib.import_module(f"{backend.value}.factory") return factory diff --git a/core/tests/style/pack/test_css.py b/core/tests/style/pack/test_css.py index 3efaab5a64..5630ab1b50 100644 --- a/core/tests/style/pack/test_css.py +++ b/core/tests/style/pack/test_css.py @@ -364,8 +364,7 @@ pytest.param( Pack(background_color=REBECCAPURPLE), ( - "flex-direction: row; flex: " - "0.0 0 auto; " + "flex-direction: row; flex: 0.0 0 auto; " "background-color: rgb(102, 51, 153);" ), id="background-color",