)]}'
{"doc/source/devref/hooks.rst":[{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"2fff8c23730516ff06b341a15d5404fc67b35138","unresolved":false,"context_lines":[{"line_number":8,"context_line":"plugin code matching the name.  The loading works via setuptools"},{"line_number":9,"context_line":"`entry points`_."},{"line_number":10,"context_line":""},{"line_number":11,"context_line":".. _`entry points`: http://packages.python.org/distribute/pkg_resources.html#entry-points  "},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"What are hooks good for?"},{"line_number":14,"context_line":"------------------------"}],"source_content_type":"text/x-rst","patch_set":9,"id":"AAAAMH%2F%2FrgU%3D","line":11,"updated":"2012-11-30 20:21:18.000000000","message":"Lots of trailing whitespace in here…","commit_id":"73b174004fff9fe27aa373e6091394213c879b69"}],"nova/hooks.py":[{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"c31b44a909128130210a2d094290a43bf1fff3ff","unresolved":false,"context_lines":[{"line_number":48,"context_line":"    cfg.StrOpt(\u0027pre_hook_delete_instance\u0027, default\u003dNone,"},{"line_number":49,"context_line":"               help\u003d_(\"Function to call before deleting an instance\")),"},{"line_number":50,"context_line":"    cfg.StrOpt(\u0027post_hook_delete_instance\u0027, default\u003dNone,"},{"line_number":51,"context_line":"               help\u003d_(\"Function to call after deleting an instance\")),"},{"line_number":52,"context_line":"]"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"CONF.register_opts(hook_opts)"}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAMH%2F%2F470%3D","line":51,"updated":"2012-11-16 21:28:03.000000000","message":"Should these be lists so multiple hooks can be installed?","commit_id":"384b97f4e4dbe10c5cad70f5d31d473e14c75464"},{"author":{"_account_id":2835,"name":"Brian Elliott","email":"bdelliott@gmail.com","username":"belliott"},"change_message_id":"f9b0cd9686173b967c8019c8e8dacb6e17f19738","unresolved":false,"context_lines":[{"line_number":48,"context_line":"    cfg.StrOpt(\u0027pre_hook_delete_instance\u0027, default\u003dNone,"},{"line_number":49,"context_line":"               help\u003d_(\"Function to call before deleting an instance\")),"},{"line_number":50,"context_line":"    cfg.StrOpt(\u0027post_hook_delete_instance\u0027, default\u003dNone,"},{"line_number":51,"context_line":"               help\u003d_(\"Function to call after deleting an instance\")),"},{"line_number":52,"context_line":"]"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"CONF.register_opts(hook_opts)"}],"source_content_type":"text/x-python","patch_set":1,"id":"AAAAMH%2F%2F42w%3D","line":51,"in_reply_to":"AAAAMH%2F%2F470%3D","updated":"2012-11-16 22:38:13.000000000","message":"Good idea","commit_id":"384b97f4e4dbe10c5cad70f5d31d473e14c75464"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"2f52905587c025d0cc3aa77609c063fc495f817a","unresolved":false,"context_lines":[{"line_number":48,"context_line":"    cfg.StrOpt(\u0027pre_hook_delete_instance\u0027, default\u003dNone,"},{"line_number":49,"context_line":"               help\u003d_(\"Function to call before deleting an instance\")),"},{"line_number":50,"context_line":"    cfg.StrOpt(\u0027post_hook_delete_instance\u0027, default\u003dNone,"},{"line_number":51,"context_line":"               help\u003d_(\"Function to call after deleting an instance\")),"},{"line_number":52,"context_line":"]"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"CONF.register_opts(hook_opts)"}],"source_content_type":"text/x-python","patch_set":2,"id":"AAAAMH%2F%2F45s%3D","line":51,"updated":"2012-11-16 22:14:06.000000000","message":"There ought to be a different way of expressing these configuration options so that we don\u0027t have an explosion at the hook factory.  Maybe a list of key\u003dvalue pairs, where the key in the function?  E.g.:\n\n    pre_hook \u003d create_instance\u003dhook1,delete_instance\u003dhook2\n    post_hook \u003d create_instance\u003dhook3,delete_instance\u003dhook4","commit_id":"6bcd02ae25c5826297125110f1555c4981a7e2a2"},{"author":{"_account_id":1561,"name":"Russell Bryant","email":"rbryant@redhat.com","username":"russellb"},"change_message_id":"8f13641da32eca3e13c3fbca19367a154c958ed5","unresolved":false,"context_lines":[{"line_number":48,"context_line":"    cfg.StrOpt(\u0027pre_hook_delete_instance\u0027, default\u003dNone,"},{"line_number":49,"context_line":"               help\u003d_(\"Function to call before deleting an instance\")),"},{"line_number":50,"context_line":"    cfg.StrOpt(\u0027post_hook_delete_instance\u0027, default\u003dNone,"},{"line_number":51,"context_line":"               help\u003d_(\"Function to call after deleting an instance\")),"},{"line_number":52,"context_line":"]"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"CONF.register_opts(hook_opts)"}],"source_content_type":"text/x-python","patch_set":2,"id":"AAAAMH%2F%2F42o%3D","line":51,"in_reply_to":"AAAAMH%2F%2F45s%3D","updated":"2012-11-16 22:40:04.000000000","message":"How about something that doesn\u0027t require config options at all?\n\nHooks seem like something that could be entirely API driven.  Something like ... have a directory of plugins that get loaded when the service runs.  When the plugin is loaded (imported), it could automatically register itself into whatever it is its purpose is, such as registering hook callbacks.","commit_id":"6bcd02ae25c5826297125110f1555c4981a7e2a2"},{"author":{"_account_id":2835,"name":"Brian Elliott","email":"bdelliott@gmail.com","username":"belliott"},"change_message_id":"7276652652e3a83c12949fcda7f318e395dcd558","unresolved":false,"context_lines":[{"line_number":48,"context_line":"    cfg.StrOpt(\u0027pre_hook_delete_instance\u0027, default\u003dNone,"},{"line_number":49,"context_line":"               help\u003d_(\"Function to call before deleting an instance\")),"},{"line_number":50,"context_line":"    cfg.StrOpt(\u0027post_hook_delete_instance\u0027, default\u003dNone,"},{"line_number":51,"context_line":"               help\u003d_(\"Function to call after deleting an instance\")),"},{"line_number":52,"context_line":"]"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"CONF.register_opts(hook_opts)"}],"source_content_type":"text/x-python","patch_set":2,"id":"AAAAMH%2F%2F43A%3D","line":51,"in_reply_to":"AAAAMH%2F%2F45s%3D","updated":"2012-11-16 22:37:48.000000000","message":"Will clean up the defs.","commit_id":"6bcd02ae25c5826297125110f1555c4981a7e2a2"},{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"040263b18a8d978649d0e40417816008127b4350","unresolved":false,"context_lines":[{"line_number":70,"context_line":"    \"\"\"Execute optional pre and post hook functions around the decorated"},{"line_number":71,"context_line":"    function.  (This is useful for customization around callables.)"},{"line_number":72,"context_line":"    \"\"\""},{"line_number":73,"context_line":"    def outer(f):"},{"line_number":74,"context_line":"        @functools.wraps(f)"},{"line_number":75,"context_line":"        def inner(*args, **kwargs):"},{"line_number":76,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAAMH%2F%2F4n8%3D","line":73,"updated":"2012-11-17 01:56:23.000000000","message":"I think I would prefer to see things register the hooks they want themselves, vs having to specify them in a config.  But, if you were going to stick with this route, it appears you could ditch the need to track the HOOK_NAMES by inserting the following code here in add_hooks:\n\nopts \u003d []\nopts.append(cfg.ListOpt(\u0027pre_hooks_%s\u0027 % name, default\u003d[]))\nopts.append(cfg.ListOpt(\u0027post_hooks_%s\u0027 % name, default\u003d[]))\nCONF.register_opts(opts)\n\nMinimal testing I did shows this works as add_hooks() is called at module-load time with modules that use it (even if they are in classes defined at the module level).\n\nStill like the idea of registering, instead, though.","commit_id":"0e206badf20326d55808e61487b12e90d0a61e0b"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"44cbb871046627b8199ae58e39afa85523fef500","unresolved":false,"context_lines":[{"line_number":92,"context_line":""},{"line_number":93,"context_line":"            rv \u003d f(*args, **kwargs)"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"            for hook in hooks:"},{"line_number":96,"context_line":"                hook.post(rv, *args, **kwargs)"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"            return rv"}],"source_content_type":"text/x-python","patch_set":4,"id":"AAAAMH%2F%2F3QA%3D","line":95,"updated":"2012-11-19 18:35:10.000000000","message":"I might suggest using reversed() on hooks here; that is, if you have hook1, hook2, and hook3, all set on a single function, you have the call order: hook1.pre(); hook2.pre(); hook3.pre(); f(); hook3.post(); hook2.post(); hook1.post().\n\nAlso, you might give some thought to what happens if pre() or post() returns a value (allowing them to override the function, say) or raises a value.  This could be slated for a future patch set, of course.","commit_id":"f69b68341a1e1a1923d6c26e175d0bee897e9fc9"},{"author":{"_account_id":2835,"name":"Brian Elliott","email":"bdelliott@gmail.com","username":"belliott"},"change_message_id":"3100157dfb09f698efbb796aa8454ec940b9b46e","unresolved":false,"context_lines":[{"line_number":92,"context_line":""},{"line_number":93,"context_line":"            rv \u003d f(*args, **kwargs)"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"            for hook in hooks:"},{"line_number":96,"context_line":"                hook.post(rv, *args, **kwargs)"},{"line_number":97,"context_line":""},{"line_number":98,"context_line":"            return rv"}],"source_content_type":"text/x-python","patch_set":4,"id":"AAAAMH%2F%2F2%2F8%3D","line":95,"in_reply_to":"AAAAMH%2F%2F3QA%3D","updated":"2012-11-19 21:17:15.000000000","message":"Not sure what you mean, I tried it and the hooks get called in order. :)","commit_id":"f69b68341a1e1a1923d6c26e175d0bee897e9fc9"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"5a292d75a5c3dc41890b48e5b217f07f5bf829e9","unresolved":false,"context_lines":[{"line_number":85,"context_line":"    def outer(f):"},{"line_number":86,"context_line":"        @functools.wraps(f)"},{"line_number":87,"context_line":"        def inner(*args, **kwargs):"},{"line_number":88,"context_line":"            manager \u003d _HOOKS.setdefault(name, HookManager(name))"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"            manager.run_pre(name, args, kwargs)"},{"line_number":91,"context_line":"            rv \u003d f(*args, **kwargs)"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAMH%2F%2Fsrc%3D","line":88,"updated":"2012-11-29 20:41:55.000000000","message":"Hmmm…is it meaningful to have multiple functions decorated with the same hook?  Maybe we should consider throwing an exception if name already exists in _HOOKS.  Just a thought…","commit_id":"2ccfcc764d5b47df003d08e78e6c8cde22b96ae4"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"5a292d75a5c3dc41890b48e5b217f07f5bf829e9","unresolved":false,"context_lines":[{"line_number":89,"context_line":""},{"line_number":90,"context_line":"            manager.run_pre(name, args, kwargs)"},{"line_number":91,"context_line":"            rv \u003d f(*args, **kwargs)"},{"line_number":92,"context_line":"            manager.run_post(name, rv, args, kwargs)"},{"line_number":93,"context_line":""},{"line_number":94,"context_line":"            return rv"},{"line_number":95,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAMH%2F%2FsrE%3D","line":92,"updated":"2012-11-29 20:41:55.000000000","message":"Here\u0027s a thought for handling exception raising: add an exc() function to class Hook, then modify this to:\n\n    manager.run_pre(name, args, kwargs)\n    try:\n        rv \u003d f(*args, **kwargs)\n    except Exception as exc:\n        manager.run_exc(name, exc, args, kwargs)\n        raise\n    else:\n        manager.run_post(name, rv, args, kwargs)\n\n(for future work, mind you)","commit_id":"2ccfcc764d5b47df003d08e78e6c8cde22b96ae4"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"0647a063981db389cf91cb13824188932716af7e","unresolved":false,"context_lines":[{"line_number":89,"context_line":""},{"line_number":90,"context_line":"            manager.run_pre(name, args, kwargs)"},{"line_number":91,"context_line":"            rv \u003d f(*args, **kwargs)"},{"line_number":92,"context_line":"            manager.run_post(name, rv, args, kwargs)"},{"line_number":93,"context_line":""},{"line_number":94,"context_line":"            return rv"},{"line_number":95,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAMH%2F%2Fr2Q%3D","line":92,"in_reply_to":"AAAAMH%2F%2Fr4o%3D","updated":"2012-11-30 16:18:34.000000000","message":"I think there is, but again, I think it\u0027s better for future work…","commit_id":"2ccfcc764d5b47df003d08e78e6c8cde22b96ae4"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"d2ce1fe4623c9a42d1d25c9162826b56902fe61f","unresolved":false,"context_lines":[{"line_number":89,"context_line":""},{"line_number":90,"context_line":"            manager.run_pre(name, args, kwargs)"},{"line_number":91,"context_line":"            rv \u003d f(*args, **kwargs)"},{"line_number":92,"context_line":"            manager.run_post(name, rv, args, kwargs)"},{"line_number":93,"context_line":""},{"line_number":94,"context_line":"            return rv"},{"line_number":95,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAMH%2F%2Fr4o%3D","line":92,"in_reply_to":"AAAAMH%2F%2FsrE%3D","updated":"2012-11-30 16:05:17.000000000","message":"I agree with Vek. It\u0027s probably a good idea to ensure the original exception gets raised, and not any that are generated by the run_exc() hook.\n\nAlso, is there any value in having the post hook be able to change the return value?","commit_id":"2ccfcc764d5b47df003d08e78e6c8cde22b96ae4"}],"nova/hooks/__init__.py":[{"author":{"_account_id":1561,"name":"Russell Bryant","email":"rbryant@redhat.com","username":"russellb"},"change_message_id":"ab1b6ff4178794b85631b86a9cf805582ba90588","unresolved":false,"context_lines":[{"line_number":70,"context_line":""},{"line_number":71,"context_line":"    def load_hooks(self):"},{"line_number":72,"context_line":"        hook_classes \u003d self.get_all_classes()"},{"line_number":73,"context_line":"        return [cls() for cls in hook_classes]"},{"line_number":74,"context_line":""},{"line_number":75,"context_line":""},{"line_number":76,"context_line":"class BaseHook(object):"}],"source_content_type":"text/x-python","patch_set":5,"id":"AAAAMH%2F%2F27g%3D","line":73,"updated":"2012-11-19 21:47:34.000000000","message":"This is returning a list, but nothing is using it?","commit_id":"95f11c516a60a44432c1e869aa889c4f86af7bce"}],"nova/tests/test_hooks.py":[{"author":{"_account_id":1030,"name":"Chris Behrens","email":"cbehrens@codestud.com","username":"cbehrens"},"change_message_id":"0a479b24aca9372ec10eb1b505e3900b89d6c09a","unresolved":false,"context_lines":[{"line_number":71,"context_line":""},{"line_number":72,"context_line":"    @hooks.add_hook(\u0027test_hook\u0027)"},{"line_number":73,"context_line":"    def _hooked(self, a, b\u003d1, c\u003d2, called\u003dNone):"},{"line_number":74,"context_line":"        return 42"},{"line_number":75,"context_line":""},{"line_number":76,"context_line":"    def test_basic(self):"},{"line_number":77,"context_line":"        self.assertEqual(42, self._hooked(1))"}],"source_content_type":"text/x-python","patch_set":8,"id":"AAAAMH%2F%2FsMo%3D","line":74,"updated":"2012-11-30 08:05:21.000000000","message":"Excellent return value.","commit_id":"2ccfcc764d5b47df003d08e78e6c8cde22b96ae4"},{"author":{"_account_id":2472,"name":"Doug Hellmann","email":"dhellmann@redhat.com","username":"doug-hellmann"},"change_message_id":"6f8b74801ff4e402f993f4620cb158a279141ba9","unresolved":false,"context_lines":[{"line_number":66,"context_line":""},{"line_number":67,"context_line":"        hooks.reset()"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":"        self.stubs.Set(stevedore.extension.ExtensionManager, \u0027_load_plugins\u0027,"},{"line_number":70,"context_line":"                       self._mock_load_plugins)"},{"line_number":71,"context_line":""},{"line_number":72,"context_line":"    @hooks.add_hook(\u0027test_hook\u0027)"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAM3%2F%2F4dY%3D","line":69,"updated":"2012-12-26 21:37:58.000000000","message":"If you have ideas for how to make this mock work easier, let me know. I\u0027d be happy to have a patch to stevedore.","commit_id":"e937a53065377ecb7c30372ce880bd3d358f4572"}]}
