From 699f322cb3a8add8c303e82e9e0e26c710349931 Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Tue, 18 Mar 2025 10:31:13 +0100 Subject: [PATCH 1/4] Use lazy imports in topology/ Loads IPython and scipy only when actually needed. Made build123d load about 1 second faster on my machine. Python caches modules so all in all this should only be a net benefit. --- src/build123d/topology/one_d.py | 6 ++++-- src/build123d/topology/shape_core.py | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/build123d/topology/one_d.py b/src/build123d/topology/one_d.py index 08c1cd4c..fe7c3809 100644 --- a/src/build123d/topology/one_d.py +++ b/src/build123d/topology/one_d.py @@ -60,8 +60,6 @@ from typing import Literal, overload, TYPE_CHECKING from typing_extensions import Self from numpy import ndarray -from scipy.optimize import minimize -from scipy.spatial import ConvexHull import OCP.TopAbs as ta from OCP.BRep import BRep_Tool @@ -1972,6 +1970,8 @@ def intersect( def param_at_point(self, point: VectorLike) -> float: """Normalized parameter at point along Edge""" + from scipy.optimize import minimize + # Note that this search algorithm would ideally be replaced with # an OCP based solution, something like that which is shown below. # However, there are known issues with the OCP methods for some @@ -2438,6 +2438,8 @@ def make_convex_hull(cls, edges: Iterable[Edge], tolerance: float = 1e-3) -> Wir Returns: Wire: convex hull perimeter """ + from scipy.spatial import ConvexHull + # pylint: disable=too-many-branches, too-many-locals # Algorithm: # 1) create a cloud of points along all edges diff --git a/src/build123d/topology/shape_core.py b/src/build123d/topology/shape_core.py index 905a5b3b..8c2f9c33 100644 --- a/src/build123d/topology/shape_core.py +++ b/src/build123d/topology/shape_core.py @@ -67,7 +67,6 @@ import OCP.GeomAbs as ga import OCP.TopAbs as ta -from IPython.lib.pretty import pretty, RepresentationPrinter from OCP.BOPAlgo import BOPAlgo_GlueEnum from OCP.BRep import BRep_Tool from OCP.BRepAdaptor import BRepAdaptor_Curve, BRepAdaptor_Surface @@ -157,6 +156,7 @@ from .three_d import Solid # pylint: disable=R0801 from .composite import Compound # pylint: disable=R0801 from build123d.build_part import BuildPart # pylint: disable=R0801 + from IPython.lib.pretty import RepresentationPrinter Shapes = Literal["Vertex", "Edge", "Wire", "Face", "Shell", "Solid", "Compound"] TrimmingTool = Union[Plane, "Shell", "Face"] @@ -2266,6 +2266,8 @@ def __repr__(self): return repr(ShapeList(self)) def __str__(self): + from IPython.lib.pretty import pretty + return pretty(self) def group(self, key: K): From cda904e41c29e981ebe346f2ad88aca00a054f18 Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Tue, 18 Mar 2025 10:43:49 +0100 Subject: [PATCH 2/4] Make pylint happy --- src/build123d/topology/one_d.py | 4 ++-- src/build123d/topology/shape_core.py | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/build123d/topology/one_d.py b/src/build123d/topology/one_d.py index fe7c3809..e77ccf51 100644 --- a/src/build123d/topology/one_d.py +++ b/src/build123d/topology/one_d.py @@ -1970,7 +1970,7 @@ def intersect( def param_at_point(self, point: VectorLike) -> float: """Normalized parameter at point along Edge""" - from scipy.optimize import minimize + from scipy.optimize import minimize # pylint: disable=C0415 # Note that this search algorithm would ideally be replaced with # an OCP based solution, something like that which is shown below. @@ -2438,7 +2438,7 @@ def make_convex_hull(cls, edges: Iterable[Edge], tolerance: float = 1e-3) -> Wir Returns: Wire: convex hull perimeter """ - from scipy.spatial import ConvexHull + from scipy.spatial import ConvexHull # pylint: disable=C0415 # pylint: disable=too-many-branches, too-many-locals # Algorithm: diff --git a/src/build123d/topology/shape_core.py b/src/build123d/topology/shape_core.py index 8c2f9c33..aeda75ec 100644 --- a/src/build123d/topology/shape_core.py +++ b/src/build123d/topology/shape_core.py @@ -60,8 +60,10 @@ TypeVar, Union, overload, + Literal, TYPE_CHECKING, ) +from typing_extensions import Self from collections.abc import Callable, Iterable, Iterator @@ -144,10 +146,6 @@ VectorLike, logger, ) -from typing_extensions import Self - -from typing import Literal - if TYPE_CHECKING: # pragma: no cover from .zero_d import Vertex # pylint: disable=R0801 @@ -2266,7 +2264,7 @@ def __repr__(self): return repr(ShapeList(self)) def __str__(self): - from IPython.lib.pretty import pretty + from IPython.lib.pretty import pretty # pylint: disable=C0415 return pretty(self) From 6657639723dd556e652bf9a2b3167e85b011f28c Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Wed, 2 Apr 2025 14:03:54 +0200 Subject: [PATCH 3/4] Lazy import more stuff --- src/build123d/exporters.py | 9 ++++++--- src/build123d/importers.py | 5 +++-- src/build123d/objects_curve.py | 3 ++- src/build123d/operations_sketch.py | 3 ++- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/build123d/exporters.py b/src/build123d/exporters.py index 49339eed..e90319f2 100644 --- a/src/build123d/exporters.py +++ b/src/build123d/exporters.py @@ -30,6 +30,8 @@ # pylint: disable=no-name-in-module, import-error # pylint: disable=too-many-lines +from __future__ import annotations +from typing import TYPE_CHECKING import math import xml.etree.ElementTree as ET from copy import copy @@ -41,7 +43,6 @@ from collections.abc import Callable, Iterable import ezdxf -import svgpathtools as PT from ezdxf import zoom from ezdxf.colors import RGB, aci2rgb from ezdxf.math import Vec2 @@ -69,8 +70,10 @@ ) from build123d.build_common import UNITS_PER_METER -PathSegment: TypeAlias = PT.Line | PT.Arc | PT.QuadraticBezier | PT.CubicBezier -"""A type alias for the various path segment types in the svgpathtools library.""" +if TYPE_CHECKING: + import svgpathtools as PT + PathSegment: TypeAlias = PT.Line | PT.Arc | PT.QuadraticBezier | PT.CubicBezier + """A type alias for the various path segment types in the svgpathtools library.""" # --------------------------------------------------------------------------- # --------------------------------------------------------------------------- diff --git a/src/build123d/importers.py b/src/build123d/importers.py index 73be5a7d..d7785aa3 100644 --- a/src/build123d/importers.py +++ b/src/build123d/importers.py @@ -67,8 +67,6 @@ XCAFDoc_ColorSurf, XCAFDoc_DocumentTool, ) -from ocpsvg import ColorAndLabel, import_svg_document -from svgpathtools import svg2paths from build123d.build_enums import Align from build123d.geometry import Color, Location, Vector, to_align_offset @@ -270,6 +268,7 @@ def import_svg_as_buildline_code( Returns: tuple[str, str]: code, builder instance name """ + from svgpathtools import svg2paths translator = { "Line": ["Line", "start", "end"], @@ -361,6 +360,8 @@ def import_svg( Returns: ShapeList[Union[Wire, Face]]: objects contained in svg """ + from ocpsvg import ColorAndLabel, import_svg_document + if is_inkscape_label is not None: # TODO remove for `1.0` release msg = "`is_inkscape_label` parameter is deprecated" if is_inkscape_label: diff --git a/src/build123d/objects_curve.py b/src/build123d/objects_curve.py index 633cad38..4f70e0dd 100644 --- a/src/build123d/objects_curve.py +++ b/src/build123d/objects_curve.py @@ -30,7 +30,6 @@ import copy as copy_module from math import copysign, cos, radians, sin, sqrt -from scipy.optimize import minimize from collections.abc import Iterable @@ -204,6 +203,8 @@ def __init__( keep: Keep = Keep.TOP, mode: Mode = Mode.ADD, ): + from scipy.optimize import minimize + context: BuildLine | None = BuildLine._get_context(self) validate_inputs(context, self) diff --git a/src/build123d/operations_sketch.py b/src/build123d/operations_sketch.py index 4883be5c..ff4cda60 100644 --- a/src/build123d/operations_sketch.py +++ b/src/build123d/operations_sketch.py @@ -30,7 +30,6 @@ from __future__ import annotations from collections.abc import Iterable -from scipy.spatial import Voronoi from build123d.build_enums import Mode, SortBy from build123d.topology import ( Compound, @@ -76,6 +75,8 @@ def full_round( geometric center of the arc, and the third the radius of the arc """ + from scipy.spatial import Voronoi + context: BuildSketch | None = BuildSketch._get_context("full_round") if not isinstance(edge, Edge): From ccead2727dd9a99813affe9ba11ac1c68aa32b10 Mon Sep 17 00:00:00 2001 From: Jasmin Bom Date: Wed, 2 Apr 2025 14:15:53 +0200 Subject: [PATCH 4/4] Make pylint happy Whoops, forgot pylint warns on non top-level imports --- src/build123d/exporters.py | 2 +- src/build123d/importers.py | 4 ++-- src/build123d/objects_curve.py | 2 +- src/build123d/operations_sketch.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/build123d/exporters.py b/src/build123d/exporters.py index e90319f2..91e47531 100644 --- a/src/build123d/exporters.py +++ b/src/build123d/exporters.py @@ -71,7 +71,7 @@ from build123d.build_common import UNITS_PER_METER if TYPE_CHECKING: - import svgpathtools as PT + import svgpathtools as PT # pylint: disable=C0415 PathSegment: TypeAlias = PT.Line | PT.Arc | PT.QuadraticBezier | PT.CubicBezier """A type alias for the various path segment types in the svgpathtools library.""" diff --git a/src/build123d/importers.py b/src/build123d/importers.py index d7785aa3..fd225651 100644 --- a/src/build123d/importers.py +++ b/src/build123d/importers.py @@ -268,7 +268,7 @@ def import_svg_as_buildline_code( Returns: tuple[str, str]: code, builder instance name """ - from svgpathtools import svg2paths + from svgpathtools import svg2paths # pylint: disable=C0415 translator = { "Line": ["Line", "start", "end"], @@ -360,7 +360,7 @@ def import_svg( Returns: ShapeList[Union[Wire, Face]]: objects contained in svg """ - from ocpsvg import ColorAndLabel, import_svg_document + from ocpsvg import ColorAndLabel, import_svg_document # pylint: disable=C0415 if is_inkscape_label is not None: # TODO remove for `1.0` release msg = "`is_inkscape_label` parameter is deprecated" diff --git a/src/build123d/objects_curve.py b/src/build123d/objects_curve.py index 4f70e0dd..35f6913c 100644 --- a/src/build123d/objects_curve.py +++ b/src/build123d/objects_curve.py @@ -203,7 +203,7 @@ def __init__( keep: Keep = Keep.TOP, mode: Mode = Mode.ADD, ): - from scipy.optimize import minimize + from scipy.optimize import minimize # pylint: disable=C0415 context: BuildLine | None = BuildLine._get_context(self) validate_inputs(context, self) diff --git a/src/build123d/operations_sketch.py b/src/build123d/operations_sketch.py index ff4cda60..c075e6de 100644 --- a/src/build123d/operations_sketch.py +++ b/src/build123d/operations_sketch.py @@ -75,7 +75,7 @@ def full_round( geometric center of the arc, and the third the radius of the arc """ - from scipy.spatial import Voronoi + from scipy.spatial import Voronoi # pylint: disable=C0415 context: BuildSketch | None = BuildSketch._get_context("full_round")