)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":6854,"name":"YAMAMOTO Takashi","email":"yamamoto@midokura.com","username":"yamamoto"},"change_message_id":"591ece9f8b52b3c4847f1dacbf92df2cb20defa7","unresolved":false,"context_lines":[{"line_number":13,"context_line":"subscriptions and will allow the fact that a method is subscribed"},{"line_number":14,"context_line":"to a resource to be visible right above the method itself."},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"See the follow-up patch for an example of how this can clean things"},{"line_number":17,"context_line":"up."},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"Change-Id: I1020c5ddec57f535e5b94f803144dfa19d668937"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"da36d5c6_ce35eada","line":16,"range":{"start_line":16,"start_character":4,"end_line":16,"end_character":23},"updated":"2017-02-21 14:27:48.000000000","message":"depending the merge timing, it might be difficult to find  out which patch is from git history.  it\u0027s better to mention change-id.","commit_id":"0cc0074507f3455d869c64d341db49f1257bea2a"},{"author":{"_account_id":7787,"name":"Kevin Benton","email":"kevin@benton.pub","username":"blak111"},"change_message_id":"c89e329e3a74c5146761ab4f4ce7e3bf29fe2891","unresolved":false,"context_lines":[{"line_number":13,"context_line":"subscriptions and will allow the fact that a method is subscribed"},{"line_number":14,"context_line":"to a resource to be visible right above the method itself."},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"See the follow-up patch for an example of how this can clean things"},{"line_number":17,"context_line":"up."},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"Change-Id: I1020c5ddec57f535e5b94f803144dfa19d668937"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"da36d5c6_1fb00d43","line":16,"range":{"start_line":16,"start_character":4,"end_line":16,"end_character":23},"in_reply_to":"da36d5c6_ce35eada","updated":"2017-02-21 15:50:45.000000000","message":"Done","commit_id":"0cc0074507f3455d869c64d341db49f1257bea2a"}],"neutron/callbacks/registry.py":[{"author":{"_account_id":7787,"name":"Kevin Benton","email":"kevin@benton.pub","username":"blak111"},"change_message_id":"adcca8424e777ae70a4c887e34ae6eff9368cd0b","unresolved":false,"context_lines":[{"line_number":79,"context_line":""},{"line_number":80,"context_line":"    def replacement_new(cls, *args, **kwargs):"},{"line_number":81,"context_line":"        instance \u003d orig_new(*args, **kwargs)"},{"line_number":82,"context_line":"        for name, unbound_method in cls.__dict__.items():"},{"line_number":83,"context_line":"            for resource, event in _REGISTERED_CLASS_METHODS[unbound_method]:"},{"line_number":84,"context_line":"                # subscribe the bound method"},{"line_number":85,"context_line":"                subscribe(getattr(instance, name), resource, event)"}],"source_content_type":"text/x-python","patch_set":1,"id":"da36d5c6_976dd49a","line":82,"updated":"2017-02-21 09:22:15.000000000","message":"Oh, possibly. I\u0027ll switch to that after some more reviews to see if people like this approach.","commit_id":"cc0581309086308b00f84c74dd533e826f77e30f"},{"author":{"_account_id":6854,"name":"YAMAMOTO Takashi","email":"yamamoto@midokura.com","username":"yamamoto"},"change_message_id":"676f28999860c1c640c92ff22c114f7074ea4e48","unresolved":false,"context_lines":[{"line_number":79,"context_line":""},{"line_number":80,"context_line":"    def replacement_new(cls, *args, **kwargs):"},{"line_number":81,"context_line":"        instance \u003d orig_new(*args, **kwargs)"},{"line_number":82,"context_line":"        for name, unbound_method in cls.__dict__.items():"},{"line_number":83,"context_line":"            for resource, event in _REGISTERED_CLASS_METHODS[unbound_method]:"},{"line_number":84,"context_line":"                # subscribe the bound method"},{"line_number":85,"context_line":"                subscribe(getattr(instance, name), resource, event)"}],"source_content_type":"text/x-python","patch_set":1,"id":"da36d5c6_d104bc7f","line":82,"range":{"start_line":82,"start_character":36,"end_line":82,"end_character":56},"updated":"2017-02-21 08:32:48.000000000","message":"can\u0027t this use inspect.getmembers for some reasons?","commit_id":"cc0581309086308b00f84c74dd533e826f77e30f"},{"author":{"_account_id":7787,"name":"Kevin Benton","email":"kevin@benton.pub","username":"blak111"},"change_message_id":"f46862c18074b69661dcd153f8b8732902b5e1fb","unresolved":false,"context_lines":[{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    def replacement_new(cls, *args, **kwargs):"},{"line_number":82,"context_line":"        instance \u003d orig_new(*args, **kwargs)"},{"line_number":83,"context_line":"        for name, unbound_method in inspect.getmembers(cls):"},{"line_number":84,"context_line":"            if (not inspect.ismethod(unbound_method) and"},{"line_number":85,"context_line":"                    not inspect.isfunction(unbound_method)):"},{"line_number":86,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":3,"id":"da36d5c6_dfb89aca","line":83,"updated":"2017-02-26 13:30:40.000000000","message":"Right. A class that would use this decorator was already subcribing in __new__ so if it was being instantiated multiple times per process we would have had tons of extra subscriptions.","commit_id":"82a4c59e9e39ed92ef7773ba4129f0c810b6701a"},{"author":{"_account_id":5948,"name":"Oleg Bondarev","email":"obondarev@mirantis.com","username":"obondarev"},"change_message_id":"4ed0516491aa7f245c5d95e18c7048ba4863478d","unresolved":false,"context_lines":[{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    def replacement_new(cls, *args, **kwargs):"},{"line_number":82,"context_line":"        instance \u003d orig_new(*args, **kwargs)"},{"line_number":83,"context_line":"        for name, unbound_method in inspect.getmembers(cls):"},{"line_number":84,"context_line":"            if (not inspect.ismethod(unbound_method) and"},{"line_number":85,"context_line":"                    not inspect.isfunction(unbound_method)):"},{"line_number":86,"context_line":"                continue"}],"source_content_type":"text/x-python","patch_set":3,"id":"da36d5c6_ef9fec4d","line":83,"range":{"start_line":83,"start_character":8,"end_line":83,"end_character":60},"updated":"2017-02-22 09:23:37.000000000","message":"below adds performance penalty, but it seems classes with callbacks are normally instantiated once per process","commit_id":"82a4c59e9e39ed92ef7773ba4129f0c810b6701a"},{"author":{"_account_id":7787,"name":"Kevin Benton","email":"kevin@benton.pub","username":"blak111"},"change_message_id":"f46862c18074b69661dcd153f8b8732902b5e1fb","unresolved":false,"context_lines":[{"line_number":90,"context_line":"                continue"},{"line_number":91,"context_line":"            for resource, event in _REGISTERED_CLASS_METHODS[func]:"},{"line_number":92,"context_line":"                # subscribe the bound method"},{"line_number":93,"context_line":"                subscribe(getattr(instance, name), resource, event)"},{"line_number":94,"context_line":"        return instance"},{"line_number":95,"context_line":"    cls.__new__ \u003d classmethod(replacement_new)"},{"line_number":96,"context_line":"    return cls"}],"source_content_type":"text/x-python","patch_set":3,"id":"da36d5c6_ffbb9ec1","line":93,"updated":"2017-02-26 13:30:40.000000000","message":"The purpose was to have a decorator right above the function so it\u0027s very easy to see which events end up calling a particular function. If we move all of the subscribed methods up to a single class variable, then I don\u0027t think we are gaining the same self documentation that this provides.\n\nI agree about the complexity, but the general idea is that we just have complexity in one spot that we cover with tests and then everyone else can subscribe with the really simple decorator.","commit_id":"82a4c59e9e39ed92ef7773ba4129f0c810b6701a"},{"author":{"_account_id":5948,"name":"Oleg Bondarev","email":"obondarev@mirantis.com","username":"obondarev"},"change_message_id":"4ed0516491aa7f245c5d95e18c7048ba4863478d","unresolved":false,"context_lines":[{"line_number":81,"context_line":"    def replacement_new(cls, *args, **kwargs):"},{"line_number":82,"context_line":"        instance \u003d orig_new(*args, **kwargs)"},{"line_number":83,"context_line":"        for name, unbound_method in inspect.getmembers(cls):"},{"line_number":84,"context_line":"            if (not inspect.ismethod(unbound_method) and"},{"line_number":85,"context_line":"                    not inspect.isfunction(unbound_method)):"},{"line_number":86,"context_line":"                continue"},{"line_number":87,"context_line":"            # handle py27/py34 difference"},{"line_number":88,"context_line":"            func \u003d getattr(unbound_method, \u0027im_func\u0027, unbound_method)"},{"line_number":89,"context_line":"            if func not in _REGISTERED_CLASS_METHODS:"},{"line_number":90,"context_line":"                continue"},{"line_number":91,"context_line":"            for resource, event in _REGISTERED_CLASS_METHODS[func]:"},{"line_number":92,"context_line":"                # subscribe the bound method"},{"line_number":93,"context_line":"                subscribe(getattr(instance, name), resource, event)"},{"line_number":94,"context_line":"        return instance"},{"line_number":95,"context_line":"    cls.__new__ \u003d classmethod(replacement_new)"},{"line_number":96,"context_line":"    return cls"}],"source_content_type":"text/x-python","patch_set":3,"id":"da36d5c6_0ffe0037","line":93,"range":{"start_line":84,"start_character":12,"end_line":93,"end_character":67},"updated":"2017-02-22 09:23:37.000000000","message":"a bit complex and takes time to understand, though lets register callbacks with just decorators as described in the commit message. Another option would be to only have this class decorator calling some predefined \"register_callbacks\" which every interested class has to define (no inspect magic)","commit_id":"82a4c59e9e39ed92ef7773ba4129f0c810b6701a"},{"author":{"_account_id":5948,"name":"Oleg Bondarev","email":"obondarev@mirantis.com","username":"obondarev"},"change_message_id":"016092db7e50c53006130e63e33c71158e3638c9","unresolved":false,"context_lines":[{"line_number":90,"context_line":"                continue"},{"line_number":91,"context_line":"            for resource, event in _REGISTERED_CLASS_METHODS[func]:"},{"line_number":92,"context_line":"                # subscribe the bound method"},{"line_number":93,"context_line":"                subscribe(getattr(instance, name), resource, event)"},{"line_number":94,"context_line":"        return instance"},{"line_number":95,"context_line":"    cls.__new__ \u003d classmethod(replacement_new)"},{"line_number":96,"context_line":"    return cls"}],"source_content_type":"text/x-python","patch_set":3,"id":"da36d5c6_b5e6a741","line":93,"in_reply_to":"da36d5c6_ffbb9ec1","updated":"2017-02-26 16:34:43.000000000","message":"makes sense to me, thanks","commit_id":"82a4c59e9e39ed92ef7773ba4129f0c810b6701a"}]}
