Enable pyupgrade rules in ruff

This commit is contained in:
Dan Yeaw 2024-10-14 20:43:12 -04:00
parent 7f6ab8d4f6
commit 047293f6d5
No known key found for this signature in database
GPG Key ID: 86B9FEF88B780F2B
81 changed files with 207 additions and 250 deletions

View File

@ -1,6 +1,6 @@
"""C4 Model Language entrypoint."""
from typing import Iterable
from collections.abc import Iterable
from gaphor.abc import ModelingLanguage
from gaphor.C4Model import c4model, diagramitems

View File

@ -1,5 +1,3 @@
from typing import Union
from gaphor.C4Model import c4model
from gaphor.core import Transaction
from gaphor.diagram.propertypages import (
@ -22,9 +20,7 @@ PropertyPages.register(c4model.C4Dependency, NamePropertyPage)
class DescriptionPropertyPage(PropertyPageBase):
order = 14
def __init__(
self, subject: Union[c4model.C4Container, c4model.C4Person], event_manager
):
def __init__(self, subject: c4model.C4Container | c4model.C4Person, event_manager):
super().__init__()
assert subject
self.subject = subject

View File

@ -1,7 +1,7 @@
"""The RAAML Modeling Language module is the entrypoint for RAAML related
assets."""
from typing import Iterable
from collections.abc import Iterable
from gaphor.abc import ModelingLanguage
from gaphor.core import gettext

View File

@ -1,5 +1,3 @@
from typing import Union
from gaphas.connector import Handle, Port
from gaphor import UML
@ -18,7 +16,7 @@ from gaphor.UML.deployments import ConnectorItem
class BlockProperyProxyPortConnector:
def __init__(
self,
block_or_property: Union[BlockItem, PropertyItem, InterfaceBlockItem],
block_or_property: BlockItem | PropertyItem | InterfaceBlockItem,
proxy_port: ProxyPortItem,
) -> None:
self.element = block_or_property
@ -71,14 +69,14 @@ class PropertyConnectorConnector(RelationshipConnect):
"""Connect a Connector to a Port or Property."""
line: ConnectorItem
element: Union[PropertyItem, ProxyPortItem]
element: PropertyItem | ProxyPortItem
def allow(self, handle, port):
element = self.element
# Element should be connected -> have a subject
return super().allow(handle, port) and isinstance(
element.subject, (UML.Port, UML.Property)
element.subject, UML.Port | UML.Property
)
def connect_subject(self, handle):

View File

@ -1,7 +1,7 @@
"""The SysML Modeling Language module is the entrypoint for SysML related
assets."""
from typing import Iterable
from collections.abc import Iterable
from gaphor.abc import ModelingLanguage
from gaphor.core import gettext

View File

@ -49,7 +49,7 @@ def test_all_named_elements_have_named_items(item_class, element_class):
assert issubclass(item_class, Named)
if issubclass(item_class, Named):
assert issubclass(element_class, (NamedElement, Relationship))
assert issubclass(element_class, NamedElement | Relationship)
CLASSIFIED_EXCLUSIONS = []

View File

@ -1,7 +1,5 @@
"""Flow item adapter connections."""
from typing import Type, Union
from gaphor import UML
from gaphor.core.modeling import swap_element_type
from gaphor.diagram.connectors import Connector, RelationshipConnect
@ -25,7 +23,7 @@ from gaphor.UML.actions.pin import InputPinItem, OutputPinItem
class FlowConnect(RelationshipConnect):
"""Connect FlowItem and Action, initial/final nodes."""
line: Union[ControlFlowItem, ObjectFlowItem]
line: ControlFlowItem | ObjectFlowItem
def allow(self, handle, port):
line = self.line
@ -33,9 +31,9 @@ class FlowConnect(RelationshipConnect):
if (
handle is line.head
and isinstance(subject, (UML.FinalNode, UML.InputPin))
and isinstance(subject, UML.FinalNode | UML.InputPin)
or handle is line.tail
and isinstance(subject, (UML.InitialNode, UML.OutputPin))
and isinstance(subject, UML.InitialNode | UML.OutputPin)
):
return False
@ -65,7 +63,7 @@ class FlowConnect(RelationshipConnect):
element_type = get_model_element(type(line))
metadata = get_diagram_item_metadata(type(line))
relation: Union[UML.ControlFlow, UML.ObjectFlow] = self.relationship_or_new(
relation: UML.ControlFlow | UML.ObjectFlow = self.relationship_or_new(
element_type, metadata["head"], metadata["tail"]
)
@ -81,8 +79,8 @@ class FlowConnect(RelationshipConnect):
otc = self.get_connected(opposite)
if (
opposite
and (isinstance(line, (ControlFlowItem, ObjectFlowItem)))
and isinstance(otc, (ForkNodeItem, DecisionNodeItem))
and (isinstance(line, ControlFlowItem | ObjectFlowItem))
and isinstance(otc, ForkNodeItem | DecisionNodeItem)
):
adapter = Connector(otc, line)
adapter.combine_nodes()
@ -94,8 +92,8 @@ class FlowConnect(RelationshipConnect):
otc = self.get_connected(opposite)
if (
opposite
and (isinstance(line, (ControlFlowItem, ObjectFlowItem)))
and isinstance(otc, (ForkNodeItem, DecisionNodeItem))
and (isinstance(line, ControlFlowItem | ObjectFlowItem))
and isinstance(otc, ForkNodeItem | DecisionNodeItem)
):
adapter = Connector(otc, line)
adapter.decombine_nodes()
@ -120,9 +118,9 @@ class FlowForkDecisionNodeFlowConnect(FlowConnect):
"""Abstract class with common behaviour for Fork/Join node and
Decision/Merge node."""
element: Union[ForkNodeItem, DecisionNodeItem]
fork_node_cls: Type[UML.ControlNode]
join_node_cls: Type[UML.ControlNode]
element: ForkNodeItem | DecisionNodeItem
fork_node_cls: type[UML.ControlNode]
join_node_cls: type[UML.ControlNode]
def allow(self, handle, port):
# No cyclic connect is possible on a Flow/Decision node:

View File

@ -31,7 +31,7 @@ class ActionPinConnector:
UML.InputPin if isinstance(pin, InputPinItem) else UML.OutputPin
)
assert isinstance(pin.subject, (UML.InputPin, UML.OutputPin))
assert isinstance(pin.subject, UML.InputPin | UML.OutputPin)
pin.subject.opaqueAction = self.action.subject
# This raises the item in the item hierarchy

View File

@ -9,7 +9,6 @@ Plan:
from dataclasses import replace
from math import pi
from typing import Optional
from gaphas.connector import Handle
from gaphas.geometry import Rectangle, distance_rectangle_point
@ -328,7 +327,7 @@ class AssociationEnd:
be recreated by the owning Association.
"""
def __init__(self, owner: AssociationItem, end: Optional[str] = None):
def __init__(self, owner: AssociationItem, end: str | None = None):
self._canvas = None
self._owner = owner
self._end = end
@ -358,7 +357,7 @@ class AssociationEnd:
return self._owner.head if self is self._owner.head_end else self._owner.tail
@property
def subject(self) -> Optional[UML.Property]:
def subject(self) -> UML.Property | None:
return getattr(self.owner, f"{self._end}_subject") # type:ignore[no-any-return]
@property

View File

@ -55,7 +55,7 @@ class NamedElementPropertyPage(NamePropertyPage):
not self.subject
or UML.recipes.is_metaclass(self.subject)
or isinstance(
self.subject, (UML.ActivityPartition, UML.ActivityParameterNode)
self.subject, UML.ActivityPartition | UML.ActivityParameterNode
)
):
return

View File

@ -31,7 +31,7 @@ class ContainmentConnect(BaseConnector):
return super().allow(handle, port) and (
isinstance(container, UML.Package)
and isinstance(contained, (UML.Type, UML.Package))
and isinstance(contained, UML.Type | UML.Package)
or isinstance(container, UML.Package)
and isinstance(contained, (Diagram))
or isinstance(container, UML.Class)
@ -59,11 +59,11 @@ class ContainmentConnect(BaseConnector):
if hct and oct:
if oct.subject and hct.subject in oct.subject.ownedElement:
assert isinstance(hct.subject, (UML.Type, UML.Package))
assert isinstance(hct.subject, UML.Type | UML.Package)
ungroup(oct.subject, hct.subject)
hct.subject.package = owner_package(hct.diagram.owner)
if hct.subject and oct.subject in hct.subject.ownedElement:
assert isinstance(oct.subject, (UML.Type, UML.Package))
assert isinstance(oct.subject, UML.Type | UML.Package)
ungroup(hct.subject, oct.subject)
oct.subject.package = owner_package(oct.diagram.owner)

View File

@ -1,4 +1,4 @@
from typing import Callable
from collections.abc import Callable
from gaphas.geometry import Rectangle

View File

@ -1,6 +1,7 @@
from __future__ import annotations
from typing import Iterator, NamedTuple
from collections.abc import Iterator
from typing import NamedTuple
from gaphor.core.modeling.element import Id
from gaphor.diagram.copypaste import (

View File

@ -4,8 +4,6 @@ Implemented using interface item in assembly connector mode, see
`gaphor.diagram.connector` module for details.
"""
from typing import Union
from gaphor import UML
from gaphor.diagram.connectors import BaseConnector, Connector
from gaphor.UML.classes.component import ComponentItem
@ -22,7 +20,7 @@ class LegacyConnectorConnectBase(BaseConnector):
palette.
"""
element: Union[ComponentItem, InterfaceItem]
element: ComponentItem | InterfaceItem
line: ConnectorItem
def get_connecting(self, iface, both=False):

View File

@ -1,7 +1,5 @@
"""Message item connection adapters."""
from typing import Optional
from gaphor import UML
from gaphor.core.modeling import Element, Presentation
from gaphor.diagram.connectors import BaseConnector, Connector
@ -12,7 +10,7 @@ from gaphor.UML.interactions.lifeline import LifelineItem
from gaphor.UML.interactions.message import MessageItem
def get_connected(item, handle) -> Optional[Presentation[Element]]:
def get_connected(item, handle) -> Presentation[Element] | None:
"""Get item connected to a handle."""
if cinfo := item.diagram.connections.get_connection(handle):
return cinfo.connected # type: ignore[no-any-return] # noqa: F723
@ -145,7 +143,7 @@ class MessageLifelineConnect(BaseConnector):
def disconnect(self, handle):
line = self.line
send: Optional[Presentation[Element]] = get_connected(line, line.head)
send: Presentation[Element] | None = get_connected(line, line.head)
received = self.get_connected(line.tail)
# if a message is a deleted message, then the disconnection causes
@ -248,7 +246,7 @@ class ExecutionSpecificationExecutionSpecificationConnect(BaseConnector):
# Can connect child exec spec if parent is not connected
return True
connected_item: Optional[Presentation[Element]]
connected_item: Presentation[Element] | None
connected_item = self.get_connected(self.element.handles()[0])
assert connected_item
Connector(connected_item, self.line).connect(handle, None)

View File

@ -1,7 +1,7 @@
"""The UML Modeling Language module is the entrypoint for UML related
assets."""
from typing import Iterable
from collections.abc import Iterable
from gaphor.abc import ModelingLanguage
from gaphor.core import gettext

View File

@ -9,7 +9,8 @@ Functions collected in this module allow to
from __future__ import annotations
import itertools
from typing import Iterable, Sequence, TypeVar
from collections.abc import Iterable, Sequence
from typing import TypeVar
from gaphor.UML.uml import (
Artifact,

View File

@ -1,7 +1,7 @@
"""The Sanitize module is dedicated to adapters (stuff) that keeps the model
clean and in sync with diagrams."""
from typing import Iterable
from collections.abc import Iterable
from gaphor import UML
from gaphor.abc import Service

View File

@ -61,7 +61,7 @@ def test_all_named_elements_have_named_items(item_class, element_class):
assert issubclass(item_class, Named)
if issubclass(item_class, Named):
assert issubclass(element_class, (NamedElement, Relationship))
assert issubclass(element_class, NamedElement | Relationship)
CLASSIFIED_EXCLUSIONS = [

View File

@ -72,9 +72,9 @@ def test_class(factory):
assert (
operation1 in element.feature
), f"Classifier.feature does not contain ownedOperation - {element.feature}"
assert operation1 in element.ownedMember, (
"Namespace.ownedMember does not contain ownedOperation" % element.ownedMember
)
assert (
operation1 in element.ownedMember
), "Namespace.ownedMember does not contain ownedOperation".format()
def test_comment(factory):

View File

@ -1,7 +1,6 @@
"""Formatting of UML elements like attributes, operations, stereotypes, etc."""
import re
from typing import Tuple
from gaphor.core.format import format
from gaphor.i18n import gettext
@ -70,7 +69,7 @@ def format_property(
tag_vals.extend(format(slot) for slot in el.appliedStereotype[:].slot if slot)
if tag_vals:
s.append(" { %s }" % ", ".join(tag_vals))
s.append(" {{ {} }}".format(", ".join(tag_vals)))
if note and el.note:
s.append(f" # {el.note}")
@ -78,7 +77,7 @@ def format_property(
return "".join(s)
def format_association_end(el) -> Tuple[str, str]:
def format_association_end(el) -> tuple[str, str]:
"""Format association end."""
name = ""
if el.name:
@ -91,7 +90,7 @@ def format_association_end(el) -> Tuple[str, str]:
m = [format_multiplicity(el, bare=True)]
if slots := [format(slot) for slot in el.appliedStereotype[:].slot if slot]:
m.append(" { %s }" % ",\n".join(slots))
m.append(" {{ {} }}".format(",\n".join(slots)))
mult = "".join(m)
return name, mult

View File

@ -62,8 +62,8 @@ def property_navigability(self: uml.Property) -> list[bool | None]:
return [None] # assume unknown
owner = self.opposite.type
if (
isinstance(owner, (uml.Class, uml.DataType, uml.Interface))
and isinstance(self.type, (uml.Class, uml.DataType, uml.Interface))
isinstance(owner, uml.Class | uml.DataType | uml.Interface)
and isinstance(self.type, uml.Class | uml.DataType | uml.Interface)
and (self in owner.ownedAttribute)
or self in assoc.navigableOwnedEnd
):

View File

@ -1,7 +1,8 @@
from __future__ import annotations
import abc
from typing import TYPE_CHECKING, Iterable
from collections.abc import Iterable
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from gaphor.core.modeling import Element

View File

@ -2,7 +2,8 @@
from __future__ import annotations
from typing import Any, Callable, Iterator, get_type_hints
from collections.abc import Callable, Iterator
from typing import Any, get_type_hints
class action:

View File

@ -8,8 +8,9 @@ from __future__ import annotations
import importlib.metadata
import logging
from collections.abc import Iterator
from pathlib import Path
from typing import Iterator, TypeVar, cast
from typing import TypeVar, cast
from uuid import uuid1
from gaphor.abc import ActionProvider, Service

View File

@ -27,8 +27,8 @@ import contextlib
import logging
import sys
import textwrap
from collections.abc import Iterable
from pathlib import Path
from typing import Iterable
from gaphor import UML
from gaphor.codegen.override import Overrides

View File

@ -9,7 +9,6 @@ This is a simple rip-off of the override script used in PyGTK.
# ruff: noqa: T201
import re
from typing import List
OVERRIDE_RE = re.compile(
r"^override\s+(?P<name>[\w.]+)(?:\((?P<derived>[^)]+)\))?\s*(?::\s*(?P<type_hint>[\w\s\[\],\"| ]+))?$"
@ -35,7 +34,7 @@ class Overrides:
# bufs contains a list of (lines, line_number) pairs.
bufs = []
line_number = 1
lines: List[str] = []
lines: list[str] = []
line = fp.readline()
linenum = 1
while line:

View File

@ -1,7 +1,7 @@
from __future__ import annotations
from collections.abc import Iterable
from operator import setitem
from typing import Iterable
from gaphor.core.modeling import (
Element,

View File

@ -3,7 +3,8 @@
from __future__ import annotations
import contextlib
from typing import Generic, Iterator, Sequence, Type, TypeVar, overload
from collections.abc import Iterator, Sequence
from typing import Generic, TypeVar, overload
from gaphor.core.modeling.event import AssociationUpdated
@ -13,7 +14,7 @@ T = TypeVar("T")
class collection(Generic[T]):
"""Collection (set-like) for model elements' 1:n and n:m relationships."""
def __init__(self, property, object, type: Type[T]):
def __init__(self, property, object, type: type[T]):
self.property = property
self.object = object
self.type = type

View File

@ -80,7 +80,7 @@ class DrawContext:
dropzone: bool
@lru_cache()
@lru_cache
def attrname(obj, lower_name):
"""Look up a real attribute name based on a lower case (normalized)
name."""
@ -94,7 +94,7 @@ def rgetattr(obj, names):
"""Recursively get a name, based on a list of names."""
name, *tail = names
v = getattr(obj, attrname(obj, name), NO_ATTR)
if isinstance(v, (collection, list, tuple)):
if isinstance(v, collection | list | tuple):
if tail and not v:
yield NO_ATTR
if tail:
@ -112,7 +112,7 @@ def attrstr(obj):
"""Returns lower-case string representation of an attribute."""
if isinstance(obj, str):
return obj.lower()
elif isinstance(obj, (bool, int)):
elif isinstance(obj, bool | int):
return "true" if obj else ""
elif isinstance(obj, Element):
return obj.__class__.__name__.lower()

View File

@ -4,7 +4,8 @@
from __future__ import annotations
import logging
from typing import TYPE_CHECKING, Callable, Iterator, Protocol, TypeVar, overload
from collections.abc import Callable, Iterator
from typing import TYPE_CHECKING, Protocol, TypeVar, overload
from uuid import uuid1
from gaphor.core.modeling.collection import collection

View File

@ -242,17 +242,14 @@ class ElementDispatcher(Service):
# Handle add/removal of handlers based on the kind of event
# Filter out handlers that have no remaining properties
if (
isinstance(event, (AssociationSet, AssociationDeleted))
isinstance(event, AssociationSet | AssociationDeleted)
and event.old_value
):
for handler, remainders in handlers.items():
for remainder in remainders:
self._remove_handlers(event.old_value, remainder[0], handler)
if (
isinstance(event, (AssociationSet, AssociationAdded))
and event.new_value
):
if isinstance(event, AssociationSet | AssociationAdded) and event.new_value:
for handler, remainders in handlers.items():
for remainder in remainders:
self._add_handlers(event.new_value, remainder, handler)

View File

@ -3,8 +3,9 @@
from __future__ import annotations
from collections import OrderedDict
from collections.abc import Callable, Iterator
from contextlib import contextmanager
from typing import Callable, Iterator, Protocol, TypeVar, overload
from typing import Protocol, TypeVar, overload
from gaphor.abc import Service
from gaphor.core.eventmanager import EventManager, event_handler

View File

@ -26,16 +26,13 @@ methods:
from __future__ import annotations
import logging
from collections.abc import Callable, Iterable, Sequence
from typing import (
Any,
Callable,
Generic,
Iterable,
Literal,
Protocol,
Sequence,
TypeVar,
Union,
overload,
)
@ -100,12 +97,12 @@ class relation_many(Protocol[E]):
def __delete__(self, obj) -> None: ...
relation = Union[relation_one, relation_many]
relation = relation_one | relation_many
T = TypeVar("T")
Lower = Union[Literal[0], Literal[1], Literal[2]]
Upper = Union[Literal[1], Literal[2], Literal["*"]]
Lower = Literal[0] | Literal[1] | Literal[2]
Upper = Literal[1] | Literal[2] | Literal["*"]
class umlproperty:
@ -210,7 +207,7 @@ class attribute(umlproperty, Generic[T]):
or self.type
)
if self.type is int and isinstance(value, (str, bool)):
if self.type is int and isinstance(value, str | bool):
value = 0 if value == "False" else 1 if value == "True" else int(value)
if value == self.get(obj):
@ -439,7 +436,7 @@ class association(umlproperty):
self.stub = associationstub(self)
# Do not let property start with underscore, or it will not be found
# as an umlproperty.
setattr(self.type, "GAPHOR__associationstub__%x" % id(self), self.stub)
setattr(self.type, f"GAPHOR__associationstub__{id(self):x}", self.stub)
self.stub.set(value, obj)
def delete(self, obj, value, from_opposite=False, do_notify=True):
@ -519,7 +516,7 @@ class associationstub(umlproperty):
"""
def __init__(self, association: association):
super().__init__("stub_%x" % id(self))
super().__init__(f"stub_{id(self):x}")
self.association = association
def __get__(self, obj, class_=None):
@ -605,7 +602,7 @@ class derived(umlproperty, Generic[T]):
def add(self, subset):
self.subsets.add(subset)
assert isinstance(
subset, (association, derived)
subset, association | derived
), f"have element {subset}, expected association"
subset.dependent_properties.add(self)
@ -814,7 +811,7 @@ class redefine(umlproperty):
):
super().__init__(name)
assert isinstance(
original, (association, derived)
original, association | derived
), f"expected association or derived, got {original}"
self.decl_class = decl_class
self.type = type

View File

@ -164,12 +164,12 @@ def test_association_1_n():
b2 = B()
b1.two = a1
assert len(b1.two) == 1, "len(b1.two) == %d" % len(b1.two)
assert len(b1.two) == 1, f"len(b1.two) == {len(b1.two)}"
assert a1 in b1.two
assert a1.one is b1, f"{a1.one}/{b1}"
b1.two = a1
b1.two = a1
assert len(b1.two) == 1, "len(b1.two) == %d" % len(b1.two)
assert len(b1.two) == 1, f"len(b1.two) == {len(b1.two)}"
assert a1 in b1.two
assert a1.one is b1, f"{a1.one}/{b1}"

View File

@ -1,8 +1,8 @@
from __future__ import annotations
import functools
from collections.abc import Hashable
from typing import Callable, Iterator, Protocol, Sequence, TypedDict, Union
from collections.abc import Callable, Hashable, Iterator, Sequence
from typing import Protocol, TypedDict
from gaphor.core.styling.compiler import compile_style_sheet
from gaphor.core.styling.declarations import (
@ -38,7 +38,7 @@ Style = TypedDict(
"dash-style": Sequence[Number],
"padding": Padding,
"font-family": str,
"font-size": Union[int, float, str],
"font-size": int | float | str,
"font-style": FontStyle,
"font-weight": FontWeight,
"justify-content": JustifyContent,

View File

@ -5,8 +5,9 @@ Ayoub.
"""
import re
from collections.abc import Callable, Iterator
from functools import singledispatch
from typing import Callable, Dict, Iterator, Literal, Tuple, Union
from typing import Literal
import tinycss2
@ -17,10 +18,10 @@ from gaphor.core.styling.declarations import parse_declarations
split_whitespace = re.compile("[^ \t\r\n\f]+").findall
Rule = Union[
Tuple[Callable[[object], bool], Dict[str, object]],
Tuple[Literal["error"], Union[tinycss2.ast.ParseError, selectors.SelectorError]],
]
Rule = (
tuple[Callable[[object], bool], dict[str, object]]
| tuple[Literal["error"], tinycss2.ast.ParseError | selectors.SelectorError]
)
def compile_style_sheet(*css: str) -> Iterator[Rule]:

View File

@ -1,15 +1,16 @@
"""Definitions (types) for style sheets."""
from collections.abc import Callable, Sequence
from enum import Enum
from typing import Callable, Dict, List, NamedTuple, Optional, Sequence, Tuple, Union
from typing import NamedTuple
import tinycss2.color3
from tinycss2.ast import FunctionBlock
from tinycss2.parser import parse_declaration_list
Number = Union[int, float]
Color = Tuple[float, float, float, float] # RGBA
Padding = Tuple[Number, Number, Number, Number] # top/right/bottom/left
Number = int | float
Color = tuple[float, float, float, float] # RGBA
Padding = tuple[Number, Number, Number, Number] # top/right/bottom/left
class TextAlign(Enum):
@ -82,9 +83,7 @@ class _Declarations:
"""Convert raw CSS declarations into Gaphor styling declarations."""
def __init__(self) -> None:
self.declarations: List[
Tuple[str, Callable[[str, object], Optional[object]]]
] = []
self.declarations: list[tuple[str, Callable[[str, object], object | None]]] = []
def register(self, *properties):
def reg(func):
@ -162,19 +161,19 @@ def parse_color(prop, value):
"vertical-spacing",
"border-radius",
)
def parse_positive_number(prop, value) -> Optional[Number]:
def parse_positive_number(prop, value) -> Number | None:
return value if isinstance(value, number) and value >= 0 else None
@declarations.register(
"opacity",
)
def parse_factor(prop, value) -> Optional[Number]:
def parse_factor(prop, value) -> Number | None:
return value if isinstance(value, number) and 0 <= value <= 1 else None
@declarations.register("font-family")
def parse_string(prop, value) -> Optional[str]:
def parse_string(prop, value) -> str | None:
if isinstance(value, str):
return value
elif value:
@ -183,14 +182,14 @@ def parse_string(prop, value) -> Optional[str]:
@declarations.register("font-size")
def parse_font_size(prop, value) -> Union[None, int, float, str]:
def parse_font_size(prop, value) -> None | int | float | str:
if isinstance(value, number) and value > 0:
return value
return value if isinstance(value, str) and value in FONT_SIZE_VALUES else None
@declarations.register("padding")
def parse_padding(prop, value) -> Optional[Padding]:
def parse_padding(prop, value) -> Padding | None:
if isinstance(value, number):
return (value, value, value, value)
n = len(value)
@ -207,18 +206,18 @@ def parse_padding(prop, value) -> Optional[Padding]:
@declarations.register("dash-style")
def parse_sequence_numbers(
prop, value: Union[Number, Sequence[Number]]
) -> Optional[Sequence[Number]]:
prop, value: Number | Sequence[Number]
) -> Sequence[Number] | None:
if value == 0:
return ()
if isinstance(value, number):
return (value, value)
elif all(isinstance(v, (int, float)) for v in value):
elif all(isinstance(v, int | float) for v in value):
return value
return None
enum_styles: Dict[str, Dict[str, object]] = {
enum_styles: dict[str, dict[str, object]] = {
"font-style": {e.value: e for e in FontStyle},
"font-weight": {e.value: e for e in FontWeight},
"justify-content": {e.value: e for e in JustifyContent},

View File

@ -1,4 +1,4 @@
from typing import Iterator, Sequence
from collections.abc import Iterator, Sequence
from gaphor.core.styling import CompiledStyleSheet, Style, StyleNode

View File

@ -298,7 +298,7 @@ class CombinedSelector:
return a1 + a2, b1 + b2, c1 + c2
def __repr__(self):
return "{!r}{}{!r}".format(self.left, self.combinator, self.right)
return f"{self.left!r}{self.combinator}{self.right!r}"
class CompoundSelector:
@ -347,7 +347,7 @@ class NamespaceSelector:
self.namespace = namespace
def __repr__(self):
return "|" if self.namespace == "" else "{%s}|" % self.namespace
return "|" if self.namespace == "" else f"{{{self.namespace}}}|"
class IDSelector:
@ -382,8 +382,8 @@ class AttributeSelector:
self.value = value
def __repr__(self):
namespace = "*|" if self.namespace is None else "{%s}" % self.namespace
return "[{}{}{}{!r}]".format(namespace, self.name, self.operator, self.value)
namespace = "*|" if self.namespace is None else f"{{{self.namespace}}}"
return f"[{namespace}{self.name}{self.operator}{self.value!r}]"
class PseudoClassSelector:
@ -414,4 +414,4 @@ class FunctionalPseudoClassSelector:
self.arguments = arguments
def __repr__(self):
return ":{}{!r}".format(self.name, tuple(self.arguments))
return f":{self.name}{tuple(self.arguments)!r}"

View File

@ -8,7 +8,8 @@ from __future__ import annotations
import functools
import itertools
from typing import Iterator, Protocol, TypeVar
from collections.abc import Iterator
from typing import Protocol, TypeVar
from gaphas.connections import Connection
from gaphas.connector import ConnectionSink, Handle, Port
@ -129,7 +130,7 @@ Connector: FunctionDispatcher[type[ConnectorProtocol]] = multidispatch(object, o
)
@functools.lru_cache()
@functools.lru_cache
def can_connect(parent, element_type) -> bool:
parent_type = type(parent)
get_registration = Connector.registry.get_registration
@ -170,8 +171,8 @@ class RelationshipConnect(BaseConnector):
head - tuple (association name on the line, association name on the element)
tail - tuple (association name on the line, association name on the element)
"""
assert isinstance(head, (association, redefine)), f"head is {head}"
assert isinstance(tail, (association, redefine)), f"tail is {tail}"
assert isinstance(head, association | redefine), f"head is {head}"
assert isinstance(tail, association | redefine), f"tail is {tail}"
line = self.line

View File

@ -21,9 +21,9 @@ complete the model loading.
from __future__ import annotations
from collections.abc import Iterable
from collections.abc import Callable, Collection, Iterable, Iterator
from functools import singledispatch
from typing import Callable, Collection, Iterator, NamedTuple
from typing import NamedTuple
from gaphor.core.modeling import Diagram, Presentation
from gaphor.core.modeling.collection import collection

View File

@ -7,14 +7,9 @@ the actions bound to the toolbuttons should change as well.
import getpass
import time
from collections.abc import Callable, Collection, Sequence
from typing import (
Callable,
Collection,
NamedTuple,
Optional,
Sequence,
Tuple,
Type,
TypeVar,
)
@ -25,7 +20,7 @@ from gaphor.core.modeling import Comment, Diagram, Element, Picture, Presentatio
from gaphor.diagram import general
from gaphor.diagram.group import group
ItemFactory = Callable[[Diagram, Optional[Presentation]], Presentation]
ItemFactory = Callable[[Diagram, Presentation | None], Presentation]
P = TypeVar("P", bound=Presentation, covariant=True)
ConfigFuncType = Callable[[P], None]
@ -34,8 +29,8 @@ class ToolDef(NamedTuple):
id: str
name: str
icon_name: str
shortcut: Optional[str]
item_factory: Optional[ItemFactory]
shortcut: str | None
item_factory: ItemFactory | None
handle_index: int = -1
@ -57,7 +52,7 @@ class DiagramType:
self.name = name
self.sections = sections
def allowed(self, element: Type[Element]) -> bool:
def allowed(self, element: type[Element]) -> bool:
return True
def create(self, element_factory, element):
@ -75,11 +70,11 @@ DiagramTypes = Sequence[DiagramType]
class ElementCreateInfo(NamedTuple):
id: str
name: str
element_type: Type[Element]
allowed_owning_elements: Collection[Type[Element]]
element_type: type[Element]
allowed_owning_elements: Collection[type[Element]]
def tooliter(toolbox_actions: Sequence[Tuple[str, Sequence[ToolDef]]]):
def tooliter(toolbox_actions: Sequence[tuple[str, Sequence[ToolDef]]]):
"""Iterate toolbox items, regardless of section headers."""
for _name, section in toolbox_actions:
yield from section
@ -92,9 +87,9 @@ def get_tool_def(modeling_language, tool_name):
def new_item_factory(
item_class: Type[Presentation],
subject_class: Optional[Type[Element]] = None,
config_func: Optional[ConfigFuncType] = None,
item_class: type[Presentation],
subject_class: type[Element] | None = None,
config_func: ConfigFuncType | None = None,
):
"""``config_func`` may be a function accepting the newly created item."""

View File

@ -1,7 +1,7 @@
from __future__ import annotations
import logging
from typing import Callable
from collections.abc import Callable
from gaphas.geometry import Rectangle
from gaphas.item import NW, SE

View File

@ -1,7 +1,6 @@
"""Connect comments."""
import logging
from typing import Union
from gaphor.core.modeling import Comment
from gaphor.diagram.connectors import BaseConnector, Connector
@ -17,7 +16,7 @@ logger = logging.getLogger(__name__)
class CommentLineElementConnect(BaseConnector):
"""Connect a comment line to any element item."""
element: Union[CommentItem, ElementPresentation]
element: CommentItem | ElementPresentation
line: CommentLineItem
def allow(self, handle, port):

View File

@ -9,7 +9,7 @@
from __future__ import annotations
import itertools
from typing import Callable
from collections.abc import Callable
from generic.multidispatch import FunctionDispatcher, multidispatch

View File

@ -8,7 +8,7 @@ from __future__ import annotations
import abc
import textwrap
from typing import Iterator
from collections.abc import Iterator
import gaphas.item
from gaphas.segment import Segment

View File

@ -1,4 +1,4 @@
from typing import Iterable, Optional, Set
from collections.abc import Iterable
from gaphas.item import Item
from gaphas.selection import Selection as _Selection
@ -7,8 +7,8 @@ from gaphas.selection import Selection as _Selection
class Selection(_Selection):
def __init__(self):
super().__init__()
self._dropzone_item: Optional[Item] = None
self._grayed_out_items: Set[Item] = set()
self._dropzone_item: Item | None = None
self._grayed_out_items: set[Item] = set()
def clear(self):
self._dropzone_item = None
@ -16,16 +16,16 @@ class Selection(_Selection):
super().clear()
@property
def dropzone_item(self) -> Optional[Item]:
def dropzone_item(self) -> Item | None:
return self._dropzone_item
@dropzone_item.setter
def dropzone_item(self, item: Optional[Item]) -> None:
def dropzone_item(self, item: Item | None) -> None:
if item is not self._dropzone_item:
self._dropzone_item = item
@property
def grayed_out_items(self) -> Set[Item]:
def grayed_out_items(self) -> set[Item]:
return self._grayed_out_items
@grayed_out_items.setter

View File

@ -1,11 +1,11 @@
from __future__ import annotations
import math
from collections.abc import Iterable, Iterator, Sequence
from collections.abc import Callable, Iterable, Iterator, Sequence
from dataclasses import replace
from enum import Enum
from math import pi
from typing import Callable, Protocol
from typing import Protocol
from gaphas.geometry import Rectangle

View File

@ -1,7 +1,5 @@
"""For ease of creation, maintain a mapping from Element to Diagram Item."""
from typing import Dict
from gaphor.core.modeling import Element, Presentation
@ -16,8 +14,8 @@ def represents(uml_element, **metadata):
# Map elements to their (default) representation.
_element_to_item_map: Dict[type[Element], type[Presentation]] = {}
_item_to_metadata_map: Dict[type[Presentation], dict[str, object]] = {}
_element_to_item_map: dict[type[Element], type[Presentation]] = {}
_item_to_metadata_map: dict[type[Presentation], dict[str, object]] = {}
def get_diagram_item(element_cls: type[Element]) -> type[Presentation] | None:

View File

@ -1,5 +1,3 @@
from typing import Optional
from gaphas.connector import Handle
from gaphas.guide import GuidedItemHandleMoveMixin
from gaphas.handlemove import ConnectionSinkType, HandleMove, ItemHandleMove
@ -43,7 +41,7 @@ class GrayOutLineHandleMoveMixin:
def glue(
self, pos: Pos, distance: int = ItemHandleMove.GLUE_DISTANCE
) -> Optional[ConnectionSinkType]:
) -> ConnectionSinkType | None:
sink = super().glue(pos, distance) # type: ignore[misc]
self.view.selection.dropzone_item = sink and sink.item
return sink

View File

@ -1,5 +1,4 @@
import logging
from typing import Optional
from gaphas.decorators import g_async
from gaphas.handlemove import HandleMove
@ -23,7 +22,7 @@ class PlacementState:
self.factory = factory
self.event_manager = event_manager
self.handle_index = handle_index
self.moving: Optional[MoveType] = None
self.moving: MoveType | None = None
def placement_tool(factory: ItemFactory, event_manager, handle_index: int):

View File

@ -1,7 +1,7 @@
from __future__ import annotations
import logging
from typing import Iterable
from collections.abc import Iterable
from gi.repository import Gtk

View File

@ -2,14 +2,14 @@ import functools
import importlib.metadata
import inspect
import logging
from typing import Dict, TypeVar
from typing import TypeVar
T = TypeVar("T")
logger = logging.getLogger(__name__)
def initialize(scope, services=None, **known_services: T) -> Dict[str, T]:
def initialize(scope, services=None, **known_services: T) -> dict[str, T]:
return init_entry_points(load_entry_points(scope, services), **known_services)
@ -18,7 +18,7 @@ def list_entry_points(group):
return importlib.metadata.entry_points(group=group)
def load_entry_points(scope, services=None) -> Dict[str, type]:
def load_entry_points(scope, services=None) -> dict[str, type]:
"""Load services from resources."""
uninitialized_services = {}
for ep in list_entry_points(scope):
@ -30,15 +30,15 @@ def load_entry_points(scope, services=None) -> Dict[str, type]:
def init_entry_points(
uninitialized_services: Dict[str, type[T]], **known_services: T
) -> Dict[str, T]:
uninitialized_services: dict[str, type[T]], **known_services: T
) -> dict[str, T]:
"""Instantiate service definitions, taking into account dependencies
defined in the constructor.
Given a dictionary `{name: service-class}`, return a map `{name:
service-instance}`.
"""
ready: Dict[str, T] = known_services.copy()
ready: dict[str, T] = known_services.copy()
def pop(name):
try:

View File

@ -1,7 +1,7 @@
from __future__ import annotations
from collections.abc import Iterable, Iterator
from functools import singledispatch
from typing import Iterable, Iterator
import pydot
from gaphas.connector import ConnectionSink, Connector

View File

@ -14,7 +14,6 @@ import code
import sys
import textwrap
import traceback
from typing import Dict, List
import jedi
from gi.repository import Gdk, GLib, Gtk, Pango
@ -152,7 +151,7 @@ class GTKInterpreterConsole(Gtk.ScrolledWindow):
__gtype_name__ = "GTKInterpreterConsole"
def __init__(self, locals: Dict[str, object], banner=banner):
def __init__(self, locals: dict[str, object], banner=banner):
Gtk.ScrolledWindow.__init__(self)
self.set_vexpand(True)
@ -165,8 +164,8 @@ class GTKInterpreterConsole(Gtk.ScrolledWindow):
self.interpreter = code.InteractiveInterpreter(locals)
self.locals = locals
self.buffer: List[str] = []
self.history: List[str] = []
self.buffer: list[str] = []
self.history: list[str] = []
self.banner = banner
self.text_controller = Gtk.EventControllerKey.new()

View File

@ -1,6 +1,5 @@
import logging
from pathlib import Path
from typing import List
from gaphor.core.modeling import Diagram
from gaphor.diagram.export import escape_filename
@ -10,7 +9,7 @@ log = logging.getLogger(__name__)
def pkg2dir(package):
"""Return directory path from package class."""
name: List[str] = []
name: list[str] = []
while package:
name.insert(0, package.name)
package = package.package

View File

@ -2,7 +2,8 @@
import functools
import inspect
from typing import Iterator, List, Tuple, Type, TypeVar
from collections.abc import Iterator
from typing import TypeVar
from gaphor.abc import Service
@ -18,7 +19,7 @@ class ComponentRegistry(Service):
components."""
def __init__(self) -> None:
self._comp: List[Tuple[str, object]] = []
self._comp: list[tuple[str, object]] = []
def shutdown(self) -> None:
pass
@ -36,7 +37,7 @@ class ComponentRegistry(Service):
def unregister(self, component: object) -> None:
self._comp = [(n, c) for n, c in self._comp if c is not component]
def get(self, base: Type[T], name: str) -> T:
def get(self, base: type[T], name: str) -> T:
found = [(n, c) for n, c in self._comp if isinstance(c, base) and n == name]
if len(found) > 1:
raise ComponentLookupError(
@ -48,7 +49,7 @@ class ComponentRegistry(Service):
)
return found[0][1]
def all(self, base: Type[T]) -> Iterator[Tuple[str, T]]:
def all(self, base: type[T]) -> Iterator[tuple[str, T]]:
return ((n, c) for n, c in self._comp if isinstance(c, base))
def partial(self, func):

View File

@ -1,4 +1,4 @@
from typing import Dict, Iterable
from collections.abc import Iterable
from gaphor.abc import ActionProvider, ModelingLanguage, Service
from gaphor.action import action
@ -27,7 +27,7 @@ class ModelingLanguageService(Service, ActionProvider, ModelingLanguage):
self.event_manager = event_manager
self.properties = properties
self._modeling_languages: Dict[str, ModelingLanguage] = initialize(
self._modeling_languages: dict[str, ModelingLanguage] = initialize(
"gaphor.modelinglanguages"
)
if event_manager:

View File

@ -8,7 +8,6 @@ import ast
import logging
import pprint
from pathlib import Path
from typing import Dict
from gaphor import settings
from gaphor.abc import Service
@ -48,7 +47,7 @@ class Properties(Service):
def __init__(self, event_manager):
self.event_manager = event_manager
self.filename: Path = properties_filename("")
self._properties: Dict[str, object] = {}
self._properties: dict[str, object] = {}
event_manager.subscribe(self.on_model_loaded)
event_manager.subscribe(self.on_model_saved)

View File

@ -13,7 +13,7 @@ NOTE: it would be nice to use actions in conjunction with functools.partial.
from __future__ import annotations
import logging
from typing import Callable, List
from collections.abc import Callable
from gaphor.abc import ActionProvider, Service
from gaphor.action import action
@ -57,7 +57,7 @@ class ActionStack:
"""
def __init__(self):
self._actions: List[Callable[[], None]] = []
self._actions: list[Callable[[], None]] = []
def add(self, action):
self._actions.append(action)
@ -121,8 +121,8 @@ class UndoManager(Service, ActionProvider):
def __init__(self, event_manager, element_factory):
self.event_manager = event_manager
self.element_factory: RepositoryProtocol = element_factory
self._undo_stack: List[ActionStack] = []
self._redo_stack: List[ActionStack] = []
self._undo_stack: list[ActionStack] = []
self._redo_stack: list[ActionStack] = []
self._stack_depth = 20
self._current_transaction = None

View File

@ -343,7 +343,7 @@ class Recorder:
@event_handler(AssociationAdded, AssociationSet)
def on_association_set_event(self, event: AssociationSet | AssociationAdded):
if isinstance(event, (DerivedUpdated, RedefinedAdded, RedefinedSet)):
if isinstance(event, DerivedUpdated | RedefinedAdded | RedefinedSet):
return
self.events.append(
(
@ -356,7 +356,7 @@ class Recorder:
@event_handler(AssociationDeleted)
def on_association_delete_event(self, event: AssociationDeleted):
if isinstance(event, (DerivedUpdated, RedefinedDeleted)):
if isinstance(event, DerivedUpdated | RedefinedDeleted):
return
self.events.append(
(

View File

@ -8,8 +8,8 @@ __all__ = ["load", "save"]
import io
import logging
from collections.abc import Callable, Iterable
from functools import partial
from typing import Callable, Iterable
from gaphor import application
from gaphor.core.modeling import Diagram, Element, ElementFactory, Presentation

View File

@ -18,7 +18,7 @@ def test_elements_1():
xml_w.startElement("foo", {})
xml_w.endElement("foo")
xml = """<?xml version="1.0" encoding="%s"?>\n<foo/>""" % sys.getdefaultencoding()
xml = f"""<?xml version="1.0" encoding="{sys.getdefaultencoding()}"?>\n<foo/>"""
assert w.s == xml, f"{w.s} != {xml}"
@ -31,10 +31,7 @@ def test_elements_2():
xml_w.endElement("bar")
xml_w.endElement("foo")
xml = (
"""<?xml version="1.0" encoding="%s"?>\n<foo>\n<bar/>\n</foo>"""
% sys.getdefaultencoding()
)
xml = f"""<?xml version="1.0" encoding="{sys.getdefaultencoding()}"?>\n<foo>\n<bar/>\n</foo>"""
assert w.s == xml, w.s
@ -48,10 +45,7 @@ def test_elements_test():
xml_w.endElement("bar")
xml_w.endElement("foo")
xml = (
"""<?xml version="1.0" encoding="%s"?>\n<foo>\n<bar>hello</bar>\n</foo>"""
% sys.getdefaultencoding()
)
xml = f"""<?xml version="1.0" encoding="{sys.getdefaultencoding()}"?>\n<foo>\n<bar>hello</bar>\n</foo>"""
assert w.s == xml, w.s
@ -63,10 +57,7 @@ def test_elements_ns_default():
xml_w.startElementNS(("http://gaphor.devjavu.com/schema", "foo"), "qn", {})
xml_w.endElementNS(("http://gaphor.devjavu.com/schema", "foo"), "qn")
xml = (
"""<?xml version="1.0" encoding="%s"?>\n<foo xmlns="http://gaphor.devjavu.com/schema"/>"""
% sys.getdefaultencoding()
)
xml = f"""<?xml version="1.0" encoding="{sys.getdefaultencoding()}"?>\n<foo xmlns="http://gaphor.devjavu.com/schema"/>"""
assert w.s == xml, w.s
@ -78,8 +69,5 @@ def test_elements_ns_1():
xml_w.startElementNS(("http://gaphor.devjavu.com/schema", "foo"), "qn", {})
xml_w.endElementNS(("http://gaphor.devjavu.com/schema", "foo"), "qn")
xml = (
"""<?xml version="1.0" encoding="%s"?>\n<g:foo xmlns:g="http://gaphor.devjavu.com/schema"/>"""
% sys.getdefaultencoding()
)
xml = f"""<?xml version="1.0" encoding="{sys.getdefaultencoding()}"?>\n<g:foo xmlns:g="http://gaphor.devjavu.com/schema"/>"""
assert w.s == xml, w.s

View File

@ -1,5 +1,4 @@
import xml.sax.handler
from typing import Dict, List, Tuple
from xml.sax.saxutils import escape, quoteattr
# See whether the xmlcharrefreplace error handler is
@ -18,9 +17,9 @@ class XMLWriter(xml.sax.handler.ContentHandler):
super().__init__()
self._out = out
self._encoding = encoding
self._ns_contexts: List[Dict[str, str]] = [{}] # contains uri -> prefix dicts
self._ns_contexts: list[dict[str, str]] = [{}] # contains uri -> prefix dicts
self._current_context = self._ns_contexts[-1]
self._undeclared_ns_maps: List[Tuple[str, str]] = []
self._undeclared_ns_maps: list[tuple[str, str]] = []
self._in_cdata = False
self._in_start_tag = False

View File

@ -2,7 +2,7 @@
from __future__ import annotations
from typing import Callable, Collection
from collections.abc import Callable, Collection
from gi.repository import Gdk, GLib, GObject

View File

@ -1,7 +1,6 @@
import functools
import importlib
import logging
from typing import Optional
from gaphas.guide import GuidePainter
from gaphas.painter import FreeHandPainter, HandlePainter, PainterChain
@ -79,9 +78,9 @@ class DiagramPage:
self.modeling_language = modeling_language
self.style_manager = Adw.StyleManager.get_default()
self.view: Optional[GtkView] = None
self.widget: Optional[Gtk.Widget] = None
self.diagram_css: Optional[Gtk.CssProvider] = None
self.view: GtkView | None = None
self.widget: Gtk.Widget | None = None
self.diagram_css: Gtk.CssProvider | None = None
self.rubberband_state = RubberbandState()
self.context_menu = Gtk.PopoverMenu.new_from_model(popup_model(diagram))

View File

@ -2,7 +2,7 @@
import importlib.resources
import logging
from typing import Iterator, Optional
from collections.abc import Iterator
from unicodedata import normalize
from babel import Locale
@ -166,7 +166,7 @@ class EditorStack:
self.diagrams = diagrams
self.properties = properties
self.vbox: Optional[Gtk.Box] = None
self.vbox: Gtk.Box | None = None
self._current_item = None
def open(self, builder):

View File

@ -5,8 +5,8 @@ from __future__ import annotations
import os
import sys
from collections.abc import Callable
from pathlib import Path
from typing import Callable
from gi.repository import Gio, Gtk

View File

@ -4,9 +4,9 @@ from __future__ import annotations
import logging
import tempfile
from collections.abc import Callable
from functools import partial
from pathlib import Path
from typing import Callable
from gaphas.decorators import g_async
from gi.repository import Adw, Gio, GLib, Gtk

View File

@ -3,8 +3,8 @@
from __future__ import annotations
import logging
from collections.abc import Callable
from pathlib import Path
from typing import Callable
from gi.repository import Gio, GLib, Gtk

View File

@ -1,7 +1,7 @@
from __future__ import annotations
from collections.abc import Iterable, Sequence
from itertools import groupby
from typing import Iterable, Sequence
from gi.repository import Gio, GObject
@ -93,7 +93,7 @@ def organize_changes(element_factory, modeling_language):
def not_presentation(change: RefChange):
element_type = lookup_element(change.property_ref)
return element_type and not issubclass(element_type, (Diagram, Presentation))
return element_type and not issubclass(element_type, Diagram | Presentation)
def composite_and_not_presentation(change: RefChange):
return composite(change) and not_presentation(change)

View File

@ -1,4 +1,4 @@
from typing import Iterable
from collections.abc import Iterable
from gaphor import UML
from gaphor.core.changeset.compare import compare

View File

@ -5,7 +5,6 @@ This is the toolbox in the lower left of the screen.
import functools
import logging
from typing import Optional, Tuple
from gi.repository import Gdk, GLib, GObject, Gtk
@ -34,8 +33,8 @@ class Toolbox(UIComponent):
self.event_manager = event_manager
self.properties = properties
self.modeling_language = modeling_language
self._toolbox: Optional[Gtk.Box] = None
self._toolbox_container: Optional[Gtk.ScrolledWindow] = None
self._toolbox: Gtk.Box | None = None
self._toolbox_container: Gtk.ScrolledWindow | None = None
self._current_diagram_type = ""
def open(self) -> Gtk.ScrolledWindow:
@ -201,7 +200,7 @@ def create_toolbox_button(
action_name: str,
icon_name: str,
label: str,
shortcut: Optional[str],
shortcut: str | None,
draggable: bool,
) -> Gtk.Button:
"""Creates a tool button for the toolbox."""
@ -255,6 +254,6 @@ _upper_offset: int = ord("A") - ord("a")
@functools.cache
def parse_shortcut(shortcut: str) -> Tuple[Tuple[int, int], Gdk.ModifierType]:
def parse_shortcut(shortcut: str) -> tuple[tuple[int, int], Gdk.ModifierType]:
_, key, mod = Gtk.accelerator_parse(shortcut)
return (key, key + _upper_offset), mod

View File

@ -55,7 +55,7 @@ class TreeItem(GObject.Object):
self.icon_visible = bool(
self.icon
and not isinstance(
element, (UML.Parameter, UML.Property, UML.Operation)
element, UML.Parameter | UML.Property | UML.Operation
)
)
self.attributes = pango_attributes(element)
@ -135,14 +135,12 @@ def visible(element: Element) -> bool:
return not (
isinstance(
element,
(
Comment,
Presentation,
StyleSheet,
UML.InstanceSpecification,
UML.OccurrenceSpecification,
UML.Slot,
),
Comment
| Presentation
| StyleSheet
| UML.InstanceSpecification
| UML.OccurrenceSpecification
| UML.Slot,
)
or (
# Some types we want to show, except at top level
@ -311,7 +309,7 @@ def pango_attributes(element):
attrs.insert(
Pango.attr_style_new(
Pango.Style.ITALIC
if isinstance(element, (UML.Classifier, UML.BehavioralFeature))
if isinstance(element, UML.Classifier | UML.BehavioralFeature)
and element.isAbstract
else Pango.Style.NORMAL
)

View File

@ -1,5 +1,5 @@
import functools
from typing import Iterable
from collections.abc import Iterable
from unicodedata import normalize
from gaphor.ui.treemodel import TreeItem, tree_item_sort

View File

@ -259,10 +259,11 @@ select = [
"C",
"E",
"F",
"PLW1",
"SLF",
"T20",
"UP",
"W",
"PLW1",
]
extend-select = ["I"]

View File

@ -31,7 +31,7 @@ def test_action_issue(element_factory, modeling_language, test_models):
for e in actions + flows:
assert 1 == len(e.presentation), e
for i in diagram.select(lambda e: isinstance(e, (ControlFlowItem, ActionItem))):
for i in diagram.select(lambda e: isinstance(e, ControlFlowItem | ActionItem)):
assert i.subject, i
# Loaded as:

View File

@ -7,7 +7,7 @@ from __future__ import annotations
import contextlib
import itertools
from typing import Iterable
from collections.abc import Iterable
import hypothesis
from hypothesis import settings

View File

@ -24,9 +24,9 @@ from __future__ import annotations
import contextlib
import itertools
from collections.abc import Iterable
from functools import singledispatch
from io import StringIO
from typing import Iterable
import hypothesis
from gaphas.connector import Handle

View File

@ -1,5 +1,3 @@
from typing import Dict, List
import pytest
from gi.repository import Gtk
@ -110,7 +108,7 @@ def test_placement_partition(tab, element_factory, event_manager):
],
)
def test_uml_toolbox_actions_shortcut_unique(toolbox_actions):
shortcuts: Dict[str, List[str]] = {}
shortcuts: dict[str, list[str]] = {}
for _category, items in toolbox_actions:
for action_name, _label, _icon_name, shortcut, *_rest in items: