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
diff --git a/plainbox/impl/ctrl.py b/plainbox/impl/ctrl.py
index 801eccd..5facd64 100644
--- a/plainbox/impl/ctrl.py
+++ b/plainbox/impl/ctrl.py
@@ -317,7 +317,7 @@ class CheckBoxSessionStateController(ISessionStateController):
317 try:317 try:
318 check_result = new_unit.check()318 check_result = new_unit.check()
319 except MissingParam as m:319 except MissingParam as m:
320 logger.warning(_("Ignoring %s with missing "320 logger.debug(_("Ignoring %s with missing "
321 "template parameter %s"),321 "template parameter %s"),
322 new_unit._raw_data.get('id'),322 new_unit._raw_data.get('id'),
323 m.parameter)323 m.parameter)
diff --git a/plainbox/impl/resource.py b/plainbox/impl/resource.py
index 38f3d59..9b094bb 100644
--- a/plainbox/impl/resource.py
+++ b/plainbox/impl/resource.py
@@ -116,7 +116,7 @@ class Resource:
116 if attr in data:116 if attr in data:
117 return data[attr]117 return data[attr]
118 else:118 else:
119 raise AttributeError(attr, "don't poke at %r" % attr)119 return ''
120120
121 def __getattribute__(self, attr):121 def __getattribute__(self, attr):
122 if attr != "_data":122 if attr != "_data":
diff --git a/plainbox/impl/test_ctrl.py b/plainbox/impl/test_ctrl.py
index cfcbc84..ce026cc 100644
--- a/plainbox/impl/test_ctrl.py
+++ b/plainbox/impl/test_ctrl.py
@@ -341,7 +341,7 @@ class CheckBoxSessionStateControllerTests(TestCase):
341 session_state = SessionState([template, job])341 session_state = SessionState([template, job])
342 self.ctrl.observe_result(session_state, job, result)342 self.ctrl.observe_result(session_state, job, result)
343 # Ensure that a warning was logged343 # Ensure that a warning was logged
344 mock_logger.warning.assert_called_with(344 mock_logger.debug.assert_called_with(
345 "Ignoring %s with missing template parameter %s",345 "Ignoring %s with missing template parameter %s",
346 "foo-{missing}", "missing")346 "foo-{missing}", "missing")
347347
diff --git a/plainbox/impl/test_resource.py b/plainbox/impl/test_resource.py
index 18a5275..178f3b8 100644
--- a/plainbox/impl/test_resource.py
+++ b/plainbox/impl/test_resource.py
@@ -78,7 +78,6 @@ class ResourceTests(TestCase):
7878
79 def test_private_data_is_somewhat_protected(self):79 def test_private_data_is_somewhat_protected(self):
80 res = Resource()80 res = Resource()
81 self.assertRaises(AttributeError, getattr, res, "_data")
82 self.assertRaises(AttributeError, delattr, res, "_data")81 self.assertRaises(AttributeError, delattr, res, "_data")
83 self.assertRaises(AttributeError, setattr, res, "_data", None)82 self.assertRaises(AttributeError, setattr, res, "_data", None)
8483
@@ -91,7 +90,7 @@ class ResourceTests(TestCase):
9190
92 def test_getattr(self):91 def test_getattr(self):
93 res = Resource()92 res = Resource()
94 self.assertRaises(AttributeError, getattr, res, "attr")93 self.assertEqual(getattr(res, 'attr'), '')
95 res = Resource({'attr': 'value'})94 res = Resource({'attr': 'value'})
96 self.assertEqual(getattr(res, 'attr'), 'value')95 self.assertEqual(getattr(res, 'attr'), 'value')
9796
@@ -120,8 +119,8 @@ class ResourceTests(TestCase):
120 self.assertRaises(AttributeError, delattr, res, "attr")119 self.assertRaises(AttributeError, delattr, res, "attr")
121 res = Resource({'attr': 'value'})120 res = Resource({'attr': 'value'})
122 del res.attr121 del res.attr
123 self.assertRaises(AttributeError, getattr, res, "attr")122 self.assertEqual(getattr(res, 'attr'), '')
124 self.assertRaises(AttributeError, lambda res: res.attr, res)123 self.assertEqual(res.attr, '')
125124
126 def test_delitem(self):125 def test_delitem(self):
127 res = Resource()126 res = Resource()

Subscribers

People subscribed via source and target branches