def _load_from_structure(self, structure): table = Table(self.layout.meta) for part_name, part_structure in structure["layout"].items(): table.append([part_name, "", part_structure["x"], part_structure["y"], part_structure["visible"]]) self.set_layout(table) self.run_hook(self.Load, self.create_part_tasks(), structure)
def test_dict_roundtrip(self): t = Table(self.meta) d = t.to_dict() d2 = d.copy() d2.pop("typeid") t2 = Table(self.meta, d2) self.assertEqual(d, t2.to_dict())
def test_validate_from_good_table(self): tm = self.tm t = Table(tm) t.c1 = ["me", "me3"] t_serialized = t.to_dict() t = tm.validate(t) assert t.to_dict() == t_serialized
def test_validate_from_good_table(self): tm = self.tm t = Table(tm) t.c1 = ["me", "me3"] t_serialized = t.to_dict() t = tm.validate(t) self.assertEqual(t.to_dict(), t_serialized)
def update_datasets_table(self, context, part_info): # Update the dataset table datasets_table = Table(dataset_table_meta) for i in DatasetProducedInfo.filter_values(part_info): if i.name not in datasets_table.name: row = [i.name, i.filename, i.type, i.rank, i.path, i.uniqueid] datasets_table.append(row) self.datasets.set_value(datasets_table)
def update_datasets_table(self, task, part_info): # Update the dataset table datasets_table = Table(dataset_table_meta) for i in DatasetProducedInfo.filter_values(part_info): if i.name not in datasets_table.name: row = [i.name, i.filename, i.type, i.rank, i.path, i.uniqueid] datasets_table.append(row) self.datasets.set_value(datasets_table)
def setUp(self): meta = Mock() meta.elements = OrderedDict() meta.elements["e1"] = NumberArrayMeta("int32") meta.elements["e2"] = NumberArrayMeta("int32") meta.elements["e3"] = NumberArrayMeta("int32") self.t = Table(meta) self.t.e1 = [1] self.t.e2 = [2] self.t.e3 = [3]
def test_to_dict(self): columns = OrderedDict() columns["foo"] = StringArrayMeta(label="Foo") columns["bar"] = StringArrayMeta() meta = TableMeta(description="desc", tags=[], writeable=True, label="my label", columns=columns) value = Table(meta) value.foo = ["foo1", "foo2"] value.bar = ["bar1", "bar2"] o = meta.make_attribute(value) self.assertEqual(o.to_dict(), self.serialized)
def set_layout(self, value): part_info = self.run_hook(self.ReportOutports, self.create_part_tasks()) part_info = self.run_hook( self.Layout, self.create_part_tasks(), part_info, value) layout_table = Table(self.layout.meta) for name, layout_infos in LayoutInfo.filter_parts(part_info).items(): assert len(layout_infos) == 1, \ "%s returned more than 1 layout infos" % name layout_info = layout_infos[0] row = [name, layout_info.mri, layout_info.x, layout_info.y, layout_info.visible] layout_table.append(row) self.layout.set_value(layout_table)
def test_layout(self): b = self.p.block_view("mainBlock") new_layout = Table(self.c.layout.meta) new_layout.name = ["partchild1", "partchild2", "partchild3"] new_layout.mri = ["part1", "part2", "part3"] new_layout.x = [10, 11, 12] new_layout.y = [20, 21, 22] new_layout.visible = [True, True, True] b.layout.put_value(new_layout) assert self.c.parts['partchild1'].x == 10 assert self.c.parts['partchild1'].y == 20 assert self.c.parts['partchild1'].visible == True assert self.c.parts['partchild2'].x == 11 assert self.c.parts['partchild2'].y == 21 assert self.c.parts['partchild2'].visible == True assert self.c.parts['partchild3'].x == 12 assert self.c.parts['partchild3'].y == 22 assert self.c.parts['partchild3'].visible == True new_layout.visible = [True, False, True] b.layout.put_value(new_layout) assert self.c.parts['partchild1'].visible == True assert self.c.parts['partchild2'].visible == False assert self.c.parts['partchild3'].visible == True
def test_layout(self): self.c.edit() self.checkState(sm.EDITABLE) new_layout = Table(self.c.layout.meta) new_layout.name = ["partchild1", "partchild2", "partchild3"] new_layout.mri = ["part1", "part2", "part3"] new_layout.x = [10, 11, 12] new_layout.y = [20, 21, 22] new_layout.visible = [True, True, True] self.b.layout = new_layout self.assertEqual(self.c.parts['partchild1'].x, 10) self.assertEqual(self.c.parts['partchild1'].y, 20) self.assertEqual(self.c.parts['partchild1'].visible, True) self.assertEqual(self.c.parts['partchild2'].x, 11) self.assertEqual(self.c.parts['partchild2'].y, 21) self.assertEqual(self.c.parts['partchild2'].visible, True) self.assertEqual(self.c.parts['partchild3'].x, 12) self.assertEqual(self.c.parts['partchild3'].y, 22) self.assertEqual(self.c.parts['partchild3'].visible, True) new_layout.visible = [True, False, True] self.b.layout = new_layout self.assertEqual(self.c.parts['partchild1'].visible, True) self.assertEqual(self.c.parts['partchild2'].visible, False) self.assertEqual(self.c.parts['partchild3'].visible, True)
def test_list_from_table(self): table = Table(self.meta) table.append([32, True, True, 4294967295]) table.append([0, True, False, 1]) table.append([0, False, False, 0]) l = self.o.list_from_table(table) assert l == ([32, 0x10001, 4294967295, 0, 0x1, 1, 0, 0x0, 0])
def table_from_list(self, int_values): table = Table(self.meta) if self.fields: nconsume = self._calc_nconsume() for i in range(int(len(int_values) / nconsume)): int_value = 0 for c in range(nconsume): int_value += int_values[i*nconsume+c] << (32 * c) row = [] for name, (bits_hi, bits_lo) in self.fields.items(): field_value = (int_value & (2 ** (bits_hi + 1) - 1)) >> bits_lo row.append(field_value) table.append(row) return table
def set_layout(self, value): # If it isn't a table, make it one if not isinstance(value, Table): value = Table(self.layout.meta, value) part_info = self.run_hook(self.ReportOutports, self.create_part_tasks()) part_info = self.run_hook( self.Layout, self.create_part_tasks(), part_info, value) layout_table = Table(self.layout.meta) for name, layout_infos in LayoutInfo.filter_parts(part_info).items(): assert len(layout_infos) == 1, \ "%s returned more than 1 layout infos" % name layout_info = layout_infos[0] row = [name, layout_info.mri, layout_info.x, layout_info.y, layout_info.visible] layout_table.append(row) self.layout.set_value(layout_table)
def table_from_list(self, int_values): table = Table(self.meta) if self.fields: nconsume = self._calc_nconsume() for i in range(int(len(int_values) / nconsume)): int_value = 0 for c in range(nconsume): int_value += int(int_values[i*nconsume+c]) << (32 * c) row = [] for name, (bits_hi, bits_lo) in self.fields.items(): mask = 2 ** (bits_hi + 1) - 1 field_value = (int_value & mask) >> bits_lo row.append(field_value) table.append(row) return table
def test_from_dict(self): d = {"e2": [0, 1, 2], "e1": ["value"], "e3": [6, 7]} t = Table(self.meta, d) assert self.meta == t.meta assert [0, 1, 2] == list(t.e2) assert ("value", ) == t.e1 assert [6, 7] == list(t.e3)
def test_from_dict(self): d = {"e2": [0, 1, 2], "e1": ["value"], "e3": [6, 7]} t = Table(self.meta, d) self.assertEqual(self.meta, t.meta) self.assertEqual([0, 1, 2], list(t.e2)) self.assertEqual(("value", ), t.e1) self.assertEqual([6, 7], list(t.e3))
def test_to_dict(self): t = Table(self.meta) t.e1 = ["value"] t.e2 = [1, 2] t.e3 = [0] expected = OrderedDict() expected["typeid"] = "malcolm:core/Table:1.0" expected["e1"] = ["value"] expected["e2"] = [1, 2] expected["e3"] = [0] actual = t.to_dict() # numpy compare gets in the way... for k, v in actual.items(): if k != "typeid": actual[k] = list(v) self.assertEquals(expected, actual)
def test_configure(self): params = Mock() params.info_table = Table(info_table_meta) params.info_table.name = ["x", "y"] params.info_table.cs_axis = ["A", "B"] params.info_table.cs_port = ["CS1", "CS1"] params.info_table.acceleration_time = [0.1, 0.1] params.info_table.resolution = [0.001, 0.001] params.info_table.offset = [0, 0] params.info_table.max_velocity = [1.0, 1.0] params.info_table.current_position = [0.5, 0.0] params.start_step = 0 xs = LineGenerator("x", "mm", 0.0, 0.5, 3, alternate_direction=True) ys = LineGenerator("y", "mm", 0.0, 0.1, 2) params.generator = CompoundGenerator([ys, xs], [], []) params.exposure = 1.0 params.axes_to_move = ["x", "y"] task = Mock() self.o.configure(task, params) self.assertEqual(task.put.call_count, 4) self.assertEqual(task.post.call_count, 3) self.check_resolutions_and_use(task.put.call_args_list[0][0][0]) self.assertEqual( task.put.call_args_list[1][0][0], { self.child["time_array"]: [400, 1750, 400], self.child["velocity_mode"]: [2, 1, 3], self.child["user_programs"]: [0, 0, 0], self.child["num_points"]: 3, self.child["positionsA"]: [0.45, -0.087500000000000008, -0.1375], self.child["positionsB"]: [0.0, 0.0, 0.0] }) self.assertEqual(task.post.call_args_list[0], call(self.child["build_profile"])) self.assertEqual(task.post.call_args_list[1], call(self.child["execute_profile"])) self.check_resolutions_and_use(task.put.call_args_list[2][0][0]) self.assertEqual( task.put.call_args_list[3][0][0], { self.child["time_array"]: [ 400, 2000, 2000, 2000, 2000, 2000, 2000, 400, 400, 2000, 2000, 2000, 2000, 2000, 2000, 400 ], self.child["velocity_mode"]: [2, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 1, 3], self.child["user_programs"]: [3, 4, 3, 4, 3, 4, 2, 8, 3, 4, 3, 4, 3, 4, 2, 8], self.child["num_points"]: 16, self.child["positionsA"]: [ -0.125, 0.0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.6375, 0.625, 0.5, 0.375, 0.25, 0.125, 0.0, -0.125, -0.1375 ], self.child["positionsB"]: [ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.05, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 ] })
def test_set_export_parts(self): context = Context(self.p) b = context.block_view("mainBlock") assert list(b) == [ 'meta', 'health', 'state', 'layout', 'design', 'exports', 'modified', 'disable', 'reset', 'save', 'attr' ] new_exports = Table(self.c.exports.meta) new_exports.append(('part2.attr', 'childAttr')) new_exports.append(('part2.reset', 'childReset')) self.c.set_exports(new_exports) assert self.c.modified.value == True assert self.c.modified.alarm.message == "exports changed" call_with_params(self.c.save, design='testSaveLayout') assert self.c.modified.value == False # block has changed, get a new view b = context.block_view("mainBlock") assert list(b) == [ 'meta', 'health', 'state', 'layout', 'design', 'exports', 'modified', 'disable', 'reset', 'save', 'attr', 'childAttr', 'childReset' ] assert self.c.state.value == "Ready" assert b.childAttr.value == "defaultv" assert self.c.modified.value == False m = MagicMock() f = b.childAttr.subscribe_value(m) # allow a subscription to come through context.sleep(0.1) m.assert_called_once_with("defaultv") m.reset_mock() self.c_part.attr.set_value("newv") assert b.childAttr.value == "newv" assert self.c_part.attr.value == "newv" assert self.c.modified.value == True assert self.c.modified.alarm.message == \ "part2.attr.value = 'newv' not 'defaultv'" # allow a subscription to come through context.sleep(0.1) m.assert_called_once_with("newv") b.childAttr.put_value("again") assert b.childAttr.value == "again" assert self.c_part.attr.value == "again" assert self.c.modified.value == True assert self.c.modified.alarm.message == \ "part2.attr.value = 'again' not 'defaultv'" # remove the field new_exports = Table(self.c.exports.meta) self.c.set_exports(new_exports) assert self.c.modified.value == True call_with_params(self.c.save) assert self.c.modified.value == False # block has changed, get a new view b = context.block_view("mainBlock") assert "childAttr" not in b
def test_set_and_load_layout(self): self.c.edit() self.checkState(self.sm.EDITABLE, child=False) new_layout = Table(self.c.layout.meta) new_layout.name = ["part2"] new_layout.mri = ["P45-MRI"] new_layout.x = [10] new_layout.y = [20] new_layout.visible = [True] self.b.layout = new_layout self.assertEqual(self.c.parts["part2"].x, 10) self.assertEqual(self.c.parts["part2"].y, 20) self.assertEqual(self.c.parts["part2"].visible, True) # save the layout, modify and restore it params = {"layoutName": "testSaveLayout"} params = ManagerController.save.MethodMeta.prepare_input_map(**params) self.c.save(params) self.c.edit() new_layout.x = [30] self.b.layout = new_layout self.assertEqual(self.c.parts["part2"].x, 30) self.b.layoutName = "testSaveLayout" self.assertEqual(self.c.parts["part2"].x, 10)
def test_layout(self): self.c.edit() self.checkState(sm.EDITABLE) new_layout = Table(self.c.layout.meta) new_layout.name = ["partchild1", "partchild2", "partchild3"] new_layout.mri = ["part1", "part2", "part3"] new_layout.x = [10, 11, 12] new_layout.y = [20, 21, 22] new_layout.visible = [True, True, True] self.b.layout = new_layout self.assertEqual(self.c.parts['partchild1'].x, 10) self.assertEqual(self.c.parts['partchild1'].y, 20) self.assertEqual(self.c.parts['partchild1'].visible, True) self.assertEqual(self.c.parts['partchild2'].x, 11) self.assertEqual(self.c.parts['partchild2'].y, 21) self.assertEqual(self.c.parts['partchild2'].visible, True) self.assertEqual(self.c.parts['partchild3'].x, 12) self.assertEqual(self.c.parts['partchild3'].y, 22) self.assertEqual(self.c.parts['partchild3'].visible, True) new_layout.visible = [True, False, True] self.b.layout= new_layout self.assertEqual(self.c.parts['partchild1'].visible, True) self.assertEqual(self.c.parts['partchild2'].visible, False) self.assertEqual(self.c.parts['partchild3'].visible, True)
def test_init(self): meta = Mock() s = StringArrayMeta() meta.elements = {"e1": s, "e2": s, "e3": s} t = Table(meta) self.assertEquals((), t.e1) self.assertEquals((), t.e2) self.assertEquals((), t.e3) self.assertEquals("malcolm:core/Table:1.0", t.typeid)
def test_init(self): meta = Mock() s = StringArrayMeta() meta.elements = {"e1": s, "e2": s, "e3": s} t = Table(meta) assert () == t.e1 assert () == t.e2 assert () == t.e3 assert "malcolm:core/Table:1.0" == t.typeid
def move_child_block(self): new_layout = Table(self.c.layout.meta) new_layout.name = ["part2"] new_layout.mri = ["anything"] new_layout.x = [10] new_layout.y = [20] new_layout.visible = [True] self.c.set_layout(new_layout)
def validate(self, value): if not isinstance(value, Table): # turn it into a table value = Table.from_dict(value, meta=self) else: # Check that it's using the same meta object assert self == value.meta, \ "Supplied table with wrong meta type" # Check column lengths value.verify_column_lengths() return value
def test_list_from_table(self): table = Table(self.meta) table.append([32, True, True, 4294967295]) table.append([0, True, False, 1]) table.append([0, False, False, 0]) l = self.o.list_from_table(table) self.assertEqual(l, [32, 0x10001, 4294967295, 0, 0x1, 1, 0, 0x0, 0])
def move_child_block(self): self.assertEqual(self.b.layout.x, [0]) new_layout = Table(self.c.layout.meta) new_layout.name = ["part2"] new_layout.mri = ["P45-MRI"] new_layout.x = [10] new_layout.y = [20] new_layout.visible = [True] self.b.layout = new_layout self.assertEqual(self.b.layout.x, [10])
def test_dict_roundtrip(self): t = Table(self.meta) d = t.to_dict() d2 = d.copy() d2.pop("typeid") t2 = Table(self.meta, d2) assert d == t2.to_dict()
def test_init_with_dict(self): meta = Mock() meta.elements = { "e1": NumberArrayMeta("int32"), "e2": StringArrayMeta(), "e3": StringArrayMeta() } d = {"e1": [0, 1], "e3": ["value"]} t = Table(meta, d) assert [0, 1] == list(t.e1) assert () == t.e2 assert ("value", ) == t.e3 assert "malcolm:core/Table:1.0" == t.typeid
def test_init_with_dict(self): meta = Mock() meta.elements = { "e1": NumberArrayMeta("int32"), "e2": StringArrayMeta(), "e3": StringArrayMeta() } d = {"e1": [0, 1], "e3": ["value"]} t = Table(meta, d) self.assertEquals([0, 1], list(t.e1)) self.assertEquals((), t.e2) self.assertEquals(("value", ), t.e3) self.assertEquals("malcolm:core/Table:1.0", t.typeid)
def do_init(self): # This will do an initial poll of the exportable parts, # so don't update here super(ManagerController, self).do_init() # List the configDir and add to choices self._set_layout_names() # This will trigger all parts to report their layout, making sure # the layout table has a valid value. This will also call # self._update_block_endpoints() self.set_layout(Table(self.layout.meta)) # If given a default config, load this if self.params.initialDesign: self.do_load(self.params.initialDesign)
def do_reset(self): super(ManagerController, self).do_reset() # This will trigger all parts to report their layout, making sure the # layout table has a valid value self.set_layout(Table(self.layout.meta)) # List the configDir and add to choices self._set_layout_names() # If we have no load_structure (initial reset) define one if self.load_structure is None: if self.params.defaultConfig: self.load_layout(self.params.defaultConfig) else: self.load_structure = self._save_to_structure()
def merge_non_writeable_table( default: Table, supplied: Table, non_writeable: List[int] ) -> Table: default_rows = list(default.rows()) for supplied_row in supplied.rows(): key = [supplied_row[i] for i in non_writeable] for default_row in default_rows: if key == [default_row[i] for i in non_writeable]: break else: d = OrderedDict() for i, k in enumerate(supplied.call_types): if i in non_writeable: d[k] = supplied_row[i] raise ValueError( "Table row with %s doesn't match a row in the default table" % json_encode(d) ) for i, v in enumerate(supplied_row): if i not in non_writeable: default_row[i] = v table = default.from_rows(default_rows) return table
def set_layout(self, value): """Set the layout table value. Called on attribute put""" # If it isn't a table, make it one if not isinstance(value, Table): value = Table(self.layout.meta, value) # Can't do this with changes_squashed as it will call update_modified # from another thread and deadlock part_info = self.run_hook( self.Layout, self.create_part_contexts(only_visible=False), self.port_info, value) with self.changes_squashed: layout_table = Table(self.layout.meta) layout_parts = LayoutInfo.filter_parts(part_info) for name, layout_infos in layout_parts.items(): assert len(layout_infos) == 1, \ "%s returned more than 1 layout infos" % name layout_parts[name] = layout_infos[0] layout_table.name = list(layout_parts) layout_table.mri = [i.mri for i in layout_parts.values()] layout_table.x = [i.x for i in layout_parts.values()] layout_table.y = [i.y for i in layout_parts.values()] layout_table.visible = [i.visible for i in layout_parts.values()] try: np.testing.assert_equal( layout_table.visible, self.layout.value.visible) except AssertionError: visibility_changed = True else: visibility_changed = False self.layout.set_value(layout_table) if self.saved_visibility is None: # First write of table, set layout and exports saves self.saved_visibility = layout_table.visible self.saved_exports = self.exports.value.to_dict() if visibility_changed: self.update_modified() self.update_exportable() # Part visibility changed, might have attributes or methods # that we need to hide or show self._update_block_endpoints()
def do_load(self, design): filename = self._validated_config_filename(design) with open(filename, "r") as f: text = f.read() structure = json_decode(text) # Set the layout table layout_table = Table(self.layout.meta) for part_name, part_structure in structure.get("layout", {}).items(): layout_table.append([ part_name, "", part_structure["x"], part_structure["y"], part_structure["visible"]]) self.set_layout(layout_table) # Set the exports table exports_table = Table(self.exports.meta) for name, export_name in structure.get("exports", {}).items(): exports_table.append([name, export_name]) self.exports.set_value(exports_table) # Run the load hook to get parts to load their own structure self.run_hook(self.Load, self.create_part_contexts(only_visible=False), structure) self._mark_clean(design)
def validate(self, value): if value is None: value = {} if isinstance(value, Table): if self != value.meta: # Make a table using ourself as the meta value = value.to_dict() value.pop("typeid", None) value = Table(self, value) else: # Should be a dict value = Table(self, value) # Check column lengths value.verify_column_lengths() return value
def test_to_dict(self): t = Table(self.meta) t.e1 = ["value"] t.e2 = [1, 2] t.e3 = [0] expected = OrderedDict() expected["typeid"] = "malcolm:core/Table:1.0" expected["e1"] = ["value"] expected["e2"] = [1, 2] expected["e3"] = [0] actual = t.to_dict() # numpy compare gets in the way... for k, v in actual.items(): if k != "typeid": actual[k] = list(v) assert expected == actual
def test_set_and_load_layout(self): new_layout = Table(self.c.layout.meta) new_layout.name = ["part2"] new_layout.mri = ["anything"] new_layout.x = [10] new_layout.y = [20] new_layout.visible = [False] self.c.set_layout(new_layout) assert self.c.parts['part2'].x == 10 assert self.c.parts['part2'].y == 20 assert self.c.parts['part2'].visible == False assert self.c.modified.value == True assert self.c.modified.alarm.message == "layout changed" # save the layout, modify and restore it call_with_params(self.c.save, design='testSaveLayout') assert self.c.modified.value == False self.check_expected_save(10.0, 20.0, "false") self.c.parts['part2'].x = 30 self.c.set_design('testSaveLayout') assert self.c.parts['part2'].x == 10
def test_set_and_load_layout(self): self.c.edit() self.checkState(self.sm.EDITABLE, child=False) new_layout = Table(self.c.layout.meta) new_layout.name = ["part2"] new_layout.mri = ["P45-MRI"] new_layout.x = [10] new_layout.y = [20] new_layout.visible = [True] self.b.layout = new_layout self.assertEqual(self.c.parts['part2'].x, 10) self.assertEqual(self.c.parts['part2'].y, 20) self.assertEqual(self.c.parts['part2'].visible, True) # save the layout, modify and restore it params = {'layoutName': 'testSaveLayout'} params = ManagerController.save.MethodMeta.prepare_input_map(**params) self.c.save(params) self.check_expected_save(10.0, 20.0, "true") self.c.parts['part2'].x = 30 self.b.layoutName = 'testSaveLayout' self.assertEqual(self.c.parts['part2'].x, 10)
class TestTableRowOperations(unittest.TestCase): def setUp(self): meta = Mock() meta.elements = OrderedDict() meta.elements["e1"] = NumberArrayMeta("int32") meta.elements["e2"] = NumberArrayMeta("int32") meta.elements["e3"] = NumberArrayMeta("int32") self.t = Table(meta) self.t.e1 = [1] self.t.e2 = [2] self.t.e3 = [3] def test_row_access(self): self.assertEqual([1, 2, 3], self.t[0]) def test_string_access(self): self.assertEqual(self.t.e1, self.t["e1"]) self.assertEqual(self.t.e2, self.t["e2"]) def test_string_setters(self): self.t["e2"] = [4] self.assertEqual(list(self.t.e2), [4]) def test_row_access_index_error(self): with self.assertRaises(IndexError): self.t[1] self.t.e1 = [1, 11] self.t.e2 = [2, 12] self.t.e3 = [3, 13] self.t[1] with self.assertRaises(IndexError): self.t[2] def test_row_assignment(self): self.t[0] = [7, 8, 9] self.assertEqual([7], self.t.e1) self.assertEqual([8], self.t.e2) self.assertEqual([9], self.t.e3) def test_row_assignment_bad_row_raises(self): with self.assertRaises(ValueError): self.t[0] = [7, 8] self.assertEqual([1], self.t.e1) self.assertEqual([2], self.t.e2) self.assertEqual([3], self.t.e3) def test_row_assingment_index_error(self): with self.assertRaises(IndexError): self.t[1] = [7, 8, 9] def test_row_append(self): self.t.append([11, 12, 13]) self.t.append([21, 22, 23]) self.assertEquals([1, 11, 21], list(self.t.e1)) self.assertEquals([2, 12, 22], list(self.t.e2)) self.assertEquals([3, 13, 23], list(self.t.e3)) def test_row_append_bad_row_raises(self): self.assertRaises(ValueError, self.t.append, [11, 12]) self.assertRaises(ValueError, self.t.append, [11, 12, 13, 14]) def test_bad_columns_raise(self): self.t.e1 = [1, 2] with self.assertRaises(AssertionError): self.t[0] with self.assertRaises(AssertionError): self.t[0] = [0, 0, 0] with self.assertRaises(AssertionError): self.t.append([0, 0, 0])