-
-
Notifications
You must be signed in to change notification settings - Fork 779
implement Lazy Loading for Cocoa core imports #3599
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
Draft
KRRT7
wants to merge
6
commits into
beeware:main
Choose a base branch
from
KRRT7:fix-type-hints
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Imports from the ``cocoa`` core namespace has been modified to use lazy importing. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,35 @@ | ||
import travertino | ||
import importlib | ||
from pathlib import Path | ||
|
||
__version__ = travertino._package_version(__file__, __name__) | ||
from travertino import _package_version | ||
|
||
|
||
def lazy_load(): | ||
toga_cocoa_imports = {} | ||
pyi = Path(__file__).with_suffix(".pyi") | ||
with pyi.open() as f: | ||
for line in f: | ||
segments = line.split() | ||
if segments and segments[0] == "from": | ||
toga_cocoa_imports[segments[3]] = segments[1] | ||
return toga_cocoa_imports | ||
|
||
|
||
toga_cocoa_imports = lazy_load() | ||
|
||
__all__ = list(toga_cocoa_imports.keys()) | ||
|
||
|
||
def __getattr__(name): | ||
try: | ||
module_name = toga_cocoa_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 | ||
|
||
|
||
__version__ = _package_version(__file__, __name__) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# flake8: noqa | ||
""" | ||
isort:skip_file | ||
""" | ||
|
||
from toga_cocoa.factory import not_implemented as not_implemented | ||
from toga_cocoa.factory import App as App | ||
from toga_cocoa.factory import Command as Command | ||
from toga_cocoa.factory import Font as Font | ||
from toga_cocoa.factory import Icon as Icon | ||
from toga_cocoa.factory import Image as Image | ||
from toga_cocoa.factory import Paths as Paths | ||
from toga_cocoa.factory import dialogs as dialogs | ||
from toga_cocoa.factory import Camera as Camera | ||
from toga_cocoa.factory import Location as Location | ||
from toga_cocoa.factory import MenuStatusIcon as MenuStatusIcon | ||
from toga_cocoa.factory import SimpleStatusIcon as SimpleStatusIcon | ||
from toga_cocoa.factory import StatusIconSet as StatusIconSet | ||
from toga_cocoa.factory import ActivityIndicator as ActivityIndicator | ||
from toga_cocoa.factory import Box as Box | ||
from toga_cocoa.factory import Button as Button | ||
from toga_cocoa.factory import Canvas as Canvas | ||
from toga_cocoa.factory import DateInput as DateInput | ||
from toga_cocoa.factory import DetailedList as DetailedList | ||
from toga_cocoa.factory import Divider as Divider | ||
from toga_cocoa.factory import ImageView as ImageView | ||
from toga_cocoa.factory import Label as Label | ||
from toga_cocoa.factory import MapView as MapView | ||
from toga_cocoa.factory import MultilineTextInput as MultilineTextInput | ||
from toga_cocoa.factory import NumberInput as NumberInput | ||
from toga_cocoa.factory import OptionContainer as OptionContainer | ||
from toga_cocoa.factory import PasswordInput as PasswordInput | ||
from toga_cocoa.factory import ProgressBar as ProgressBar | ||
from toga_cocoa.factory import ScrollContainer as ScrollContainer | ||
from toga_cocoa.factory import Selection as Selection | ||
from toga_cocoa.factory import Slider as Slider | ||
from toga_cocoa.factory import SplitContainer as SplitContainer | ||
from toga_cocoa.factory import Switch as Switch | ||
from toga_cocoa.factory import Table as Table | ||
from toga_cocoa.factory import TextInput as TextInput | ||
from toga_cocoa.factory import TimeInput as TimeInput | ||
from toga_cocoa.factory import Tree as Tree | ||
from toga_cocoa.factory import WebView as WebView | ||
from toga_cocoa.factory import MainWindow as MainWindow | ||
from toga_cocoa.factory import Window as Window |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import sys | ||
|
||
import pytest | ||
|
||
|
||
def test_lazy_succeed(monkeypatch): | ||
"""Submodules are imported on demand.""" | ||
for mod_name in ["toga_cocoa", "toga_cocoa.factory", "toga_cocoa.widgets.button"]: | ||
monkeypatch.delitem(sys.modules, mod_name, raising=False) | ||
|
||
# clean import of the top-level toga_cocoa module should not import any submodules. | ||
import toga_cocoa | ||
|
||
assert "toga_cocoa.factory" not in sys.modules | ||
assert "toga_cocoa.widgets.button" not in sys.modules | ||
|
||
# Accessing a name should import only the necessary submodules. | ||
Button = toga_cocoa.Button | ||
assert "toga_cocoa.factory" in sys.modules | ||
assert "toga_cocoa.widgets.button" in sys.modules | ||
|
||
# Accessing a name multiple times should return the same object. | ||
assert Button is toga_cocoa.Button | ||
assert Button is sys.modules["toga_cocoa.factory"].Button | ||
|
||
# Same again with a different attribute. | ||
App = toga_cocoa.App | ||
assert App is sys.modules["toga_cocoa.factory"].App | ||
|
||
assert hasattr(toga_cocoa, "Button") | ||
assert hasattr(toga_cocoa, "App") | ||
cached_button = toga_cocoa.Button | ||
assert cached_button is Button | ||
|
||
|
||
def test_lazy_fail(): | ||
"""Nonexistent names should raise a normal AttributeError.""" | ||
import toga_cocoa | ||
|
||
with pytest.raises( | ||
AttributeError, match="module 'toga_cocoa' has no attribute 'nonexistent'" | ||
): | ||
_ = toga_cocoa.nonexistent | ||
|
||
|
||
def test_lazy_load_cache(monkeypatch): | ||
import toga_cocoa | ||
|
||
if "Button" in toga_cocoa.__dict__: | ||
del toga_cocoa.__dict__["Button"] | ||
btn = toga_cocoa.Button | ||
assert btn is toga_cocoa.Button | ||
|
||
|
||
def test_lazy_attribute_error(monkeypatch): | ||
import toga_cocoa | ||
|
||
with pytest.raises( | ||
AttributeError, match="module 'toga_cocoa' has no attribute 'nonexistent'" | ||
): | ||
_ = toga_cocoa.nonexistent |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My two cents is that the
tests_backend
stuff aren't being run as tests -- they just support the test files in the tests directory in the testbed, so this file isn't been ran at all. Not sure if this is right, but I think you'd need to generalize this to not writetoga_cocoa
but to work out a name to change the tested import depending on backend in the testbed tests directory, and then skip the test on everything besides Cocoa for now.