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.""" """C4 Model Language entrypoint."""
from typing import Iterable from collections.abc import Iterable
from gaphor.abc import ModelingLanguage from gaphor.abc import ModelingLanguage
from gaphor.C4Model import c4model, diagramitems from gaphor.C4Model import c4model, diagramitems

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
"""The SysML Modeling Language module is the entrypoint for SysML related """The SysML Modeling Language module is the entrypoint for SysML related
assets.""" assets."""
from typing import Iterable from collections.abc import Iterable
from gaphor.abc import ModelingLanguage from gaphor.abc import ModelingLanguage
from gaphor.core import gettext 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) assert issubclass(item_class, Named)
if issubclass(item_class, Named): if issubclass(item_class, Named):
assert issubclass(element_class, (NamedElement, Relationship)) assert issubclass(element_class, NamedElement | Relationship)
CLASSIFIED_EXCLUSIONS = [] CLASSIFIED_EXCLUSIONS = []

View File

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

View File

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

View File

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

View File

@ -31,7 +31,7 @@ class ContainmentConnect(BaseConnector):
return super().allow(handle, port) and ( return super().allow(handle, port) and (
isinstance(container, UML.Package) isinstance(container, UML.Package)
and isinstance(contained, (UML.Type, UML.Package)) and isinstance(contained, UML.Type | UML.Package)
or isinstance(container, UML.Package) or isinstance(container, UML.Package)
and isinstance(contained, (Diagram)) and isinstance(contained, (Diagram))
or isinstance(container, UML.Class) or isinstance(container, UML.Class)
@ -59,11 +59,11 @@ class ContainmentConnect(BaseConnector):
if hct and oct: if hct and oct:
if oct.subject and hct.subject in oct.subject.ownedElement: 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) ungroup(oct.subject, hct.subject)
hct.subject.package = owner_package(hct.diagram.owner) hct.subject.package = owner_package(hct.diagram.owner)
if hct.subject and oct.subject in hct.subject.ownedElement: 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) ungroup(hct.subject, oct.subject)
oct.subject.package = owner_package(oct.diagram.owner) 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 from gaphas.geometry import Rectangle

View File

@ -1,6 +1,7 @@
from __future__ import annotations 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.core.modeling.element import Id
from gaphor.diagram.copypaste import ( 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. `gaphor.diagram.connector` module for details.
""" """
from typing import Union
from gaphor import UML from gaphor import UML
from gaphor.diagram.connectors import BaseConnector, Connector from gaphor.diagram.connectors import BaseConnector, Connector
from gaphor.UML.classes.component import ComponentItem from gaphor.UML.classes.component import ComponentItem
@ -22,7 +20,7 @@ class LegacyConnectorConnectBase(BaseConnector):
palette. palette.
""" """
element: Union[ComponentItem, InterfaceItem] element: ComponentItem | InterfaceItem
line: ConnectorItem line: ConnectorItem
def get_connecting(self, iface, both=False): def get_connecting(self, iface, both=False):

View File

@ -1,7 +1,5 @@
"""Message item connection adapters.""" """Message item connection adapters."""
from typing import Optional
from gaphor import UML from gaphor import UML
from gaphor.core.modeling import Element, Presentation from gaphor.core.modeling import Element, Presentation
from gaphor.diagram.connectors import BaseConnector, Connector 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 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.""" """Get item connected to a handle."""
if cinfo := item.diagram.connections.get_connection(handle): if cinfo := item.diagram.connections.get_connection(handle):
return cinfo.connected # type: ignore[no-any-return] # noqa: F723 return cinfo.connected # type: ignore[no-any-return] # noqa: F723
@ -145,7 +143,7 @@ class MessageLifelineConnect(BaseConnector):
def disconnect(self, handle): def disconnect(self, handle):
line = self.line 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) received = self.get_connected(line.tail)
# if a message is a deleted message, then the disconnection causes # 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 # Can connect child exec spec if parent is not connected
return True return True
connected_item: Optional[Presentation[Element]] connected_item: Presentation[Element] | None
connected_item = self.get_connected(self.element.handles()[0]) connected_item = self.get_connected(self.element.handles()[0])
assert connected_item assert connected_item
Connector(connected_item, self.line).connect(handle, None) 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 """The UML Modeling Language module is the entrypoint for UML related
assets.""" assets."""
from typing import Iterable from collections.abc import Iterable
from gaphor.abc import ModelingLanguage from gaphor.abc import ModelingLanguage
from gaphor.core import gettext from gaphor.core import gettext

View File

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

View File

@ -1,7 +1,7 @@
"""The Sanitize module is dedicated to adapters (stuff) that keeps the model """The Sanitize module is dedicated to adapters (stuff) that keeps the model
clean and in sync with diagrams.""" clean and in sync with diagrams."""
from typing import Iterable from collections.abc import Iterable
from gaphor import UML from gaphor import UML
from gaphor.abc import Service 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) assert issubclass(item_class, Named)
if issubclass(item_class, Named): if issubclass(item_class, Named):
assert issubclass(element_class, (NamedElement, Relationship)) assert issubclass(element_class, NamedElement | Relationship)
CLASSIFIED_EXCLUSIONS = [ CLASSIFIED_EXCLUSIONS = [

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,8 @@
from __future__ import annotations 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: class action:

View File

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

View File

@ -27,8 +27,8 @@ import contextlib
import logging import logging
import sys import sys
import textwrap import textwrap
from collections.abc import Iterable
from pathlib import Path from pathlib import Path
from typing import Iterable
from gaphor import UML from gaphor import UML
from gaphor.codegen.override import Overrides 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 # ruff: noqa: T201
import re import re
from typing import List
OVERRIDE_RE = re.compile( OVERRIDE_RE = re.compile(
r"^override\s+(?P<name>[\w.]+)(?:\((?P<derived>[^)]+)\))?\s*(?::\s*(?P<type_hint>[\w\s\[\],\"| ]+))?$" 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 contains a list of (lines, line_number) pairs.
bufs = [] bufs = []
line_number = 1 line_number = 1
lines: List[str] = [] lines: list[str] = []
line = fp.readline() line = fp.readline()
linenum = 1 linenum = 1
while line: while line:

View File

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

View File

@ -3,7 +3,8 @@
from __future__ import annotations from __future__ import annotations
import contextlib 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 from gaphor.core.modeling.event import AssociationUpdated
@ -13,7 +14,7 @@ T = TypeVar("T")
class collection(Generic[T]): class collection(Generic[T]):
"""Collection (set-like) for model elements' 1:n and n:m relationships.""" """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.property = property
self.object = object self.object = object
self.type = type self.type = type

View File

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

View File

@ -4,7 +4,8 @@
from __future__ import annotations from __future__ import annotations
import logging 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 uuid import uuid1
from gaphor.core.modeling.collection import collection 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 # Handle add/removal of handlers based on the kind of event
# Filter out handlers that have no remaining properties # Filter out handlers that have no remaining properties
if ( if (
isinstance(event, (AssociationSet, AssociationDeleted)) isinstance(event, AssociationSet | AssociationDeleted)
and event.old_value and event.old_value
): ):
for handler, remainders in handlers.items(): for handler, remainders in handlers.items():
for remainder in remainders: for remainder in remainders:
self._remove_handlers(event.old_value, remainder[0], handler) self._remove_handlers(event.old_value, remainder[0], handler)
if ( if isinstance(event, AssociationSet | AssociationAdded) and event.new_value:
isinstance(event, (AssociationSet, AssociationAdded))
and event.new_value
):
for handler, remainders in handlers.items(): for handler, remainders in handlers.items():
for remainder in remainders: for remainder in remainders:
self._add_handlers(event.new_value, remainder, handler) self._add_handlers(event.new_value, remainder, handler)

View File

@ -3,8 +3,9 @@
from __future__ import annotations from __future__ import annotations
from collections import OrderedDict from collections import OrderedDict
from collections.abc import Callable, Iterator
from contextlib import contextmanager 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.abc import Service
from gaphor.core.eventmanager import EventManager, event_handler from gaphor.core.eventmanager import EventManager, event_handler

View File

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

View File

@ -164,12 +164,12 @@ def test_association_1_n():
b2 = B() b2 = B()
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 in b1.two
assert a1.one is b1, f"{a1.one}/{b1}" assert a1.one is b1, f"{a1.one}/{b1}"
b1.two = a1 b1.two = a1
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 in b1.two
assert a1.one is b1, f"{a1.one}/{b1}" assert a1.one is b1, f"{a1.one}/{b1}"

View File

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

View File

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

View File

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

View File

@ -298,7 +298,7 @@ class CombinedSelector:
return a1 + a2, b1 + b2, c1 + c2 return a1 + a2, b1 + b2, c1 + c2
def __repr__(self): 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: class CompoundSelector:
@ -347,7 +347,7 @@ class NamespaceSelector:
self.namespace = namespace self.namespace = namespace
def __repr__(self): def __repr__(self):
return "|" if self.namespace == "" else "{%s}|" % self.namespace return "|" if self.namespace == "" else f"{{{self.namespace}}}|"
class IDSelector: class IDSelector:
@ -382,8 +382,8 @@ class AttributeSelector:
self.value = value self.value = value
def __repr__(self): def __repr__(self):
namespace = "*|" if self.namespace is None else "{%s}" % self.namespace namespace = "*|" if self.namespace is None else f"{{{self.namespace}}}"
return "[{}{}{}{!r}]".format(namespace, self.name, self.operator, self.value) return f"[{namespace}{self.name}{self.operator}{self.value!r}]"
class PseudoClassSelector: class PseudoClassSelector:
@ -414,4 +414,4 @@ class FunctionalPseudoClassSelector:
self.arguments = arguments self.arguments = arguments
def __repr__(self): 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 functools
import itertools 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.connections import Connection
from gaphas.connector import ConnectionSink, Handle, Port 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: def can_connect(parent, element_type) -> bool:
parent_type = type(parent) parent_type = type(parent)
get_registration = Connector.registry.get_registration 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) head - tuple (association name on the line, association name on the element)
tail - 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(head, association | redefine), f"head is {head}"
assert isinstance(tail, (association, redefine)), f"tail is {tail}" assert isinstance(tail, association | redefine), f"tail is {tail}"
line = self.line line = self.line

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@ from __future__ import annotations
import abc import abc
import textwrap import textwrap
from typing import Iterator from collections.abc import Iterator
import gaphas.item import gaphas.item
from gaphas.segment import Segment 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.item import Item
from gaphas.selection import Selection as _Selection from gaphas.selection import Selection as _Selection
@ -7,8 +7,8 @@ from gaphas.selection import Selection as _Selection
class Selection(_Selection): class Selection(_Selection):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self._dropzone_item: Optional[Item] = None self._dropzone_item: Item | None = None
self._grayed_out_items: Set[Item] = set() self._grayed_out_items: set[Item] = set()
def clear(self): def clear(self):
self._dropzone_item = None self._dropzone_item = None
@ -16,16 +16,16 @@ class Selection(_Selection):
super().clear() super().clear()
@property @property
def dropzone_item(self) -> Optional[Item]: def dropzone_item(self) -> Item | None:
return self._dropzone_item return self._dropzone_item
@dropzone_item.setter @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: if item is not self._dropzone_item:
self._dropzone_item = item self._dropzone_item = item
@property @property
def grayed_out_items(self) -> Set[Item]: def grayed_out_items(self) -> set[Item]:
return self._grayed_out_items return self._grayed_out_items
@grayed_out_items.setter @grayed_out_items.setter

View File

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

View File

@ -1,7 +1,5 @@
"""For ease of creation, maintain a mapping from Element to Diagram Item.""" """For ease of creation, maintain a mapping from Element to Diagram Item."""
from typing import Dict
from gaphor.core.modeling import Element, Presentation from gaphor.core.modeling import Element, Presentation
@ -16,8 +14,8 @@ def represents(uml_element, **metadata):
# Map elements to their (default) representation. # Map elements to their (default) representation.
_element_to_item_map: Dict[type[Element], type[Presentation]] = {} _element_to_item_map: dict[type[Element], type[Presentation]] = {}
_item_to_metadata_map: Dict[type[Presentation], dict[str, object]] = {} _item_to_metadata_map: dict[type[Presentation], dict[str, object]] = {}
def get_diagram_item(element_cls: type[Element]) -> type[Presentation] | None: 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.connector import Handle
from gaphas.guide import GuidedItemHandleMoveMixin from gaphas.guide import GuidedItemHandleMoveMixin
from gaphas.handlemove import ConnectionSinkType, HandleMove, ItemHandleMove from gaphas.handlemove import ConnectionSinkType, HandleMove, ItemHandleMove
@ -43,7 +41,7 @@ class GrayOutLineHandleMoveMixin:
def glue( def glue(
self, pos: Pos, distance: int = ItemHandleMove.GLUE_DISTANCE self, pos: Pos, distance: int = ItemHandleMove.GLUE_DISTANCE
) -> Optional[ConnectionSinkType]: ) -> ConnectionSinkType | None:
sink = super().glue(pos, distance) # type: ignore[misc] sink = super().glue(pos, distance) # type: ignore[misc]
self.view.selection.dropzone_item = sink and sink.item self.view.selection.dropzone_item = sink and sink.item
return sink return sink

View File

@ -1,5 +1,4 @@
import logging import logging
from typing import Optional
from gaphas.decorators import g_async from gaphas.decorators import g_async
from gaphas.handlemove import HandleMove from gaphas.handlemove import HandleMove
@ -23,7 +22,7 @@ class PlacementState:
self.factory = factory self.factory = factory
self.event_manager = event_manager self.event_manager = event_manager
self.handle_index = handle_index 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): def placement_tool(factory: ItemFactory, event_manager, handle_index: int):

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,8 @@
import functools import functools
import inspect import inspect
from typing import Iterator, List, Tuple, Type, TypeVar from collections.abc import Iterator
from typing import TypeVar
from gaphor.abc import Service from gaphor.abc import Service
@ -18,7 +19,7 @@ class ComponentRegistry(Service):
components.""" components."""
def __init__(self) -> None: def __init__(self) -> None:
self._comp: List[Tuple[str, object]] = [] self._comp: list[tuple[str, object]] = []
def shutdown(self) -> None: def shutdown(self) -> None:
pass pass
@ -36,7 +37,7 @@ class ComponentRegistry(Service):
def unregister(self, component: object) -> None: def unregister(self, component: object) -> None:
self._comp = [(n, c) for n, c in self._comp if c is not component] 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] found = [(n, c) for n, c in self._comp if isinstance(c, base) and n == name]
if len(found) > 1: if len(found) > 1:
raise ComponentLookupError( raise ComponentLookupError(
@ -48,7 +49,7 @@ class ComponentRegistry(Service):
) )
return found[0][1] 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)) return ((n, c) for n, c in self._comp if isinstance(c, base))
def partial(self, func): 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.abc import ActionProvider, ModelingLanguage, Service
from gaphor.action import action from gaphor.action import action
@ -27,7 +27,7 @@ class ModelingLanguageService(Service, ActionProvider, ModelingLanguage):
self.event_manager = event_manager self.event_manager = event_manager
self.properties = properties self.properties = properties
self._modeling_languages: Dict[str, ModelingLanguage] = initialize( self._modeling_languages: dict[str, ModelingLanguage] = initialize(
"gaphor.modelinglanguages" "gaphor.modelinglanguages"
) )
if event_manager: if event_manager:

View File

@ -8,7 +8,6 @@ import ast
import logging import logging
import pprint import pprint
from pathlib import Path from pathlib import Path
from typing import Dict
from gaphor import settings from gaphor import settings
from gaphor.abc import Service from gaphor.abc import Service
@ -48,7 +47,7 @@ class Properties(Service):
def __init__(self, event_manager): def __init__(self, event_manager):
self.event_manager = event_manager self.event_manager = event_manager
self.filename: Path = properties_filename("") 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_loaded)
event_manager.subscribe(self.on_model_saved) 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 from __future__ import annotations
import logging import logging
from typing import Callable, List from collections.abc import Callable
from gaphor.abc import ActionProvider, Service from gaphor.abc import ActionProvider, Service
from gaphor.action import action from gaphor.action import action
@ -57,7 +57,7 @@ class ActionStack:
""" """
def __init__(self): def __init__(self):
self._actions: List[Callable[[], None]] = [] self._actions: list[Callable[[], None]] = []
def add(self, action): def add(self, action):
self._actions.append(action) self._actions.append(action)
@ -121,8 +121,8 @@ class UndoManager(Service, ActionProvider):
def __init__(self, event_manager, element_factory): def __init__(self, event_manager, element_factory):
self.event_manager = event_manager self.event_manager = event_manager
self.element_factory: RepositoryProtocol = element_factory self.element_factory: RepositoryProtocol = element_factory
self._undo_stack: List[ActionStack] = [] self._undo_stack: list[ActionStack] = []
self._redo_stack: List[ActionStack] = [] self._redo_stack: list[ActionStack] = []
self._stack_depth = 20 self._stack_depth = 20
self._current_transaction = None self._current_transaction = None

View File

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

View File

@ -8,8 +8,8 @@ __all__ = ["load", "save"]
import io import io
import logging import logging
from collections.abc import Callable, Iterable
from functools import partial from functools import partial
from typing import Callable, Iterable
from gaphor import application from gaphor import application
from gaphor.core.modeling import Diagram, Element, ElementFactory, Presentation 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.startElement("foo", {})
xml_w.endElement("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}" assert w.s == xml, f"{w.s} != {xml}"
@ -31,10 +31,7 @@ def test_elements_2():
xml_w.endElement("bar") xml_w.endElement("bar")
xml_w.endElement("foo") xml_w.endElement("foo")
xml = ( xml = f"""<?xml version="1.0" encoding="{sys.getdefaultencoding()}"?>\n<foo>\n<bar/>\n</foo>"""
"""<?xml version="1.0" encoding="%s"?>\n<foo>\n<bar/>\n</foo>"""
% sys.getdefaultencoding()
)
assert w.s == xml, w.s assert w.s == xml, w.s
@ -48,10 +45,7 @@ def test_elements_test():
xml_w.endElement("bar") xml_w.endElement("bar")
xml_w.endElement("foo") xml_w.endElement("foo")
xml = ( xml = f"""<?xml version="1.0" encoding="{sys.getdefaultencoding()}"?>\n<foo>\n<bar>hello</bar>\n</foo>"""
"""<?xml version="1.0" encoding="%s"?>\n<foo>\n<bar>hello</bar>\n</foo>"""
% sys.getdefaultencoding()
)
assert w.s == xml, w.s 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.startElementNS(("http://gaphor.devjavu.com/schema", "foo"), "qn", {})
xml_w.endElementNS(("http://gaphor.devjavu.com/schema", "foo"), "qn") xml_w.endElementNS(("http://gaphor.devjavu.com/schema", "foo"), "qn")
xml = ( xml = f"""<?xml version="1.0" encoding="{sys.getdefaultencoding()}"?>\n<foo xmlns="http://gaphor.devjavu.com/schema"/>"""
"""<?xml version="1.0" encoding="%s"?>\n<foo xmlns="http://gaphor.devjavu.com/schema"/>"""
% sys.getdefaultencoding()
)
assert w.s == xml, w.s 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.startElementNS(("http://gaphor.devjavu.com/schema", "foo"), "qn", {})
xml_w.endElementNS(("http://gaphor.devjavu.com/schema", "foo"), "qn") xml_w.endElementNS(("http://gaphor.devjavu.com/schema", "foo"), "qn")
xml = ( xml = f"""<?xml version="1.0" encoding="{sys.getdefaultencoding()}"?>\n<g:foo xmlns:g="http://gaphor.devjavu.com/schema"/>"""
"""<?xml version="1.0" encoding="%s"?>\n<g:foo xmlns:g="http://gaphor.devjavu.com/schema"/>"""
% sys.getdefaultencoding()
)
assert w.s == xml, w.s assert w.s == xml, w.s

View File

@ -1,5 +1,4 @@
import xml.sax.handler import xml.sax.handler
from typing import Dict, List, Tuple
from xml.sax.saxutils import escape, quoteattr from xml.sax.saxutils import escape, quoteattr
# See whether the xmlcharrefreplace error handler is # See whether the xmlcharrefreplace error handler is
@ -18,9 +17,9 @@ class XMLWriter(xml.sax.handler.ContentHandler):
super().__init__() super().__init__()
self._out = out self._out = out
self._encoding = encoding 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._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_cdata = False
self._in_start_tag = False self._in_start_tag = False

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
from collections.abc import Iterable, Sequence
from itertools import groupby from itertools import groupby
from typing import Iterable, Sequence
from gi.repository import Gio, GObject from gi.repository import Gio, GObject
@ -93,7 +93,7 @@ def organize_changes(element_factory, modeling_language):
def not_presentation(change: RefChange): def not_presentation(change: RefChange):
element_type = lookup_element(change.property_ref) 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): def composite_and_not_presentation(change: RefChange):
return composite(change) and not_presentation(change) 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 import UML
from gaphor.core.changeset.compare import compare 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 functools
import logging import logging
from typing import Optional, Tuple
from gi.repository import Gdk, GLib, GObject, Gtk from gi.repository import Gdk, GLib, GObject, Gtk
@ -34,8 +33,8 @@ class Toolbox(UIComponent):
self.event_manager = event_manager self.event_manager = event_manager
self.properties = properties self.properties = properties
self.modeling_language = modeling_language self.modeling_language = modeling_language
self._toolbox: Optional[Gtk.Box] = None self._toolbox: Gtk.Box | None = None
self._toolbox_container: Optional[Gtk.ScrolledWindow] = None self._toolbox_container: Gtk.ScrolledWindow | None = None
self._current_diagram_type = "" self._current_diagram_type = ""
def open(self) -> Gtk.ScrolledWindow: def open(self) -> Gtk.ScrolledWindow:
@ -201,7 +200,7 @@ def create_toolbox_button(
action_name: str, action_name: str,
icon_name: str, icon_name: str,
label: str, label: str,
shortcut: Optional[str], shortcut: str | None,
draggable: bool, draggable: bool,
) -> Gtk.Button: ) -> Gtk.Button:
"""Creates a tool button for the toolbox.""" """Creates a tool button for the toolbox."""
@ -255,6 +254,6 @@ _upper_offset: int = ord("A") - ord("a")
@functools.cache @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) _, key, mod = Gtk.accelerator_parse(shortcut)
return (key, key + _upper_offset), mod return (key, key + _upper_offset), mod

View File

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

View File

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

View File

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

View File

@ -31,7 +31,7 @@ def test_action_issue(element_factory, modeling_language, test_models):
for e in actions + flows: for e in actions + flows:
assert 1 == len(e.presentation), e 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 assert i.subject, i
# Loaded as: # Loaded as:

View File

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

View File

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

View File

@ -1,5 +1,3 @@
from typing import Dict, List
import pytest import pytest
from gi.repository import Gtk 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): 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 _category, items in toolbox_actions:
for action_name, _label, _icon_name, shortcut, *_rest in items: for action_name, _label, _icon_name, shortcut, *_rest in items: