Fixed typing problems

This commit is contained in:
gumyr 2025-01-13 14:48:01 -05:00
parent c0c3189b81
commit 953019a4a6
12 changed files with 90 additions and 66 deletions

View file

@ -17,6 +17,9 @@ ignore_missing_imports = True
[mypy-OCP.*]
ignore_missing_imports = True
[mypy-ocpsvg.*]
ignore_missing_imports = True
[mypy-scipy.*]
ignore_missing_imports = True

View file

@ -174,6 +174,9 @@ operations_apply_to = {
"thicken": ["BuildPart"],
}
B = TypeVar("B", bound="Builder")
"""Builder type hint"""
class Builder(ABC):
"""Builder
@ -318,10 +321,10 @@ class Builder(ABC):
@classmethod
def _get_context(
cls,
cls: Type[B],
caller: Builder | Shape | Joint | str | None = None,
log: bool = True,
) -> Builder | None:
) -> B | None:
"""Return the instance of the current builder"""
result = cls._current.get(None)
context_name = "None" if result is None else type(result).__name__
@ -335,7 +338,7 @@ class Builder(ABC):
caller_name = "None"
logger.info("%s context requested by %s", context_name, caller_name)
return result
return cast(B, result)
def _add_to_context(
self,

View file

@ -69,24 +69,28 @@ class BuildLine(Builder):
_shape = Edge # Type of shapes being constructed
_sub_class = Curve # Class of line/_obj
@property
def _obj(self) -> Curve:
return self.line
@_obj.setter
def _obj(self, value: Curve) -> None:
self.line = value
def __init__(
self,
workplane: Face | Plane | Location = Plane.XY,
mode: Mode = Mode.ADD,
):
self.line: Curve = None
self._line: Curve | None = None
super().__init__(workplane, mode=mode)
if len(self.workplanes) > 1:
raise ValueError("BuildLine only accepts one workplane")
@property
def line(self) -> Curve | None:
"""Get the current line"""
return self._line
@line.setter
def line(self, value: Curve) -> None:
"""Set the current line"""
self._line = value
_obj = line # Alias _obj to line
def __exit__(self, exception_type, exception_value, traceback):
"""Upon exiting restore context and send object to parent"""
self._current.reset(self._reset_tok)
@ -126,6 +130,6 @@ class BuildLine(Builder):
"""solid() not implemented"""
raise NotImplementedError("solid() doesn't apply to BuildLine")
def _add_to_pending(self, *objects: Edge | Face, face_plane: Plane = None):
def _add_to_pending(self, *objects: Edge | Face, face_plane: Plane | None = None):
"""_add_to_pending not implemented"""
raise NotImplementedError("_add_to_pending doesn't apply to BuildLine")

View file

@ -63,14 +63,27 @@ class BuildSketch(Builder):
_shape = Face # Type of shapes being constructed
_sub_class = Sketch # Class of sketch/_obj
@property
def _obj(self) -> Sketch:
"""The builder's object"""
return self.sketch_local
def __init__(
self,
*workplanes: Face | Plane | Location,
mode: Mode = Mode.ADD,
):
self.mode = mode
self._sketch_local: Sketch | None = None
self.pending_edges: ShapeList[Edge] = ShapeList()
super().__init__(*workplanes, mode=mode)
@_obj.setter
def _obj(self, value: Sketch) -> None:
self.sketch_local = value
@property
def sketch_local(self) -> Sketch | None:
"""Get the builder's object"""
return self._sketch_local
@sketch_local.setter
def sketch_local(self, value: Sketch) -> None:
"""Set the builder's object"""
self._sketch_local = value
_obj = sketch_local # Alias _obj to sketch_local
@property
def sketch(self):
@ -85,16 +98,6 @@ class BuildSketch(Builder):
global_objs.append(plane.from_local_coords(self._obj))
return Sketch(Compound(global_objs).wrapped)
def __init__(
self,
*workplanes: Face | Plane | Location,
mode: Mode = Mode.ADD,
):
self.mode = mode
self.sketch_local: Sketch = None
self.pending_edges: ShapeList[Edge] = ShapeList()
super().__init__(*workplanes, mode=mode)
def solids(self, *args):
"""solids() not implemented"""
raise NotImplementedError("solids() doesn't apply to BuildSketch")
@ -108,7 +111,7 @@ class BuildSketch(Builder):
wires = Wire.combine(self.pending_edges)
return wires if len(wires) > 1 else wires[0]
def _add_to_pending(self, *objects: Edge, face_plane: Plane = None):
def _add_to_pending(self, *objects: Edge, face_plane: Plane | None = None):
"""Integrate a sequence of objects into existing builder object"""
if face_plane:
raise NotImplementedError("face_plane arg not supported for this method")

View file

@ -108,10 +108,11 @@ def import_brep(file_name: PathLike | str | bytes) -> Shape:
shape = TopoDS_Shape()
builder = BRep_Builder()
BRepTools.Read_s(shape, fsdecode(file_name), builder)
file_name_str = fsdecode(file_name)
BRepTools.Read_s(shape, file_name_str, builder)
if shape.IsNull():
raise ValueError(f"Could not import {file_name}")
raise ValueError(f"Could not import {file_name_str}")
return Compound.cast(shape)
@ -219,7 +220,6 @@ def import_step(filename: PathLike | str | bytes) -> Compound:
reader.Transfer(doc)
root = Compound()
root.for_construction = None
root.children = build_assembly()
# Remove empty Compound wrapper if single free object
if len(root.children) == 1:

View file

@ -84,7 +84,7 @@ class RigidJoint(Joint):
to_part: Solid | Compound | None = None,
joint_location: Location | None = None,
):
context: BuildPart = BuildPart._get_context(self)
context: BuildPart | None = BuildPart._get_context(self)
validate_inputs(context, self)
if to_part is None:
if context is not None:
@ -97,6 +97,8 @@ class RigidJoint(Joint):
if joint_location is None:
joint_location = Location()
if part_or_builder.location is None:
raise ValueError("Part must have a location")
self.relative_location = part_or_builder.location.inverse() * joint_location
part_or_builder.joints[label] = self
super().__init__(label, part_or_builder)
@ -269,7 +271,7 @@ class RevoluteJoint(Joint):
angle_reference: VectorLike | None = None,
angular_range: tuple[float, float] = (0, 360),
):
context: BuildPart = BuildPart._get_context(self)
context: BuildPart | None = BuildPart._get_context(self)
validate_inputs(context, self)
if to_part is None:
if context is not None:
@ -287,6 +289,8 @@ class RevoluteJoint(Joint):
else:
self.angle_reference = Plane(origin=(0, 0, 0), z_dir=axis.direction).x_dir
self._angle: float | None = None
if part_or_builder.location is None:
raise ValueError("Part must have a location")
self.relative_axis = axis.located(part_or_builder.location.inverse())
part_or_builder.joints[label] = self
super().__init__(label, part_or_builder)
@ -384,7 +388,7 @@ class LinearJoint(Joint):
axis: Axis = Axis.Z,
linear_range: tuple[float, float] = (0, inf),
):
context: BuildPart = BuildPart._get_context(self)
context: BuildPart | None = BuildPart._get_context(self)
validate_inputs(context, self)
if to_part is None:
if context is not None:
@ -396,6 +400,8 @@ class LinearJoint(Joint):
self.axis = axis
self.linear_range = linear_range
self.position = None
if part_or_builder.location is None:
raise ValueError("Part must have a location")
self.relative_axis = axis.located(part_or_builder.location.inverse())
self.angle = None
part_or_builder.joints[label] = self
@ -571,7 +577,7 @@ class CylindricalJoint(Joint):
linear_range: tuple[float, float] = (0, inf),
angular_range: tuple[float, float] = (0, 360),
):
context: BuildPart = BuildPart._get_context(self)
context: BuildPart | None = BuildPart._get_context(self)
validate_inputs(context, self)
if to_part is None:
if context is not None:
@ -591,6 +597,8 @@ class CylindricalJoint(Joint):
self.angle_reference = Plane(origin=(0, 0, 0), z_dir=axis.direction).x_dir
self.angular_range = angular_range
self.linear_range = linear_range
if part_or_builder.location is None:
raise ValueError("Part must have a location")
self.relative_axis = axis.located(part_or_builder.location.inverse())
self.position: float | None = None
self.angle: float | None = None
@ -733,7 +741,7 @@ class BallJoint(Joint):
] = ((0, 360), (0, 360), (0, 360)),
angle_reference: Plane = Plane.XY,
):
context: BuildPart = BuildPart._get_context(self)
context: BuildPart | None = BuildPart._get_context(self)
validate_inputs(context, self)
if to_part is None:
if context is not None:
@ -745,6 +753,8 @@ class BallJoint(Joint):
if joint_location is None:
joint_location = Location()
if part_or_builder.location is None:
raise ValueError("Part must have a location")
self.relative_location = part_or_builder.location.inverse() * joint_location
part_or_builder.joints[label] = self
self.angular_range = angular_range

View file

@ -86,10 +86,10 @@ import ctypes
import math
import os
import sys
import uuid
import warnings
from os import PathLike, fsdecode
from typing import Union
from uuid import UUID
from collections.abc import Iterable
@ -295,6 +295,8 @@ class Mesher:
ocp_mesh_vertices.append(pnt)
# Store the triangles from the triangulated faces
if facet.wrapped is None:
continue
facet_reversed = facet.wrapped.Orientation() == ta.TopAbs_REVERSED
order = [1, 3, 2] if facet_reversed else [1, 2, 3]
for tri in poly_triangulation.Triangles():
@ -305,7 +307,7 @@ class Mesher:
@staticmethod
def _create_3mf_mesh(
ocp_mesh_vertices: list[tuple[float, float, float]],
triangles: list[list[int, int, int]],
triangles: list[list[int]],
):
# Round off the vertices to avoid vertices within tolerance being
# considered as different vertices
@ -337,7 +339,7 @@ class Mesher:
# Remove degenerate triangles
if len(set(mapped_indices)) != 3:
continue
c_array = (ctypes.c_uint * 3)(*mapped_indices)
c_array = (ctypes.c_uint * 3)(*mapped_indices) # type: ignore[assignment]
triangles_3mf.append(Lib3MF.Triangle(c_array))
return (vertices_3mf, triangles_3mf)
@ -360,8 +362,8 @@ class Mesher:
linear_deflection: float = 0.001,
angular_deflection: float = 0.1,
mesh_type: MeshType = MeshType.MODEL,
part_number: str = None,
uuid_value: uuid = None,
part_number: str | None = None,
uuid_value: UUID | None = None,
):
"""add_shape
@ -507,7 +509,6 @@ class Mesher:
# Extract 3MF meshes and translate to OCP meshes
mesh_iterator: Lib3MF.MeshObjectIterator = self.model.GetMeshObjects()
self.meshes: list[Lib3MF.MeshObject]
for _i in range(mesh_iterator.Count()):
mesh_iterator.MoveNext()
self.meshes.append(mesh_iterator.GetCurrentMeshObject())

View file

@ -164,6 +164,8 @@ def extrude(
target_object = context.part
else:
target_object = target
if target_object is None:
raise ValueError("No target object provided")
new_solids.append(
Solid.extrude_until(
@ -509,7 +511,7 @@ def section(
if obj is not None:
to_section = obj
elif context is not None:
elif context is not None and context.part is not None:
to_section = context.part
else:
raise ValueError("No object to section")

View file

@ -437,7 +437,7 @@ class Mixin1D(Shape):
return result
def edge(self) -> Edge:
def edge(self) -> Edge | None:
"""Return the Edge"""
return Shape.get_single_shape(self, "Edge")
@ -1086,7 +1086,7 @@ class Mixin1D(Shape):
return Vector(gp_Dir(res))
def vertex(self) -> Vertex:
def vertex(self) -> Vertex | None:
"""Return the Vertex"""
return Shape.get_single_shape(self, "Vertex")
@ -1094,7 +1094,7 @@ class Mixin1D(Shape):
"""vertices - all the vertices in this Shape"""
return Shape.get_shape_list(self, "Vertex")
def wire(self) -> Wire:
def wire(self) -> Wire | None:
"""Return the Wire"""
return Shape.get_single_shape(self, "Wire")

View file

@ -576,7 +576,7 @@ class Mixin3D(Shape):
return offset_solid
def solid(self) -> Solid:
def solid(self) -> Solid | None:
"""Return the Solid"""
return Shape.get_single_shape(self, "Solid")
@ -1043,9 +1043,7 @@ class Solid(Mixin3D, Shape[TopoDS_Solid]):
)
@classmethod
def make_loft(
cls, objs: Iterable[Vertex | Wire], ruled: bool = False
) -> Solid:
def make_loft(cls, objs: Iterable[Vertex | Wire], ruled: bool = False) -> Solid:
"""make loft
Makes a loft from a list of wires and vertices. Vertices can appear only at the

View file

@ -187,7 +187,7 @@ class Mixin2D(Shape):
return new_surface
def face(self) -> Face:
def face(self) -> Face | None:
"""Return the Face"""
return Shape.get_single_shape(self, "Face")
@ -246,7 +246,7 @@ class Mixin2D(Shape):
"""Return a copy of self moved along the normal by amount"""
return copy.deepcopy(self).moved(Location(self.normal_at() * amount))
def shell(self) -> Shell:
def shell(self) -> Shell | None:
"""Return the Shell"""
return Shape.get_single_shape(self, "Shell")
@ -1191,10 +1191,15 @@ class Face(Mixin2D, Shape[TopoDS_Face]):
intersected_shapes.append(Shell(topods_shell))
intersected_shapes = intersected_shapes.sort_by(Axis(self.center(), direction))
intersected_shapes = ShapeList(
s.face() if len(s.faces()) == 1 else s for s in intersected_shapes
)
return intersected_shapes
projected_shapes: ShapeList[Face | Shell] = ShapeList()
for shape in intersected_shapes:
if len(shape.faces()) == 1:
shape_face = shape.face()
if shape_face is not None:
projected_shapes.append(shape_face)
else:
projected_shapes.append(shape)
return projected_shapes
def to_arcs(self, tolerance: float = 1e-3) -> Face:
"""to_arcs
@ -1306,9 +1311,7 @@ class Shell(Mixin2D, Shape[TopoDS_Shell]):
return Shell(TopoDS.Shell_s(_extrude_topods_shape(obj.wrapped, direction)))
@classmethod
def make_loft(
cls, objs: Iterable[Vertex | Wire], ruled: bool = False
) -> Shell:
def make_loft(cls, objs: Iterable[Vertex | Wire], ruled: bool = False) -> Shell:
"""make loft
Makes a loft from a list of wires and vertices. Vertices can appear only at the

View file

@ -54,7 +54,7 @@ license:
from __future__ import annotations
from math import radians, sin, cos, isclose
from typing import Any, Union, TYPE_CHECKING
from typing import Any, TYPE_CHECKING
from collections.abc import Iterable
@ -91,9 +91,6 @@ from .shape_core import Shape, ShapeList, downcast, shapetype, unwrap_topods_com
if TYPE_CHECKING: # pragma: no cover
from .zero_d import Vertex # pylint: disable=R0801
from .one_d import Edge, Wire # pylint: disable=R0801
from .two_d import Face, Shell # pylint: disable=R0801
from .three_d import Solid # pylint: disable=R0801
from .composite import Compound, Curve, Sketch, Part # pylint: disable=R0801
def _extrude_topods_shape(obj: TopoDS_Shape, direction: VectorLike) -> TopoDS_Shape: