diff --git a/qubes/__init__.py b/qubes/__init__.py index ef04b8ab..4c4c9923 100644 --- a/qubes/__init__.py +++ b/qubes/__init__.py @@ -685,8 +685,11 @@ class property(object): # pylint: disable=redefined-builtin,invalid-name def __repr__(self): - return '<{} object at {:#x} name={!r} default={!r}>'.format( - self.__class__.__name__, id(self), self.__name__, self._default) + default = ' default={!r}'.format(self._default) \ + if self._default is not self._NO_DEFAULT \ + else '' + return '<{} object at {:#x} name={!r}{}>'.format( + self.__class__.__name__, id(self), self.__name__, default) \ def __hash__(self): @@ -856,10 +859,12 @@ class PropertyHolder(qubes.events.Emitter): :param qubes.property prop: property object of particular interest :rtype: bool - ''' + ''' # pylint: disable=protected-access - # pylint: disable=protected-access - return hasattr(self, self.property_get_def(prop)._attr_name) + # both property_get_def() and ._attr_name may throw AttributeError, + # which we don't want to catch + attrname = self.property_get_def(prop)._attr_name + return not hasattr(self, attrname) @classmethod diff --git a/qubes/tests/init.py b/qubes/tests/init.py index 78f1b421..15931215 100644 --- a/qubes/tests/init.py +++ b/qubes/tests/init.py @@ -198,8 +198,18 @@ class TC_20_PropertyHolder(qubes.tests.QubesTestCase): self.holder = TestHolder(xml) + def test_000_property_list(self): + self.assertListEqual([p.__name__ for p in self.holder.property_list()], + ['testprop1', 'testprop2', 'testprop3', 'testprop4']) + + def test_001_property_get_def(self): + self.assertIs( + self.holder.property_get_def('testprop1'), TestHolder.testprop1) + self.assertIs(self.holder.property_get_def(TestHolder.testprop1), + TestHolder.testprop1) + @unittest.expectedFailure - def test_000_load_properties(self): + def test_002_load_properties(self): self.holder.load_properties() self.assertEventFired(self.holder, 'property-loaded') @@ -212,7 +222,24 @@ class TC_20_PropertyHolder(qubes.tests.QubesTestCase): with self.assertRaises(AttributeError): self.holder.testprop4 - def test_001_save_properties(self): + def test_003_property_is_default(self): + self.holder.load_properties() + self.assertFalse(self.holder.property_is_default('testprop1')) + self.assertFalse(self.holder.property_is_default('testprop2')) + self.assertTrue(self.holder.property_is_default('testprop3')) + self.assertTrue(self.holder.property_is_default('testprop4')) + with self.assertRaises(AttributeError): + self.holder.property_is_default('testprop5') + + @unittest.skip('test not implemented') + def test_004_property_init(self): + pass + + @unittest.skip('test not implemented') + def test_005_clone_properties(self): + pass + + def test_006_xml_properties(self): self.holder.load_properties() elements = self.holder.xml_properties() @@ -233,6 +260,10 @@ class TC_20_PropertyHolder(qubes.tests.QubesTestCase): expected_prop3.text = 'testdefault' self.assertXMLEqual(elements_with_defaults[2], expected_prop3) + @unittest.skip('test not implemented') + def test_010_property_require(self): + pass + class TestVM(qubes.vm.BaseVM): qid = qubes.property('qid', type=int)