Merge lp:~stub/charm-helpers/bug-1182959-no-implicit-serializable-magic into lp:charm-helpers

Proposed by Stuart Bishop
Status: Merged
Merged at revision: 42
Proposed branch: lp:~stub/charm-helpers/bug-1182959-no-implicit-serializable-magic
Merge into: lp:charm-helpers
Prerequisite: lp:~stub/charm-helpers/bug-1192845-fix-serializable
Diff against target: 187 lines (+58/-32)
2 files modified
charmhelpers/core/hookenv.py (+10/-14)
tests/core/test_hookenv.py (+48/-18)
To merge this branch: bzr merge lp:~stub/charm-helpers/bug-1182959-no-implicit-serializable-magic
Reviewer Review Type Date Requested Status
Matthew Wedgwood (community) Approve
Charm Helper Maintainers Pending
Review via email: mp+170557@code.launchpad.net

Description of the change

Going further than https://code.launchpad.net/~stub/charm-helpers/bug-1192845-fix-serializable/+merge/170555, I put forward that implicitly wrapping results with Serializable is surprising and more harm than help. It introduces time bombs, such as if the implementation is moved to a different module old pickles in charm state will fail to load.

The alternative is when a wrapped object is desired that it be explicitly wrapped.

To post a comment you must log in.
Revision history for this message
Matthew Wedgwood (mew) wrote :

Yep, fair enough. Better tear of the bandage now while we're still under heavy development.

review: Approve
Revision history for this message
Matthew Wedgwood (mew) :
review: Needs Fixing
Revision history for this message
Matthew Wedgwood (mew) wrote :

Sorry, after being more prudent, I see that this fails tests.

review: Needs Fixing
31. By Stuart Bishop

Merged bug-1192845-fix-serializable into bug-1182959-no-implicit-serializable-magic.

32. By Stuart Bishop

Fix tests

Revision history for this message
Stuart Bishop (stub) wrote :

I've fixed the tests so they no longer rely on magic, and removed one explicitly checking that magic was returned.

33. By Stuart Bishop

Merged fix-executution-environment into bug-1182959-no-implicit-serializable-magic.

Revision history for this message
Matthew Wedgwood (mew) wrote :

Perfect, thanks.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charmhelpers/core/hookenv.py'
--- charmhelpers/core/hookenv.py 2013-06-20 08:32:11 +0000
+++ charmhelpers/core/hookenv.py 2013-06-28 17:11:26 +0000
@@ -108,11 +108,12 @@
108 """A convenient bundling of the current execution context"""108 """A convenient bundling of the current execution context"""
109 context = {}109 context = {}
110 context['conf'] = config()110 context['conf'] = config()
111 context['reltype'] = relation_type()111 if relation_id():
112 context['relid'] = relation_id()112 context['reltype'] = relation_type()
113 context['relid'] = relation_id()
114 context['rel'] = relation_get()
113 context['unit'] = local_unit()115 context['unit'] = local_unit()
114 context['rels'] = relations()116 context['rels'] = relations()
115 context['rel'] = relation_get()
116 context['env'] = os.environ117 context['env'] = os.environ
117 return context118 return context
118119
@@ -150,13 +151,9 @@
150 config_cmd_line.append(scope)151 config_cmd_line.append(scope)
151 config_cmd_line.append('--format=json')152 config_cmd_line.append('--format=json')
152 try:153 try:
153 value = json.loads(subprocess.check_output(config_cmd_line))154 return json.loads(subprocess.check_output(config_cmd_line))
154 except ValueError:155 except ValueError:
155 return None156 return None
156 if isinstance(value, dict):
157 return Serializable(value)
158 else:
159 return value
160157
161158
162@cached159@cached
@@ -169,13 +166,9 @@
169 if unit:166 if unit:
170 _args.append(unit)167 _args.append(unit)
171 try:168 try:
172 value = json.loads(subprocess.check_output(_args))169 return json.loads(subprocess.check_output(_args))
173 except ValueError:170 except ValueError:
174 return None171 return None
175 if isinstance(value, dict):
176 return Serializable(value)
177 else:
178 return value
179172
180173
181def relation_set(relation_id=None, relation_settings={}, **kwargs):174def relation_set(relation_id=None, relation_settings={}, **kwargs):
@@ -222,7 +215,7 @@
222 if key.endswith('-list'):215 if key.endswith('-list'):
223 relation[key] = relation[key].split()216 relation[key] = relation[key].split()
224 relation['__unit__'] = unit217 relation['__unit__'] = unit
225 return Serializable(relation)218 return relation
226219
227220
228@cached221@cached
@@ -331,5 +324,8 @@
331 self.register(hook_name, decorated)324 self.register(hook_name, decorated)
332 else:325 else:
333 self.register(decorated.__name__, decorated)326 self.register(decorated.__name__, decorated)
327 if '_' in decorated.__name__:
328 self.register(
329 decorated.__name__.replace('_', '-'), decorated)
334 return decorated330 return decorated
335 return wrapper331 return wrapper
336332
=== modified file 'tests/core/test_hookenv.py'
--- tests/core/test_hookenv.py 2013-06-20 08:53:31 +0000
+++ tests/core/test_hookenv.py 2013-06-28 17:11:26 +0000
@@ -140,17 +140,6 @@
140 mock_call.assert_called_with(['juju-log', '-l', level, 'foo'])140 mock_call.assert_called_with(['juju-log', '-l', level, 'foo'])
141141
142 @patch('subprocess.check_output')142 @patch('subprocess.check_output')
143 def test_gets_charm_config_as_serializable(self, check_output):
144 config_data = {'foo': 'bar'}
145 check_output.return_value = json.dumps(config_data)
146
147 result = hookenv.config()
148
149 self.assert_(isinstance(result, hookenv.Serializable))
150 self.assertEqual(result.foo, 'bar')
151 check_output.assert_called_with(['config-get', '--format=json'])
152
153 @patch('subprocess.check_output')
154 def test_gets_charm_config_with_scope(self, check_output):143 def test_gets_charm_config_with_scope(self, check_output):
155 config_data = 'bar'144 config_data = 'bar'
156 check_output.return_value = json.dumps(config_data)145 check_output.return_value = json.dumps(config_data)
@@ -311,15 +300,14 @@
311 unit = 'foo-unit'300 unit = 'foo-unit'
312 raw_relation = {301 raw_relation = {
313 'foo': 'bar',302 'foo': 'bar',
314 'baz-list': '1 2 3',
315 }303 }
316 remote_unit.return_value = unit304 remote_unit.return_value = unit
317 relation_get.return_value = raw_relation305 relation_get.return_value = raw_relation
318306
319 result = hookenv.relation_for_unit()307 result = hookenv.relation_for_unit()
320308
321 self.assertEqual(result.__unit__, unit)309 self.assertEqual(result['__unit__'], unit)
322 self.assertEqual(getattr(result, 'baz-list'), ['1', '2', '3'])310 self.assertEqual(result['foo'], 'bar')
323 relation_get.assert_called_with(unit=unit, rid=None)311 relation_get.assert_called_with(unit=unit, rid=None)
324312
325 @patch('charmhelpers.core.hookenv.remote_unit')313 @patch('charmhelpers.core.hookenv.remote_unit')
@@ -328,14 +316,13 @@
328 unit = 'foo-unit'316 unit = 'foo-unit'
329 raw_relation = {317 raw_relation = {
330 'foo': 'bar',318 'foo': 'bar',
331 'baz-list': '1 2 3',
332 }319 }
333 relation_get.return_value = raw_relation320 relation_get.return_value = raw_relation
334321
335 result = hookenv.relation_for_unit(unit)322 result = hookenv.relation_for_unit(unit)
336323
337 self.assertEqual(result.__unit__, unit)324 self.assertEqual(result['__unit__'], unit)
338 self.assertEqual(getattr(result, 'baz-list'), ['1', '2', '3'])325 self.assertEqual(result['foo'], 'bar')
339 relation_get.assert_called_with(unit=unit, rid=None)326 relation_get.assert_called_with(unit=unit, rid=None)
340 self.assertFalse(remote_unit.called)327 self.assertFalse(remote_unit.called)
341328
@@ -496,6 +483,34 @@
496 'env': 'some-environment',483 'env': 'some-environment',
497 })484 })
498485
486 @patch('charmhelpers.core.hookenv.config')
487 @patch('charmhelpers.core.hookenv.relation_type')
488 @patch('charmhelpers.core.hookenv.local_unit')
489 @patch('charmhelpers.core.hookenv.relation_id')
490 @patch('charmhelpers.core.hookenv.relations')
491 @patch('charmhelpers.core.hookenv.relation_get')
492 @patch('charmhelpers.core.hookenv.os')
493 def test_gets_execution_environment_no_relation(
494 self, os_, relations_get, relations, relation_id,
495 local_unit, relation_type, config):
496 config.return_value = 'some-config'
497 relation_type.return_value = 'some-type'
498 local_unit.return_value = 'some-unit'
499 relation_id.return_value = None
500 relations.return_value = 'all-relations'
501 relations_get.return_value = 'some-relations'
502 os_.environ = 'some-environment'
503
504 result = hookenv.execution_environment()
505
506 self.assertEqual(result, {
507 'conf': 'some-config',
508 'unit': 'some-unit',
509 'rels': 'all-relations',
510 'env': 'some-environment',
511 })
512
513
499 @patch('charmhelpers.core.hookenv.os')514 @patch('charmhelpers.core.hookenv.os')
500 def test_gets_the_relation_id(self, os_):515 def test_gets_the_relation_id(self, os_):
501 os_.environ = {516 os_.environ = {
@@ -515,7 +530,7 @@
515 check_output.return_value = json.dumps(data)530 check_output.return_value = json.dumps(data)
516 result = hookenv.relation_get()531 result = hookenv.relation_get()
517532
518 self.assertEqual(result.foo, 'BAR')533 self.assertEqual(result['foo'], 'BAR')
519 check_output.assert_called_with(['relation-get', '--format=json', '-'])534 check_output.assert_called_with(['relation-get', '--format=json', '-'])
520535
521 @patch('subprocess.check_output')536 @patch('subprocess.check_output')
@@ -697,3 +712,18 @@
697 self.assertRaises(hookenv.UnregisteredHookError, hooks.execute,712 self.assertRaises(hookenv.UnregisteredHookError, hooks.execute,
698 ['brew'])713 ['brew'])
699 self.assertEqual(execs, [True])714 self.assertEqual(execs, [True])
715
716 def test_magic_underscores(self):
717 # Juju hook names use hypens as separators. Python functions use
718 # underscores. If explicit names have not been provided, hooks
719 # are registered with both the function name and the function
720 # name with underscores replaced with hypens for convenience.
721 execs = []
722 hooks = hookenv.Hooks()
723 @hooks.hook()
724 def call_me_maybe():
725 execs.append(True)
726
727 hooks.execute(['call-me-maybe'])
728 hooks.execute(['call_me_maybe'])
729 self.assertEqual(execs, [True, True])

Subscribers

People subscribed via source and target branches