Format Python files with ruff

This commit is contained in:
Simon Hausmann 2025-02-12 23:06:38 +01:00 committed by Simon Hausmann
parent 9001966dc9
commit 3358bc24e3
15 changed files with 261 additions and 191 deletions

View file

@ -55,6 +55,14 @@ jobs:
run: cargo xtask check_license_headers --fix-it run: cargo xtask check_license_headers --fix-it
- name: remove trailing whitespace - name: remove trailing whitespace
run: git grep -I -l -O'sed -i "s/[[:space:]]*$//"' -e '' -- ':!*.patch' run: git grep -I -l -O'sed -i "s/[[:space:]]*$//"' -e '' -- ':!*.patch'
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Format Python
working-directory: api/python
run: uv tool run ruff format
- name: Suggest format changes - name: Suggest format changes
uses: autofix-ci/action@551dded8c6cc8a1054039c8bc0b8b48c51dfc6ef uses: autofix-ci/action@551dded8c6cc8a1054039c8bc0b8b48c51dfc6ef
- name: Build wasm-interpreter before type check - name: Build wasm-interpreter before type check

View file

@ -3,6 +3,7 @@
import nox import nox
@nox.session(python="3.12") @nox.session(python="3.12")
def python(session: nox.Session): def python(session: nox.Session):
session.env["MATURIN_PEP517_ARGS"] = "--profile=dev" session.env["MATURIN_PEP517_ARGS"] = "--profile=dev"

View file

@ -50,6 +50,7 @@ dev = [
"nox>=2024.10.9", "nox>=2024.10.9",
"pdoc>=15.0.1", "pdoc>=15.0.1",
"pytest>=8.3.4", "pytest>=8.3.4",
"ruff>=0.9.6",
] ]
[tool.uv] [tool.uv]

View file

@ -1,9 +1,9 @@
# Copyright © SixtyFPS GmbH <info@slint.dev> # Copyright © SixtyFPS GmbH <info@slint.dev>
# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0 # SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
r''' r"""
.. include:: ../README.md .. include:: ../README.md
''' """
from importlib.machinery import ModuleSpec from importlib.machinery import ModuleSpec
import os import os
@ -21,6 +21,7 @@ from .slint import Image, Color, Brush, Timer, TimerMode
Struct = native.PyStruct Struct = native.PyStruct
class CompileError(Exception): class CompileError(Exception):
def __init__(self, message: str, diagnostics: list[native.PyDiagnostic]): def __init__(self, message: str, diagnostics: list[native.PyDiagnostic]):
self.message = message self.message = message
@ -53,14 +54,14 @@ def _build_global_class(compdef: native.ComponentDefinition, global_name: str) -
logging.warning(f"Duplicated property {prop_name}") logging.warning(f"Duplicated property {prop_name}")
continue continue
def mk_setter_getter(prop_name: str): # type: ignore def mk_setter_getter(prop_name: str): # type: ignore
def getter(self): # type: ignore def getter(self): # type: ignore
return self.__instance__.get_global_property( return self.__instance__.get_global_property(global_name, prop_name)
global_name, prop_name)
def setter(self, value): # type: ignore def setter(self, value): # type: ignore
return self.__instance__.set_global_property( return self.__instance__.set_global_property(
global_name, prop_name, value) global_name, prop_name, value
)
return property(getter, setter) return property(getter, setter)
@ -72,15 +73,19 @@ def _build_global_class(compdef: native.ComponentDefinition, global_name: str) -
logging.warning(f"Duplicated property {prop_name}") logging.warning(f"Duplicated property {prop_name}")
continue continue
def mk_setter_getter(callback_name: str): # type: ignore def mk_setter_getter(callback_name: str): # type: ignore
def getter(self): # type: ignore def getter(self): # type: ignore
def call(*args: Any) -> Any: def call(*args: Any) -> Any:
return self.__instance__.invoke_global(global_name, callback_name, *args) return self.__instance__.invoke_global(
global_name, callback_name, *args
)
return call return call
def setter(self, value): # type: ignore def setter(self, value): # type: ignore
return self.__instance__.set_global_callback( return self.__instance__.set_global_callback(
global_name, callback_name, value) global_name, callback_name, value
)
return property(getter, setter) return property(getter, setter)
@ -92,10 +97,13 @@ def _build_global_class(compdef: native.ComponentDefinition, global_name: str) -
logging.warning(f"Duplicated function {prop_name}") logging.warning(f"Duplicated function {prop_name}")
continue continue
def mk_getter(function_name: str): # type: ignore def mk_getter(function_name: str): # type: ignore
def getter(self): # type: ignore def getter(self): # type: ignore
def call(*args: Any) -> Any: def call(*args: Any) -> Any:
return self.__instance__.invoke_global(global_name, function_name, *args) return self.__instance__.invoke_global(
global_name, function_name, *args
)
return call return call
return property(getter) return property(getter)
@ -105,33 +113,33 @@ def _build_global_class(compdef: native.ComponentDefinition, global_name: str) -
return type("SlintGlobalClassWrapper", (), properties_and_callbacks) return type("SlintGlobalClassWrapper", (), properties_and_callbacks)
def _build_class(compdef: native.ComponentDefinition): # type: ignore def _build_class(compdef: native.ComponentDefinition): # type: ignore
def cls_init(self: Any, **kwargs) -> Any: # type: ignore
def cls_init(self: Any, **kwargs) -> Any: # type: ignore
self.__instance__ = compdef.create() self.__instance__ = compdef.create()
for name, value in self.__class__.__dict__.items(): for name, value in self.__class__.__dict__.items():
if hasattr(value, "slint.callback"): if hasattr(value, "slint.callback"):
callback_info = getattr(value, "slint.callback") callback_info = getattr(value, "slint.callback")
name = callback_info["name"] name = callback_info["name"]
def mk_callback(self: Any, callback: typing.Callable[..., Any]) -> typing.Callable[..., Any]: def mk_callback(
self: Any, callback: typing.Callable[..., Any]
) -> typing.Callable[..., Any]:
def invoke(*args: Any, **kwargs: Any) -> Any: def invoke(*args: Any, **kwargs: Any) -> Any:
return callback(self, *args, **kwargs) return callback(self, *args, **kwargs)
return invoke return invoke
if "global_name" in callback_info: if "global_name" in callback_info:
self.__instance__.set_global_callback( self.__instance__.set_global_callback(
callback_info["global_name"], name, mk_callback(self, value)) callback_info["global_name"], name, mk_callback(self, value)
)
else: else:
self.__instance__.set_callback( self.__instance__.set_callback(name, mk_callback(self, value))
name, mk_callback(self, value))
for prop, val in kwargs.items(): for prop, val in kwargs.items():
setattr(self, prop, val) setattr(self, prop, val)
properties_and_callbacks = { properties_and_callbacks = {"__init__": cls_init}
"__init__": cls_init
}
for prop_name in compdef.properties.keys(): for prop_name in compdef.properties.keys():
python_prop = _normalize_prop(prop_name) python_prop = _normalize_prop(prop_name)
@ -140,12 +148,11 @@ def _build_class(compdef: native.ComponentDefinition): # type: ignore
continue continue
def mk_setter_getter(prop_name: str) -> Any: def mk_setter_getter(prop_name: str) -> Any:
def getter(self) -> Any: # type: ignore def getter(self) -> Any: # type: ignore
return self.__instance__.get_property(prop_name) return self.__instance__.get_property(prop_name)
def setter(self, value: Any) -> None: # type: ignore def setter(self, value: Any) -> None: # type: ignore
self.__instance__.set_property( self.__instance__.set_property(prop_name, value)
prop_name, value)
return property(getter, setter) return property(getter, setter)
@ -157,13 +164,14 @@ def _build_class(compdef: native.ComponentDefinition): # type: ignore
logging.warning(f"Duplicated property {prop_name}") logging.warning(f"Duplicated property {prop_name}")
continue continue
def mk_setter_getter(callback_name: str) -> Any: # type: ignore def mk_setter_getter(callback_name: str) -> Any: # type: ignore
def getter(self): # type: ignore def getter(self): # type: ignore
def call(*args: Any) -> Any: def call(*args: Any) -> Any:
return self.__instance__.invoke(callback_name, *args) return self.__instance__.invoke(callback_name, *args)
return call return call
def setter(self, value: any): # type: ignore def setter(self, value: any): # type: ignore
self.__instance__.set_callback(callback_name, value) self.__instance__.set_callback(callback_name, value)
return property(getter, setter) return property(getter, setter)
@ -176,10 +184,11 @@ def _build_class(compdef: native.ComponentDefinition): # type: ignore
logging.warning(f"Duplicated function {prop_name}") logging.warning(f"Duplicated function {prop_name}")
continue continue
def mk_getter(function_name: str): # type: ignore def mk_getter(function_name: str): # type: ignore
def getter(self) -> Any: # type: ignore def getter(self) -> Any: # type: ignore
def call(*args: Any) -> Any: def call(*args: Any) -> Any:
return self.__instance__.invoke(function_name, *args) return self.__instance__.invoke(function_name, *args)
return call return call
return property(getter) return property(getter)
@ -189,8 +198,8 @@ def _build_class(compdef: native.ComponentDefinition): # type: ignore
for global_name in compdef.globals: for global_name in compdef.globals:
global_class = _build_global_class(compdef, global_name) global_class = _build_global_class(compdef, global_name)
def mk_global(global_class: typing.Callable[..., Any]): # type: ignore def mk_global(global_class: typing.Callable[..., Any]): # type: ignore
def global_getter(self) -> Any: # type: ignore def global_getter(self) -> Any: # type: ignore
wrapper = global_class() wrapper = global_class()
setattr(wrapper, "__instance__", self.__instance__) setattr(wrapper, "__instance__", self.__instance__)
return wrapper return wrapper
@ -203,7 +212,6 @@ def _build_class(compdef: native.ComponentDefinition): # type: ignore
def _build_struct(name: str, struct_prototype: native.PyStruct) -> type: def _build_struct(name: str, struct_prototype: native.PyStruct) -> type:
def new_struct(cls: Any, *args: Any, **kwargs: Any) -> native.PyStruct: def new_struct(cls: Any, *args: Any, **kwargs: Any) -> native.PyStruct:
inst = copy.copy(struct_prototype) inst = copy.copy(struct_prototype)
@ -219,7 +227,18 @@ def _build_struct(name: str, struct_prototype: native.PyStruct) -> type:
return type(name, (), type_dict) return type(name, (), type_dict)
def load_file(path: str | os.PathLike[Any] | pathlib.Path, quiet:bool=False, style:typing.Optional[str]=None, include_paths:typing.Optional[typing.List[str | os.PathLike[Any] | pathlib.Path]]=None, library_paths:typing.Optional[typing.List[str | os.PathLike[Any] | pathlib.Path]]=None, translation_domain:typing.Optional[str]=None) -> Any: def load_file(
path: str | os.PathLike[Any] | pathlib.Path,
quiet: bool = False,
style: typing.Optional[str] = None,
include_paths: typing.Optional[
typing.List[str | os.PathLike[Any] | pathlib.Path]
] = None,
library_paths: typing.Optional[
typing.List[str | os.PathLike[Any] | pathlib.Path]
] = None,
translation_domain: typing.Optional[str] = None,
) -> Any:
compiler = native.Compiler() compiler = native.Compiler()
if style is not None: if style is not None:
@ -240,8 +259,11 @@ def load_file(path: str | os.PathLike[Any] | pathlib.Path, quiet:bool=False, sty
if diag.level == native.DiagnosticLevel.Warning: if diag.level == native.DiagnosticLevel.Warning:
logging.warning(diag) logging.warning(diag)
errors = [diag for diag in diagnostics if diag.level == errors = [
native.DiagnosticLevel.Error] diag
for diag in diagnostics
if diag.level == native.DiagnosticLevel.Error
]
if errors: if errors:
raise CompileError(f"Could not compile {path}", diagnostics) raise CompileError(f"Could not compile {path}", diagnostics)
@ -265,11 +287,11 @@ def load_file(path: str | os.PathLike[Any] | pathlib.Path, quiet:bool=False, sty
class SlintAutoLoader: class SlintAutoLoader:
def __init__(self, base_dir: str | None=None): def __init__(self, base_dir: str | None = None):
self.local_dirs: typing.List[str] | None = None self.local_dirs: typing.List[str] | None = None
if base_dir: if base_dir:
self.local_dirs = [base_dir] self.local_dirs = [base_dir]
def __getattr__(self, name: str) -> Any: def __getattr__(self, name: str) -> Any:
for path in self.local_dirs or sys.path: for path in self.local_dirs or sys.path:
dir_candidate = os.path.join(path, name) dir_candidate = os.path.join(path, name)
@ -284,7 +306,7 @@ class SlintAutoLoader:
setattr(self, name, type_namespace) setattr(self, name, type_namespace)
return type_namespace return type_namespace
dir_candidate = os.path.join(path, name.replace('_', '-')) dir_candidate = os.path.join(path, name.replace("_", "-"))
file_candidate = dir_candidate + ".slint" file_candidate = dir_candidate + ".slint"
if os.path.isfile(file_candidate): if os.path.isfile(file_candidate):
type_namespace = load_file(file_candidate) type_namespace = load_file(file_candidate)
@ -297,14 +319,18 @@ class SlintAutoLoader:
loader = SlintAutoLoader() loader = SlintAutoLoader()
def _callback_decorator(callable: typing.Callable[..., Any], info: typing.Dict[str, Any]) -> typing.Callable[..., Any]: def _callback_decorator(
callable: typing.Callable[..., Any], info: typing.Dict[str, Any]
) -> typing.Callable[..., Any]:
if "name" not in info: if "name" not in info:
info["name"] = callable.__name__ info["name"] = callable.__name__
setattr(callable, "slint.callback", info) setattr(callable, "slint.callback", info)
return callable return callable
def callback(global_name: str | None=None, name : str | None=None) -> typing.Callable[..., Any]: def callback(
global_name: str | None = None, name: str | None = None
) -> typing.Callable[..., Any]:
if callable(global_name): if callable(global_name):
callback = global_name callback = global_name
return _callback_decorator(callback, {}) return _callback_decorator(callback, {})
@ -316,9 +342,23 @@ def callback(global_name: str | None=None, name : str | None=None) -> typing.Cal
info["global_name"] = global_name info["global_name"] = global_name
return lambda callback: _callback_decorator(callback, info) return lambda callback: _callback_decorator(callback, info)
def set_xdg_app_id(app_id: str) -> None: def set_xdg_app_id(app_id: str) -> None:
native.set_xdg_app_id(app_id) native.set_xdg_app_id(app_id)
__all__ = ["CompileError", "Component", "load_file", "loader", "Image", "Color",
"Brush", "Model", "ListModel", "Timer", "TimerMode", "set_xdg_app_id", __all__ = [
"callback"] "CompileError",
"Component",
"load_file",
"loader",
"Image",
"Color",
"Brush",
"Model",
"ListModel",
"Timer",
"TimerMode",
"set_xdg_app_id",
"callback",
]

View file

@ -25,7 +25,7 @@ class Model[T](native.PyModelBase, Iterable[T]):
def __iter__(self) -> Iterator[T]: def __iter__(self) -> Iterator[T]:
return ModelIterator(self) return ModelIterator(self)
def notify_row_changed(self, row: int) -> None: def notify_row_changed(self, row: int) -> None:
super().notify_row_changed(row) super().notify_row_changed(row)
@ -38,8 +38,9 @@ class Model[T](native.PyModelBase, Iterable[T]):
def row_data(self, row: int) -> typing.Optional[T]: def row_data(self, row: int) -> typing.Optional[T]:
return cast(T, super().row_data(row)) return cast(T, super().row_data(row))
class ListModel[T](Model[T]): class ListModel[T](Model[T]):
def __init__(self, iterable: typing.Optional[Iterable[T]]=None): def __init__(self, iterable: typing.Optional[Iterable[T]] = None):
super().__init__() super().__init__()
if iterable is not None: if iterable is not None:
self.list = list(iterable) self.list = list(iterable)
@ -49,7 +50,7 @@ class ListModel[T](Model[T]):
def row_count(self) -> int: def row_count(self) -> int:
return len(self.list) return len(self.list)
def row_data(self, row:int ) -> typing.Optional[T]: def row_data(self, row: int) -> typing.Optional[T]:
return self.list[row] return self.list[row]
def set_row_data(self, row: int, data: T) -> None: def set_row_data(self, row: int, data: T) -> None:

View file

@ -13,7 +13,6 @@ from typing import Any, List
from collections.abc import Callable from collections.abc import Callable
from enum import Enum, auto from enum import Enum, auto
class RgbColor: class RgbColor:
red: builtins.int red: builtins.int
green: builtins.int green: builtins.int
@ -25,117 +24,83 @@ class RgbaColor:
blue: builtins.int blue: builtins.int
alpha: builtins.int alpha: builtins.int
class Color: class Color:
red: builtins.int red: builtins.int
green: builtins.int green: builtins.int
blue: builtins.int blue: builtins.int
alpha: builtins.int alpha: builtins.int
def __new__(cls,maybe_value:typing.Optional[builtins.str | RgbaColor | RgbColor | typing.Dict[str, int]] = None) -> "Color": ... def __new__(
def brighter(self, factor:builtins.float) -> "Color": cls,
... maybe_value: typing.Optional[
builtins.str | RgbaColor | RgbColor | typing.Dict[str, int]
def darker(self, factor:builtins.float) -> "Color": ] = None,
... ) -> "Color": ...
def brighter(self, factor: builtins.float) -> "Color": ...
def transparentize(self, factor:builtins.float) -> "Color": def darker(self, factor: builtins.float) -> "Color": ...
... def transparentize(self, factor: builtins.float) -> "Color": ...
def mix(self, other: "Image", factor: builtins.float) -> "Color": ...
def mix(self, other:"Image", factor:builtins.float) -> "Color": def with_alpha(self, alpha: builtins.float) -> "Color": ...
... def __str__(self) -> builtins.str: ...
def __eq__(self, other: object) -> builtins.bool: ...
def with_alpha(self, alpha:builtins.float) -> "Color":
...
def __str__(self) -> builtins.str:
...
def __eq__(self, other:object) -> builtins.bool:
...
class Brush: class Brush:
color: Color color: Color
def __new__(cls,maybe_value:typing.Optional[Color]) -> "Brush": ... def __new__(cls, maybe_value: typing.Optional[Color]) -> "Brush": ...
def is_transparent(self) -> builtins.bool: def is_transparent(self) -> builtins.bool: ...
... def is_opaque(self) -> builtins.bool: ...
def brighter(self, factor: builtins.float) -> "Brush": ...
def is_opaque(self) -> builtins.bool: def darker(self, factor: builtins.float) -> "Brush": ...
... def transparentize(self, amount: builtins.float) -> "Brush": ...
def with_alpha(self, alpha: builtins.float) -> "Brush": ...
def brighter(self, factor:builtins.float) -> "Brush": def __eq__(self, other: object) -> builtins.bool: ...
...
def darker(self, factor:builtins.float) -> "Brush":
...
def transparentize(self, amount:builtins.float) -> "Brush":
...
def with_alpha(self, alpha:builtins.float) -> "Brush":
...
def __eq__(self, other:object) -> builtins.bool:
...
class Image: class Image:
r""" r"""
Image objects can be set on Slint Image elements for display. Construct Image objects from a path to an Image objects can be set on Slint Image elements for display. Construct Image objects from a path to an
image file on disk, using `Image.load_from_path`. image file on disk, using `Image.load_from_path`.
""" """
size: tuple[builtins.int, builtins.int] size: tuple[builtins.int, builtins.int]
width: builtins.int width: builtins.int
height: builtins.int height: builtins.int
path: typing.Optional[builtins.str] path: typing.Optional[builtins.str]
def __new__(cls,) -> "Image": ... def __new__(
cls,
) -> "Image": ...
@staticmethod @staticmethod
def load_from_path(path:builtins.str | os.PathLike[Any] | pathlib.Path) -> "Image": def load_from_path(path: builtins.str | os.PathLike[Any] | pathlib.Path) -> "Image":
r""" r"""
Loads the image from the specified path. Returns None if the image can't be loaded. Loads the image from the specified path. Returns None if the image can't be loaded.
""" """
... ...
@staticmethod @staticmethod
def load_from_svg_data(data:typing.Sequence[builtins.int]) -> "Image": def load_from_svg_data(data: typing.Sequence[builtins.int]) -> "Image":
r""" r"""
Creates a new image from a string that describes the image in SVG format. Creates a new image from a string that describes the image in SVG format.
""" """
... ...
class TimerMode(Enum): class TimerMode(Enum):
SingleShot = auto() SingleShot = auto()
Repeated = auto() Repeated = auto()
class Timer: class Timer:
def __new__(cls,) -> "Timer": ... def __new__(
def start(self, mode:TimerMode, interval:datetime.timedelta, callback:typing.Any) -> None: cls,
... ) -> "Timer": ...
def start(
self, mode: TimerMode, interval: datetime.timedelta, callback: typing.Any
) -> None: ...
@staticmethod @staticmethod
def single_shot(duration:datetime.timedelta, callback:typing.Any) -> None: def single_shot(duration: datetime.timedelta, callback: typing.Any) -> None: ...
... def stop(self) -> None: ...
def restart(self) -> None: ...
def stop(self) -> None: def running(self) -> builtins.bool: ...
... def set_interval(self, interval: datetime.timedelta) -> None: ...
def restart(self) -> None:
...
def running(self) -> builtins.bool:
...
def set_interval(self, interval:datetime.timedelta) -> None:
...
def set_xdg_app_id(app_id: str) -> None:
...
def set_xdg_app_id(app_id: str) -> None: ...
def run_event_loop() -> None: ... def run_event_loop() -> None: ...
def quit_event_loop() -> None: ... def quit_event_loop() -> None: ...
class PyModelBase: class PyModelBase:
@ -147,9 +112,7 @@ class PyModelBase:
def notify_row_removed(self, row: int, count: int) -> None: ... def notify_row_removed(self, row: int, count: int) -> None: ...
def notify_row_added(self, row: int, count: int) -> None: ... def notify_row_added(self, row: int, count: int) -> None: ...
class PyStruct(Any): class PyStruct(Any): ...
...
class ValueType(Enum): class ValueType(Enum):
Void = auto() Void = auto()
@ -172,21 +135,27 @@ class PyDiagnostic:
column_number: int column_number: int
source_file: typing.Optional[str] source_file: typing.Optional[str]
class ComponentInstance: class ComponentInstance:
def show(self) -> None: ... def show(self) -> None: ...
def hide(self) -> None: ... def hide(self) -> None: ...
def run(self) -> None: ... def run(self) -> None: ...
def invoke(self, callback_name: str, *args: Any) -> Any: ... def invoke(self, callback_name: str, *args: Any) -> Any: ...
def invoke_global(self, global_name: str, callback_name: str, *args: Any) -> Any: ... def invoke_global(
self, global_name: str, callback_name: str, *args: Any
) -> Any: ...
def set_property(self, property_name: str, value: Any) -> None: ... def set_property(self, property_name: str, value: Any) -> None: ...
def get_property(self, property_name: str) -> Any: ... def get_property(self, property_name: str) -> Any: ...
def set_callback(self, callback_name: str, callback: Callable[..., Any]) -> None: ... def set_callback(
def set_global_callback(self, global_name: str, callback_name: str, callback: Callable[..., Any]) -> None: ... self, callback_name: str, callback: Callable[..., Any]
def set_global_property(self, global_name: str, property_name: str, value: Any) -> None: ... ) -> None: ...
def set_global_callback(
self, global_name: str, callback_name: str, callback: Callable[..., Any]
) -> None: ...
def set_global_property(
self, global_name: str, property_name: str, value: Any
) -> None: ...
def get_global_property(self, global_name: str, property_name: str) -> Any: ... def get_global_property(self, global_name: str, property_name: str) -> Any: ...
class ComponentDefinition: class ComponentDefinition:
def create(self) -> ComponentInstance: ... def create(self) -> ComponentInstance: ...
name: str name: str
@ -198,7 +167,6 @@ class ComponentDefinition:
def global_callbacks(self, global_name: str) -> list[str]: ... def global_callbacks(self, global_name: str) -> list[str]: ...
def global_properties(self, global_name: str) -> typing.Dict[str, ValueType]: ... def global_properties(self, global_name: str) -> typing.Dict[str, ValueType]: ...
class CompilationResult: class CompilationResult:
component_names: list[str] component_names: list[str]
diagnostics: list[PyDiagnostic] diagnostics: list[PyDiagnostic]
@ -211,5 +179,9 @@ class Compiler:
library_paths: list[str | os.PathLike[Any] | pathlib.Path] library_paths: list[str | os.PathLike[Any] | pathlib.Path]
translation_domain: str translation_domain: str
style: str style: str
def build_from_path(self, path:str | os.PathLike[Any] | pathlib.Path) -> CompilationResult: ... def build_from_path(
def build_from_source(self, source:str, path: str | os.PathLike[Any] | pathlib.Path) -> CompilationResult: ... self, path: str | os.PathLike[Any] | pathlib.Path
) -> CompilationResult: ...
def build_from_source(
self, source: str, path: str | os.PathLike[Any] | pathlib.Path
) -> CompilationResult: ...

View file

@ -5,7 +5,6 @@ from slint import slint as native
from slint import Color, Brush from slint import Color, Brush
def test_col_default() -> None: def test_col_default() -> None:
col = Color() col = Color()
assert col.red == 0 assert col.red == 0
@ -24,7 +23,7 @@ def test_col_from_str() -> None:
def test_col_from_rgb_dict() -> None: def test_col_from_rgb_dict() -> None:
coldict = {'red': 0x12, 'green': 0x34, 'blue': 0x56} coldict = {"red": 0x12, "green": 0x34, "blue": 0x56}
col = Color(coldict) col = Color(coldict)
assert col.red == 0x12 assert col.red == 0x12
assert col.green == 0x34 assert col.green == 0x34
@ -33,7 +32,7 @@ def test_col_from_rgb_dict() -> None:
def test_col_from_rgba_dict() -> None: def test_col_from_rgba_dict() -> None:
coldict = {'red': 0x12, 'green': 0x34, 'blue': 0x56, 'alpha': 128} coldict = {"red": 0x12, "green": 0x34, "blue": 0x56, "alpha": 128}
col = Color(coldict) col = Color(coldict)
assert col.red == 0x12 assert col.red == 0x12
assert col.green == 0x34 assert col.green == 0x34

View file

@ -19,7 +19,7 @@ def base_dir() -> str:
def test_callback_decorators(caplog: pytest.LogCaptureFixture) -> None: def test_callback_decorators(caplog: pytest.LogCaptureFixture) -> None:
module = load_file(os.path.join(base_dir(), "test-load-file.slint"), quiet=False) module = load_file(os.path.join(base_dir(), "test-load-file.slint"), quiet=False)
class SubClass(module.App): # type: ignore class SubClass(module.App): # type: ignore
@slint.callback() @slint.callback()
def say_hello_again(self, arg: str) -> str: def say_hello_again(self, arg: str) -> str:
return "say_hello_again:" + arg return "say_hello_again:" + arg

View file

@ -15,7 +15,8 @@ def test_basic_compiler() -> None:
assert len(compiler.build_from_source("Garbage", "").component_names) == 0 assert len(compiler.build_from_source("Garbage", "").component_names) == 0
result = compiler.build_from_source(""" result = compiler.build_from_source(
"""
export global TestGlobal { export global TestGlobal {
in property <string> theglobalprop; in property <string> theglobalprop;
callback globallogic(); callback globallogic();
@ -35,7 +36,9 @@ def test_basic_compiler() -> None:
callback test-callback(); callback test-callback();
public function ff() {} public function ff() {}
} }
""", "") """,
"",
)
assert result.component_names == ["Test"] assert result.component_names == ["Test"]
compdef = result.component("Test") compdef = result.component("Test")
@ -44,8 +47,16 @@ def test_basic_compiler() -> None:
assert compdef.name == "Test" assert compdef.name == "Test"
props = [(name, type) for name, type in compdef.properties.items()] props = [(name, type) for name, type in compdef.properties.items()]
assert props == [('boolprop', ValueType.Bool), ('brushprop', ValueType.Brush), ('colprop', ValueType.Brush), ('floatprop', ValueType.Number), assert props == [
('imgprop', ValueType.Image), ('intprop', ValueType.Number), ('modelprop', ValueType.Model), ('strprop', ValueType.String)] ("boolprop", ValueType.Bool),
("brushprop", ValueType.Brush),
("colprop", ValueType.Brush),
("floatprop", ValueType.Number),
("imgprop", ValueType.Image),
("intprop", ValueType.Number),
("modelprop", ValueType.Model),
("strprop", ValueType.String),
]
assert compdef.callbacks == ["test-callback"] assert compdef.callbacks == ["test-callback"]
assert compdef.functions == ["ff"] assert compdef.functions == ["ff"]
@ -53,8 +64,9 @@ def test_basic_compiler() -> None:
assert compdef.globals == ["TestGlobal"] assert compdef.globals == ["TestGlobal"]
assert compdef.global_properties("Garbage") == None assert compdef.global_properties("Garbage") == None
assert [(name, type) for name, type in compdef.global_properties( assert [
"TestGlobal").items()] == [('theglobalprop', ValueType.String)] (name, type) for name, type in compdef.global_properties("TestGlobal").items()
] == [("theglobalprop", ValueType.String)]
assert compdef.global_callbacks("Garbage") == None assert compdef.global_callbacks("Garbage") == None
assert compdef.global_callbacks("TestGlobal") == ["globallogic"] assert compdef.global_callbacks("TestGlobal") == ["globallogic"]

View file

@ -10,12 +10,15 @@ import typing
def test_callback_gc() -> None: def test_callback_gc() -> None:
compiler = native.Compiler() compiler = native.Compiler()
compdef = compiler.build_from_source(""" compdef = compiler.build_from_source(
"""
export component Test { export component Test {
out property <string> test-value: "Ok"; out property <string> test-value: "Ok";
callback test-callback(string) -> string; callback test-callback(string) -> string;
} }
""", "").component("Test") """,
"",
).component("Test")
assert compdef != None assert compdef != None
instance: native.ComponentInstance | None = compdef.create() instance: native.ComponentInstance | None = compdef.create()
@ -30,8 +33,7 @@ def test_callback_gc() -> None:
handler: Handler | None = Handler(instance) handler: Handler | None = Handler(instance)
assert handler is not None assert handler is not None
instance.set_callback( instance.set_callback("test-callback", handler.python_callback)
"test-callback", handler.python_callback)
handler = None handler = None
assert instance.invoke("test-callback", "World") == "WorldOk" assert instance.invoke("test-callback", "World") == "WorldOk"

View file

@ -7,11 +7,11 @@ from slint.slint import ValueType, Image, Color, Brush
import os import os
def test_property_access() -> None: def test_property_access() -> None:
compiler = native.Compiler() compiler = native.Compiler()
compdef = compiler.build_from_source(""" compdef = compiler.build_from_source(
"""
export global TestGlobal { export global TestGlobal {
in property <string> theglobalprop: "Hey"; in property <string> theglobalprop: "Hey";
callback globallogic(); callback globallogic();
@ -41,7 +41,9 @@ def test_property_access() -> None:
callback test-callback(); callback test-callback();
} }
""", os.path.join(os.path.dirname(__file__), "main.slint")).component("Test") """,
os.path.join(os.path.dirname(__file__), "main.slint"),
).component("Test")
assert compdef != None assert compdef != None
instance = compdef.create() instance = compdef.create()
@ -80,7 +82,8 @@ def test_property_access() -> None:
assert structval.finished == True assert structval.finished == True
assert structval.dash_prop == True assert structval.dash_prop == True
instance.set_property( instance.set_property(
"structprop", {'title': 'new', 'finished': False, 'dash_prop': False}) "structprop", {"title": "new", "finished": False, "dash_prop": False}
)
structval = instance.get_property("structprop") structval = instance.get_property("structprop")
assert structval.title == "new" assert structval.title == "new"
assert structval.finished == False assert structval.finished == False
@ -94,14 +97,23 @@ def test_property_access() -> None:
with pytest.raises(RuntimeError, match="The image cannot be loaded"): with pytest.raises(RuntimeError, match="The image cannot be loaded"):
Image.load_from_path("non-existent.png") Image.load_from_path("non-existent.png")
instance.set_property("imageprop", Image.load_from_path(os.path.join( instance.set_property(
os.path.dirname(__file__), "../../../examples/iot-dashboard/images/humidity.png"))) "imageprop",
Image.load_from_path(
os.path.join(
os.path.dirname(__file__),
"../../../examples/iot-dashboard/images/humidity.png",
)
),
)
imageval = instance.get_property("imageprop") imageval = instance.get_property("imageprop")
assert imageval.size == (36, 36) assert imageval.size == (36, 36)
assert "humidity.png" in imageval.path assert "humidity.png" in imageval.path
with pytest.raises(TypeError, match="'int' object cannot be converted to 'PyString'"): with pytest.raises(
instance.set_property("structprop", {42: 'wrong'}) TypeError, match="'int' object cannot be converted to 'PyString'"
):
instance.set_property("structprop", {42: "wrong"})
brushval = instance.get_property("brushprop") brushval = instance.get_property("brushprop")
assert str(brushval.color) == "argb(255, 255, 0, 255)" assert str(brushval.color) == "argb(255, 255, 0, 255)"
@ -128,7 +140,8 @@ def test_property_access() -> None:
def test_callbacks() -> None: def test_callbacks() -> None:
compiler = native.Compiler() compiler = native.Compiler()
compdef = compiler.build_from_source(""" compdef = compiler.build_from_source(
"""
export global TestGlobal { export global TestGlobal {
callback globallogic(string) -> string; callback globallogic(string) -> string;
globallogic(value) => { globallogic(value) => {
@ -143,7 +156,9 @@ def test_callbacks() -> None:
} }
callback void-callback(); callback void-callback();
} }
""", "").component("Test") """,
"",
).component("Test")
assert compdef != None assert compdef != None
instance = compdef.create() instance = compdef.create()
@ -151,8 +166,7 @@ def test_callbacks() -> None:
assert instance.invoke("test-callback", "foo") == "local foo" assert instance.invoke("test-callback", "foo") == "local foo"
assert instance.invoke_global( assert instance.invoke_global("TestGlobal", "globallogic", "foo") == "global foo"
"TestGlobal", "globallogic", "foo") == "global foo"
with pytest.raises(RuntimeError, match="no such callback"): with pytest.raises(RuntimeError, match="no such callback"):
instance.set_callback("non-existent", lambda x: x) instance.set_callback("non-existent", lambda x: x)
@ -164,9 +178,12 @@ def test_callbacks() -> None:
instance.set_global_callback("TestGlobal", "non-existent", lambda x: x) instance.set_global_callback("TestGlobal", "non-existent", lambda x: x)
instance.set_global_callback( instance.set_global_callback(
"TestGlobal", "globallogic", lambda x: "python global " + x) "TestGlobal", "globallogic", lambda x: "python global " + x
assert instance.invoke_global( )
"TestGlobal", "globallogic", "foo") == "python global foo" assert (
instance.invoke_global("TestGlobal", "globallogic", "foo")
== "python global foo"
)
instance.set_callback("void-callback", lambda: None) instance.set_callback("void-callback", lambda: None)
instance.invoke("void-callback") instance.invoke("void-callback")
@ -174,9 +191,8 @@ def test_callbacks() -> None:
if __name__ == "__main__": if __name__ == "__main__":
import slint import slint
module = slint.load_file(
"../../demos/printerdemo/ui/printerdemo.slint") module = slint.load_file("../../demos/printerdemo/ui/printerdemo.slint")
instance = module.MainWindow() instance = module.MainWindow()
instance.PrinterQueue.start_job = lambda title: print( instance.PrinterQueue.start_job = lambda title: print(f"new print job {title}")
f"new print job {title}")
instance.run() instance.run()

View file

@ -14,10 +14,14 @@ def base_dir() -> str:
assert base_dir is not None assert base_dir is not None
return base_dir return base_dir
def test_load_file(caplog: pytest.LogCaptureFixture) -> None: def test_load_file(caplog: pytest.LogCaptureFixture) -> None:
module = load_file(os.path.join(base_dir(), "test-load-file.slint"), quiet=False) module = load_file(os.path.join(base_dir(), "test-load-file.slint"), quiet=False)
assert "The property 'color' has been deprecated. Please use 'background' instead" in caplog.text assert (
"The property 'color' has been deprecated. Please use 'background' instead"
in caplog.text
)
assert len(list(module.__dict__.keys())) == 6 assert len(list(module.__dict__.keys())) == 6
assert "App" in module.__dict__ assert "App" in module.__dict__

View file

@ -17,8 +17,7 @@ def test_magic_import_path() -> None:
oldsyspath = sys.path oldsyspath = sys.path
assert loader.printerdemo == None assert loader.printerdemo == None
try: try:
sys.path.append(os.path.join(os.path.dirname(__file__), sys.path.append(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
"..", "..", ".."))
instance = loader.demos.printerdemo.ui.printerdemo.MainWindow() instance = loader.demos.printerdemo.ui.printerdemo.MainWindow()
del instance del instance
finally: finally:

View file

@ -9,7 +9,8 @@ import typing
def test_model_notify() -> None: def test_model_notify() -> None:
compiler = native.Compiler() compiler = native.Compiler()
compdef = compiler.build_from_source(""" compdef = compiler.build_from_source(
"""
export component App { export component App {
width: 300px; width: 300px;
height: 300px; height: 300px;
@ -29,7 +30,9 @@ def test_model_notify() -> None:
} }
} }
""", "").component("App") """,
"",
).component("App")
assert compdef != None assert compdef != None
instance = compdef.create() instance = compdef.create()
@ -37,8 +40,7 @@ def test_model_notify() -> None:
model = models.ListModel([100, 0]) model = models.ListModel([100, 0])
instance.set_property( instance.set_property("fixed-height-model", model)
"fixed-height-model", model)
assert instance.get_property("layout-height") == 100 assert instance.get_property("layout-height") == 100
model.set_row_data(1, 50) model.set_row_data(1, 50)
@ -48,18 +50,20 @@ def test_model_notify() -> None:
del model[1:] del model[1:]
assert instance.get_property("layout-height") == 100 assert instance.get_property("layout-height") == 100
assert isinstance(instance.get_property( assert isinstance(instance.get_property("fixed-height-model"), models.ListModel)
"fixed-height-model"), models.ListModel)
def test_model_from_list() -> None: def test_model_from_list() -> None:
compiler = native.Compiler() compiler = native.Compiler()
compdef = compiler.build_from_source(""" compdef = compiler.build_from_source(
"""
export component App { export component App {
in-out property<[int]> data: [1, 2, 3, 4]; in-out property<[int]> data: [1, 2, 3, 4];
} }
""", "").component("App") """,
"",
).component("App")
assert compdef != None assert compdef != None
instance = compdef.create() instance = compdef.create()
@ -100,11 +104,14 @@ def test_python_model_iterable() -> None:
def test_rust_model_sequence() -> None: def test_rust_model_sequence() -> None:
compiler = native.Compiler() compiler = native.Compiler()
compdef = compiler.build_from_source(""" compdef = compiler.build_from_source(
"""
export component App { export component App {
in-out property<[int]> data: [1, 2, 3, 4, 5]; in-out property<[int]> data: [1, 2, 3, 4, 5];
} }
""", "").component("App") """,
"",
).component("App")
assert compdef != None assert compdef != None
instance = compdef.create() instance = compdef.create()
@ -120,7 +127,8 @@ def test_rust_model_sequence() -> None:
def test_model_writeback() -> None: def test_model_writeback() -> None:
compiler = native.Compiler() compiler = native.Compiler()
compdef = compiler.build_from_source(""" compdef = compiler.build_from_source(
"""
export component App { export component App {
width: 300px; width: 300px;
height: 300px; height: 300px;
@ -132,7 +140,9 @@ def test_model_writeback() -> None:
} }
} }
""", "").component("App") """,
"",
).component("App")
assert compdef != None assert compdef != None
instance = compdef.create() instance = compdef.create()
@ -140,8 +150,7 @@ def test_model_writeback() -> None:
model = models.ListModel([100, 0]) model = models.ListModel([100, 0])
instance.set_property( instance.set_property("model", model)
"model", model)
instance.invoke("write-to-model", 1, 42) instance.invoke("write-to-model", 1, 42)
assert list(instance.get_property("model")) == [100, 42] assert list(instance.get_property("model")) == [100, 42]

View file

@ -3,7 +3,7 @@
import pytest import pytest
from slint import slint as native from slint import slint as native
from slint.slint import ValueType; from slint.slint import ValueType
from datetime import timedelta from datetime import timedelta
counter: int counter: int
@ -12,6 +12,7 @@ counter: int
def test_timer() -> None: def test_timer() -> None:
global counter global counter
counter = 0 counter = 0
def quit_after_two_invocations() -> None: def quit_after_two_invocations() -> None:
global counter global counter
counter = min(counter + 1, 2) counter = min(counter + 1, 2)
@ -19,10 +20,15 @@ def test_timer() -> None:
native.quit_event_loop() native.quit_event_loop()
test_timer = native.Timer() test_timer = native.Timer()
test_timer.start(native.TimerMode.Repeated, timedelta(milliseconds=100), quit_after_two_invocations) test_timer.start(
native.TimerMode.Repeated,
timedelta(milliseconds=100),
quit_after_two_invocations,
)
native.run_event_loop() native.run_event_loop()
test_timer.stop() test_timer.stop()
assert(counter == 2) assert counter == 2
def test_single_shot() -> None: def test_single_shot() -> None:
native.Timer.single_shot(timedelta(milliseconds=100), native.quit_event_loop) native.Timer.single_shot(timedelta(milliseconds=100), native.quit_event_loop)