Skip to content

Commit 1730b93

Browse files
committed
change default repr to 'eval' + adjust HTML formatting
1 parent 06fcb90 commit 1730b93

File tree

9 files changed

+289
-187
lines changed

9 files changed

+289
-187
lines changed

control/iosys.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
'iosys.indexed_system_name_suffix': '$indexed',
3232
'iosys.converted_system_name_prefix': '',
3333
'iosys.converted_system_name_suffix': '$converted',
34-
'iosys.repr_format': 'info',
34+
'iosys.repr_format': 'eval',
3535
}
3636

3737

control/nlsys.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,7 @@ def outfcn(t, x, u, params):
784784

785785
def __str__(self):
786786
import textwrap
787-
out = super().__str__()
787+
out = InputOutputSystem.__str__(self)
788788

789789
out += f"\n\nSubsystems ({len(self.syslist)}):\n"
790790
for sys in self.syslist:
@@ -845,7 +845,7 @@ def cxn_string(signal, gain, first):
845845
cxn, width=78, initial_indent=" * ",
846846
subsequent_indent=" ")) + "\n"
847847

848-
return out[:-1]
848+
return out
849849

850850
def _update_params(self, params, warning=False):
851851
for sys in self.syslist:
@@ -1087,7 +1087,7 @@ def unused_signals(self):
10871087
def connection_table(self, show_names=False, column_width=32):
10881088
"""Print table of connections inside an interconnected system model.
10891089
1090-
Intended primarily for :class:`InterconnectedSystems` that have been
1090+
Intended primarily for :class:`InterconnectedSystem`'s that have been
10911091
connected implicitly using signal names.
10921092
10931093
Parameters

control/statesp.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,9 +1479,38 @@ def __init__(self, io_sys, ss_sys=None, connection_type=None):
14791479
outputs=io_sys.output_labels, states=io_sys.state_labels,
14801480
params=io_sys.params, remove_useless_states=False)
14811481

1482-
# Use StateSpace.__call__ to evaluate at a given complex value
1483-
def __call__(self, *args, **kwargs):
1484-
return StateSpace.__call__(self, *args, **kwargs)
1482+
# Use StateSpace.__call__ to evaluate at a given complex value
1483+
def __call__(self, *args, **kwargs):
1484+
return StateSpace.__call__(self, *args, **kwargs)
1485+
1486+
def __str__(self):
1487+
string = InterconnectedSystem.__str__(self) + "\n"
1488+
string += "\n\n".join([
1489+
"{} = {}".format(Mvar,
1490+
"\n ".join(str(M).splitlines()))
1491+
for Mvar, M in zip(["A", "B", "C", "D"],
1492+
[self.A, self.B, self.C, self.D])])
1493+
return string
1494+
1495+
# Use InputOutputSystem repr for 'eval' since we can't recreate structure
1496+
# (without this, StateSpace._repr_eval_ gets used...)
1497+
def _repr_eval_(self):
1498+
return InputOutputSystem._repr_eval_(self)
1499+
1500+
def _repr_html_(self):
1501+
syssize = self.nstates + max(self.noutputs, self.ninputs)
1502+
if syssize > config.defaults['statesp.latex_maxsize']:
1503+
return None
1504+
elif config.defaults['statesp.latex_repr_type'] == 'partitioned':
1505+
return InterconnectedSystem._repr_info_(self, html=True) + \
1506+
"\n" + StateSpace._latex_partitioned(self)
1507+
elif config.defaults['statesp.latex_repr_type'] == 'separate':
1508+
return InterconnectedSystem._repr_info_(self, html=True) + \
1509+
"\n" + StateSpace._latex_separate(self)
1510+
else:
1511+
raise ValueError(
1512+
"Unknown statesp.latex_repr_type '{cfg}'".format(
1513+
cfg=config.defaults['statesp.latex_repr_type']))
14851514

14861515
# The following text needs to be replicated from StateSpace in order for
14871516
# this entry to show up properly in sphinx doccumentation (not sure why,

control/tests/config_test.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -320,15 +320,11 @@ def test_system_indexing(self):
320320
sys2 = sys[1:, 1:]
321321
assert sys2.name == 'PRE' + sys.name + 'POST'
322322

323-
def test_legacy_repr_format(self):
323+
def test_repr_format(self):
324324
from ..statesp import StateSpace
325325
from numpy import array
326326

327327
sys = ct.ss([[1]], [[1]], [[1]], [[0]])
328-
with pytest.raises(SyntaxError, match="invalid syntax"):
329-
new = eval(repr(sys)) # iosys is default
330-
331-
ct.use_legacy_defaults('0.10.1') # loadable is default
332328
new = eval(repr(sys))
333329
for attr in ['A', 'B', 'C', 'D']:
334330
assert getattr(sys, attr) == getattr(sys, attr)

control/tests/iosys_test.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2357,12 +2357,18 @@ def test_iosys_repr(fcn, spec, expected, missing, format):
23572357
if missing is not None:
23582358
assert re.search(missing, out) is None
23592359

2360-
# Make sure we can change the default format back to 'info'
2361-
sys.repr_format = None
2360+
elif format == 'info':
2361+
assert out == info_expected
2362+
2363+
# Make sure we can change back to the default format
2364+
sys.repr_format = None
23622365

2363-
# Test 'info', either set explicitly or via config.defaults
2366+
# Make sure the default format is OK
23642367
out = repr(sys)
2365-
assert out == info_expected
2368+
if ct.config.defaults['iosys.repr_format'] == 'info':
2369+
assert out == info_expected
2370+
elif ct.config.defaults['iosys.repr_format'] == 'eval':
2371+
assert re.search(expected, out) != None
23662372

23672373

23682374
@pytest.mark.parametrize("fcn", [ct.ss, ct.tf, ct.frd, ct.nlsys, fs.flatsys])

control/tests/namedio_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def test_named_ss():
3434
assert sys.input_labels == ['u[0]', 'u[1]']
3535
assert sys.output_labels == ['y[0]', 'y[1]']
3636
assert sys.state_labels == ['x[0]', 'x[1]']
37-
assert ct.InputOutputSystem.__repr__(sys) == \
37+
assert ct.iosys_repr(sys, format='info') == \
3838
"<StateSpace sys[0]: ['u[0]', 'u[1]'] -> ['y[0]', 'y[1]']>"
3939

4040
# Pass the names as arguments
@@ -46,7 +46,7 @@ def test_named_ss():
4646
assert sys.input_labels == ['u1', 'u2']
4747
assert sys.output_labels == ['y1', 'y2']
4848
assert sys.state_labels == ['x1', 'x2']
49-
assert ct.InputOutputSystem.__repr__(sys) == \
49+
assert ct.iosys_repr(sys, format='info') == \
5050
"<StateSpace system: ['u1', 'u2'] -> ['y1', 'y2']>"
5151

5252
# Do the same with rss
@@ -56,7 +56,7 @@ def test_named_ss():
5656
assert sys.input_labels == ['u1']
5757
assert sys.output_labels == ['y1', 'y2']
5858
assert sys.state_labels == ['x1', 'x2', 'x3']
59-
assert ct.InputOutputSystem.__repr__(sys) == \
59+
assert ct.iosys_repr(sys, format='info') == \
6060
"<StateSpace random: ['u1'] -> ['y1', 'y2']>"
6161

6262

control/tests/nlsys_test.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,6 @@ def test_ICsystem_str():
224224
r"Outputs \(2\): \['y1', 'y2'\]" + "\n" + \
225225
r"States \(4\): \['sys1_x\[0\].*'sys2_x\[1\]'\]" + "\n" + \
226226
"\n" + \
227-
r"A = \[\[.*\]\]" + "\n\n" + \
228-
r"B = \[\[.*\]\]" + "\n\n" + \
229-
r"C = \[\[.*\]\]" + "\n\n" + \
230-
r"D = \[\[.*\]\]" + "\n" + \
231-
"\n" + \
232227
r"Subsystems \(2\):" + "\n" + \
233228
r" \* <StateSpace sys1: \[.*\] -> \['y\[0\]', 'y\[1\]']>" + "\n" + \
234229
r" \* <StateSpace sys2: \['u\[0\]', 'u\[1\]'] -> \[.*\]>" + "\n" + \
@@ -242,6 +237,11 @@ def test_ICsystem_str():
242237
"\n\n" + \
243238
r"Outputs:" + "\n" + \
244239
r" \* y1 <- sys2.y\[0\]" + "\n" + \
245-
r" \* y2 <- sys2.y\[1\]"
240+
r" \* y2 <- sys2.y\[1\]" + \
241+
"\n\n" + \
242+
r"A = \[\[.*\]\]" + "\n\n" + \
243+
r"B = \[\[.*\]\]" + "\n\n" + \
244+
r"C = \[\[.*\]\]" + "\n\n" + \
245+
r"D = \[\[.*\]\]"
246246

247247
assert re.match(ref, str(sys), re.DOTALL)

0 commit comments

Comments
 (0)