Skip to content

Commit

Permalink
Add writeable property to Method
Browse files Browse the repository at this point in the history
Disallows __call__ if not set to true (true is the default value).
  • Loading branch information
c-mita committed Jun 21, 2016
1 parent 6f5f592 commit 735fe5e
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 1 deletion.
11 changes: 11 additions & 0 deletions malcolm/core/method.py
Expand Up @@ -16,6 +16,7 @@ def __init__(self, name, description):
self.takes = None
self.returns = None
self.defaults = None
self.writeable = True

def set_function(self, func):
"""Set the function to expose.
Expand All @@ -41,11 +42,19 @@ def set_function_returns(self, return_meta):
"""Set the return parameters for the method to validate against"""
self.returns = return_meta

def set_writeable(self, writeable):
"""Set writeable property to enable or disable calling method"""
self.writeable = writeable
self.on_changed([[["writeable"], writeable]])

def __call__(self, *args, **kwargs):
"""Call the exposed function using regular keyword argument parameters.
Will validate the output against provided return parameters.
"""

if not self.writeable:
raise ValueError("Can not call a method that is not writeable")

# Assumes positional arguments represent arguments *before* any kw-args
# in the ordered dictionary.
for arg, arg_val in zip(self.takes.elements.keys(), args):
Expand Down Expand Up @@ -95,6 +104,7 @@ def to_dict(self):
serialized["takes"] = self.takes.to_dict()
serialized["defaults"] = self.defaults.copy()
serialized["returns"] = self.returns.to_dict()
serialized["writeable"] = self.writeable
return serialized

@classmethod
Expand All @@ -110,6 +120,7 @@ def from_dict(cls, name, d):
method.set_function_takes(takes, d["defaults"])
returns = MapMeta.from_dict("returns", d["returns"])
method.set_function_returns(returns)
method.writeable = d["writeable"]
return method

@classmethod
Expand Down
1 change: 1 addition & 0 deletions tests/test_controllers/test_clientcontroller.py
Expand Up @@ -45,6 +45,7 @@ def setUp(self):
),
required=["response"],
),
writeable=True,
),
)

Expand Down
25 changes: 24 additions & 1 deletion tests/test_core/test_method.py
Expand Up @@ -149,6 +149,23 @@ def test_handle_request_error(self):
self.assertEquals(
"Method test_method raised an error: Test error", response.message)

def test_not_writeable_stops_call(self):
m = Method("test_method", "test_description")
m.set_function(Mock())
m.set_writeable(False)
with self.assertRaises(ValueError,
msg="Can not call a method that is not writeable"):
m()

def test_set_writeable_notifies(self):
m = Method("test_method", "test_description")
m.on_changed = MagicMock(side_effect=m.on_changed)
m.set_writeable(False)
m.on_changed.assert_called_once_with([[["writeable"], False]])
m.on_changed.reset_mock()
m.set_writeable(True)
m.on_changed.assert_called_once_with([[["writeable"], True]])

def test_to_dict_serialization(self):
func = Mock(return_value={"out": "dummy"})
defaults = {"in_attr": "default"}
Expand All @@ -158,15 +175,18 @@ def test_to_dict_serialization(self):
return_meta = Mock(elements={"out": Mock()},
to_dict=Mock(
return_value=OrderedDict({"dict": "return"})))
writeable_mock = Mock()
m = Method("test_method", "test_description")
m.set_function(func)
m.set_function_takes(args_meta, defaults)
m.set_function_returns(return_meta)
m.set_writeable(writeable_mock)
expected = OrderedDict()
expected["description"] = "test_description"
expected["takes"] = OrderedDict({"dict": "args"})
expected["defaults"] = OrderedDict({"in_attr": "default"})
expected["returns"] = OrderedDict({"dict": "return"})
expected["writeable"] = writeable_mock
self.assertEquals(expected, m.to_dict())

@patch("malcolm.core.method.MapMeta")
Expand All @@ -176,15 +196,18 @@ def test_from_dict_deserialize(self, mock_mapmeta):
takes = dict(a=object(), b=object())
returns = dict(c=object())
defaults = dict(a=43)
writeable_mock = Mock()
d = dict(description=description, takes=takes,
returns=returns, defaults=defaults)
returns=returns, defaults=defaults,
writeable=writeable_mock)
m = Method.from_dict(name, d)
self.assertEqual(mock_mapmeta.from_dict.call_args_list, [
call("takes", takes), call("returns", returns)])
self.assertEqual(m.name, name)
self.assertEqual(m.takes, mock_mapmeta.from_dict.return_value)
self.assertEqual(m.returns, mock_mapmeta.from_dict.return_value)
self.assertEqual(m.defaults, defaults)
self.assertEquals(m.writeable, writeable_mock)

@patch("malcolm.core.method.MapMeta")
def test_takes_given_optional(self, map_meta_mock):
Expand Down

0 comments on commit 735fe5e

Please sign in to comment.