From f0e49061f092f152318994acd274cedd75fce01f Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Mon, 22 Oct 2018 12:27:57 -0400 Subject: [PATCH 1/9] added test_command_uid --- test/test_properties.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 test/test_properties.py diff --git a/test/test_properties.py b/test/test_properties.py new file mode 100644 index 00000000..6cca98c0 --- /dev/null +++ b/test/test_properties.py @@ -0,0 +1,7 @@ +import pytest + +from houston.ardu.copter.goto import GoTo as CopterGoTo + + +def test_command_uid(): + assert CopterGoTo.uid == 'ardu:copter:goto' From 102689eff2dd3b4651212200bb34e7bd9da3d7b2 Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Mon, 22 Oct 2018 12:32:15 -0400 Subject: [PATCH 2/9] added fault revealing test --- test/test_properties.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test_properties.py b/test/test_properties.py index 6cca98c0..8ef384bc 100644 --- a/test/test_properties.py +++ b/test/test_properties.py @@ -1,7 +1,9 @@ import pytest +from houston.ardu.common import ArmDisarm from houston.ardu.copter.goto import GoTo as CopterGoTo def test_command_uid(): assert CopterGoTo.uid == 'ardu:copter:goto' + assert ArmDisarm.uid == 'houston.ardu.common.ArmDisarm' From b094c2259633abedea1d9a428364ea1ed5a6c502 Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Mon, 22 Oct 2018 12:43:57 -0400 Subject: [PATCH 3/9] added UID to ArmDisarm --- houston/ardu/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/houston/ardu/common.py b/houston/ardu/common.py index 19c69db0..afeff02d 100644 --- a/houston/ardu/common.py +++ b/houston/ardu/common.py @@ -52,6 +52,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])) From 793be5bbceb0ac2d35c0b402279bcab461155565 Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Mon, 22 Oct 2018 12:44:46 -0400 Subject: [PATCH 4/9] added uid to C1 --- test/test_command.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_command.py b/test/test_command.py index eeca864d..7e935ac0 100644 --- a/test/test_command.py +++ b/test/test_command.py @@ -7,6 +7,7 @@ def test_eq(): class C1(Command): + uid = 'test:c1' name = 'c1' parameters = [ Parameter('foo', DiscreteValueRange(['ON', 'OFF'])) From ef6858a2be07d4eeb08389fc5994804b1ca4c0ab Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Mon, 22 Oct 2018 12:46:20 -0400 Subject: [PATCH 5/9] bug fix: to_json -> to_dict --- houston/command.py | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/houston/command.py b/houston/command.py index 8d15ca96..f3545646 100644 --- a/houston/command.py +++ b/houston/command.py @@ -80,6 +80,29 @@ 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)) + + # convert uid to a read-only property + ns['uid'] = property(lambda u=uid: u) + + logger.debug("obtained command UID: %s", uid) + # build parameters logger.debug("building command parameters") try: @@ -136,26 +159,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)) @@ -253,7 +258,7 @@ def to_dict(self) -> Dict[str, Any]: return fields def __repr__(self) -> str: - fields = self.to_json() + fields = self.to_dict() for (name, val) in fields.items(): if isinstance(val, float): s = "{:.3f}".format(val) From b85247c07a430af1ff2afaa5fed532063f60227c Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Mon, 22 Oct 2018 12:48:53 -0400 Subject: [PATCH 6/9] don't use property to create read-only attribute --- houston/command.py | 4 ++-- test/test_properties.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/houston/command.py b/houston/command.py index f3545646..d2754ce0 100644 --- a/houston/command.py +++ b/houston/command.py @@ -98,8 +98,8 @@ def __new__(mcl, 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) + # FIXME convert uid to a read-only property + # ns['uid'] = property(lambda u=uid: u) logger.debug("obtained command UID: %s", uid) diff --git a/test/test_properties.py b/test/test_properties.py index 8ef384bc..6499cf6f 100644 --- a/test/test_properties.py +++ b/test/test_properties.py @@ -6,4 +6,4 @@ def test_command_uid(): assert CopterGoTo.uid == 'ardu:copter:goto' - assert ArmDisarm.uid == 'houston.ardu.common.ArmDisarm' + assert ArmDisarm.uid == 'ardu:common:arm' From dff47be171b086d20b0f37dc7a9e714ba578aee0 Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Mon, 22 Oct 2018 12:51:48 -0400 Subject: [PATCH 7/9] added FIXME note --- houston/command.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/houston/command.py b/houston/command.py index d2754ce0..a8f95aba 100644 --- a/houston/command.py +++ b/houston/command.py @@ -98,8 +98,7 @@ def __new__(mcl, msg = "'uid' field must not be an empty string" raise TypeError(tpl_err.format(msg)) - # FIXME convert uid to a read-only property - # ns['uid'] = property(lambda u=uid: u) + # FIXME convert uid to a read-only attribute logger.debug("obtained command UID: %s", uid) From ec0153aad75843464f4d49f9fe82cbeb07b95623 Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Mon, 22 Oct 2018 12:52:47 -0400 Subject: [PATCH 8/9] added fault-revealing test for System.name --- test/test_properties.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test_properties.py b/test/test_properties.py index 6499cf6f..fb2243c5 100644 --- a/test/test_properties.py +++ b/test/test_properties.py @@ -2,8 +2,13 @@ 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' From 4b15b4e993c5712acfddbefc435a118108e01c0c Mon Sep 17 00:00:00 2001 From: ChrisTimperley Date: Mon, 22 Oct 2018 12:56:33 -0400 Subject: [PATCH 9/9] bug fix: don't try to create immutable properties --- houston/system.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/houston/system.py b/houston/system.py index 716d7236..cafd7ea5 100644 --- a/houston/system.py +++ b/houston/system.py @@ -38,8 +38,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: @@ -53,7 +53,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"