Skip to content

Commit

Permalink
add mypy workflow (#41)
Browse files Browse the repository at this point in the history
* add `mypy` workflow

* fix mypy errors
  • Loading branch information
snoyer authored Jan 26, 2025
1 parent 4b254f5 commit 6b59f1b
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 33 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/mypy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: mypy

on:
- push
- pull_request

jobs:
mypy:
strategy:
fail-fast: false
matrix:
python-version:
- "3.10"
- "3.12"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install mypy
pip install .
- name: Typecheck with mypy
run: |
mypy --ignore-missing-imports ocpsvg
19 changes: 10 additions & 9 deletions ocpsvg/hlr.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
Mapping,
Optional,
Sequence,
TypeAlias,
Union,
)
from xml.etree import ElementTree as ET
Expand All @@ -38,16 +39,16 @@
}


Padding = Union[
Padding: TypeAlias = Union[
float,
tuple[float],
tuple[float, float],
tuple[float, float, float],
tuple[float, float, float, float],
]
CssStyle = Mapping[str, Mapping[str, Any]]
RGB = tuple[float, float, float]
EdgeColor = Union[RGB, tuple[RGB, RGB]]
CssStyle: TypeAlias = Mapping[str, Mapping[str, Any]]
RGB: TypeAlias = tuple[float, float, float]
EdgeColor: TypeAlias = Union[RGB, tuple[RGB, RGB]]


PRIMARY_EDGES = "sharp", "outline"
Expand Down Expand Up @@ -253,12 +254,12 @@ def basic_style(
) -> CssStyle:
if secondary_linewidth is None:
secondary_linewidth = linewidth * 0.75
color, hidden_color = _edge_color_pair(color)
visible_color, hidden_color = _edge_color_pair(color)

style = {
style: dict[str, dict[str, Union[str, float]]] = {
"path": {
"fill": "none",
"stroke": hexcolor(color),
"stroke": hexcolor(visible_color),
"stroke-width": linewidth,
"stroke-linecap": "round",
"stroke-linejoin": "round",
Expand All @@ -278,8 +279,8 @@ def basic_style(

if shape_colors:
for i, color in shape_colors.items():
color, hidden_color = _edge_color_pair(color)
style[f".s{i}"] = {"stroke": hexcolor(color)}
visible_color, hidden_color = _edge_color_pair(color)
style[f".s{i}"] = {"stroke": hexcolor(visible_color)}
style[f".s{i}.hidden"] = {"stroke": hexcolor(hidden_color)}

return style
Expand Down
2 changes: 2 additions & 0 deletions ocpsvg/ocp.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ def circle_curve(
) -> Union[Geom_Circle, Geom_TrimmedCurve]:
circle_gp = gp_Circ(gp_Ax2(gp_Pnt(), normal), radius)

circle: Union[Geom_Circle, Geom_TrimmedCurve] # for mypy
if start_angle == end_angle:
circle = GC_MakeCircle(circle_gp).Value()
else:
Expand Down Expand Up @@ -360,6 +361,7 @@ def ellipse_curve(
ellipse_gp = gp_Elips(gp_Ax2(gp_Pnt(), normal), major_radius, minor_radius)
ellipse_gp.Rotate(gp_Ax1(), radians(angle_adjustment))

ellipse: Union[Geom_Ellipse, Geom_TrimmedCurve] # for mypy
if start_angle == end_angle:
ellipse = GC_MakeEllipse(ellipse_gp).Value()
else:
Expand Down
54 changes: 30 additions & 24 deletions ocpsvg/svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
Optional,
Sequence,
TextIO,
TypeAlias,
TypeVar,
Union,
overload,
Expand Down Expand Up @@ -109,11 +110,11 @@ def format_svg(path: Iterable[SvgPathCommand], float_format: str = "f") -> str:
)


SvgPathLike = Union[str, Iterable[SvgPathCommand], svgelements.Path]
ShapeElement = svgelements.Shape
ParentElement = Union[svgelements.Group, svgelements.Use]
SvgPathLike: TypeAlias = Union[str, Iterable[SvgPathCommand], svgelements.Path]
ShapeElement: TypeAlias = svgelements.Shape
ParentElement: TypeAlias = Union[svgelements.Group, svgelements.Use]

FaceOrWire = Union[TopoDS_Wire, TopoDS_Face]
FaceOrWire: TypeAlias = Union[TopoDS_Wire, TopoDS_Face]


class DocumentInfo(NamedTuple):
Expand Down Expand Up @@ -220,31 +221,31 @@ def process_wire(
yield from wires

if metadata:
wires_from_doc = wires_from_svg_document(
wires_from_doc_with_metadata = wires_from_svg_document(
svg_file,
ignore_visibility=ignore_visibility,
metadata_factory=metadata,
)
transform = doc_transform(wires_from_doc.doc_info)
transform = doc_transform(wires_from_doc_with_metadata.doc_info)
items = (
(transform(face_or_wire), m)
for wires, is_filled, m in wires_from_doc
(transform(face_or_wire), metadata)
for wires, is_filled, metadata in wires_from_doc_with_metadata
for face_or_wire in process_wire(wires, is_filled)
)
return ItemsFromDocument(items, wires_from_doc.doc_info)
return ItemsFromDocument(items, wires_from_doc_with_metadata.doc_info)
else:
wires_from_doc = wires_from_svg_document(
wires_from_doc_without_metadata = wires_from_svg_document(
svg_file,
ignore_visibility=ignore_visibility,
metadata_factory=None,
)
transform = doc_transform(wires_from_doc.doc_info)
transform = doc_transform(wires_from_doc_without_metadata.doc_info)
items = (
transform(face_or_wire)
for wires, is_filled, _metadata in wires_from_doc
for wires, is_filled, _metadata in wires_from_doc_without_metadata
for face_or_wire in process_wire(wires, is_filled)
)
return ItemsFromDocument(items, wires_from_doc.doc_info)
return ItemsFromDocument(items, wires_from_doc_without_metadata.doc_info)


class ColorAndLabel:
Expand Down Expand Up @@ -274,6 +275,8 @@ def _color(
return tuple(float(v) / 255 for v in rgba) # type: ignore
except TypeError:
return 0, 0, 0, 1
else:
return None

@staticmethod
def _label(element: Union[ShapeElement, ParentElement], label_by: str):
Expand Down Expand Up @@ -312,6 +315,8 @@ def check_unskewed_transform() -> Union[tuple[float, float, float], None]:
is_skewed = abs(o.angle_to(y) - o.angle_to(x)) != pi / 2 # type: ignore
if not is_skewed:
return o.distance_to(x), o.distance_to(y), o.angle_to(x) # type: ignore
else:
return None

element.reify()

Expand All @@ -325,11 +330,12 @@ def check_unskewed_transform() -> Union[tuple[float, float, float], None]:
scale_x, scale_y, angle = scale_and_angle
r1 = float(element.rx) * scale_x # type: ignore
r2 = float(element.ry) * scale_y # type: ignore
if r1 == r2:
curve = circle_curve(r1, center=center)
else:
curve = ellipse_curve(r1, r2, center=center, rotation=degrees(angle))
yield wire_from_continuous_edges((edge_from_curve(curve),))
circle_or_ellpise = (
circle_curve(r1, center=center)
if r1 == r2
else ellipse_curve(r1, r2, center=center, rotation=degrees(angle))
)
yield wire_from_continuous_edges((edge_from_curve(circle_or_ellpise),))

elif path := svg_element_to_path(element):
yield from wires_from_svg_path(path)
Expand Down Expand Up @@ -503,7 +509,7 @@ def wire_to_svg_path(
# but wires can be non-manifold or otherwise degenerate and may not have visit them all.
# We'll add remaining edges individually

#TODO use a set if/when OCP implements `__eq__`
# TODO use a set if/when OCP implements `__eq__`
all_edges = {hash(e): e for e in map(TopoDS.Edge_s, topoDS_iterator(wire))}

if len(ordered_edges) < len(all_edges):
Expand Down Expand Up @@ -777,25 +783,25 @@ def is_filled(element: ShapeElement):
return fill.value is not None # type: ignore

if callable(metadata_factory):
wires = (
wires_with_metadata = (
(
list(wires_from_svg_element(source_element)),
is_filled(source_element),
metadata_factory(source_element, source_parents),
)
for source_element, source_parents in elements
)
return ItemsFromDocument(wires, elements.doc_info)
return ItemsFromDocument(wires_with_metadata, elements.doc_info)
else:
wires = (
wires_without_metadata = (
(
list(wires_from_svg_element(source_element)),
is_filled(source_element),
None,
)
for source_element, _source_parents in elements
)
return ItemsFromDocument(wires, elements.doc_info)
return ItemsFromDocument(wires_without_metadata, elements.doc_info)


def find_shapes_svg_in_document(
Expand All @@ -806,7 +812,7 @@ def find_shapes_svg_in_document(
def walk_svg_element(
element: svgelements.SVGElement, parents: tuple[ParentElement, ...] = ()
) -> Iterator[tuple[ShapeElement, tuple[ParentElement, ...]]]:
if isinstance(element, ShapeElement):
if isinstance(element, svgelements.Shape):
yield element, parents
elif isinstance(element, (svgelements.Group, svgelements.Use)):
new_parents = *parents, element
Expand Down

0 comments on commit 6b59f1b

Please sign in to comment.