Skip to content

Commit 2435a6a

Browse files
authored
Merge pull request #1182 from roryyorke/rory/test-markers
Use pytest markers for slycot, cvxopt, and pandas tests
2 parents abeb0e4 + 01d76fd commit 2435a6a

20 files changed

+98
-101
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: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,22 @@
66

77
import control
88

9+
def pytest_runtest_setup(item):
10+
if (not control.exception.slycot_check()
11+
and any(mark.name == 'slycot'
12+
for mark in item.iter_markers())):
13+
pytest.skip("slycot not installed")
14+
15+
if (not control.exception.cvxopt_check()
16+
and any(mark.name == 'cvxopt'
17+
for mark in item.iter_markers())):
18+
pytest.skip("cvxopt not installed")
19+
20+
if (not control.exception.pandas_check()
21+
and any(mark.name == 'pandas'
22+
for mark in item.iter_markers())):
23+
pytest.skip("pandas not installed")
924

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")
14-
cvxoptonly = pytest.mark.skipif(
15-
not control.exception.cvxopt_check(), reason="cvxopt not installed")
1625

1726

1827
@pytest.fixture(scope="session", autouse=True)

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: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +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
16-
from control.exception import pandas_check
1715

1816

1917
class TestFRD:
@@ -567,7 +565,7 @@ def test_mul_mimo_siso(self, left, right, expected):
567565
np.testing.assert_array_almost_equal(expected_frd.omega, result.omega)
568566
np.testing.assert_array_almost_equal(expected_frd.frdata, result.frdata)
569567

570-
@slycotonly
568+
@pytest.mark.slycot
571569
def test_truediv_mimo_siso(self):
572570
omega = np.logspace(-1, 1, 10)
573571
tf_mimo = TransferFunction([1], [1, 0]) * np.eye(2)
@@ -592,7 +590,7 @@ def test_truediv_mimo_siso(self):
592590
np.testing.assert_array_almost_equal(expected.omega, result.omega)
593591
np.testing.assert_array_almost_equal(expected.frdata, result.frdata)
594592

595-
@slycotonly
593+
@pytest.mark.slycot
596594
def test_rtruediv_mimo_siso(self):
597595
omega = np.logspace(-1, 1, 10)
598596
tf_mimo = TransferFunction([1], [1, 0]) * np.eye(2)
@@ -821,7 +819,7 @@ def test_named_signals():
821819
assert f1.output_labels == ['y0']
822820

823821

824-
@pytest.mark.skipif(not pandas_check(), reason="pandas not installed")
822+
@pytest.mark.pandas
825823
def test_to_pandas():
826824
# Create a SISO frequency response
827825
h1 = TransferFunction([1], [1, 2, 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)