class TestSerialization(unittest.TestCase): def setUp(self): self.serialized = OrderedDict() self.serialized["typeid"] = "malcolm:core/Method:1.0" self.takes = MapMeta() self.takes.set_elements(OrderedDict({"in_attr": StringMeta("desc")})) self.serialized["takes"] = self.takes.to_dict() self.serialized["defaults"] = OrderedDict({"in_attr": "default"}) self.serialized["description"] = "test_description" self.serialized["tags"] = [] self.serialized["writeable"] = True self.serialized["label"] = "" self.serialized["returns"] = MapMeta().to_dict() def test_to_dict(self): m = Method("test_description") m.set_takes(self.takes) m.set_defaults(self.serialized["defaults"]) self.assertEqual(m.to_dict(), self.serialized) def test_from_dict(self): m = Method.from_dict(self.serialized.copy()) self.assertEqual(m.takes.to_dict(), self.takes.to_dict()) self.assertEqual(m.defaults, self.serialized["defaults"]) self.assertEqual(m.tags, []) self.assertEqual(m.writeable, True) self.assertEqual(m.label, "") self.assertEqual(m.returns.to_dict(), MapMeta().to_dict())
def test_returns_dict(self, _): e1 = MagicMock() e1.name = "one" a1 = OrderedDict() e1.to_dict.return_value = a1 e2 = MagicMock() e2.name = "two" a2 = OrderedDict() e2.to_dict.return_value = a2 self.meta_map = MapMeta("Test") self.meta_map.add_element(e1, required=True) self.meta_map.add_element(e2, required=False) expected_elements_dict = OrderedDict() expected_elements_dict['one'] = a1 expected_elements_dict['two'] = a2 expected_dict = OrderedDict() expected_dict['elements'] = expected_elements_dict expected_dict['required'] = ["one"] response = self.meta_map.to_dict() self.assertEqual(expected_dict, response)
class TestSerialization(unittest.TestCase): def setUp(self): self.serialized = OrderedDict() self.serialized["typeid"] = "malcolm:core/Method:1.0" self.takes = MapMeta() self.takes.set_elements({"in_attr": StringMeta("desc")}) self.serialized["takes"] = self.takes.to_dict() self.serialized["defaults"] = OrderedDict({"in_attr": "default"}) self.serialized["description"] = "test_description" self.serialized["tags"] = () self.serialized["writeable"] = True self.serialized["label"] = "" self.serialized["returns"] = MapMeta().to_dict() def test_to_dict(self): m = MethodModel("test_description") m.set_takes(self.takes) m.set_defaults(self.serialized["defaults"]) assert m.to_dict() == self.serialized def test_from_dict(self): m = MethodModel.from_dict(self.serialized) assert m.takes.to_dict() == self.takes.to_dict() assert m.defaults == self.serialized["defaults"] assert m.tags == () assert m.writeable == True assert m.label == "" assert m.returns.to_dict() == MapMeta().to_dict()
class TestSerialization(unittest.TestCase): def setUp(self): self.serialized = OrderedDict() self.serialized["typeid"] = "malcolm:core/MethodMeta:1.0" self.takes = MapMeta() self.takes.set_elements(ElementMap({"in_attr": StringMeta("desc")})) self.serialized["takes"] = self.takes.to_dict() self.serialized["defaults"] = OrderedDict({"in_attr": "default"}) self.serialized["description"] = "test_description" self.serialized["tags"] = [] self.serialized["writeable"] = True self.serialized["label"] = "" self.serialized["returns"] = MapMeta().to_dict() def test_to_dict(self): m = MethodMeta("test_description") m.set_takes(self.takes) m.set_defaults(self.serialized["defaults"]) self.assertEqual(m.to_dict(), self.serialized) def test_from_dict(self): m = MethodMeta.from_dict(self.serialized.copy()) self.assertEqual(m.takes.to_dict(), self.takes.to_dict()) self.assertEqual(m.defaults, self.serialized["defaults"]) self.assertEqual(m.tags, []) self.assertEqual(m.writeable, True) self.assertEqual(m.label, "") self.assertEqual(m.returns.to_dict(), MapMeta().to_dict())
def _prepare_map_meta(args, allow_defaults, defaults=None, elements=None, required=None): # prepare some data structures that will be used for the takes MapMeta if defaults is None: defaults = OrderedDict() if elements is None: elements = OrderedDict() if required is None: required = [] for index in range(0, len(args), 3): # pick out 3 arguments name = args[index] check_camel_case(name) meta = args[index + 1] default = args[index + 2] # store them in the right structures elements[name] = meta if default is REQUIRED: required.append(name) elif default is not OPTIONAL: assert allow_defaults, "Defaults not allowed in this structure" defaults[name] = default # Setup the takes MapMeta and attach it to the function's MethodMeta meta = MapMeta() meta.set_elements(ElementMap(elements)) meta.set_required(required) return meta, defaults
def recreate_from_others(self, method_metas, without=None): if without is None: without = [] defaults = OrderedDict() elements = OrderedDict() required = [] # Populate the intermediate data structures for method_meta in method_metas: for element in method_meta.takes.elements: if element not in without: # Serialize it to copy it serialized = method_meta.takes.elements[element].to_dict() elements[element] = serialized if element in method_meta.takes.required and element not in required: required.append(element) if element in method_meta.defaults: defaults.pop(element, None) defaults[element] = method_meta.defaults[element] # TODO: what about returns? # remove required args that are now defaulted required = [r for r in required if r not in defaults] # Update ourself from these structures takes = MapMeta() takes.set_elements(ElementMap(elements)) takes.set_required(required) self.set_takes(takes) self.set_defaults(defaults)
def __init__(self, description="", tags=None, writeable=True, label=""): super(Method, self).__init__(description, tags, writeable, label) self.func = None self.set_takes(MapMeta()) self.set_returns(MapMeta()) self.defaults = OrderedDict() # List of state names that we are writeable in self.only_in = None
def setUp(self): n = NumberMeta(description='a number') s = StringMeta(description="a string") self.meta = MapMeta() self.meta.set_elements({"a": s, "b": s}) self.meta.set_required(["a"]) self.nmeta = MapMeta() self.nmeta.set_elements({"a": n, "b": n}) self.nmeta.set_required(["a"])
def setUp(self): n = NumberMeta(description='a number') s = StringMeta(description="a string") self.meta = MapMeta() self.meta.set_elements(ElementMap({"a": s, "b": s})) self.meta.set_required(["a"]) self.nmeta = MapMeta() self.nmeta.set_elements(ElementMap({"a": n, "b": n})) self.nmeta.set_required(["a"])
def test_takes_given_defaults(self): @method_takes("hello", StringMeta(), "Something") def say_hello(params): """Say hello""" print("Hello" + params.name) itakes = MapMeta() itakes.set_elements(ElementMap(OrderedDict(hello=StringMeta()))) self.assertEqual(say_hello.MethodMeta.takes.to_dict(), itakes.to_dict()) self.assertEqual(say_hello.MethodMeta.returns.to_dict(), MapMeta().to_dict()) self.assertEqual(say_hello.MethodMeta.defaults, {"hello": "Something"})
def test_takes_given_optional(self): @takes("hello", StringMeta(), OPTIONAL) def say_hello(params): """Say hello""" print("Hello" + params.name) itakes = MapMeta() itakes.set_elements(OrderedDict(hello=StringMeta())) self.assertEqual(say_hello.Method.takes.to_dict(), itakes.to_dict()) self.assertEqual(say_hello.Method.returns.to_dict(), MapMeta().to_dict()) self.assertEqual(say_hello.Method.defaults, {})
def setUp(self): self.serialized = OrderedDict() self.serialized["typeid"] = "malcolm:core/Method:1.0" self.takes = MapMeta() self.takes.set_elements(OrderedDict({"in_attr": StringMeta("desc")})) self.serialized["takes"] = self.takes.to_dict() self.serialized["defaults"] = OrderedDict({"in_attr": "default"}) self.serialized["description"] = "test_description" self.serialized["tags"] = [] self.serialized["writeable"] = True self.serialized["label"] = "" self.serialized["returns"] = MapMeta().to_dict()
def from_dict(cls, name, d): """Create a Method instance from the serialized version of itself Args: name (str): Method instance name d (dict): Something that self.to_dict() would create """ method = cls(name, d["description"]) takes = MapMeta.from_dict("takes", d["takes"]) method.set_function_takes(takes, d["defaults"]) returns = MapMeta.from_dict("returns", d["returns"]) method.set_function_returns(returns) return method
class TestToDict(unittest.TestCase): @patch('malcolm.core.attributemeta.AttributeMeta.to_dict') def test_returns_dict(self, _): e1 = MagicMock() e1.name = "one" a1 = OrderedDict() e1.to_dict.return_value = a1 e2 = MagicMock() e2.name = "two" a2 = OrderedDict() e2.to_dict.return_value = a2 self.meta_map = MapMeta("Test") self.meta_map.add_element(e1, required=True) self.meta_map.add_element(e2, required=False) expected_elements_dict = OrderedDict() expected_elements_dict['one'] = a1 expected_elements_dict['two'] = a2 expected_dict = OrderedDict() expected_dict['elements'] = expected_elements_dict expected_dict['required'] = ["one"] response = self.meta_map.to_dict() self.assertEqual(expected_dict, response) @patch('malcolm.core.mapmeta.AttributeMeta') def test_from_dict_deserialize(self, am_mock): # prep dict elements = OrderedDict() elements["one"] = "e1" elements["two"] = "e2" required = ["one"] d = dict(elements=elements, required=required) # prep from_dict with AttributeMetas to return am1 = MagicMock() am1.name = "one" am2 = MagicMock() am2.name = "two" am_mock.from_dict.side_effect = [am1, am2] map_meta = MapMeta.from_dict("Test", d) self.assertEqual(am_mock.from_dict.call_args_list, [ call("one", "e1"), call("two", "e2")]) self.assertEqual(map_meta.name, "Test") self.assertEqual(map_meta.required, ["one"]) self.assertEqual(map_meta.elements, dict(one=am1, two=am2))
class TestAddElement(unittest.TestCase): def setUp(self): self.meta_map = MapMeta("Test") self.attribute_mock = MagicMock() def test_given_valid_required_element_then_add(self): self.meta_map.add_element(self.attribute_mock, required=True) self.assertEqual(self.attribute_mock, self.meta_map.elements[self.attribute_mock.name]) self.assertEqual([self.attribute_mock.name], self.meta_map.required) def test_given_valid_optional_element_then_add(self): self.meta_map.add_element(self.attribute_mock, required=False) self.assertEqual(self.attribute_mock, self.meta_map.elements[self.attribute_mock.name]) self.assertEqual([], self.meta_map.required) def test_given_existing_element_then_raise_error(self): self.meta_map.add_element(self.attribute_mock, required=False) expected_error_message = "Element already exists in dictionary" with self.assertRaises(ValueError) as error: self.meta_map.add_element(self.attribute_mock, required=False) self.assertEqual(expected_error_message, error.exception.message)
def test_from_dict(self): tm = MapMeta.from_dict(self.serialized) self.assertEquals(tm.description, "desc") self.assertEquals(len(tm.elements), 1) self.assertEquals(tm.elements["c1"].to_dict(), self.sam.to_dict()) self.assertEquals(tm.tags, []) self.assertEquals(tm.required, ["c1"])
def test_from_dict(self): m = Method.from_dict(self.serialized.copy()) self.assertEqual(m.takes.to_dict(), self.takes.to_dict()) self.assertEqual(m.defaults, self.serialized["defaults"]) self.assertEqual(m.tags, []) self.assertEqual(m.writeable, True) self.assertEqual(m.label, "") self.assertEqual(m.returns.to_dict(), MapMeta().to_dict())
def test_recreate(self): @method_takes( "arg1", StringMeta("Arg1"), REQUIRED, "extra", StringMeta(), REQUIRED, ) def method1(): pass @method_takes( "arg8", StringMeta("Arg8"), REQUIRED, "arg3", StringMeta("Arg3"), "32", "arg4", StringMeta("Arg4"), OPTIONAL, ) def method2(): pass @method_takes( "arg8", StringMeta("Arg8"), "2", "arg3", StringMeta("Arg3"), "33", ) def method3(): pass m = MethodModel("Test") m.recreate_from_others( [method1.MethodModel, method2.MethodModel, method3.MethodModel], without=["extra"]) itakes = MapMeta() elements = OrderedDict() elements["arg1"] = StringMeta("Arg1") elements["arg8"] = StringMeta("Arg8") elements["arg3"] = StringMeta("Arg3") elements["arg4"] = StringMeta("Arg4") itakes.set_elements(elements) itakes.set_required(["arg1"]) defaults = OrderedDict() defaults["arg8"] = "2" defaults["arg3"] = "33" assert m.takes.to_dict() == itakes.to_dict() assert m.returns.to_dict() == MapMeta().to_dict() assert m.defaults == defaults
def test_defaults(self): func = Mock(return_value={"first_out": "test"}) m = Method("test_description", writeable=True) m.set_parent(Mock(), "test_method") s = StringMeta(description='desc') args_meta = MapMeta() args_meta.elements = {"first": s, "second": s} m.set_takes(args_meta) m.set_defaults({"second": "default"}) m.set_function(func) self.assertEquals({"first_out": "test"}, m.call_function(dict(first="test"))) call_arg = func.call_args[0][0] self.assertEqual("test", call_arg.first) self.assertEqual("default", call_arg.second) self.assertEqual(args_meta, call_arg.meta)
def test_from_dict(self): m = MethodModel.from_dict(self.serialized) assert m.takes.to_dict() == self.takes.to_dict() assert m.defaults == self.serialized["defaults"] assert m.tags == () assert m.writeable == True assert m.label == "" assert m.returns.to_dict() == MapMeta().to_dict()
def test_to_dict(self): s = StringMeta(description="a string") meta = MapMeta() elements = OrderedDict() elements["b"] = s elements["c"] = s elements["d"] = NumberMeta("int32") elements["e"] = s meta.set_elements(elements) m = Map(meta, {"b": "test", "d": 123, "e": "e"}) expected = OrderedDict() expected["typeid"] = "malcolm:core/Map:1.0" expected["b"] = "test" expected["d"] = 123 expected["e"] = "e" assert expected == m.to_dict()
def test_from_dict(self): tm = MapMeta.from_dict(self.serialized) assert tm.description == "desc" assert len(tm.elements) == 1 expected = self.sam.to_dict() expected["label"] = "C1" assert tm.elements["c1"].to_dict() == expected assert tm.tags == () assert tm.required == ("c1",)
def create_methods(self): """Create a Method wrapper for say_hello and return it""" method = Method("say_hello", "says hello") method.set_function(self.say_hello) takes = MapMeta("takes") takes.add_element(StringMeta("name", "a name")) method.set_function_takes(takes) returns = MapMeta("returns") returns.add_element(StringMeta("greeting", "a greeting")) method.set_function_returns(returns) yield method
def test_takes_given_required(self): @method_takes("hello", StringMeta(), REQUIRED) def say_hello(params): """Say hello""" print("Hello" + params.name) itakes = MapMeta() itakes.set_elements(OrderedDict(hello=StringMeta())) itakes.set_required(["hello"]) assert say_hello.MethodModel.takes.to_dict() == itakes.to_dict() assert say_hello.MethodModel.returns.to_dict() == MapMeta().to_dict() assert say_hello.MethodModel.defaults == {}
class TestSetters(unittest.TestCase): def setUp(self): self.mm = MapMeta("description") def test_values_set(self): self.assertIsInstance(self.mm.elements, OrderedDict) self.assertEqual(self.mm.elements, {}) self.assertEqual(self.mm.typeid, "malcolm:core/MapMeta:1.0") self.assertEqual(self.mm.description, "description") def test_set_elements(self): els = dict(sam=StringArrayMeta()) self.mm.set_elements(els) self.assertEqual(self.mm.elements, els) def test_set_required(self): req = ["ddd", "2"] self.mm.set_required(req) self.assertEqual(self.mm.required, req)
def decorator(func): if not hasattr(func, "Method"): Method.wrap_method(func) returns_meta = MapMeta("returns") for index in range(0, len(args), 2): if args[index + 1] not in [OPTIONAL, REQUIRED]: raise ValueError( "Must specify if return value is REQUIRED or OPTIONAL") meta = args[index] is_required = args[index + 1] is REQUIRED returns_meta.add_element(meta, is_required) func.Method.set_function_returns(returns_meta) return func
class TestSetters(unittest.TestCase): def setUp(self): self.mm = MapMeta("description") def test_values_set(self): self.assertIsInstance(self.mm.elements, ElementMap) self.assertEqual(len(self.mm.elements), 0) self.assertEqual(self.mm.typeid, "malcolm:core/MapMeta:1.0") self.assertEqual(self.mm.description, "description") def test_set_elements(self): els = ElementMap(dict(sam=StringArrayMeta())) self.mm.set_elements(els) self.assertEqual(self.mm.elements, els) def test_set_required(self): self.test_set_elements() req = ["sam"] self.mm.set_required(req) self.assertEqual(self.mm.required, req)
def test_returns_given_valid_sets(self): @method_returns("hello", StringMeta(), REQUIRED) def say_hello(ret): """Say hello""" ret.hello = "Hello" return ret ireturns = MapMeta() ireturns.set_elements(OrderedDict(hello=StringMeta())) ireturns.set_required(["hello"]) assert say_hello.MethodModel.takes.to_dict() == MapMeta().to_dict() assert say_hello.MethodModel.returns.to_dict() == ireturns.to_dict() assert say_hello.MethodModel.defaults == {}
def test_takes_given_required(self): @takes("hello", StringMeta(), REQUIRED) def say_hello(params): """Say hello""" print("Hello" + params.name) itakes = MapMeta() itakes.set_elements(OrderedDict(hello=StringMeta())) itakes.set_required(["hello"]) self.assertEqual(say_hello.Method.takes.to_dict(), itakes.to_dict()) self.assertEqual(say_hello.Method.returns.to_dict(), MapMeta().to_dict()) self.assertEqual(say_hello.Method.defaults, {})
def test_incomplete_return(self): func = Mock(return_value={"output1": 2}) m = Method("test_description", writeable=True) m.name = "test_method" m.set_function(func) s = StringMeta(description='desc') args_meta = MapMeta() args_meta.set_elements({"first": s, "second": s}) return_meta = MapMeta() return_meta.set_elements({"output1": s, "output2": s}) return_meta.set_required(["output2"]) m.set_takes(args_meta) m.set_returns(return_meta) with self.assertRaises(KeyError): m.call_function(dict(first=1, second=2)) call_arg1, call_arg2 = func.call_args_list[0][0] self.assertEqual('1', call_arg1.first) self.assertEqual('2', call_arg1.second) self.assertEqual(args_meta, call_arg1.meta) self.assertEqual(return_meta, call_arg2.meta)
def decorator(func): if not hasattr(func, "Method"): Method.wrap_method(func) takes_meta = MapMeta("takes") defaults = OrderedDict() for index in range(0, len(args), 2): meta = args[index] is_required = args[index + 1] is REQUIRED takes_meta.add_element(meta, is_required) # If second of pair is not REQUIRED or OPTIONAL it is taken as # the default value if args[index + 1] not in [OPTIONAL, REQUIRED]: defaults[meta.name] = args[index + 1] func.Method.set_function_takes(takes_meta, defaults) return func
class TestSetters(unittest.TestCase): def setUp(self): self.mm = MapMeta("description") def test_values_set(self): self.assertIsInstance(self.mm.elements, dict) assert len(self.mm.elements) == 0 assert self.mm.typeid == "malcolm:core/MapMeta:1.0" assert self.mm.description == "description" def test_set_elements(self): els = dict(sam=StringArrayMeta()) self.mm.set_elements(els) assert self.mm.elements == els def test_set_required(self): self.test_set_elements() req = ("sam",) self.mm.set_required(req) assert self.mm.required == req
def recreate_from_others(self, method_metas, without=None): if without is None: without = [] defaults = OrderedDict() elements = OrderedDict() required = [] # Populate the intermediate data structures for method_meta in method_metas: for element in method_meta.takes.elements: if element not in without: # Serialize it to copy it serialized = method_meta.takes.elements[element].to_dict() elements[element] = serialized if element in method_meta.takes.required and \ element not in required: required.append(element) if element in method_meta.defaults: defaults.pop(element, None) defaults[element] = method_meta.defaults[element] # TODO: what about returns? # remove required args that are now defaulted required = [r for r in required if r not in defaults] # Update ourself from these structures takes = MapMeta() takes.set_elements(ElementMap(elements)) takes.set_required(required) self.set_takes(takes) self.set_defaults(defaults)
def test_returns_given_valid_sets(self): @returns("hello", StringMeta(), REQUIRED) def say_hello(ret): """Say hello""" ret.hello = "Hello" return ret ireturns = MapMeta() ireturns.set_elements(OrderedDict(hello=StringMeta())) ireturns.set_required(["hello"]) self.assertEqual(say_hello.Method.takes.to_dict(), MapMeta().to_dict()) self.assertEqual(say_hello.Method.returns.to_dict(), ireturns.to_dict()) self.assertEqual(say_hello.Method.defaults, {})
def _prepare_map_meta(args, allow_defaults, defaults=None, elements=None, required=None): # prepare some data structures that will be used for the takes MapMeta if defaults is None: defaults = OrderedDict() if elements is None: elements = OrderedDict() if required is None: required = [] for index in range(0, len(args), 3): # pick out 3 arguments name = args[index] check_camel_case(name) meta = args[index + 1] default = args[index + 2] # store them in the right structures elements[name] = meta if default is REQUIRED: required.append(name) elif default is not OPTIONAL: assert allow_defaults, \ "Defaults not allowed in this structure" defaults[name] = default # Setup the takes MapMeta and attach it to the function's MethodMeta meta = MapMeta() meta.set_elements(ElementMap(elements)) meta.set_required(required) return meta, defaults
def test_takes_given_defaults(self): @method_takes("hello", StringMeta(), "Something") def say_hello(params): """Say hello""" print("Hello" + params.name) itakes = MapMeta() itakes.set_elements(OrderedDict(hello=StringMeta())) assert say_hello.MethodModel.takes.to_dict() == itakes.to_dict() assert say_hello.MethodModel.returns.to_dict() == MapMeta().to_dict() assert say_hello.MethodModel.defaults == {"hello": "Something"}