|
| 1 | +"""Regression tests for optional SymPy loading in fresh interpreters.""" |
| 2 | + |
| 3 | +import subprocess |
| 4 | +import sys |
| 5 | +import textwrap |
| 6 | + |
| 7 | +import pytest |
| 8 | + |
| 9 | + |
| 10 | +def run_python(source): |
| 11 | + """Run an isolated check with the same interpreter as pytest.""" |
| 12 | + subprocess.run([sys.executable, "-c", textwrap.dedent(source)], check=True) |
| 13 | + |
| 14 | + |
| 15 | +def test_numeric_import_does_not_load_sympy(): |
| 16 | + run_python( |
| 17 | + """ |
| 18 | + import sys |
| 19 | + import numpy as np |
| 20 | + import spatialmath |
| 21 | + from spatialmath import base as smb |
| 22 | + assert not any(n == 'sympy' or n.startswith('sympy.') for n in sys.modules) |
| 23 | + assert smb.isscalar(1.0) |
| 24 | + assert smb.isvector([1, 2]) |
| 25 | + assert smb.isnumberlist([1, 2]) |
| 26 | + assert smb.norm([3, 4]) == 5 |
| 27 | + assert np.allclose(smb.rot2(0), np.eye(2)) |
| 28 | + assert not any(n == 'sympy' or n.startswith('sympy.') for n in sys.modules) |
| 29 | + """ |
| 30 | + ) |
| 31 | + |
| 32 | + |
| 33 | +@pytest.mark.parametrize("sympy_first", [False, True]) |
| 34 | +def test_symbolic_operations_in_both_import_orders(sympy_first): |
| 35 | + prefix = "import sympy as sp\n" if sympy_first else "" |
| 36 | + run_python( |
| 37 | + prefix |
| 38 | + + """ |
| 39 | +import numpy as np |
| 40 | +from spatialmath import base as smb |
| 41 | +import sympy as sp |
| 42 | +x = sp.Symbol('x', real=True) |
| 43 | +assert smb.issymbol(x) |
| 44 | +assert smb.issymbol([1, x]) |
| 45 | +assert smb.issymbol((x, 1)) |
| 46 | +assert not smb.issymbol([1, 2]) |
| 47 | +assert smb.isscalar(x) |
| 48 | +assert not smb.isscalar([x]) |
| 49 | +assert not smb.isscalar((x,)) |
| 50 | +assert smb.isvector([x, 1]) |
| 51 | +assert smb.isnumberlist([x, 1]) |
| 52 | +assert smb.getvector(x)[0] == x |
| 53 | +assert smb.getvector([x, 1])[0] == x |
| 54 | +assert smb.sin(x) == sp.sin(x) |
| 55 | +assert smb.cos(x) == sp.cos(x) |
| 56 | +assert smb.tan(x) == sp.tan(x) |
| 57 | +assert smb.sqrt(x) == sp.sqrt(x) |
| 58 | +assert smb.norm([x, 1]) == sp.sqrt(x*x + 1) |
| 59 | +assert smb.det(np.array([[x, 0], [0, 1]], dtype=object)) == x |
| 60 | +T = smb.trot2(x) |
| 61 | +assert sp.simplify(smb.tr2xyt(T)[2] - sp.atan2(sp.sin(x), sp.cos(x))) == 0 |
| 62 | +assert smb.simplify(sp.sin(x)**2 + sp.cos(x)**2) == 1 |
| 63 | +""" |
| 64 | + ) |
| 65 | + |
| 66 | + |
| 67 | +@pytest.mark.parametrize("helper", ["symbol", "zero", "one", "negative_one", "pi"]) |
| 68 | +def test_explicit_symbolic_helpers_load_sympy(helper): |
| 69 | + run_python( |
| 70 | + textwrap.dedent(f"helper = {helper!r}\n") |
| 71 | + + textwrap.dedent( |
| 72 | + """ |
| 73 | + import sys |
| 74 | + from spatialmath.base import symbolic as sym |
| 75 | + assert 'sympy' not in sys.modules |
| 76 | + getattr(sym, helper)(*(['x'] if helper == 'symbol' else [])) |
| 77 | + assert 'sympy' in sys.modules |
| 78 | + x = sym.symbol('x') |
| 79 | + import sympy as sp |
| 80 | + assert isinstance(x, sp.Symbol) |
| 81 | + from spatialmath.base.symbolic import Symbol, symtype |
| 82 | + assert Symbol is sp.Symbol |
| 83 | + assert symtype == (sp.Expr,) |
| 84 | + assert sym.zero() == sp.S.Zero |
| 85 | + assert sym.one() == sp.S.One |
| 86 | + assert sym.negative_one() == sp.S.NegativeOne |
| 87 | + assert sym.pi() == sp.pi |
| 88 | + """ |
| 89 | + ) |
| 90 | + ) |
| 91 | + |
| 92 | + |
| 93 | +def test_numeric_operations_without_sympy(): |
| 94 | + run_python( |
| 95 | + """ |
| 96 | + import importlib.abc |
| 97 | + import sys |
| 98 | + class BlockSympy(importlib.abc.MetaPathFinder): |
| 99 | + def find_spec(self, fullname, path=None, target=None): |
| 100 | + if fullname == 'sympy' or fullname.startswith('sympy.'): |
| 101 | + raise ModuleNotFoundError('SymPy blocked for this test') |
| 102 | + sys.meta_path.insert(0, BlockSympy()) |
| 103 | + from spatialmath import base as smb |
| 104 | + assert not smb.issymbol(1) |
| 105 | + assert smb.norm([3, 4]) == 5 |
| 106 | + assert smb.sin(0) == 0 |
| 107 | + assert smb.simplify(2) == 2 |
| 108 | + assert smb.isscalar(1) |
| 109 | + assert smb.isvector([1, 2]) |
| 110 | + """ |
| 111 | + ) |
0 commit comments