Skip to content

Commit f34a49d

Browse files
authored
Add Python 3.14 classifier and update specs (#113)
* Add Python 3.14 classifier and update specs * Use different type checkers for different versions * remove ty * pyrefly check * make mypy not strict * remove pyrefly * Fixes for pyrefly, run on py 3.14 * reformat imports * pyrefly ignores
1 parent 3bdf232 commit f34a49d

25 files changed

+157
-120
lines changed

.github/workflows/lint.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
strategy:
1111
matrix:
12-
python-version: ["3.10", "3.11", "3.12", "3.13"]
12+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
1313
steps:
1414
- uses: actions/checkout@v4
1515
- name: Setup Graphviz
@@ -30,8 +30,12 @@ jobs:
3030
if [[ '${{ steps.cpython3.outputs.python-version }}' == 3.11* ]]; then
3131
pip install pytype
3232
pytype -j auto graphviz2drawio
33+
elif [[ '${{ steps.cpython3.outputs.python-version }}' == 3.14* ]]; then
34+
echo "Using pyrefly for Python 3.14"
35+
pip install pyrefly
36+
pyrefly check
3337
else
34-
echo "pytype does not support >= 3.12: https://github.com/google/pytype/issues/1475"
38+
echo "Using mypy for Python 3.12"
3539
pip install mypy
3640
mypy graphviz2drawio --ignore-missing-imports
3741
fi

graphviz2drawio/graphviz2drawio.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from pygraphviz import AGraph
66

7+
from .models.Errors import UnableToParseGraphError
78
from .models.SvgParser import parse_nodes_edges_clusters
89
from .mx.MxGraph import MxGraph
910

@@ -16,12 +17,17 @@ def convert(graph_to_convert: AGraph | str | IO, layout_prog: str = "dot") -> st
1617

1718
graph_edges: dict[str, dict] = {
1819
f"{e[0]}->{e[1]}-"
20+
# pyrefly: ignore # missing-attribute
1921
+ (e.attr.get("xlabel") or e.attr.get("label") or ""): e.attr.to_dict()
2022
for e in graph.edges_iter()
2123
}
24+
# pyrefly: ignore # missing-attribute
2225
graph_nodes: dict[str, dict] = {n: n.attr.to_dict() for n in graph.nodes_iter()}
2326

24-
svg_graph = graph.draw(prog=layout_prog, format="svg")
27+
svg_graph: bytes | None = graph.draw(prog=layout_prog, format="svg")
28+
29+
if svg_graph is None:
30+
raise UnableToParseGraphError(graph)
2531

2632
nodes, edges, clusters = parse_nodes_edges_clusters(
2733
svg_data=svg_graph,

graphviz2drawio/models/Errors.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from xml.etree.ElementTree import Element
22

3+
from pygraphviz import AGraph
4+
35

46
class GdValueError(ValueError):
57
"""Base class for exceptions raised during conversion."""
@@ -40,3 +42,12 @@ def __init__(self, sid: str | None, gid: str | None) -> None:
4042
super().__init__(
4143
f"Missing identifiers for a geometry: sid(id): {sid}, gid(title): {gid}.",
4244
)
45+
46+
47+
class UnableToParseGraphError(GdValueError):
48+
"""Graph was unexpectedly None."""
49+
50+
def __init__(self, graph: AGraph) -> None:
51+
super().__init__(
52+
f"Graph.draw() returned by pygraphviz was unexpectedly None: {graph}",
53+
)

graphviz2drawio/models/SvgParser.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,30 @@
22
from collections import OrderedDict
33
from collections.abc import Iterable
44
from math import isclose
5+
from typing import TYPE_CHECKING
56
from xml.etree import ElementTree
67

7-
from graphviz2drawio.mx.Edge import Edge
8-
from graphviz2drawio.mx.EdgeFactory import EdgeFactory
9-
from graphviz2drawio.mx.Node import Gradient, Node
10-
from graphviz2drawio.mx.NodeFactory import NodeFactory
11-
128
from ..mx.Curve import LINE_TOLERANCE
9+
from ..mx.Edge import Edge
10+
from ..mx.EdgeFactory import EdgeFactory
11+
from ..mx.Node import Gradient, Node
12+
from ..mx.NodeFactory import NodeFactory
1313
from ..mx.utils import adjust_color_opacity
1414
from . import SVG
1515
from .commented_tree_builder import COMMENT, CommentedTreeBuilder
1616
from .CoordsTranslate import CoordsTranslate
1717
from .Errors import MissingTitleError
1818

19+
if TYPE_CHECKING:
20+
from xml.etree.ElementTree import Element
21+
1922

2023
def parse_nodes_edges_clusters(
2124
svg_data: bytes,
2225
*,
2326
is_directed: bool,
2427
) -> tuple[OrderedDict[str, Node], list[Edge], OrderedDict[str, Node]]:
25-
root = ElementTree.fromstring(
28+
root: Element = ElementTree.fromstring(
2629
svg_data,
2730
parser=ElementTree.XMLParser(target=CommentedTreeBuilder()),
2831
)[0]
@@ -37,6 +40,7 @@ def parse_nodes_edges_clusters(
3740
gradients = dict[str, Gradient]()
3841

3942
prev_comment = None
43+
# pyrefly: ignore # unknown
4044
for g in root:
4145
if g.tag == COMMENT:
4246
prev_comment = g.text

graphviz2drawio/models/commented_tree_builder.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@ def __init__(self):
1818
self.was_root_set = False
1919

2020
def start(self, tag, attrs):
21-
super().start(tag, attrs)
21+
elem = super().start(tag, attrs)
2222
self.was_root_set = True
23+
return elem
2324

2425
def comment(self, data):
26+
rv = super().comment(data)
2527
if not self.was_root_set:
26-
return
28+
return rv
2729
self.start(COMMENT, {})
2830
self.data(unescape(data.strip()))
2931
self.end(COMMENT)
32+
return rv

graphviz2drawio/mx/CurveFactory.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ def from_svg(self, svg_path: str) -> Curve:
4242
]
4343
points.extend(split_controls)
4444

45-
start = self.coords.complex_translate(path[0].start)
46-
end = self.coords.complex_translate(path[-1].end)
45+
# pyrefly: ignore # missing-attribute
46+
start: complex = self.coords.complex_translate(path[0].start)
47+
# pyrefly: ignore # missing-attribute
48+
end: complex = self.coords.complex_translate(path[-1].end)
4749

4850
if len(points) > 0 and cmath.isclose(
4951
start,

graphviz2drawio/mx/Edge.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
from graphviz2drawio.models import DotAttr
2-
1+
from ..models import DotAttr
32
from ..models.Rect import Rect
43
from . import MxConst
54
from .Curve import Curve

graphviz2drawio/mx/EdgeFactory.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from xml.etree.ElementTree import Element
22

3-
from graphviz2drawio.models import SVG, DotAttr
4-
3+
from ..models import SVG, DotAttr
54
from ..models.CoordsTranslate import CoordsTranslate
65
from .CurveFactory import CurveFactory
76
from .Edge import Edge
@@ -22,7 +21,8 @@ def from_svg(self, g: Element, title: str) -> Edge:
2221
stroke = "#000000"
2322
stroke_width = DEFAULT_STROKE_WIDTH
2423
line_style = None
25-
labels = [
24+
# pyrefly: ignore # bad-assignment
25+
labels: list[Text] = [
2626
text_from_tag
2727
for tag in g
2828
if SVG.is_tag(tag, "text")

graphviz2drawio/mx/MxGraph.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from collections import OrderedDict
22
from xml.etree.ElementTree import Element, SubElement, indent, tostring
33

4-
from graphviz2drawio.models import DotAttr
5-
from graphviz2drawio.models.Rect import Rect
6-
from graphviz2drawio.mx import MxConst
7-
from graphviz2drawio.mx.Curve import Curve
8-
from graphviz2drawio.mx.Edge import Edge
9-
from graphviz2drawio.mx.Node import Node
10-
from graphviz2drawio.mx.Styles import Styles
4+
from ..models import DotAttr
5+
from ..models.Rect import Rect
6+
from . import MxConst
7+
from .Curve import Curve
8+
from .Edge import Edge
9+
from .Node import Node
10+
from .Styles import Styles
1111

1212

1313
class MxGraph:

graphviz2drawio/mx/Node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ def get_node_style(self) -> str:
6666
)
6767

6868
if (rect := self.rect) is not None and (image_path := rect.image) is not None:
69-
from graphviz2drawio.mx.image import image_data_for_path
69+
from .image import image_data_for_path
7070

7171
attributes["image"] = image_data_for_path(image_path)
7272

0 commit comments

Comments
 (0)