Skip to content

Commit 4be4767

Browse files
author
Rory Yorke
committed
Replace test decorator slycotonly with pytest mark slycot
The pytest marker slycot is equivalent to the slycotonly decorator, and also allows slycot tests to be included or excluded at the pytest command-line.
1 parent abeb0e4 commit 4be4767

19 files changed

+82
-94
lines changed

control/tests/canonical_test.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
import pytest
55
import scipy.linalg
66

7-
from control.tests.conftest import slycotonly
8-
97
from control import ss, tf, tf2ss
108
from control.canonical import canonical_form, reachable_form, \
119
observable_form, modal_form, similarity_transform, bdschur
@@ -244,7 +242,7 @@ def block_diag_from_eig(eigvals):
244242
return scipy.linalg.block_diag(*blocks)
245243

246244

247-
@slycotonly
245+
@pytest.mark.slycot
248246
@pytest.mark.parametrize(
249247
"eigvals, condmax, blksizes",
250248
[
@@ -269,7 +267,7 @@ def test_bdschur_ref(eigvals, condmax, blksizes):
269267
np.testing.assert_array_almost_equal(solve(t, a) @ t, b)
270268

271269

272-
@slycotonly
270+
@pytest.mark.slycot
273271
@pytest.mark.parametrize(
274272
"eigvals, sorted_blk_eigvals, sort",
275273
[
@@ -300,7 +298,7 @@ def test_bdschur_sort(eigvals, sorted_blk_eigvals, sort):
300298
blk_eigval.imag)
301299

302300

303-
@slycotonly
301+
@pytest.mark.slycot
304302
def test_bdschur_defective():
305303
# the eigenvalues of this simple defective matrix cannot be separated
306304
# a previous version of the bdschur would fail on this
@@ -323,14 +321,14 @@ def test_bdschur_condmax_lt_1():
323321
bdschur(1, condmax=np.nextafter(1, 0))
324322

325323

326-
@slycotonly
324+
@pytest.mark.slycot
327325
def test_bdschur_invalid_sort():
328326
# sort must be in ('continuous', 'discrete')
329327
with pytest.raises(ValueError):
330328
bdschur(1, sort='no-such-sort')
331329

332330

333-
@slycotonly
331+
@pytest.mark.slycot
334332
@pytest.mark.parametrize(
335333
"A_true, B_true, C_true, D_true",
336334
[(np.diag([4.0, 3.0, 2.0, 1.0]), # order from largest to smallest
@@ -390,7 +388,7 @@ def test_modal_form(A_true, B_true, C_true, D_true):
390388
C @ np.linalg.matrix_power(A, i) @ B)
391389

392390

393-
@slycotonly
391+
@pytest.mark.slycot
394392
@pytest.mark.parametrize(
395393
"condmax, len_blksizes",
396394
[(1.1, 1),
@@ -409,7 +407,7 @@ def test_modal_form_condmax(condmax, len_blksizes):
409407
np.testing.assert_array_almost_equal(zsys.D, xsys.D)
410408

411409

412-
@slycotonly
410+
@pytest.mark.slycot
413411
@pytest.mark.parametrize(
414412
"sys_type",
415413
['continuous',

control/tests/conftest.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66

77
import control
88

9-
10-
# some common pytest marks. These can be used as test decorators or in
11-
# pytest.param(marks=)
12-
slycotonly = pytest.mark.skipif(
13-
not control.exception.slycot_check(), reason="slycot not installed")
149
cvxoptonly = pytest.mark.skipif(
1510
not control.exception.cvxopt_check(), reason="cvxopt not installed")
1611

12+
def pytest_runtest_setup(item):
13+
if (not control.exception.slycot_check()
14+
and any(mark.name == 'slycot'
15+
for mark in item.iter_markers())):
16+
pytest.skip("slycot not installed")
17+
1718

1819
@pytest.fixture(scope="session", autouse=True)
1920
def control_defaults():

control/tests/convert_test.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
from control.statefbk import ctrb, obsv
2323
from control.freqplot import bode
2424
from control.exception import slycot_check, ControlMIMONotImplemented
25-
from control.tests.conftest import slycotonly
2625

2726

2827
# Set to True to print systems to the output.
@@ -214,7 +213,7 @@ def testSs2tfStaticMimo(self):
214213
np.testing.assert_allclose(numref,
215214
np.array(gtf.num) / np.array(gtf.den))
216215

217-
@slycotonly
216+
@pytest.mark.slycot
218217
def testTf2SsDuplicatePoles(self):
219218
"""Tests for 'too few poles for MIMO tf gh-111'"""
220219
num = [[[1], [0]],
@@ -225,7 +224,7 @@ def testTf2SsDuplicatePoles(self):
225224
s = ss(g)
226225
np.testing.assert_allclose(g.poles(), s.poles())
227226

228-
@slycotonly
227+
@pytest.mark.slycot
229228
def test_tf2ss_robustness(self):
230229
"""Unit test to make sure that tf2ss is working correctly. gh-240"""
231230
num = [ [[0], [1]], [[1], [0]] ]

control/tests/frd_test.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from control.xferfcn import TransferFunction
1313
from control.frdata import frd, _convert_to_frd, FrequencyResponseData
1414
from control import bdalg, freqplot
15-
from control.tests.conftest import slycotonly
1615
from control.exception import pandas_check
1716

1817

@@ -567,7 +566,7 @@ def test_mul_mimo_siso(self, left, right, expected):
567566
np.testing.assert_array_almost_equal(expected_frd.omega, result.omega)
568567
np.testing.assert_array_almost_equal(expected_frd.frdata, result.frdata)
569568

570-
@slycotonly
569+
@pytest.mark.slycot
571570
def test_truediv_mimo_siso(self):
572571
omega = np.logspace(-1, 1, 10)
573572
tf_mimo = TransferFunction([1], [1, 0]) * np.eye(2)
@@ -592,7 +591,7 @@ def test_truediv_mimo_siso(self):
592591
np.testing.assert_array_almost_equal(expected.omega, result.omega)
593592
np.testing.assert_array_almost_equal(expected.frdata, result.frdata)
594593

595-
@slycotonly
594+
@pytest.mark.slycot
596595
def test_rtruediv_mimo_siso(self):
597596
omega = np.logspace(-1, 1, 10)
598597
tf_mimo = TransferFunction([1], [1, 0]) * np.eye(2)

control/tests/freqresp_test.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
singular_values_plot, singular_values_response)
2020
from control.matlab import bode, rss, ss, tf
2121
from control.statesp import StateSpace
22-
from control.tests.conftest import slycotonly
2322
from control.xferfcn import TransferFunction
2423

2524
pytestmark = pytest.mark.usefixtures("mplcleanup")
@@ -61,7 +60,7 @@ def test_freqresp_siso(ss_siso):
6160

6261

6362
@pytest.mark.filterwarnings(r"ignore:freqresp\(\) is deprecated")
64-
@slycotonly
63+
@pytest.mark.slycot
6564
def test_freqresp_mimo_legacy(ss_mimo):
6665
"""Test MIMO frequency response calls"""
6766
omega = np.linspace(10e-2, 10e2, 1000)
@@ -70,7 +69,7 @@ def test_freqresp_mimo_legacy(ss_mimo):
7069
ctrl.freqresp(tf_mimo, omega)
7170

7271

73-
@slycotonly
72+
@pytest.mark.slycot
7473
def test_freqresp_mimo(ss_mimo):
7574
"""Test MIMO frequency response calls"""
7675
omega = np.linspace(10e-2, 10e2, 1000)

control/tests/lti_test.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
isdtime, issiso, ss, tf, tf2ss
1111
from control.exception import slycot_check
1212
from control.lti import LTI, bandwidth, damp, dcgain, evalfr, poles, zeros
13-
from control.tests.conftest import slycotonly
1413

1514

1615
class TestLTI:
@@ -59,7 +58,7 @@ def test_issiso(self):
5958
assert issiso(sys)
6059
assert issiso(sys, strict=True)
6160

62-
@slycotonly
61+
@pytest.mark.slycot
6362
def test_issiso_mimo(self):
6463
# MIMO transfer function
6564
sys = tf([[[-1, 41], [1]], [[1, 2], [3, 4]]],

control/tests/mateqn_test.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
import control as ct
4343
from control.mateqn import lyap, dlyap, care, dare
4444
from control.exception import ControlArgument, ControlDimension, slycot_check
45-
from control.tests.conftest import slycotonly
4645

4746

4847
class TestMatrixEquations:
@@ -88,7 +87,7 @@ def test_lyap_sylvester(self):
8887
X_slycot = lyap(A, B, C, method='slycot')
8988
assert_array_almost_equal(X_scipy, X_slycot)
9089

91-
@slycotonly
90+
@pytest.mark.slycot
9291
def test_lyap_g(self):
9392
A = array([[-1, 2], [-3, -4]])
9493
Q = array([[3, 1], [1, 1]])
@@ -115,7 +114,7 @@ def test_dlyap(self):
115114
# print("The solution obtained is ", X)
116115
assert_array_almost_equal(A @ X @ A.T - X + Q, zeros((2,2)))
117116

118-
@slycotonly
117+
@pytest.mark.slycot
119118
def test_dlyap_g(self):
120119
A = array([[-0.6, 0],[-0.1, -0.4]])
121120
Q = array([[3, 1],[1, 1]])
@@ -129,7 +128,7 @@ def test_dlyap_g(self):
129128
with pytest.raises(ControlArgument, match="'scipy' not valid"):
130129
X = dlyap(A, Q, None, E, method='scipy')
131130

132-
@slycotonly
131+
@pytest.mark.slycot
133132
def test_dlyap_sylvester(self):
134133
A = 5
135134
B = array([[4, 3], [4, 3]])

control/tests/matlab_test.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
from control.exception import ControlArgument
3131

3232
from control.frdata import FRD
33-
from control.tests.conftest import slycotonly
3433

3534
# for running these through Matlab or Octave
3635
'''
@@ -487,29 +486,29 @@ def testEvalfr_mimo(self, mimo):
487486
ref = np.array([[44.8 - 21.4j, 0.], [0., 44.8 - 21.4j]])
488487
np.testing.assert_array_almost_equal(fr, ref)
489488

490-
@slycotonly
489+
@pytest.mark.slycot
491490
def testHsvd(self, siso):
492491
"""Call hsvd()"""
493492
hsvd(siso.ss1)
494493
hsvd(siso.ss2)
495494
hsvd(siso.ss3)
496495

497-
@slycotonly
496+
@pytest.mark.slycot
498497
def testBalred(self, siso):
499498
"""Call balred()"""
500499
balred(siso.ss1, 1)
501500
balred(siso.ss2, 2)
502501
balred(siso.ss3, [2, 2])
503502

504-
@slycotonly
503+
@pytest.mark.slycot
505504
def testModred(self, siso):
506505
"""Call modred()"""
507506
modred(siso.ss1, [1])
508507
modred(siso.ss2 * siso.ss1, [0, 1])
509508
modred(siso.ss1, [1], 'matchdc')
510509
modred(siso.ss1, [1], 'truncate')
511510

512-
@slycotonly
511+
@pytest.mark.slycot
513512
def testPlace_varga(self, siso):
514513
"""Call place_varga()"""
515514
place_varga(siso.ss1.A, siso.ss1.B, [-2, -2])
@@ -552,7 +551,7 @@ def testObsv(self, siso):
552551
obsv(siso.ss1.A, siso.ss1.C)
553552
obsv(siso.ss2.A, siso.ss2.C)
554553

555-
@slycotonly
554+
@pytest.mark.slycot
556555
def testGram(self, siso):
557556
"""Call gram()"""
558557
gram(siso.ss1, 'c')
@@ -696,7 +695,7 @@ def testFRD(self):
696695
frd2 = frd(frd1.frdata[0, 0, :], omega)
697696
assert isinstance(frd2, FRD)
698697

699-
@slycotonly
698+
@pytest.mark.slycot
700699
def testMinreal(self, verbose=False):
701700
"""Test a minreal model reduction"""
702701
# A = [-2, 0.5, 0; 0.5, -0.3, 0; 0, 0, -0.1]

control/tests/minreal_test.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,14 @@
1111
from control.statesp import StateSpace
1212
from control.xferfcn import TransferFunction
1313
from itertools import permutations
14-
from control.tests.conftest import slycotonly
1514

1615

1716
@pytest.fixture
1817
def fixedseed(scope="class"):
1918
np.random.seed(5)
2019

2120

22-
@slycotonly
21+
@pytest.mark.slycot
2322
@pytest.mark.usefixtures("fixedseed")
2423
class TestMinreal:
2524
"""Tests for the StateSpace class."""

control/tests/modelsimp_test.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,12 @@
1414
from control.exception import ControlArgument, ControlDimension
1515
from control.modelsimp import balred, eigensys_realization, hsvd, markov, \
1616
modred
17-
from control.tests.conftest import slycotonly
1817

1918

2019
class TestModelsimp:
2120
"""Test model reduction functions"""
2221

23-
@slycotonly
22+
@pytest.mark.slycot
2423
def testHSVD(self):
2524
A = np.array([[1., -2.], [3., -4.]])
2625
B = np.array([[5.], [7.]])
@@ -390,7 +389,7 @@ def testModredTruncate(self):
390389
np.testing.assert_array_almost_equal(rsys.D, Drtrue)
391390

392391

393-
@slycotonly
392+
@pytest.mark.slycot
394393
def testBalredTruncate(self):
395394
# controlable canonical realization computed in matlab for the transfer
396395
# function:
@@ -431,7 +430,7 @@ def testBalredTruncate(self):
431430
np.testing.assert_array_almost_equal(Cr, Crtrue, decimal=4)
432431
np.testing.assert_array_almost_equal(Dr, Drtrue, decimal=4)
433432

434-
@slycotonly
433+
@pytest.mark.slycot
435434
def testBalredMatchDC(self):
436435
# controlable canonical realization computed in matlab for the transfer
437436
# function:

0 commit comments

Comments
 (0)