add missing kwarg tests + small bug fixes · python-control/python-control@87cb31a
@@ -13,6 +13,7 @@
1313import inspect
1414import pytest
1515import warnings
16+import matplotlib.pyplot as plt
16171718import control
1819import control.flatsys
@@ -36,28 +37,45 @@ def test_kwarg_search(module, prefix):
3637not inspect.getmodule(obj).__name__.startswith('control'):
3738# Skip anything that isn't part of the control package
3839continue
39-40-# Look for functions with keyword arguments
41-if inspect.isfunction(obj):
42-# Get the signature for the function
43-sig = inspect.signature(obj)
44-45-# See if there is a variable keyword argument
46-for argname, par in sig.parameters.items():
47-if par.kind == inspect.Parameter.VAR_KEYWORD:
48-# Make sure there is a unit test defined
49-assert prefix + name in kwarg_unittest
50-51-# Make sure there is a unit test
52-if not hasattr(kwarg_unittest[prefix + name], '__call__'):
53-warnings.warn("No unit test defined for '%s'"
54-% prefix + name)
40+41+# Only look for functions with keyword arguments
42+if not inspect.isfunction(obj):
43+continue
44+45+# Get the signature for the function
46+sig = inspect.signature(obj)
47+48+# Skip anything that is inherited
49+if inspect.isclass(module) and obj.__name__ not in module.__dict__:
50+continue
51+52+# See if there is a variable keyword argument
53+for argname, par in sig.parameters.items():
54+if not par.kind == inspect.Parameter.VAR_KEYWORD:
55+continue
56+57+# Make sure there is a unit test defined
58+assert prefix + name in kwarg_unittest
59+60+# Make sure there is a unit test
61+if not hasattr(kwarg_unittest[prefix + name], '__call__'):
62+warnings.warn("No unit test defined for '%s'" % prefix + name)
63+source = None
64+else:
65+source = inspect.getsource(kwarg_unittest[prefix + name])
66+67+# Make sure the unit test looks for unrecognized keyword
68+if source and source.find('unrecognized keyword') < 0:
69+warnings.warn(
70+f"'unrecognized keyword' not found in unit test "
71+f"for {name}")
55725673# Look for classes and then check member functions
5774if inspect.isclass(obj):
5875test_kwarg_search(obj, prefix + obj.__name__ + '.')
5976607778+@pytest.mark.usefixtures('editsdefaults')
6179def test_unrecognized_kwargs():
6280# Create a SISO system for use in parameterized tests
6381sys = control.ss([[-1, 1], [0, -1]], [[0], [1]], [[1, 0]], 0, dt=None)
@@ -67,16 +85,20 @@ def test_unrecognized_kwargs():
6785 [control.drss, (2, 1, 1), {}],
6886 [control.input_output_response, (sys, [0, 1, 2], [1, 1, 1]), {}],
6987 [control.lqr, (sys, [[1, 0], [0, 1]], [[1]]), {}],
88+ [control.linearize, (sys, 0, 0), {}],
7089 [control.pzmap, (sys,), {}],
7190 [control.rlocus, (control.tf([1], [1, 1]), ), {}],
7291 [control.root_locus, (control.tf([1], [1, 1]), ), {}],
7392 [control.rss, (2, 1, 1), {}],
93+ [control.set_defaults, ('control',), {'default_dt': True}],
7494 [control.ss, (0, 0, 0, 0), {'dt': 1}],
7595 [control.ss2io, (sys,), {}],
96+ [control.ss2tf, (sys,), {}],
7697 [control.summing_junction, (2,), {}],
7798 [control.tf, ([1], [1, 1]), {}],
7899 [control.tf2io, (control.tf([1], [1, 1]),), {}],
79100 [control.InputOutputSystem, (1, 1, 1), {}],
101+ [control.InputOutputSystem.linearize, (sys, 0, 0), {}],
80102 [control.StateSpace, ([[-1, 0], [0, -1]], [[1], [1]], [[1, 1]], 0), {}],
81103 [control.TransferFunction, ([1], [1, 1]), {}],
82104 ]
@@ -97,10 +119,13 @@ def test_matplotlib_kwargs():
97119table = [
98120 [control.bode, (sys, ), {}],
99121 [control.bode_plot, (sys, ), {}],
122+ [control.describing_function_plot,
123+ (sys, control.descfcn.saturation_nonlinearity(1), [1, 2, 3, 4]), {}],
100124 [control.gangof4, (sys, sys), {}],
101125 [control.gangof4_plot, (sys, sys), {}],
102126 [control.nyquist, (sys, ), {}],
103127 [control.nyquist_plot, (sys, ), {}],
128+ [control.singular_values_plot, (sys, ), {}],
104129 ]
105130106131for function, args, kwargs in table:
@@ -110,7 +135,11 @@ def test_matplotlib_kwargs():
110135# Now add an unrecognized keyword and make sure there is an error
111136with pytest.raises(AttributeError, match="has no property"):
112137function(*args, **kwargs, unknown=None)
113-138+139+# If we opened any figures, close them
140+if plt.gca():
141+plt.close('all')
142+114143115144#
116145# List of all unit tests that check for unrecognized keywords
@@ -124,24 +153,23 @@ def test_matplotlib_kwargs():
124153kwarg_unittest = {
125154'bode': test_matplotlib_kwargs,
126155'bode_plot': test_matplotlib_kwargs,
127-'describing_function_plot': None,
156+'describing_function_plot': test_matplotlib_kwargs,
128157'dlqr': statefbk_test.TestStatefbk.test_lqr_errors,
129158'drss': test_unrecognized_kwargs,
130-'find_eqpt': None,
131159'gangof4': test_matplotlib_kwargs,
132160'gangof4_plot': test_matplotlib_kwargs,
133161'input_output_response': test_unrecognized_kwargs,
134162'interconnect': interconnect_test.test_interconnect_exceptions,
135-'linearize': None,
163+'linearize': test_unrecognized_kwargs,
136164'lqr': statefbk_test.TestStatefbk.test_lqr_errors,
137165'nyquist': test_matplotlib_kwargs,
138166'nyquist_plot': test_matplotlib_kwargs,
139-'pzmap': None,
167+'pzmap': test_matplotlib_kwargs,
140168'rlocus': test_unrecognized_kwargs,
141169'root_locus': test_unrecognized_kwargs,
142170'rss': test_unrecognized_kwargs,
143-'set_defaults': None,
144-'singular_values_plot': None,
171+'set_defaults': test_unrecognized_kwargs,
172+'singular_values_plot': test_matplotlib_kwargs,
145173'ss': test_unrecognized_kwargs,
146174'ss2io': test_unrecognized_kwargs,
147175'ss2tf': test_unrecognized_kwargs,
@@ -152,21 +180,15 @@ def test_matplotlib_kwargs():
152180flatsys_test.TestFlatSys.test_point_to_point_errors,
153181'FrequencyResponseData.__init__':
154182frd_test.TestFRD.test_unrecognized_keyword,
155-'InputOutputSystem.__init__': None,
156-'InputOutputSystem.linearize': None,
183+'InputOutputSystem.__init__': test_unrecognized_kwargs,
184+'InputOutputSystem.linearize': test_unrecognized_kwargs,
157185'InterconnectedSystem.__init__':
158186interconnect_test.test_interconnect_exceptions,
159-'InterconnectedSystem.linearize': None,
160-'LinearICSystem.linearize': None,
161187'LinearIOSystem.__init__':
162188interconnect_test.test_interconnect_exceptions,
163-'LinearIOSystem.linearize': None,
164189'NonlinearIOSystem.__init__':
165190interconnect_test.test_interconnect_exceptions,
166-'NonlinearIOSystem.linearize': None,
167-'StateSpace.__init__': None,
191+'StateSpace.__init__': test_unrecognized_kwargs,
168192'TimeResponseData.__call__': trdata_test.test_response_copy,
169-'TransferFunction.__init__': None,
170-'flatsys.FlatSystem.linearize': None,
171-'flatsys.LinearFlatSystem.linearize': None,
193+'TransferFunction.__init__': test_unrecognized_kwargs,
172194}