Merge ~sylvain-pineau/checkbox-ng:fix-1898900 into checkbox-ng:master

Proposed by Sylvain Pineau
Status: Merged
Approved by: Sylvain Pineau
Approved revision: e048ae62c126480369fb70c52629a40098916d22
Merged at revision: 0d597d612a0b0e67622e187684d2176b506172f9
Proposed branch: ~sylvain-pineau/checkbox-ng:fix-1898900
Merge into: checkbox-ng:master
Diff against target: 71 lines (+6/-7)
4 files modified
plainbox/impl/ctrl.py (+1/-1)
plainbox/impl/resource.py (+1/-1)
plainbox/impl/test_ctrl.py (+1/-1)
plainbox/impl/test_resource.py (+3/-4)
Reviewer Review Type Date Requested Status
Jonathan Cave (community) Approve
Sylvain Pineau (community) Needs Resubmitting
Review via email: mp+391979@code.launchpad.net

Commit message

resource: Return an empty string when trying to access non-existent resource attributes

Instead of raising AttributeError which makes the full expression line to fail even is some sub expressions could pass.

Description of the change

Fixes the linked bug by making an invalid getattr expression non fatal, i.e not raising an AttributeError, which makes the full resource expression to evaluate to False even if some sub parts could return true.

Example:

package.foo == 'bar' or snap.name == 'core'

foo does not exist and even is the core snap is present, the requirement will fail.

Proposed solution is to return an empty string when trying to access non existent attr to properly fail the sub-expression.

Tested with:
https://git.launchpad.net/plainbox-provider-checkbox/tree/units/usb/usb.pxu#n246

To post a comment you must log in.
Revision history for this message
Jonathan Cave (jocave) wrote :

This seems logical to me.

I'm trying to think of situations where it might fall down, the only situation I can think of is if a job was expecting a resource to be present but empty i.e.

something.a_field == ''

i.e. if 'a_field' was missing this would evaluate to True. However, I'm not aware that any resource would do this and the requirement really makes little practical sense

review: Approve
Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

Mute the warning about "Ignoring %s with missing template parameter"

review: Needs Resubmitting
Revision history for this message
Jonathan Cave (jocave) wrote :

Looks even better to me.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/plainbox/impl/ctrl.py b/plainbox/impl/ctrl.py
2index 801eccd..5facd64 100644
3--- a/plainbox/impl/ctrl.py
4+++ b/plainbox/impl/ctrl.py
5@@ -317,7 +317,7 @@ class CheckBoxSessionStateController(ISessionStateController):
6 try:
7 check_result = new_unit.check()
8 except MissingParam as m:
9- logger.warning(_("Ignoring %s with missing "
10+ logger.debug(_("Ignoring %s with missing "
11 "template parameter %s"),
12 new_unit._raw_data.get('id'),
13 m.parameter)
14diff --git a/plainbox/impl/resource.py b/plainbox/impl/resource.py
15index 38f3d59..9b094bb 100644
16--- a/plainbox/impl/resource.py
17+++ b/plainbox/impl/resource.py
18@@ -116,7 +116,7 @@ class Resource:
19 if attr in data:
20 return data[attr]
21 else:
22- raise AttributeError(attr, "don't poke at %r" % attr)
23+ return ''
24
25 def __getattribute__(self, attr):
26 if attr != "_data":
27diff --git a/plainbox/impl/test_ctrl.py b/plainbox/impl/test_ctrl.py
28index cfcbc84..ce026cc 100644
29--- a/plainbox/impl/test_ctrl.py
30+++ b/plainbox/impl/test_ctrl.py
31@@ -341,7 +341,7 @@ class CheckBoxSessionStateControllerTests(TestCase):
32 session_state = SessionState([template, job])
33 self.ctrl.observe_result(session_state, job, result)
34 # Ensure that a warning was logged
35- mock_logger.warning.assert_called_with(
36+ mock_logger.debug.assert_called_with(
37 "Ignoring %s with missing template parameter %s",
38 "foo-{missing}", "missing")
39
40diff --git a/plainbox/impl/test_resource.py b/plainbox/impl/test_resource.py
41index 18a5275..178f3b8 100644
42--- a/plainbox/impl/test_resource.py
43+++ b/plainbox/impl/test_resource.py
44@@ -78,7 +78,6 @@ class ResourceTests(TestCase):
45
46 def test_private_data_is_somewhat_protected(self):
47 res = Resource()
48- self.assertRaises(AttributeError, getattr, res, "_data")
49 self.assertRaises(AttributeError, delattr, res, "_data")
50 self.assertRaises(AttributeError, setattr, res, "_data", None)
51
52@@ -91,7 +90,7 @@ class ResourceTests(TestCase):
53
54 def test_getattr(self):
55 res = Resource()
56- self.assertRaises(AttributeError, getattr, res, "attr")
57+ self.assertEqual(getattr(res, 'attr'), '')
58 res = Resource({'attr': 'value'})
59 self.assertEqual(getattr(res, 'attr'), 'value')
60
61@@ -120,8 +119,8 @@ class ResourceTests(TestCase):
62 self.assertRaises(AttributeError, delattr, res, "attr")
63 res = Resource({'attr': 'value'})
64 del res.attr
65- self.assertRaises(AttributeError, getattr, res, "attr")
66- self.assertRaises(AttributeError, lambda res: res.attr, res)
67+ self.assertEqual(getattr(res, 'attr'), '')
68+ self.assertEqual(res.attr, '')
69
70 def test_delitem(self):
71 res = Resource()

Subscribers

People subscribed via source and target branches