8000 add missing kwarg tests + small bug fixes · python-control/python-control@eff0e99 · GitHub
[go: up one dir, main page]

Skip to content

Commit eff0e99

Browse files
committed
add missing kwarg tests + small bug fixes
1 parent 7ebfc3b commit eff0e99

File tree

4 files changed

+68
-43
lines changed

4 files changed

+68
-43
lines changed

control/config.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ def set_defaults(module, **keywords):
7373
if not isinstance(module, str):
7474
raise ValueError("module must be a string")
7575
for key, val in keywords.items():
76+
keyname = module + '.' + key
77+
if keyname not in defaults and f"deprecated.{keyname}" not in defaults:
78+
raise TypeError(f"unrecognized keyword: {key}")
7679
defaults[module + '.' + key] = val
7780

7881

@@ -286,6 +289,6 @@ def use_legacy_defaults(version):
286289
set_defaults('control', squeeze_time_response=True)
287290

288291
# switched mirror_style of nyquist from '-' to '--'
289-
set_defaults('nyqist', mirror_style='-')
292+
set_defaults('nyquist', mirror_style='-')
290293

291294
return (major, minor, patch)

control/iosys.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,7 +1799,7 @@ def ivp_rhs(t, x):
17991799

18001800
def find_eqpt(sys, x0, u0=[], y0=None, t=0, params={},
18011801
iu=None, iy=None, ix=None, idx=None, dx0=None,
1802-
return_y=False, return_result=False, **kw):
1802+
return_y=False, return_result=False):
18031803
"""Find the equilibrium point for an input/output system.
18041804
18051805
Returns the value of an equilibrium point given the initial state and
@@ -1903,7 +1903,7 @@ def find_eqpt(sys, x0, u0=[], y0=None, t=0, params={},
19031903
# Take u0 as fixed and minimize over x
19041904
# TODO: update to allow discrete time systems
19051905
def ode_rhs(z): return sys._rhs(t, z, u0)
1906-
result = root(ode_rhs, x0, **kw)
1906+
result = root(ode_rhs, x0)
19071907
z = (result.x, u0, sys._out(t, result.x, u0))
19081908
else:
19091909
# Take y0 as fixed and minimize over x and u
@@ -1914,7 +1914,7 @@ def rootfun(z):
19141914
return np.concatenate(
19151915
(sys._rhs(t, x, u), sys._out(t, x, u) - y0), axis=0)
19161916
z0 = np.concatenate((x0, u0), axis=0) # Put variables together
1917-
result = root(rootfun, z0, **kw) # Find the eq point
1917+
result = root(rootfun, z0) # Find the eq point
19181918
x, u = np.split(result.x, [nstates]) # Split result back in two
19191919
z = (x, u, sys._out(t, x, u))
19201920

@@ -2026,7 +2026,7 @@ def rootfun(z):
20262026
z0 = np.concatenate((x[state_vars], u[input_vars]), axis=0)
20272027

20282028
# Finally, call the root finding function
2029-
result = root(rootfun, z0, **kw)
2029+
result = root(rootfun, z0)
20302030

20312031
# Extract out the results and insert into x and u
20322032
x[state_vars] = result.x[:nstate_vars]
@@ -2105,7 +2105,7 @@ def _parse_signal_parameter(value, name, kwargs, end=False):
21052105

21062106
if end and kwargs:
21072107
raise TypeError("unrecognized keywords: ", str(kwargs))
2108-
2108+
21092109
return value
21102110

21112111

control/tests/config_test.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ class TestConfig:
2323
sys = ct.tf([10], [1, 2, 1])
2424

2525
def test_set_defaults(self):
26-
ct.config.set_defaults('config', test1=1, test2=2, test3=None)
27-
assert ct.config.defaults['config.test1'] == 1
28-
assert ct.config.defaults['config.test2'] == 2
29-
assert ct.config.defaults['config.test3'] is None
26+
ct.config.set_defaults('freqplot', dB=1, deg=2, Hz=None)
27+
assert ct.config.defaults['freqplot.dB'] == 1
28+
assert ct.config.defaults['freqplot.deg'] == 2
29+
assert ct.config.defaults['freqplot.Hz'] is None
3030

3131
@mplcleanup
3232
def test_get_param(self):

control/tests/kwargs_test.py

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import inspect
1414
import pytest
1515
import warnings
16+
import matplotlib.pyplot as plt
1617

1718
import control
1819
import control.flatsys
@@ -36,28 +37,45 @@ def test_kwarg_search(module, prefix):
3637
not inspect.getmodule(obj).__name__.startswith('control'):
3738
# Skip anything that isn't part of the control package
3839
continue
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}")
5572

5673
# Look for classes and then check member functions
5774
if inspect.isclass(obj):
5875
test_kwarg_search(obj, prefix + obj.__name__ + '.')
5976

6077

78+
@pytest.mark.usefixtures('editsdefaults')
6179
def test_unrecognized_kwargs():
6280
# Create a SISO system for use in parameterized tests
6381
sys = 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():
97119
table = [
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
]
105130

106131
for 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
111136
with pytest.raises(AttributeError, match="has no property"):
112137
function(*args, **kwargs, unknown=None)
113-
138+
139+
# If we opened any figures, close them
140+
if plt.gca():
141+
plt.close('all')
142+
114143

115144
#
116145
# List of all unit tests that check for unrecognized keywords
@@ -124,24 +153,23 @@ def test_matplotlib_kwargs():
124153
kwarg_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():
152180
flatsys_test.TestFlatSys.test_point_to_point_errors,
153181
'FrequencyResponseData.__init__':
154182
frd_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__':
158186
interconnect_test.test_interconnect_exceptions,
159-
'InterconnectedSystem.linearize': None,
160-
'LinearICSystem.linearize': None,
161187
'LinearIOSystem.__init__':
162188
interconnect_test.test_interconnect_exceptions,
163-
'LinearIOSystem.linearize': None,
164189
'NonlinearIOSystem.__init__':
165190
interconnect_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
}

0 commit comments

Comments
 (0)
0