Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
17 changes: 2 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,15 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.10", "3.12"]
python-version: ["3.9", "3.10", "3.12", "3.13"]
os: [ubuntu-latest, macos-latest, windows-latest]
pydantic: [""]
exclude:
- python-version: "3.8"
os: "macos-latest"
include:
- python-version: "3.8"
os: "macos-13"
- python-version: "3.9"
os: "macos-13"
- python-version: "3.11"
os: "ubuntu-latest"
- python-version: "3.12"
os: "ubuntu-latest"
pydantic: "'pydantic<2'"
- python-version: "3.8"
os: "ubuntu-latest"
pydantic: "'pydantic<2'"

test-qt:
uses: pyapp-kit/workflows/.github/workflows/test-pyrepo.yml@v2
Expand All @@ -58,9 +48,6 @@ jobs:
fail-fast: false
matrix:
include:
- python-version: "3.8"
os: "ubuntu-latest"
qt: "PyQt5==5.12"
- python-version: "3.10"
os: "ubuntu-latest"
qt: "PyQt5~=5.15.0"
Expand All @@ -82,7 +69,7 @@ jobs:
- python-version: "3.11"
os: "ubuntu-latest"
qt: "PySide6~=6.6.0"
- python-version: "3.11"
- python-version: "3.13"
os: "ubuntu-latest"
qt: pyqt6
- python-version: "3.10"
Expand Down
3 changes: 1 addition & 2 deletions demo/model_app.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from pathlib import Path
from typing import List

from qtpy.QtCore import QFile, QFileInfo, QSaveFile, Qt, QTextStream
from qtpy.QtWidgets import QApplication, QFileDialog, QMessageBox, QTextEdit
Expand Down Expand Up @@ -160,7 +159,7 @@ class CommandId:

ABOUT_ICON_PATH = Path(__file__).parent / "images" / "about.svg"

ACTIONS: List[types.Action] = [
ACTIONS: list[types.Action] = [
types.Action(
id="new_file",
icon="fa6-solid:file-circle-plus",
Expand Down
4 changes: 1 addition & 3 deletions demo/multi_file/actions.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from typing import List

from app_model.types import Action, KeyBindingRule, KeyCode, KeyMod, MenuRule

from . import functions
from .constants import CommandId, MenuId

ACTIONS: List[Action] = [
ACTIONS: list[Action] = [
Action(
id=CommandId.OPEN,
title="Open",
Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ build-backend = "hatchling.build"
name = "app-model"
description = "Generic application schema implemented in python"
readme = "README.md"
requires-python = ">=3.8"
requires-python = ">=3.9"
license = { text = "BSD 3-Clause License" }
authors = [{ email = "talley.lambert@gmail.com" }, { name = "Talley Lambert" }]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Desktop Environment",
"Topic :: Software Development",
"Topic :: Software Development :: User Interfaces",
Expand Down Expand Up @@ -81,7 +81,7 @@ src_paths = ["src/app_model", "tests"]
[tool.ruff]
line-length = 88
src = ["src", "tests"]
target-version = "py38"
target-version = "py39"

[tool.ruff.lint]
pydocstyle = { convention = "numpy" }
Expand Down
19 changes: 7 additions & 12 deletions src/app_model/_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,12 @@
import contextlib
import os
import sys
from collections.abc import Iterable, MutableMapping
from typing import (
TYPE_CHECKING,
ClassVar,
Dict,
Iterable,
List,
Literal,
MutableMapping,
Optional,
Tuple,
Type,
overload,
)

Expand Down Expand Up @@ -85,17 +80,17 @@ class Application:
"""

destroyed = Signal(str)
_instances: ClassVar[Dict[str, Application]] = {}
_instances: ClassVar[dict[str, Application]] = {}

def __init__(
self,
name: str,
*,
raise_synchronous_exceptions: bool = False,
commands_reg_class: Type[CommandsRegistry] = CommandsRegistry,
menus_reg_class: Type[MenusRegistry] = MenusRegistry,
keybindings_reg_class: Type[KeyBindingsRegistry] = KeyBindingsRegistry,
injection_store_class: Type[ino.Store] = ino.Store,
commands_reg_class: type[CommandsRegistry] = CommandsRegistry,
menus_reg_class: type[MenusRegistry] = MenusRegistry,
keybindings_reg_class: type[KeyBindingsRegistry] = KeyBindingsRegistry,
injection_store_class: type[ino.Store] = ino.Store,
context: Context | MutableMapping | None = None,
) -> None:
self._name = name
Expand Down Expand Up @@ -131,7 +126,7 @@ def __init__(

self.injection_store.on_unannotated_required_args = "ignore"

self._disposers: List[Tuple[str, DisposeCallable]] = []
self._disposers: list[tuple[str, DisposeCallable]] = []

@property
def raise_synchronous_exceptions(self) -> bool:
Expand Down
4 changes: 3 additions & 1 deletion src/app_model/backends/qt/_qaction.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import contextlib
from typing import TYPE_CHECKING, ClassVar, Mapping
from typing import TYPE_CHECKING, ClassVar
from weakref import WeakValueDictionary

from app_model import Application
Expand All @@ -12,6 +12,8 @@
from ._util import to_qicon

if TYPE_CHECKING:
from collections.abc import Mapping

from PyQt6.QtGui import QAction
from qtpy.QtCore import QObject
from typing_extensions import Self
Expand Down
4 changes: 3 additions & 1 deletion src/app_model/backends/qt/_qkeymap.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import operator
from functools import reduce
from typing import TYPE_CHECKING, Mapping, MutableMapping
from typing import TYPE_CHECKING

from qtpy import API, QT_VERSION
from qtpy.QtCore import QCoreApplication, Qt
Expand All @@ -19,6 +19,8 @@
from app_model.types._constants import OperatingSystem

if TYPE_CHECKING:
from collections.abc import Mapping, MutableMapping

from qtpy.QtCore import QKeyCombination

try:
Expand Down
5 changes: 4 additions & 1 deletion src/app_model/backends/qt/_qmainwindow.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from __future__ import annotations

from typing import Collection, Mapping, Sequence
from typing import TYPE_CHECKING

from qtpy.QtCore import Qt
from qtpy.QtWidgets import QMainWindow, QWidget
Expand All @@ -9,6 +9,9 @@

from ._qmenu import QModelMenuBar, QModelToolBar

if TYPE_CHECKING:
from collections.abc import Collection, Mapping, Sequence


class QModelMainWindow(QMainWindow):
"""QMainWindow with app-model support."""
Expand Down
3 changes: 2 additions & 1 deletion src/app_model/backends/qt/_qmenu.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from __future__ import annotations

import contextlib
from typing import TYPE_CHECKING, Collection, Iterable, Mapping, Sequence, cast
from collections.abc import Collection, Iterable, Mapping, Sequence
from typing import TYPE_CHECKING, cast

from qtpy.QtWidgets import QMenu, QMenuBar, QToolBar

Expand Down
4 changes: 3 additions & 1 deletion src/app_model/expressions/_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import os
import sys
from collections import ChainMap
from contextlib import contextmanager
from typing import TYPE_CHECKING, Any, Callable, ChainMap, Iterator, MutableMapping
from typing import TYPE_CHECKING, Any, Callable
from weakref import finalize

from psygnal import Signal

if TYPE_CHECKING:
from collections.abc import Iterator, MutableMapping
from types import FrameType
from typing import TypedDict

Expand Down
2 changes: 1 addition & 1 deletion src/app_model/expressions/_context_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
ClassVar,
Generic,
Literal,
MutableMapping,
NamedTuple,
TypeVar,
overload,
Expand All @@ -19,6 +18,7 @@

if TYPE_CHECKING:
import builtins
from collections.abc import MutableMapping

T = TypeVar("T")
A = TypeVar("A")
Expand Down
12 changes: 3 additions & 9 deletions src/app_model/expressions/_expressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@
Any,
Callable,
Generic,
Iterator,
Mapping,
Sequence,
SupportsIndex,
Type,
TypeVar,
Union,
cast,
Expand All @@ -29,6 +25,7 @@
V = TypeVar("V", bound=ConstType)

if TYPE_CHECKING:
from collections.abc import Iterator, Mapping, Sequence
from types import CodeType

from pydantic.annotated_handlers import GetCoreSchemaHandler
Expand Down Expand Up @@ -507,10 +504,7 @@ class Set(Expr, ast.Set):
`elts` is a list of expressions.
"""

def __init__(
self, elts: Sequence[Expr], ctx: ast.expr_context = LOAD, **kwargs: Any
) -> None:
kwargs["ctx"] = ctx
def __init__(self, elts: Sequence[Expr], **kwargs: Any) -> None:
super().__init__(elts=[Expr._cast(e) for e in elts], **kwargs)


Expand Down Expand Up @@ -643,7 +637,7 @@ def visit_IfExp(self, node: ast.IfExp) -> Any:
self.write(node.body, " if ", node.test, " else ", node.orelse)


OpType = Union[Type[ast.operator], Type[ast.cmpop], Type[ast.boolop], Type[ast.unaryop]]
OpType = Union[type[ast.operator], type[ast.cmpop], type[ast.boolop], type[ast.unaryop]]
_OPS: dict[OpType, str] = {
# ast.boolop
ast.Or: "or",
Expand Down
4 changes: 3 additions & 1 deletion src/app_model/registries/_commands_reg.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from __future__ import annotations

from concurrent.futures import Future, ThreadPoolExecutor
from typing import TYPE_CHECKING, Any, Callable, Generic, Iterator, TypeVar, cast
from typing import TYPE_CHECKING, Any, Callable, Generic, TypeVar, cast

from in_n_out import Store
from psygnal import Signal

# maintain runtime compatibility with older typing_extensions
if TYPE_CHECKING:
from collections.abc import Iterator

from typing_extensions import ParamSpec

from app_model.types import Action, DisposeCallable
Expand Down
3 changes: 2 additions & 1 deletion src/app_model/registries/_keybindings_reg.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from app_model.types import KeyBinding

if TYPE_CHECKING:
from typing import Iterator, TypeVar
from collections.abc import Iterator
from typing import TypeVar

from app_model import expressions
from app_model.types import Action, DisposeCallable, KeyBindingRule
Expand Down
4 changes: 3 additions & 1 deletion src/app_model/registries/_menus_reg.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Any, Callable, Final, Iterable, Iterator
from typing import TYPE_CHECKING, Any, Callable, Final

from psygnal import Signal

from app_model.types import MenuItem

if TYPE_CHECKING:
from collections.abc import Iterable, Iterator

from app_model.types import Action, DisposeCallable, MenuOrSubmenu

MenuId = str
Expand Down
6 changes: 3 additions & 3 deletions src/app_model/types/_action.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import TYPE_CHECKING, Callable, Generic, List, Optional, TypeVar, Union
from typing import TYPE_CHECKING, Callable, Generic, Optional, TypeVar, Union

from pydantic_compat import Field, field_validator

Expand Down Expand Up @@ -39,13 +39,13 @@ class Action(CommandRule, Generic[P, R]):
"`{obj.__module__}:{obj.__qualname__}` "
"(e.g. `my_package.a_module:some_function`)",
)
menus: Optional[List[MenuRule]] = Field(
menus: Optional[list[MenuRule]] = Field(
None,
description="(Optional) Menus to which this action should be added. Note that "
"menu items in the sequence may be supplied as a plain string, which will "
"be converted to a `MenuRule` with the string as the `id` field.",
)
keybindings: Optional[List[KeyBindingRule]] = Field(
keybindings: Optional[list[KeyBindingRule]] = Field(
None,
description="(Optional) Default keybinding(s) that will trigger this command.",
)
Expand Down
3 changes: 2 additions & 1 deletion src/app_model/types/_icon.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Any, Callable, Generator, Optional, TypedDict, Union
from collections.abc import Generator
from typing import Any, Callable, Optional, TypedDict, Union

from pydantic_compat import Field, model_validator

Expand Down
4 changes: 2 additions & 2 deletions src/app_model/types/_keybinding_rule.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Callable, Optional, Type, TypedDict, TypeVar, Union
from typing import Any, Callable, Optional, TypedDict, TypeVar, Union

from pydantic_compat import PYDANTIC2, Field, model_validator

Expand Down Expand Up @@ -69,7 +69,7 @@ def _bind_to_current_platform(self) -> Optional[KeyEncoding]:
@model_validator(mode="wrap")
@classmethod
def _model_val(
cls: Type[M], v: Any, handler: Callable[[Any], M]
cls: type[M], v: Any, handler: Callable[[Any], M]
) -> "KeyBindingRule":
if isinstance(v, StandardKeyBinding):
return v.to_keybinding_rule()
Expand Down
Loading