diff --git a/spatialmath/base/quaternions.py b/spatialmath/base/quaternions.py index 92111793..3de527f9 100755 --- a/spatialmath/base/quaternions.py +++ b/spatialmath/base/quaternions.py @@ -16,11 +16,13 @@ import spatialmath.base as smb from spatialmath.base.argcheck import getunit from spatialmath.base.types import * -import scipy.interpolate as interpolate -from typing import Optional +from typing import TYPE_CHECKING, Optional from functools import lru_cache import warnings +if TYPE_CHECKING: + import scipy.interpolate as interpolate + _eps = np.finfo(np.float64).eps @@ -897,7 +899,7 @@ def _compute_cdf_sin_squared(theta: float): @lru_cache(maxsize=1) def _generate_inv_cdf_sin_squared_interp( num_interpolation_points: int = 256, -) -> interpolate.interp1d: +) -> "interpolate.interp1d": """ Computes an interpolation function for the inverse CDF of the distribution of angular magnitude. @@ -910,6 +912,8 @@ def _generate_inv_cdf_sin_squared_interp( This function returns interpolation function for the inverse of the integral of the pdf of angular magnitudes (2/pi * sin^2(theta/2)), which is not analytically defined. """ + import scipy.interpolate as interpolate # deferred, it is slow to import + cdf_sin_squared_interp_angles = np.linspace(0, np.pi, num_interpolation_points) cdf_sin_squared_interp_values = _compute_cdf_sin_squared( cdf_sin_squared_interp_angles diff --git a/spatialmath/spline.py b/spatialmath/spline.py index 5fd66b39..c0a99cad 100644 --- a/spatialmath/spline.py +++ b/spatialmath/spline.py @@ -11,8 +11,6 @@ from typing import TYPE_CHECKING, List, Optional, Tuple import numpy as np -from scipy.interpolate import BSpline, CubicSpline -from scipy.spatial.transform import Rotation, RotationSpline from spatialmath import SE3, SO3, Twist3 from spatialmath.base.transforms3d import tranimate @@ -122,6 +120,9 @@ def __init__( self.timepoints = self.timepoints - self.timepoints[0] self.timepoints = self.timepoints / self.timepoints[-1] + from scipy.interpolate import CubicSpline # deferred, scipy is slow to import + from scipy.spatial.transform import Rotation, RotationSpline + self.spline_xyz = CubicSpline( self.timepoints, np.array([pose.t for pose in self.control_poses]), @@ -292,6 +293,8 @@ def __init__( ) # ensures the curve ends on the last control pose self.knots = knots + from scipy.interpolate import BSpline # deferred, scipy is slow to import + self.splines = [ BSpline(knots, self.control_pose_matrix[:, i], degree) for i in range(0, 6) # twists are length 6 diff --git a/tests/test_import.py b/tests/test_import.py new file mode 100644 index 00000000..e7e50fc4 --- /dev/null +++ b/tests/test_import.py @@ -0,0 +1,16 @@ +import subprocess +import sys +import unittest + + +class TestImport(unittest.TestCase): + def test_import_does_not_load_scipy(self): + # scipy is slow to import and only a few functions need it, so it is + # imported by those functions and not when spatialmath is imported + code = "import sys, spatialmath; sys.exit(any(m.split('.')[0] == 'scipy' for m in sys.modules))" + result = subprocess.run([sys.executable, "-c", code]) + self.assertEqual(result.returncode, 0, "import spatialmath loaded scipy") + + +if __name__ == "__main__": # pragma nocover + unittest.main()