diff --git a/houston/ardu/common.py b/houston/ardu/common.py index 477ad417..1f14b23e 100644 --- a/houston/ardu/common.py +++ b/houston/ardu/common.py @@ -53,6 +53,7 @@ class ArmDisarm(Command): Idle: if the conditions above cannot be met, the robot will ignore the command. """ + uid = 'ardu:common:arm' name = 'arm' parameters = [ Parameter('arm', DiscreteValueRange([True, False])) diff --git a/houston/command.py b/houston/command.py index b165e9d0..7b1b7e10 100644 --- a/houston/command.py +++ b/houston/command.py @@ -81,6 +81,28 @@ def __new__(mcl, raise TypeError(tpl_err.format(msg)) logger.debug("obtained command name: %s", name_command) + # obtain UID + logger.debug("obtaining command UID") + if 'uid' not in ns: + msg = "missing 'uid' field in Command definition" + raise TypeError(tpl_err.format(msg)) + + uid = ns['uid'] + if not isinstance(uid, str): + t = type(uid) + msg = "expected 'uid' field to be str but was {}".format(t) + raise TypeError(tpl_err.format(msg)) + logger.debug("using provided UID: %s", uid) + + # ensure uid is not an empty string + if uid == '': + msg = "'uid' field must not be an empty string" + raise TypeError(tpl_err.format(msg)) + + # FIXME convert uid to a read-only attribute + + logger.debug("obtained command UID: %s", uid) + # ensure "to_message" is implemented if 'to_message' not in ns: msg = "missing 'to_message' method in Command definition" @@ -142,26 +164,8 @@ def __init__(cls, cls_name: str, bases, ns: Dict[str, Any]): tpl_err = "failed to build definition for command [{}]: " tpl_err = tpl_err.format(cls_name) + "{}" - # obtain or generate a unique identifier - if 'uid' in ns: - uid = ns['uid'] - if not isinstance(uid, str): - t = type(uid) - msg = "expected 'uid' field to be str but was {}".format(t) - raise TypeError(tpl_err.format(msg)) - logger.debug("using provided UID: %s", uid) - else: - uid = '{}.{}'.format(cls.__module__, cls.__qualname__) - - # ensure uid is not an empty string - if uid == '': - msg = "'uid' field must not be an empty string" - raise TypeError(tpl_err.format(msg)) - - # convert uid to a read-only property - ns['uid'] = property(lambda u=uid: u) - # ensure that uid isn't already in use + uid = ns['uid'] # type: str if uid in _UID_TO_COMMAND_TYPE: msg = "'uid' already in use [%s]".format(uid) raise TypeError(tpl_error.format(msg)) diff --git a/houston/system.py b/houston/system.py index 38286705..061e4587 100644 --- a/houston/system.py +++ b/houston/system.py @@ -37,8 +37,8 @@ def __new__(mcl, else: is_abstract = False - # construct an immutable "is_abstract" property - ns['is_abstract'] = property(lambda self, v=is_abstract: v) + # FIXME create immutable attribute + ns['is_abstract'] = is_abstract if not is_abstract: if 'name' not in ns: @@ -52,7 +52,9 @@ def __new__(mcl, if sys_name == '': msg = "System name must be a non-empty string." raise TypeError(msg) - ns['name'] = property(lambda self, n=sys_name: n) + + # FIXME create immutable class attribute + ns['name'] = sys_name if 'state' not in ns: msg = "System class definition is missing 'state' property" diff --git a/test/test_command.py b/test/test_command.py index e3f81a68..10f54083 100644 --- a/test/test_command.py +++ b/test/test_command.py @@ -14,6 +14,7 @@ class M1(Message): foo = attr.ib(type=str) class C1(Command): + uid = 'test:c1' name = 'c1' parameters = [ Parameter('foo', DiscreteValueRange(['ON', 'OFF'])) diff --git a/test/test_properties.py b/test/test_properties.py new file mode 100644 index 00000000..fb2243c5 --- /dev/null +++ b/test/test_properties.py @@ -0,0 +1,14 @@ +import pytest + +from houston.ardu.common import ArmDisarm +from houston.ardu.copter.goto import GoTo as CopterGoTo +from houston.ardu.copter import ArduCopter + + +def test_command_uid(): + assert CopterGoTo.uid == 'ardu:copter:goto' + assert ArmDisarm.uid == 'ardu:common:arm' + + +def test_system_name(): + assert ArduCopter.name == 'arducopter'