Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement lazy loading in toga_core #2686

Merged
merged 12 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions android/src/toga_android/widgets/slider.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from android.widget import SeekBar
from java import dynamic_proxy

import toga
from toga.widgets.slider import IntSliderImpl

from .base import Widget

Expand All @@ -31,7 +31,7 @@ def onStopTrackingTouch(self, native_seekbar):
self.impl.interface.on_release()


class Slider(Widget, toga.widgets.slider.IntSliderImpl):
class Slider(Widget, IntSliderImpl):
focusable = False
TICK_DRAWABLE = None

Expand Down
1 change: 1 addition & 0 deletions changes/2547.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Imports from the ``toga`` core namespace has been modified to use lazy importing.
4 changes: 2 additions & 2 deletions cocoa/src/toga_cocoa/widgets/slider.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from travertino.size import at_least

import toga
from toga.widgets.slider import SliderImpl
from toga_cocoa.libs import (
SEL,
NSEventType,
Expand All @@ -27,7 +27,7 @@ def onSlide_(self, sender) -> None:
self.interface.on_change()


class Slider(Widget, toga.widgets.slider.SliderImpl):
class Slider(Widget, SliderImpl):
def create(self):
self.native = TogaSlider.alloc().init()
self.native.interface = self.interface
Expand Down
202 changes: 77 additions & 125 deletions core/src/toga/__init__.py
Original file line number Diff line number Diff line change
@@ -1,139 +1,94 @@
from __future__ import annotations

import importlib
import importlib.util
import warnings
from pathlib import Path

from .app import App, DocumentApp
from .colors import hsl, hsla, rgb, rgba
from .command import Command, Group
from .dialogs import (
ConfirmDialog,
ErrorDialog,
InfoDialog,
OpenFileDialog,
QuestionDialog,
SaveFileDialog,
SelectFolderDialog,
StackTraceDialog,
)
from .documents import Document
from .fonts import Font
from .icons import Icon
from .images import Image
from .keys import Key
from .types import LatLng, Position, Size
from .widgets.activityindicator import ActivityIndicator
from .widgets.base import Widget
from .widgets.box import Box
from .widgets.button import Button
from .widgets.canvas import Canvas
from .widgets.dateinput import DateInput, DatePicker
from .widgets.detailedlist import DetailedList
from .widgets.divider import Divider
from .widgets.imageview import ImageView
from .widgets.label import Label
from .widgets.mapview import MapPin, MapView
from .widgets.multilinetextinput import MultilineTextInput
from .widgets.numberinput import NumberInput
from .widgets.optioncontainer import OptionContainer, OptionItem
from .widgets.passwordinput import PasswordInput
from .widgets.progressbar import ProgressBar
from .widgets.scrollcontainer import ScrollContainer
from .widgets.selection import Selection
from .widgets.slider import Slider
from .widgets.splitcontainer import SplitContainer
from .widgets.switch import Switch
from .widgets.table import Table
from .widgets.textinput import TextInput
from .widgets.timeinput import TimeInput, TimePicker
from .widgets.tree import Tree
from .widgets.webview import WebView
from .window import DocumentMainWindow, MainWindow, Window
toga_core_imports = {
KRRT7 marked this conversation as resolved.
Show resolved Hide resolved
"ActivityIndicator": "toga.widgets.activityindicator",
"App": "toga.app",
"DocumentApp": "toga.app",
"DocumentMainWindow": "toga.window",
"MainWindow": "toga.window",
"Widget": "toga.widgets.base",
"Box": "toga.widgets.box",
"Button": "toga.widgets.button",
"Canvas": "toga.widgets.canvas",
"hsl": "toga.colors",
"hsla": "toga.colors",
"rgb": "toga.colors",
"rgba": "toga.colors",
"Command": "toga.command",
"Group": "toga.command",
"DateInput": "toga.widgets.dateinput",
"DatePicker": "toga.widgets.dateinput",
"DetailedList": "toga.widgets.detailedlist",
"ConfirmDialog": "toga.dialogs",
"ErrorDialog": "toga.dialogs",
"InfoDialog": "toga.dialogs",
"OpenFileDialog": "toga.dialogs",
"QuestionDialog": "toga.dialogs",
"SaveFileDialog": "toga.dialogs",
"SelectFolderDialog": "toga.dialogs",
"StackTraceDialog": "toga.dialogs",
"Divider": "toga.widgets.divider",
"Document": "toga.documents",
"Font": "toga.fonts",
"Icon": "toga.icons",
"Image": "toga.images",
"ImageView": "toga.widgets.imageview",
"Key": "toga.keys",
"Label": "toga.widgets.label",
"MapPin": "toga.widgets.mapview",
"MapView": "toga.widgets.mapview",
"MultilineTextInput": "toga.widgets.multilinetextinput",
"NumberInput": "toga.widgets.numberinput",
"OptionContainer": "toga.widgets.optioncontainer",
"OptionItem": "toga.widgets.optioncontainer",
"PasswordInput": "toga.widgets.passwordinput",
"ProgressBar": "toga.widgets.progressbar",
"ScrollContainer": "toga.widgets.scrollcontainer",
"Selection": "toga.widgets.selection",
"Slider": "toga.widgets.slider",
"SplitContainer": "toga.widgets.splitcontainer",
"Switch": "toga.widgets.switch",
"Table": "toga.widgets.table",
"TextInput": "toga.widgets.textinput",
"TimeInput": "toga.widgets.timeinput",
"TimePicker": "toga.widgets.timeinput",
"Tree": "toga.widgets.tree",
"LatLng": "toga.types",
"Position": "toga.types",
"Size": "toga.types",
"WebView": "toga.widgets.webview",
"Window": "toga.window",
}
__all__ = list(toga_core_imports.keys())


def __getattr__(name):
try:
module_name = toga_core_imports[name]
except KeyError:
raise AttributeError(f"module '{__name__}' has no attribute '{name}'") from None
else:
module = importlib.import_module(module_name)
value = getattr(module, name)
globals()[name] = value
return value


class NotImplementedWarning(RuntimeWarning):
# pytest.warns() requires that Warning() subclasses are constructed by passing a
# single argument (the warning message). Use a factory method to avoid reproducing
# the message format and the warn invocation.
@classmethod
def warn(cls, platform: str, feature: str) -> None:
def warn(self, platform: str, feature: str):
KRRT7 marked this conversation as resolved.
Show resolved Hide resolved
"""Raise a warning that a feature isn't implemented on a platform."""
warnings.warn(NotImplementedWarning(f"[{platform}] Not implemented: {feature}"))


__all__ = [
"NotImplementedWarning",
# Applications
"App",
"DocumentApp",
# Commands
"Command",
"Group",
# Documents
"Document",
# Dialogs
"ConfirmDialog",
"ErrorDialog",
"InfoDialog",
"OpenFileDialog",
"QuestionDialog",
"SaveFileDialog",
"SelectFolderDialog",
"StackTraceDialog",
# Keys
"Key",
# Resources
"hsl",
"hsla",
"rgb",
"rgba",
"Font",
"Icon",
"Image",
# Types
"LatLng",
"Position",
"Size",
# Widgets
"ActivityIndicator",
"Box",
"Button",
"Canvas",
"DateInput",
"DetailedList",
"Divider",
"ImageView",
"Label",
"MapPin",
"MapView",
"MultilineTextInput",
"NumberInput",
"OptionContainer",
"OptionItem",
"PasswordInput",
"ProgressBar",
"ScrollContainer",
"Selection",
"Slider",
"SplitContainer",
"Switch",
"Table",
"TextInput",
"TimeInput",
"Tree",
"WebView",
"Widget",
# Windows
"DocumentMainWindow",
"MainWindow",
"Window",
# Deprecated widget names
"DatePicker",
"TimePicker",
]


def _package_version(file: Path | str | None, name: str) -> str:
def _package_version(file, name):
KRRT7 marked this conversation as resolved.
Show resolved Hide resolved
try:
# Read version from SCM metadata
# This will only exist in a development environment
Expand All @@ -142,10 +97,7 @@ def _package_version(file: Path | str | None, name: str) -> str:
# Excluded from coverage because a pure test environment (such as the one
# used by tox in CI) won't have setuptools_scm
return get_version(root="../../..", relative_to=file) # pragma: no cover
except (
ModuleNotFoundError,
LookupError,
): # pragma: no-cover-if-missing-setuptools_scm
except (ModuleNotFoundError, LookupError):
KRRT7 marked this conversation as resolved.
Show resolved Hide resolved
# If setuptools_scm isn't in the environment, the call to import will fail.
# If it *is* in the environment, but the code isn't a git checkout (e.g.,
# it's been pip installed non-editable) the call to get_version() will fail.
Expand Down
4 changes: 2 additions & 2 deletions dummy/src/toga_dummy/widgets/slider.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import toga
from toga.widgets.slider import SliderImpl

from .base import Widget


class Slider(Widget, toga.widgets.slider.SliderImpl):
class Slider(Widget, SliderImpl):
def create(self):
self._action("create Slider")

Expand Down
4 changes: 2 additions & 2 deletions gtk/src/toga_gtk/widgets/slider.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from travertino.size import at_least

import toga
from toga.widgets.slider import SliderImpl

from ..libs import Gtk
from .base import Widget
Expand All @@ -16,7 +16,7 @@
# to line up at the same values.


class Slider(Widget, toga.widgets.slider.SliderImpl):
class Slider(Widget, SliderImpl):
def create(self):
self.adj = Gtk.Adjustment()
self.native = Gtk.Scale.new(Gtk.Orientation.HORIZONTAL, self.adj)
Expand Down
Loading