8000 Remove Deprecated API calls to Pytest, SciPy <1.3, Python 2 by bnavigator · Pull Request #745 · python-control/python-control · GitHub
[go: up one dir, main page]

Skip to content

Remove Deprecated API calls to Pytest, SciPy <1.3, Python 2 #745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions control/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
"""conftest.py - pytest local plugins and fixtures"""

from contextlib import contextmanager
from distutils.version import StrictVersion
import os
import sys
from contextlib import contextmanager

import matplotlib as mpl
import numpy as np
import scipy as sp
import pytest
import scipy as sp

import control

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


@pytest.fixture(scope="function", autouse=TEST_MATRIX_AND_ARRAY,
params=[pytest.param("arrayout", marks=matrixerrorfilter),
pytest.param("matrixout", marks=matrixfilter)])
Expand Down Expand Up @@ -110,10 +106,10 @@ def editsdefaults():

@pytest.fixture(scope="function")
def mplcleanup():
"""Workaround for python2
"""Clean up any plots and changes a test may have made to matplotlib.

python 2 does not like to mix the original mpl decorator with pytest
fixtures. So we roll our own.
compare matplotlib.testing.decorators.cleanup() but as a fixture instead
of a decorator.
"""
save = mpl.units.registry.copy()
try:
Expand Down
11 changes: 4 additions & 7 deletions control/tests/flatsys_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
created for that purpose.
"""

from distutils.version import StrictVersion

import numpy as np
import pytest
import scipy as sp
Expand Down Expand Up @@ -118,11 +116,10 @@ def test_kinematic_car(self, vehicle_flat, poly):
resp = ct.input_output_response(vehicle_flat, T, ud, x0)
np.testing.assert_array_almost_equal(resp.states, xd, decimal=2)

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

def test_flat_default_output(self, vehicle_flat):
# Construct a flat system with the default outputs
Expand Down
58 changes: 17 additions & 41 deletions control/tests/iosys_test.py
685C
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
"""

import re
import warnings

import numpy as np
import pytest

import control as ct
from control import iosys as ios
from control.tests.conftest import noscipy0, matrixfilter
from control.tests.conftest import matrixfilter


class TestIOSys:

Expand Down Expand Up @@ -46,7 +48,6 @@ class TSys:

return T

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

@noscipy0
def test_tf2io(self, tsys):
# Create a transfer function from the state space system
linsys = tsys.siso_linsys
Expand Down Expand Up @@ -129,7 +129,6 @@ def test_iosys_print(self, tsys, capsys):
ios_linearized = ios.linearize(ios_unspecified, [0, 0], [0])
print(ios_linearized)

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

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

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

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

@noscipy0
def test_static_nonlinearity(self, tsys):
# Linear dynamical system
linsys = tsys.siso_linsys
Expand All @@ -400,7 +395,6 @@ def test_static_nonlinearity(self, tsys):
np.testing.assert_array_almost_equal(lti_y, ios_y, decimal=2)


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

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

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

@noscipy0
def test_neg(self, tsys):
"""Test negation of a system"""

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

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

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

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

@noscipy0
def test_nonsquare_bdalg(self, tsys):
# Set up parameters for simulation
T = tsys.T
Expand Down Expand Up @@ -699,7 +686,6 @@ def test_nonsquare_bdalg(self, tsys):
with pytest.raises(ValueError):
ct.series(*args)

@noscipy0
def test_discrete(self, tsys):
"""Test discrete time functionality"""
# Create some linear and nonlinear systems to play with
Expand Down Expand Up @@ -868,7 +854,6 @@ def test_find_eqpts(self, tsys):
assert xeq is None
assert ueq is None

@noscipy0
def test_params(self, tsys):
# Start with the default set of parameters
ios_secord_default = ios.NonlinearIOSystem(
Expand Down Expand Up @@ -1433,11 +1418,10 @@ def test_duplicates(self, tsys):
nlios2 = ios.NonlinearIOSystem(None,
lambda t, x, u, params: u * u,
inputs=1, outputs=1, name="nlios2")
with pytest.warns(None) as record:
with warnings.catch_warnings():
warnings.simplefilter("error")
ct.InterconnectedSystem([nlios1, iosys_siso, nlios2],
inputs=0, outputs=0, states=0)
if record:
pytest.fail("Warning not expected: " + record[0].message)


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

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


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

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

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


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


# no warning if output explicitly ignored
with pytest.warns(None) as record:
with warnings.catch_warnings():
warnings.simplefilter("error")
# strip out matrix warnings
warnings.filterwarnings("ignore", "the matrix subclass",
category=PendingDeprecationWarning)
h = ct.interconnect([g,s,k],
inputs=['r'],
outputs=['y'],
Expand All @@ -1689,14 +1673,6 @@ def test_interconnect_unused_output():
h = ct.interconnect([g,s,k],
connections=False)

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

# warn if explicity ignored output in fact used
with pytest.warns(
UserWarning,
Expand Down
8 changes: 6 additions & 2 deletions control/tests/namedio_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import re
from copy import copy
import warnings

import numpy as np
import control as ct
Expand Down Expand Up @@ -243,9 +244,12 @@ def test_duplicate_sysname():
sys = ct.rss(4, 1, 1)

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

# Generate a warning if the system is named
sys = ct.rss(4, 1, 1, name='sys')
Expand Down
7 changes: 5 additions & 2 deletions control/tests/nyquist_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

"""

import warnings

import pytest
import numpy as np
import matplotlib.pyplot as plt
Expand Down Expand Up @@ -225,10 +227,11 @@ def test_nyquist_encirclements():
sys = 1 / (s**2 + s + 1)
with pytest.warns(UserWarning, match="encirclements was a non-integer"):
count = ct.nyquist_plot(sys, omega_limits=[0.5, 1e3])
with pytest.warns(None) as records:
with warnings.catch_warnings():
warnings.simplefilter("error")
# strip out matrix warnings
count = ct.nyquist_plot(
sys, omega_limits=[0.5, 1e3], encirclement_threshold=0.2)
assert len(records) == 0
plt.title("Non-integer number of encirclements [%g]" % count)


Expand Down
2 changes: 1 addition & 1 deletion control/tests/optimal_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ def test_optimal_logging(capsys):
x0 = [-1, 1]

# Solve it, with logging turned on (with warning due to mixed constraints)
with pytest.warns(sp.optimize.optimize.OptimizeWarning,
with pytest.warns(sp.optimize.OptimizeWarning,
match="Equality and inequality .* same element"):
res = opt.solve_ocp(
sys, time, x0, cost, input_constraint, terminal_cost=cost,
Expand Down
Loading
0