Skip to content

Commit d98ed29

Browse files
authored
Merge pull request #745 from bnavigator/remove-cruft
Remove Deprecated API calls to Pytest, SciPy <1.3, Python 2
2 parents e3ae8ed + 7f883f6 commit d98ed29

10 files changed

+45
-77
lines changed

control/tests/conftest.py

+6-10
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
"""conftest.py - pytest local plugins and fixtures"""
22

3-
from contextlib import contextmanager
4-
from distutils.version import StrictVersion
53
import os
64
import sys
5+
from contextlib import contextmanager
76

87
import matplotlib as mpl
98
import numpy as np
10-
import scipy as sp
119
import pytest
10+
import scipy as sp
1211

1312
import control
1413

@@ -18,10 +17,6 @@
1817
# pytest.param(marks=)
1918
slycotonly = pytest.mark.skipif(not control.exception.slycot_check(),
2019
reason="slycot not installed")
21-
noscipy0 = pytest.mark.skipif(StrictVersion(sp.__version__) < "1.0",
22-
reason="requires SciPy 1.0 or greater")
23-
nopython2 = pytest.mark.skipif(sys.version_info < (3, 0),
24-
reason="requires Python 3+")
2520
matrixfilter = pytest.mark.filterwarnings("ignore:.*matrix subclass:"
2621
"PendingDeprecationWarning")
2722
matrixerrorfilter = pytest.mark.filterwarnings("error:.*matrix subclass:"
@@ -43,6 +38,7 @@ def control_defaults():
4338
# assert that nothing changed it without reverting
4439
assert control.config.defaults == the_defaults
4540

41+
4642
@pytest.fixture(scope="function", autouse=TEST_MATRIX_AND_ARRAY,
4743
params=[pytest.param("arrayout", marks=matrixerrorfilter),
4844
pytest.param("matrixout", marks=matrixfilter)])
@@ -110,10 +106,10 @@ def editsdefaults():
110106

111107
@pytest.fixture(scope="function")
112108
def mplcleanup():
113-
"""Workaround for python2
109+
"""Clean up any plots and changes a test may have made to matplotlib.
114110
115-
python 2 does not like to mix the original mpl decorator with pytest
116-
fixtures. So we roll our own.
111+
compare matplotlib.testing.decorators.cleanup() but as a fixture instead
112+
of a decorator.
117113
"""
118114
save = mpl.units.registry.copy()
119115
try:

control/tests/flatsys_test.py

+4-7
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
created for that purpose.
99
"""
1010

11-
from distutils.version import StrictVersion
12-
1311
import numpy as np
1412
import pytest
1513
import scipy as sp
@@ -118,11 +116,10 @@ def test_kinematic_car(self, vehicle_flat, poly):
118116
resp = ct.input_output_response(vehicle_flat, T, ud, x0)
119117
np.testing.assert_array_almost_equal(resp.states, xd, decimal=2)
120118

121-
# For SciPy 1.0+, integrate equations and compare to desired
122-
if StrictVersion(sp.__version__) >= "1.0":
123-
t, y, x = ct.input_output_response(
124-
vehicle_flat, T, ud, x0, return_x=True)
125-
np.testing.assert_allclose(x, xd, atol=0.01, rtol=0.01)
119+
# integrate equations and compare to desired
120+
t, y, x = ct.input_output_response(
121+
vehicle_flat, T, ud, x0, return_x=True)
122+
np.testing.assert_allclose(x, xd, atol=0.01, rtol=0.01)
126123

127124
def test_flat_default_output(self, vehicle_flat):
128125
# Construct a flat system with the default outputs

control/tests/iosys_test.py

+17-41
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
"""
1010

1111
import re
12+
import warnings
1213

1314
import numpy as np
1415
import pytest
1516

1617
import control as ct
1718
from control import iosys as ios
18-
from control.tests.conftest import noscipy0, matrixfilter
19+
from control.tests.conftest import matrixfilter
20+
1921

2022
class TestIOSys:
2123

@@ -46,7 +48,6 @@ class TSys:
4648

4749
return T
4850

49-
@noscipy0
5051
def test_linear_iosys(self, tsys):
5152
# Create an input/output system from the linear system
5253
linsys = tsys.siso_linsys
@@ -65,7 +66,6 @@ def test_linear_iosys(self, tsys):
6566
np.testing.assert_array_almost_equal(lti_t, ios_t)
6667
np.testing.assert_allclose(lti_y, ios_y, atol=0.002, rtol=0.)
6768

68-
@noscipy0
6969
def test_tf2io(self, tsys):
7070
# Create a transfer function from the state space system
7171
linsys = tsys.siso_linsys
@@ -129,7 +129,6 @@ def test_iosys_print(self, tsys, capsys):
129129
ios_linearized = ios.linearize(ios_unspecified, [0, 0], [0])
130130
print(ios_linearized)
131131

132-
@noscipy0
133132
@pytest.mark.parametrize("ss", [ios.NonlinearIOSystem, ct.ss])
134133
def test_nonlinear_iosys(self, tsys, ss):
135134
# Create a simple nonlinear I/O system
@@ -236,7 +235,6 @@ def test_linearize_named_signals(self, kincar):
236235
assert lin_nocopy.find_output('x') is None
237236
assert lin_nocopy.find_state('x') is None
238237

239-
@noscipy0
240238
def test_connect(self, tsys):
241239
# Define a couple of (linear) systems to interconnection
242240
linsys1 = tsys.siso_linsys
@@ -294,7 +292,6 @@ def test_connect(self, tsys):
294292
np.testing.assert_array_almost_equal(lti_t, ios_t)
295293
np.testing.assert_allclose(lti_y, ios_y,atol=0.002,rtol=0.)
296294

297-
@noscipy0
298295
@pytest.mark.parametrize(
299296
"connections, inplist, outlist",
300297
[pytest.param([[(1, 0), (0, 0, 1)]], [[(0, 0, 1)]], [[(1, 0, 1)]],
@@ -338,7 +335,6 @@ def test_connect_spec_variants(self, tsys, connections, inplist, outlist):
338335
np.testing.assert_array_almost_equal(lti_t, ios_t)
339336
np.testing.assert_allclose(lti_y, ios_y, atol=0.002, rtol=0.)
340337

341-
@noscipy0
342338
@pytest.mark.parametrize(
343339
"connections, inplist, outlist",
344340
[pytest.param([['sys2.u[0]', 'sys1.y[0]']],
@@ -375,7 +371,6 @@ def test_connect_spec_warnings(self, tsys, connections, inplist, outlist):
375371
np.testing.assert_array_almost_equal(lti_t, ios_t)
376372
np.testing.assert_allclose(lti_y, ios_y, atol=0.002, rtol=0.)
377373

378-
@noscipy0
379374
def test_static_nonlinearity(self, tsys):
380375
# Linear dynamical system
381376
linsys = tsys.siso_linsys
@@ -400,7 +395,6 @@ def test_static_nonlinearity(self, tsys):
400395
np.testing.assert_array_almost_equal(lti_y, ios_y, decimal=2)
401396

402397

403-
@noscipy0
404398
@pytest.mark.filterwarnings("ignore:Duplicate name::control.iosys")
405399
def test_algebraic_loop(self, tsys):
406400
# Create some linear and nonlinear systems to play with
@@ -470,7 +464,6 @@ def test_algebraic_loop(self, tsys):
470464
with pytest.raises(RuntimeError):
471465
ios.input_output_response(*args)
472466

473-
@noscipy0
474467
def test_summer(self, tsys):
475468
# Construct a MIMO system for testing
476469
linsys = tsys.mimo_linsys1
@@ -489,7 +482,6 @@ def test_summer(self, tsys):
489482
ios_t, ios_y = ios.input_output_response(iosys_parallel, T, U, X0)
490483
np.testing.assert_allclose(ios_y, lin_y,atol=0.002,rtol=0.)
491484

492-
@noscipy0
493485
def test_rmul(self, tsys):
494486
# Test right multiplication
495487
# TODO: replace with better tests when conversions are implemented
@@ -510,7 +502,6 @@ def test_rmul(self, tsys):
510502
lti_t, lti_y = ct.forced_response(ioslin, T, U*U, X0)
511503
np.testing.assert_array_almost_equal(ios_y, lti_y*lti_y, decimal=3)
512504

513-
@noscipy0
514505
def test_neg(self, tsys):
515506
"""Test negation of a system"""
516507

@@ -533,7 +524,6 @@ def test_neg(self, tsys):
533524
lti_t, lti_y = ct.forced_response(ioslin, T, U*U, X0)
534525
np.testing.assert_array_almost_equal(ios_y, -lti_y, decimal=3)
535526

536-
@noscipy0
537527
def test_feedback(self, tsys):
538528
# Set up parameters for simulation
539529
T, U, X0 = tsys.T, tsys.U, tsys.X0
@@ -549,7 +539,6 @@ def test_feedback(self, tsys):
549539
lti_t, lti_y = ct.forced_response(linsys, T, U, X0)
550540
np.testing.assert_allclose(ios_y, lti_y,atol=0.002,rtol=0.)
551541

552-
@noscipy0
553542
def test_bdalg_functions(self, tsys):
554543
"""Test block diagram functions algebra on I/O systems"""
555544
# Set up parameters for simulation
@@ -596,7 +585,6 @@ def test_bdalg_functions(self, tsys):
596585
ios_t, ios_y = ios.input_output_response(iosys_feedback, T, U, X0)
597586
np.testing.assert_allclose(ios_y, lin_y,atol=0.002,rtol=0.)
598587

599-
@noscipy0
600588
def test_algebraic_functions(self, tsys):
601589
"""Test algebraic operations on I/O systems"""
602590
# Set up parameters for simulation
@@ -648,7 +636,6 @@ def test_algebraic_functions(self, tsys):
648636
ios_t, ios_y = ios.input_output_response(iosys_negate, T, U, X0)
649637
np.testing.assert_allclose(ios_y, lin_y,atol=0.002,rtol=0.)
650638

651-
@noscipy0
652639
def test_nonsquare_bdalg(self, tsys):
653640
# Set up parameters for simulation
654641
T = tsys.T
@@ -699,7 +686,6 @@ def test_nonsquare_bdalg(self, tsys):
699686
with pytest.raises(ValueError):
700687
ct.series(*args)
701688

702-
@noscipy0
703689
def test_discrete(self, tsys):
704690
"""Test discrete time functionality"""
705691
# Create some linear and nonlinear systems to play with
@@ -868,7 +854,6 @@ def test_find_eqpts(self, tsys):
868854
assert xeq is None
869855
assert ueq is None
870856

871-
@noscipy0
872857
def test_params(self, tsys):
873858
# Start with the default set of parameters
874859
ios_secord_default = ios.NonlinearIOSystem(
@@ -1433,11 +1418,10 @@ def test_duplicates(self, tsys):
14331418
nlios2 = ios.NonlinearIOSystem(None,
14341419
lambda t, x, u, params: u * u,
14351420
inputs=1, outputs=1, name="nlios2")
1436-
with pytest.warns(None) as record:
1421+
with warnings.catch_warnings():
1422+
warnings.simplefilter("error")
14371423
ct.InterconnectedSystem([nlios1, iosys_siso, nlios2],
14381424
inputs=0, outputs=0, states=0)
1439-
if record:
1440-
pytest.fail("Warning not expected: " + record[0].message)
14411425

14421426

14431427
def test_linear_interconnection():
@@ -1527,7 +1511,7 @@ def predprey(t, x, u, params={}):
15271511

15281512
def pvtol(t, x, u, params={}):
15291513
"""Reduced planar vertical takeoff and landing dynamics"""
1530-
from math import sin, cos
1514+
from math import cos, sin
15311515
m = params.get('m', 4.) # kg, system mass
15321516
J = params.get('J', 0.0475) # kg m^2, system inertia
15331517
r = params.get('r', 0.25) # m, thrust offset
@@ -1543,7 +1527,7 @@ def pvtol(t, x, u, params={}):
15431527

15441528

15451529
def pvtol_full(t, x, u, params={}):
1546-
from math import sin, cos
1530+
from math import cos, sin
15471531
m = params.get('m', 4.) # kg, system mass
15481532
J = params.get('J', 0.0475) # kg m^2, system inertia
15491533
r = params.get('r', 0.25) # m, thrust offset
@@ -1596,8 +1580,12 @@ def test_interconnect_unused_input():
15961580
inputs=['r'],
15971581
outputs=['y'])
15981582

1599-
with pytest.warns(None) as record:
1583+
with warnings.catch_warnings():
16001584
# no warning if output explicitly ignored, various argument forms
1585+
warnings.simplefilter("error")
1586+
# strip out matrix warnings
1587+
warnings.filterwarnings("ignore", "the matrix subclass",
1588+
category=PendingDeprecationWarning)
16011589
h = ct.interconnect([g,s,k],
16021590
inputs=['r'],
16031591
outputs=['y'],
@@ -1612,14 +1600,6 @@ def test_interconnect_unused_input():
16121600
h = ct.interconnect([g,s,k],
16131601
connections=False)
16141602

1615-
#https://docs.pytest.org/en/6.2.x/warnings.html#recwarn
1616-
for r in record:
1617-
# strip out matrix warnings
1618-
if re.match(r'.*matrix subclass', str(r.message)):
1619-
continue
1620-
print(r.message)
1621-
pytest.fail(f'Unexpected warning: {r.message}')
1622-
16231603

16241604
# warn if explicity ignored input in fact used
16251605
with pytest.warns(
@@ -1674,7 +1654,11 @@ def test_interconnect_unused_output():
16741654

16751655

16761656
# no warning if output explicitly ignored
1677-
with pytest.warns(None) as record:
1657+
with warnings.catch_warnings():
1658+
warnings.simplefilter("error")
1659+
# strip out matrix warnings
1660+
warnings.filterwarnings("ignore", "the matrix subclass",
1661+
category=PendingDeprecationWarning)
16781662
h = ct.interconnect([g,s,k],
16791663
inputs=['r'],
16801664
outputs=['y'],
@@ -1689,14 +1673,6 @@ def test_interconnect_unused_output():
16891673
h = ct.interconnect([g,s,k],
16901674
connections=False)
16911675

1692-
#https://docs.pytest.org/en/6.2.x/warnings.html#recwarn
1693-
for r in record:
1694-
# strip out matrix warnings
1695-
if re.match(r'.*matrix subclass', str(r.message)):
1696-
continue
1697-
print(r.message)
1698-
pytest.fail(f'Unexpected warning: {r.message}')
1699-
17001676
# warn if explicity ignored output in fact used
17011677
with pytest.warns(
17021678
UserWarning,

control/tests/namedio_test.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import re
1212
from copy import copy
13+
import warnings
1314

1415
import numpy as np
1516
import control as ct
@@ -243,9 +244,12 @@ def test_duplicate_sysname():
243244
sys = ct.rss(4, 1, 1)
244245

245246
# No warnings should be generated if we reuse an an unnamed system
246-
with pytest.warns(None) as record:
247+
with warnings.catch_warnings():
248+
warnings.simplefilter("error")
249+
# strip out matrix warnings
250+
warnings.filterwarnings("ignore", "the matrix subclass",
251+
category=PendingDeprecationWarning)
247252
res = sys * sys
248-
assert not any([type(msg) == UserWarning for msg in record])
249253

250254
# Generate a warning if the system is named
251255
sys = ct.rss(4, 1, 1, name='sys')

control/tests/nyquist_test.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
99
"""
1010

11+
import warnings
12+
1113
import pytest
1214
import numpy as np
1315
import matplotlib.pyplot as plt
@@ -225,10 +227,11 @@ def test_nyquist_encirclements():
225227
sys = 1 / (s**2 + s + 1)
226228
with pytest.warns(UserWarning, match="encirclements was a non-integer"):
227229
count = ct.nyquist_plot(sys, omega_limits=[0.5, 1e3])
228-
with pytest.warns(None) as records:
230+
with warnings.catch_warnings():
231+
warnings.simplefilter("error")
232+
# strip out matrix warnings
229233
count = ct.nyquist_plot(
230234
sys, omega_limits=[0.5, 1e3], encirclement_threshold=0.2)
231-
assert len(records) == 0
232235
plt.title("Non-integer number of encirclements [%g]" % count)
233236

234237

control/tests/optimal_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ def test_optimal_logging(capsys):
366366
x0 = [-1, 1]
367367

368368
# Solve it, with logging turned on (with warning due to mixed constraints)
369-
with pytest.warns(sp.optimize.optimize.OptimizeWarning,
369+
with pytest.warns(sp.optimize.OptimizeWarning,
370370
match="Equality and inequality .* same element"):
371371
res = opt.solve_ocp(
372372
sys, time, x0, cost, input_constraint, terminal_cost=cost,

0 commit comments

Comments
 (0)