def test_observer_item_ordered_sequence_len(self): # configure the model array_field = StructuredModel.define_array(StructuredModel.STRING) str_field = StructuredModel.define_field("a", array_field, default=["a", "b", "c"]) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) # build the observer length = 0 def len_changed(new_length: Observer.ItemValue) -> None: nonlocal length length = new_length oo = Observer.ObserverBuilder() oo.source(model).ordered_sequence_from_array("a").map( oo.x.transform(lambda x: x.upper())).len().action_fn(len_changed) with contextlib.closing(oo.make_observable()) as o: # check the observer functionality # items will be ordered self.assertEqual(3, length) model.a.insert(1, "a-b") self.assertEqual(4, length) del model.a[0] self.assertEqual(3, length)
def test_refcounts_after_record_and_apply(self) -> None: # create the model x_field = StructuredModel.define_field("x", StructuredModel.INT) y_field = StructuredModel.define_field("y", StructuredModel.INT) record = StructuredModel.define_record("R", [x_field, y_field]) array = StructuredModel.define_array(record) schema = StructuredModel.define_record("A", [StructuredModel.define_field("a", array)]) model = StructuredModel.build_model(schema, value={"a": [{"x": 1, "y": 2}, {"x": 3, "y": 4}]}) # create recorder r = Recorder.Recorder(model) # change the model model_copy = copy.deepcopy(model) model.a[1].x = 33 del model.a[0] model.a.insert(1, StructuredModel.build_model(record, value={"x": -1, "y": -2})) # confirm changes self.assertEqual(33, model.a[0].x) self.assertEqual(-2, model.a[1].y) # confirm copy self.assertEqual(1, model_copy.a[0].x) self.assertEqual(4, model_copy.a[1].y) r.apply(model_copy) self.assertEqual(33, model_copy.a[0].x) self.assertEqual(-2, model_copy.a[1].y) # check recorder refcount r_ref = weakref.ref(r) del r self.assertIsNone(r_ref())
def test_observer_item_sequence_for_each(self): # configure the model array_field = StructuredModel.define_array(StructuredModel.STRING) str_field = StructuredModel.define_field("a", array_field, default=["a", "b", "c"]) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) # build the observer values = list() class Action(Observer.AbstractAction): def __init__(self, item_value): nonlocal values values.append(item_value) def close(self): pass oo = Observer.ObserverBuilder() oo.source(model).sequence_from_array("a").for_each(oo.x.action(Action)) with contextlib.closing( typing.cast(Observer.AbstractItemSequenceSource, oo.make_observable())) as o: # check the observer functionality # items will be unordered self.assertEqual(["a", "b", "c"], values) model.a.insert(1, "a-b") self.assertEqual(["a", "b", "c", "a-b"], values)
def test_observer_item_sequence_filter(self): # configure the model array_field = StructuredModel.define_array(StructuredModel.STRING) str_field = StructuredModel.define_field("a", array_field, default=["a", "b", "c"]) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) # build the observer oo = Observer.ObserverBuilder() predicate = lambda x: not x.startswith("a") oo.source(model).ordered_sequence_from_array("a").filter(predicate) with contextlib.closing( typing.cast(Observer.AbstractItemSequenceSource, oo.make_observable())) as o: # check the observer functionality self.assertEqual(["b", "c"], o.items) # a, b, c model.a.insert(1, "a-b") self.assertEqual(["b", "c"], o.items) # a, a-b, b, c model.a.insert(0, "b-a") self.assertEqual(["b-a", "b", "c"], o.items) # b-a, a, a-b, b, c del model.a[1] self.assertEqual(["b-a", "b", "c"], o.items) # b-a, a-b, b, c del model.a[2] self.assertEqual(["b-a", "c"], o.items) # b-a, a-b, c
def test_change_array_records_value_generates_model_changed(self) -> None: x_field = StructuredModel.define_field("x", StructuredModel.INT) y_field = StructuredModel.define_field("y", StructuredModel.INT) record = StructuredModel.define_record("A", [x_field, y_field]) schema = StructuredModel.define_array(record) model = StructuredModel.build_model(schema, value=[{ "x": 1, "y": 2 }, { "x": 3, "y": 4 }]) changed_ref = [0] def property_changed() -> None: changed_ref[0] += 1 with contextlib.closing( model.model_changed_event.listen(property_changed)): self.assertEqual(0, changed_ref[0]) model.insert_item( 1, StructuredModel.build_model(record, value={ "x": 5, "y": 6 })) self.assertEqual(1, changed_ref[0]) model.items[1].x = 55 self.assertEqual(2, changed_ref[0])
def test_refcounts(self) -> None: # create the model x_field = StructuredModel.define_field("x", StructuredModel.INT) y_field = StructuredModel.define_field("y", StructuredModel.INT) record = StructuredModel.define_record("R", [x_field, y_field]) array = StructuredModel.define_array(record) schema = StructuredModel.define_record( "A", [StructuredModel.define_field("a", array)]) model = StructuredModel.build_model( schema, value={"a": [{ "x": 1, "y": 2 }, { "x": 3, "y": 4 }]}) # change the model model.a[1].x = 33 del model.a[0] model.a.insert( 1, StructuredModel.build_model(record, value={ "x": -1, "y": -2 })) # check ref counts model_ref = weakref.ref(model) del model self.assertIsNone(model_ref())
def test_get_record_array_property(self) -> None: # test that a record gives access to a array value directly through a property on the record array_field = StructuredModel.define_array(StructuredModel.STRING) str_field = StructuredModel.define_field("a", array_field) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) self.assertIsInstance(model.a, collections.abc.Sequence)
def __init__(self): self._event_loop = None # this will be injected by declarative UI engine # create a structured model by building a schema and then using the schema to create a structured model object. mode_title_field = StructuredModel.define_field( "title", StructuredModel.STRING) mode_balance_field = StructuredModel.define_field("balance", StructuredModel.INT, default=0) mode_schema = StructuredModel.define_record( "Mode", [mode_title_field, mode_balance_field]) mode_index_field = StructuredModel.define_field("mode_index", StructuredModel.INT, default=1) modes_field = StructuredModel.define_field( "modes", StructuredModel.define_array(mode_schema)) schema = StructuredModel.define_record("Configuration", [mode_index_field, modes_field]) # import pprint # print(pprint.pformat(schema)) self.model = StructuredModel.build_model(schema) # the title model is used for adding new modes. it is not part of the structured model. self.title_model = Model.PropertyModel() # the mode titles model is a property containing a list of mode titles. it is not part of the structured # model, but needs to be rebuilt when the list of modes in the model changes. add a listener for items # inserted/removed events and rebuild the mode titles model when those events are fired. self.mode_titles_model = Model.PropertyModel( [mode.title for mode in self.model.modes]) def modes_changed(k, v, i): if k == "modes": self.mode_titles_model.value = [ mode.title for mode in self.model.modes ] self.__modes_item_inserted_listener = self.model.item_inserted_event.listen( modes_changed) self.__modes_item_removed_listener = self.model.item_removed_event.listen( modes_changed) # add some initial modes self.model.modes.append( StructuredModel.build_model(mode_schema, value={"title": "One"})) self.model.modes.append( StructuredModel.build_model(mode_schema, value={"title": "Two"}))
def test_setting_value_in_array_raises_exception(self) -> None: array_field = StructuredModel.define_array(StructuredModel.STRING) str_field = StructuredModel.define_field("a", array_field, default=["a", "b", "c"]) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) with self.assertRaises(IndexError): model.a[0] = "A"
def test_get_record_array_model(self) -> None: # test that a record gives access to a array model through a property on the record with _model suffix array_field = StructuredModel.define_array(StructuredModel.STRING) str_field = StructuredModel.define_field("a", array_field, default=["a", "b", "c"]) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) self.assertIsInstance(model.a_model, StructuredModel.ArrayModel)
def test_str_array_defaults(self) -> None: # test that an array of simple fields (str) can be initialized with default values array_field = StructuredModel.define_array(StructuredModel.STRING) str_field = StructuredModel.define_field("a", array_field, default=["a", "b", "c"]) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) self.assertSequenceEqual(["a", "b", "c"], model.a)
def test_record_with_array_defaults(self) -> None: # test that a record with an array field can be initialized with default values array_field = StructuredModel.define_field( "a", StructuredModel.define_array(StructuredModel.INT)) record = StructuredModel.define_record("R", [array_field]) record_field = StructuredModel.define_field("r", record, default={"a": [3, 4, 5]}) schema = StructuredModel.define_record("Z", [record_field]) model = StructuredModel.build_model(schema) self.assertEqual(3, len(model.r.a)) self.assertEqual(4, model.r.a[1]) self.assertEqual(5, model.r.a[2])
def test_refcounts(self) -> None: # create the model x_field = StructuredModel.define_field("x", StructuredModel.INT) y_field = StructuredModel.define_field("y", StructuredModel.INT) record = StructuredModel.define_record("R", [x_field, y_field]) array = StructuredModel.define_array(record) schema = StructuredModel.define_record("A", [StructuredModel.define_field("a", array)]) model = StructuredModel.build_model(schema, value={"a": [{"x": 1, "y": 2}, {"x": 3, "y": 4}]}) # create recorder r = Recorder.Recorder(model) # check recorder refcount r_ref = weakref.ref(r) del r self.assertIsNone(r_ref())
def test_change_array_basic_value_generates_model_changed(self) -> None: schema = StructuredModel.define_array(StructuredModel.STRING) model = StructuredModel.build_model(schema, value=["a", "b", "c"]) changed_ref = [0] def property_changed() -> None: changed_ref[0] += 1 with contextlib.closing( model.model_changed_event.listen(property_changed)): self.assertEqual(0, changed_ref[0]) model.insert_item(1, "aa") self.assertEqual(1, changed_ref[0]) model.remove_item(1) self.assertEqual(2, changed_ref[0])
def test_observer_item_array(self): # configure the model array_field = StructuredModel.define_array(StructuredModel.STRING) str_field = StructuredModel.define_field("a", array_field, default=["a", "b", "c"]) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) # build the observer oo = Observer.ObserverBuilder() oo.source(model).array("a") with contextlib.closing(oo.make_observable()) as o: # check the observer functionality self.assertEqual(["a", "b", "c"], o.item) model.a.insert(1, "a-b") self.assertEqual(["a", "a-b", "b", "c"], o.item) del model.a[2] self.assertEqual(["a", "a-b", "c"], o.item)
def test_observer_item_sequence_index(self): # configure the model array_field = StructuredModel.define_array(StructuredModel.STRING) str_field = StructuredModel.define_field("a", array_field, default=["a", "b", "c"]) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) # build the observer oo = Observer.ObserverBuilder() oo.source(model).ordered_sequence_from_array("a").map(oo.x.transform(lambda x: x.upper())).index(0) with contextlib.closing(oo.make_observable()) as o: # check the observer functionality # items will be ordered self.assertEqual("A", o.item) model.a.insert(1, "a-b") self.assertEqual("A", o.item) del model.a[0] self.assertEqual("A-B", o.item)
def test_observer_item_array_sequence(self): # configure the model array_field = StructuredModel.define_array(StructuredModel.STRING) str_field = StructuredModel.define_field("a", array_field, default=["a", "b", "c"]) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) # build the observer oo = Observer.ObserverBuilder() oo.source(model).sequence_from_array("a") with contextlib.closing(typing.cast(Observer.AbstractItemSequenceSource, oo.make_observable())) as o: # check the observer functionality # items will be unordered self.assertEqual(["a", "b", "c"], o.items) model.a.insert(1, "a-b") self.assertEqual(["a", "b", "c", "a-b"], o.items) del model.a[0] self.assertEqual(["b", "c", "a-b"], o.items)
def test_array_of_records_defaults(self) -> None: # test that an array of record fields can be initialized with default values x_field = StructuredModel.define_field("x", StructuredModel.INT) y_field = StructuredModel.define_field("y", StructuredModel.INT) record = StructuredModel.define_record("A", [x_field, y_field]) array_field = StructuredModel.define_array(record) str_field = StructuredModel.define_field("a", array_field, default=[{ "x": 1, "y": 2 }, { "x": 3, "y": 4 }]) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) self.assertEqual(2, len(model.a)) self.assertEqual(1, model.a[0].x) self.assertEqual(4, model.a[1].y)
def test_removing_item_in_array_field_of_record_using_del_fires_item_removed_event( self): array_field = StructuredModel.define_array(StructuredModel.STRING) str_field = StructuredModel.define_field("a", array_field, default=["a", "b", "c"]) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) was_item_removed_ref = [False] def handle_item_removed(key, value, before_index): self.assertEqual("a", key) self.assertEqual("b", value) self.assertEqual(1, before_index) was_item_removed_ref[0] = True with contextlib.closing( model.item_removed_event.listen(handle_item_removed)): self.assertFalse(was_item_removed_ref[0]) del model.a[1] self.assertTrue(was_item_removed_ref[0])
def test_inserting_item_in_array_field_of_record_using_insert_fires_item_inserted_event( self) -> None: array_field = StructuredModel.define_array(StructuredModel.STRING) str_field = StructuredModel.define_field("a", array_field, default=["a", "b", "c"]) schema = StructuredModel.define_record("R", [str_field]) model = StructuredModel.build_model(schema) was_item_inserted_ref = [False] def handle_item_inserted(key: str, value: typing.Any, before_index: int) -> None: self.assertEqual("a", key) self.assertEqual("bb", value) self.assertEqual(1, before_index) was_item_inserted_ref[0] = True with contextlib.closing( model.item_inserted_event.listen(handle_item_inserted)): self.assertFalse(was_item_inserted_ref[0]) model.a.insert(1, "bb") self.assertTrue(was_item_inserted_ref[0])
def test_copy_array_produces_copy(self) -> None: x_field = StructuredModel.define_field("x", StructuredModel.INT) y_field = StructuredModel.define_field("y", StructuredModel.INT) record = StructuredModel.define_record("A", [x_field, y_field]) schema = StructuredModel.define_array(record) model = StructuredModel.build_model(schema, value=[{ "x": 1, "y": 2 }, { "x": 3, "y": 4 }]) model_copy = copy.deepcopy(model) self.assertEqual(len(model.items), len(model_copy.items)) self.assertEqual(model.items[1].x, model_copy.items[1].x) self.assertEqual(model.items[1].y, model_copy.items[1].y) model.items[1].x = 5 self.assertNotEqual(model.items[1].x, model_copy.items[1].x) self.assertEqual(model.items[1].y, model_copy.items[1].y) model.copy_from(model_copy) self.assertEqual(len(model.items), len(model_copy.items)) self.assertEqual(model.items[1].x, model_copy.items[1].x) self.assertEqual(model.items[1].y, model_copy.items[1].y)