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

[DO NOT MERGE]Micropython testbed failure debug #3017

Closed
wants to merge 14 commits into from
53 changes: 53 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,59 @@ jobs:
if-no-files-found: error
include-hidden-files: true

micropython:
name: MicroPython compatibility
runs-on: ubuntu-latest
needs: [ pre-commit, towncrier, package ]
steps:
- name: Build MicroPython
run: |
# The following script also works on macOS, except that due to a bug,
# threading must be enabled, i.e. THREAD must be omitted from the disabled
# feature list.
cd $RUNNER_TEMP
git clone https://github.com/micropython/micropython -b v1.24.0 --depth 1

# Create a variant with the same configuration as the PyScript build.
cd micropython/ports/unix
cp -a variants/standard variants/pyscript
grep require ../webassembly/variants/pyscript/manifest.py \
>> variants/pyscript/manifest.py
for feature in BTREE FFI SOCKET SSL TERMIOS THREAD; do
echo "MICROPY_PY_$feature = 0" >> variants/pyscript/mpconfigvariant.mk
done

export VARIANT=pyscript
make submodules
make -j $(nproc)

- name: Checkout
uses: actions/[email protected]

- name: Set up Python
uses: actions/[email protected]
with:
python-version: "3.13"

- name: Get Packages
uses: actions/[email protected]
with:
name: Packages-toga-core
path: dist

- name: Test
run: |
pip install dist/toga_core-*.whl
site_packages=$(python -c '
import sys
print([path for path in sys.path if "site-packages" in path][0])
')

cd core
export MICROPYPATH="$site_packages:.frozen"
$RUNNER_TEMP/micropython/ports/unix/build-pyscript/micropython \
micropython_check.py

core-coverage:
name: Coverage
needs: core
Expand Down
1 change: 1 addition & 0 deletions android/tests_backend/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ async def wait_for_window(
minimize=False,
full_screen=False,
state_switch_not_from_normal=False,
rapid_state_assignment=False,
):
await self.redraw(
message,
Expand Down
1 change: 1 addition & 0 deletions changes/2976.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
A subset of Toga is now compatible with MicroPython.
11 changes: 8 additions & 3 deletions cocoa/tests_backend/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,18 @@ async def wait_for_window(
minimize=False,
full_screen=False,
state_switch_not_from_normal=False,
rapid_state_assignment=False,
):
await self.redraw(
message,
delay=(
1.75
if state_switch_not_from_normal
else 0.75 if full_screen else 0.5 if minimize else 0.1
2
if rapid_state_assignment
else (
1.75
if state_switch_not_from_normal
else 0.75 if full_screen else 0.5 if minimize else 0.1
)
),
)

Expand Down
51 changes: 51 additions & 0 deletions core/micropython_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env python3
#
# This script should be run under MicroPython to check that it can import all the Toga
# modules required by Invent.

# The top-level Toga module must be imported first, to enable the standard library
# compatibility shims.
#
# isort: off
import toga

# isort: on
import sys
import traceback

# Access attributes to trigger lazy import.
failures = 0
for name in [
"App",
"Font",
"Image",
"Window",
#
"Widget",
"Box",
"Button",
"DateInput",
"Divider",
"ImageView",
"Label",
"MultilineTextInput",
"PasswordInput",
"ProgressBar",
"Slider",
"Switch",
"TextInput",
"TimeInput",
]:
try:
getattr(toga, name)
except Exception:
failures += 1
print(f"Failed to import toga.{name}:")
traceback.print_exc()
print()

if failures:
print(f"{failures} names failed to import")
sys.exit(1)
else:
print("All names imported successfully")
3 changes: 1 addition & 2 deletions core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ classifiers = [
]
dependencies = [
"travertino >= 0.3.0",
# limited to <=3.9 for the `group` argument for `entry_points()`
"importlib_metadata >= 4.4.0; python_version <= '3.9'",
]

[project.optional-dependencies]
Expand Down Expand Up @@ -114,6 +112,7 @@ relative_files = true
# See notes in the root pyproject.toml file.
source = ["src"]
source_pkgs = ["toga"]
omit = ["**/toga/compat/**"] # Only used by MicroPython.

[tool.coverage.paths]
source = [
Expand Down
37 changes: 25 additions & 12 deletions core/src/toga/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
from __future__ import annotations
# Enable the standard library compatibility shims before doing anything else.
#
# __future__ imports must be at the very top of the file, and MicroPython doesn't
# currently include a __future__ module, so this file can't contain any __future__
# imports. Other modules imported after `compat` can use __future__ as normal.
import sys

if sys.implementation.name != "cpython": # pragma: no cover
from . import compat # noqa: F401

import importlib
import warnings
from pathlib import Path
from importlib import import_module

toga_core_imports = {
# toga.app imports
Expand Down Expand Up @@ -83,15 +90,21 @@


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)
if module_name := toga_core_imports.get(name):
module = import_module(module_name)
value = getattr(module, name)
globals()[name] = value
return value
else:
# MicroPython apparently doesn't attempt a submodule import when __getattr__
# raises AttributeError, so we need to do it manually.
try:
value = import_module(f"{__name__}.{name}")
except ImportError:
raise AttributeError(
f"module '{__name__}' has no attribute '{name}'"
) from None

globals()[name] = value
return value


class NotImplementedWarning(RuntimeWarning):
Expand All @@ -104,7 +117,7 @@ def warn(cls, platform: str, feature: str) -> None:
warnings.warn(NotImplementedWarning(f"[{platform}] Not implemented: {feature}"))


def _package_version(file: Path | str | None, name: str) -> str:
def _package_version(file, name):
try:
# Read version from SCM metadata
# This will only exist in a development environment
Expand Down
Loading
Loading