1313import inspect
1414import pytest
1515import warnings
16+ import matplotlib .pyplot as plt
1617
1718import 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 } " )
5572
5673# Look for classes and then check member functions
5774if inspect .isclass (obj ):
5875test_kwarg_search (obj ,prefix + obj .__name__ + '.' )
5976
6077
78+ @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 ]
105130
106131for 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+
114143
115144#
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}