add missing kwarg tests + small bug fixes · python-control/python-control@87cb31a

@@ -13,6 +13,7 @@

1313

import inspect

1414

import pytest

1515

import warnings

16+

import matplotlib.pyplot as plt

16171718

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}")

55725673

# Look for classes and then check member functions

5774

if inspect.isclass(obj):

5875

test_kwarg_search(obj, prefix + obj.__name__ + '.')

5976607778+

@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

]

105130106131

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+114143115144

#

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

}