)]}'
{"dragonflow/db/model_framework.py":[{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"5a5e907a3ec5e8d26201efa4f8c805d444354698","unresolved":false,"context_lines":[{"line_number":18,"context_line":"from dragonflow.utils import namespace"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"def _combine_indexes(base_class, new_indexes):"},{"line_number":22,"context_line":"    result \u003d namespace.Namespace()"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    if new_indexes is not None:"}],"source_content_type":"text/x-python","patch_set":4,"id":"ba5201f7_b9aff5e1","line":21,"updated":"2017-01-11 10:39:17.000000000","message":"mising docstring","commit_id":"59014c53f9e50bd447785b4524be70894df3f28d"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"5a5e907a3ec5e8d26201efa4f8c805d444354698","unresolved":false,"context_lines":[{"line_number":38,"context_line":"    except AttributeError:"},{"line_number":39,"context_line":"        base_events \u003d ()"},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    if new_events is None:"},{"line_number":42,"context_line":"        new_events \u003d ()"},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"    return tuple(set(new_events + base_events))"},{"line_number":45,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"ba5201f7_39a145aa","line":42,"range":{"start_line":41,"start_character":0,"end_line":42,"end_character":23},"updated":"2017-01-11 10:39:17.000000000","message":"nit: Why not?:\nif not new_events:\n    return base_events","commit_id":"59014c53f9e50bd447785b4524be70894df3f28d"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"5a5e907a3ec5e8d26201efa4f8c805d444354698","unresolved":false,"context_lines":[{"line_number":55,"context_line":""},{"line_number":56,"context_line":"    @classmethod"},{"line_number":57,"context_line":"    def _emit(cls, event, *args, **kwargs):"},{"line_number":58,"context_line":"        for cb in cls._get_event_callbacks()[event]:"},{"line_number":59,"context_line":"            try:"},{"line_number":60,"context_line":"                cb(*args, **kwargs)"},{"line_number":61,"context_line":"            except Exception:"}],"source_content_type":"text/x-python","patch_set":4,"id":"ba5201f7_b9545554","line":58,"updated":"2017-01-11 10:39:17.000000000","message":"I can\u0027t find the definition of this private method.","commit_id":"59014c53f9e50bd447785b4524be70894df3f28d"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"5a5e907a3ec5e8d26201efa4f8c805d444354698","unresolved":false,"context_lines":[{"line_number":58,"context_line":"        for cb in cls._get_event_callbacks()[event]:"},{"line_number":59,"context_line":"            try:"},{"line_number":60,"context_line":"                cb(*args, **kwargs)"},{"line_number":61,"context_line":"            except Exception:"},{"line_number":62,"context_line":"                pass"},{"line_number":63,"context_line":""},{"line_number":64,"context_line":"    @classmethod"}],"source_content_type":"text/x-python","patch_set":4,"id":"ba5201f7_b97c5521","line":61,"updated":"2017-01-11 10:39:17.000000000","message":"Please add a LOG.warning/LOG.exception here","commit_id":"59014c53f9e50bd447785b4524be70894df3f28d"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"5a5e907a3ec5e8d26201efa4f8c805d444354698","unresolved":false,"context_lines":[{"line_number":77,"context_line":""},{"line_number":78,"context_line":""},{"line_number":79,"context_line":"def construct_nb_db_model(cls_\u003dNone, indexes\u003dNone, events\u003d(), nb_crud\u003dNone):"},{"line_number":80,"context_line":"    def decorator(cls_):"},{"line_number":81,"context_line":"        # Compute results ahead of time"},{"line_number":82,"context_line":"        result_indexes \u003d _combine_indexes(cls_, indexes)"},{"line_number":83,"context_line":"        result_events \u003d _combine_events(cls_, events)"}],"source_content_type":"text/x-python","patch_set":4,"id":"ba5201f7_fce7ab3d","line":80,"updated":"2017-01-11 10:39:17.000000000","message":"This entire magic function has to be filled with documentation. It is very difficult to understand.","commit_id":"59014c53f9e50bd447785b4524be70894df3f28d"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"5a5e907a3ec5e8d26201efa4f8c805d444354698","unresolved":false,"context_lines":[{"line_number":84,"context_line":"        try:"},{"line_number":85,"context_line":"            result_nb_crud \u003d nb_crud or cls_._get_nb_crud_type()"},{"line_number":86,"context_line":"        except AttributeError:"},{"line_number":87,"context_line":"            result_nb_crud \u003d None"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":"        callback_lookup \u003d collections.defaultdict(set)"},{"line_number":90,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"ba5201f7_9c5a1f29","line":87,"range":{"start_line":87,"start_character":12,"end_line":87,"end_character":26},"updated":"2017-01-11 10:39:17.000000000","message":"Isn\u0027t this an error, that there are no CRUD methods?","commit_id":"59014c53f9e50bd447785b4524be70894df3f28d"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"c21425b1ef1195828bf71220f02a6ac3411000e1","unresolved":false,"context_lines":[{"line_number":18,"context_line":"from dragonflow.utils import namespace"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"def _combine_indexes(base_class, new_indexes):"},{"line_number":22,"context_line":"    result \u003d namespace.Namespace()"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    if new_indexes is not None:"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_72f94580","line":21,"updated":"2017-01-15 17:04:10.000000000","message":"Still missing docstring","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b0e52dd6607469512d87690f10d455b161bcc6e8","unresolved":false,"context_lines":[{"line_number":18,"context_line":"from dragonflow.utils import namespace"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"def _combine_indexes(base_class, new_indexes):"},{"line_number":22,"context_line":"    result \u003d namespace.Namespace()"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    if new_indexes is not None:"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_9419337c","line":21,"in_reply_to":"7a3c09a3_72f94580","updated":"2017-01-16 08:17:23.000000000","message":"Its no longer needed","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"c21425b1ef1195828bf71220f02a6ac3411000e1","unresolved":false,"context_lines":[{"line_number":43,"context_line":""},{"line_number":44,"context_line":"    @classmethod"},{"line_number":45,"context_line":"    def _emit(cls, event, *args, **kwargs):"},{"line_number":46,"context_line":"        for cb in cls._get_event_callbacks()[event]:"},{"line_number":47,"context_line":"            try:"},{"line_number":48,"context_line":"                cb(*args, **kwargs)"},{"line_number":49,"context_line":"            except Exception:"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_3236dd52","line":46,"range":{"start_line":46,"start_character":22,"end_line":46,"end_character":42},"updated":"2017-01-15 17:04:10.000000000","message":"I still can\u0027t find the definition of this private method.","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b0e52dd6607469512d87690f10d455b161bcc6e8","unresolved":false,"context_lines":[{"line_number":43,"context_line":""},{"line_number":44,"context_line":"    @classmethod"},{"line_number":45,"context_line":"    def _emit(cls, event, *args, **kwargs):"},{"line_number":46,"context_line":"        for cb in cls._get_event_callbacks()[event]:"},{"line_number":47,"context_line":"            try:"},{"line_number":48,"context_line":"                cb(*args, **kwargs)"},{"line_number":49,"context_line":"            except Exception:"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_9102250a","line":46,"range":{"start_line":46,"start_character":22,"end_line":46,"end_character":42},"in_reply_to":"7a3c09a3_3236dd52","updated":"2017-01-16 08:17:23.000000000","message":"Its added further down in ConstructedClass","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"c21425b1ef1195828bf71220f02a6ac3411000e1","unresolved":false,"context_lines":[{"line_number":46,"context_line":"        for cb in cls._get_event_callbacks()[event]:"},{"line_number":47,"context_line":"            try:"},{"line_number":48,"context_line":"                cb(*args, **kwargs)"},{"line_number":49,"context_line":"            except Exception:"},{"line_number":50,"context_line":"                pass"},{"line_number":51,"context_line":""},{"line_number":52,"context_line":"    @classmethod"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_5239a940","line":49,"updated":"2017-01-15 17:04:10.000000000","message":"A log message is still needed here.","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b0e52dd6607469512d87690f10d455b161bcc6e8","unresolved":false,"context_lines":[{"line_number":46,"context_line":"        for cb in cls._get_event_callbacks()[event]:"},{"line_number":47,"context_line":"            try:"},{"line_number":48,"context_line":"                cb(*args, **kwargs)"},{"line_number":49,"context_line":"            except Exception:"},{"line_number":50,"context_line":"                pass"},{"line_number":51,"context_line":""},{"line_number":52,"context_line":"    @classmethod"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_4f9f3450","line":49,"in_reply_to":"7a3c09a3_5239a940","updated":"2017-01-16 08:17:23.000000000","message":"I agree","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"c21425b1ef1195828bf71220f02a6ac3411000e1","unresolved":false,"context_lines":[{"line_number":65,"context_line":"    def get_indexes(self):"},{"line_number":66,"context_line":"        return namespace.Namespace()"},{"line_number":67,"context_line":""},{"line_number":68,"context_line":"    def on_create(self):"},{"line_number":69,"context_line":"        pass"},{"line_number":70,"context_line":""},{"line_number":71,"context_line":"    def on_update(self):"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_b24acdc3","line":68,"updated":"2017-01-15 17:04:10.000000000","message":"If this is a hook, I think it should be on_create_pre, to mark that the is called before the actual call to the database (so that if model changes are needed, they can be done here, and will be saved to the db)","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b0e52dd6607469512d87690f10d455b161bcc6e8","unresolved":false,"context_lines":[{"line_number":65,"context_line":"    def get_indexes(self):"},{"line_number":66,"context_line":"        return namespace.Namespace()"},{"line_number":67,"context_line":""},{"line_number":68,"context_line":"    def on_create(self):"},{"line_number":69,"context_line":"        pass"},{"line_number":70,"context_line":""},{"line_number":71,"context_line":"    def on_update(self):"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_741e8764","line":68,"in_reply_to":"7a3c09a3_b24acdc3","updated":"2017-01-16 08:17:23.000000000","message":"Will address in next ps.","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"c21425b1ef1195828bf71220f02a6ac3411000e1","unresolved":false,"context_lines":[{"line_number":84,"context_line":"    pass"},{"line_number":85,"context_line":""},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"def construct_nb_db_model(cls_\u003dNone, indexes\u003dNone, events\u003d()):"},{"line_number":88,"context_line":"    if indexes is None:"},{"line_number":89,"context_line":"        indexes \u003d namespace.Namespace()"},{"line_number":90,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_b221edfd","line":87,"updated":"2017-01-15 17:04:10.000000000","message":"This magic function is still missing documentation. It is the basis of the new NB model, and its function and behaviour have to be clear.","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b0e52dd6607469512d87690f10d455b161bcc6e8","unresolved":false,"context_lines":[{"line_number":84,"context_line":"    pass"},{"line_number":85,"context_line":""},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"def construct_nb_db_model(cls_\u003dNone, indexes\u003dNone, events\u003d()):"},{"line_number":88,"context_line":"    if indexes is None:"},{"line_number":89,"context_line":"        indexes \u003d namespace.Namespace()"},{"line_number":90,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_3414ff42","line":87,"in_reply_to":"7a3c09a3_b221edfd","updated":"2017-01-16 08:17:23.000000000","message":"Will address in next ps.","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"8d5785ba68907be00786567d5319407cc800e3d0","unresolved":false,"context_lines":[{"line_number":106,"context_line":""},{"line_number":107,"context_line":"            return tuple(set(events + base_events))"},{"line_number":108,"context_line":""},{"line_number":109,"context_line":"        @classmethod"},{"line_number":110,"context_line":"        def _get_event_callbacks(cls):"},{"line_number":111,"context_line":"            cls.lookup \u003d callback_lookup"},{"line_number":112,"context_line":"            return callback_lookup"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":"        extra_attributes \u003d {}"},{"line_number":115,"context_line":"        extra_attributes[\u0027get_indexes\u0027] \u003d get_indexes"}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_5b2f933e","line":112,"range":{"start_line":109,"start_character":0,"end_line":112,"end_character":34},"updated":"2017-01-23 17:20:44.000000000","message":"Not sure I understand why this can\u0027t go in the parent (and cls.lookup can be initialized lazily or externally?\n\nAdditionally, cls.lookup is never used.","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b666cd0d040cd41bd5a04c8d4193b6d3efe9583c","unresolved":false,"context_lines":[{"line_number":106,"context_line":""},{"line_number":107,"context_line":"            return tuple(set(events + base_events))"},{"line_number":108,"context_line":""},{"line_number":109,"context_line":"        @classmethod"},{"line_number":110,"context_line":"        def _get_event_callbacks(cls):"},{"line_number":111,"context_line":"            cls.lookup \u003d callback_lookup"},{"line_number":112,"context_line":"            return callback_lookup"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":"        extra_attributes \u003d {}"},{"line_number":115,"context_line":"        extra_attributes[\u0027get_indexes\u0027] \u003d get_indexes"}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_27343d48","line":112,"range":{"start_line":109,"start_character":0,"end_line":112,"end_character":34},"in_reply_to":"5a3905b3_5b2f933e","updated":"2017-01-24 13:53:38.000000000","message":"Oops, cls.lookup \u003d callback_lookup  is a debug leftover\nThis method is needed to be present in each deriving class so we wont inherit this dict from parent and have shared callbacks.","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"8d5785ba68907be00786567d5319407cc800e3d0","unresolved":false,"context_lines":[{"line_number":115,"context_line":"        extra_attributes[\u0027get_indexes\u0027] \u003d get_indexes"},{"line_number":116,"context_line":"        extra_attributes[\u0027get_events\u0027] \u003d get_events"},{"line_number":117,"context_line":"        extra_attributes[\u0027_get_event_callbacks\u0027] \u003d _get_event_callbacks"},{"line_number":118,"context_line":"        for event in tuple(set(events + cls_.get_events())):"},{"line_number":119,"context_line":"            @classmethod"},{"line_number":120,"context_line":"            def register_event(cls, cb):"},{"line_number":121,"context_line":"                cls._register(event, cb)"}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_5b50730b","line":118,"range":{"start_line":118,"start_character":21,"end_line":118,"end_character":30},"updated":"2017-01-23 17:20:44.000000000","message":"Not sure I understand why this is needed?","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b666cd0d040cd41bd5a04c8d4193b6d3efe9583c","unresolved":false,"context_lines":[{"line_number":115,"context_line":"        extra_attributes[\u0027get_indexes\u0027] \u003d get_indexes"},{"line_number":116,"context_line":"        extra_attributes[\u0027get_events\u0027] \u003d get_events"},{"line_number":117,"context_line":"        extra_attributes[\u0027_get_event_callbacks\u0027] \u003d _get_event_callbacks"},{"line_number":118,"context_line":"        for event in tuple(set(events + cls_.get_events())):"},{"line_number":119,"context_line":"            @classmethod"},{"line_number":120,"context_line":"            def register_event(cls, cb):"},{"line_number":121,"context_line":"                cls._register(event, cb)"}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_e714f5a0","line":118,"range":{"start_line":118,"start_character":21,"end_line":118,"end_character":30},"in_reply_to":"5a3905b3_5b50730b","updated":"2017-01-24 13:53:38.000000000","message":"to get rid of duplicates in case we define event twice","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b666cd0d040cd41bd5a04c8d4193b6d3efe9583c","unresolved":false,"context_lines":[{"line_number":131,"context_line":"            extra_attributes[\u0027unregister_{0}\u0027.format(event)] \u003d unregister_event"},{"line_number":132,"context_line":"            extra_attributes[\u0027emit_{0}\u0027.format(event)] \u003d emit_event"},{"line_number":133,"context_line":""},{"line_number":134,"context_line":"        # Wrap all methods in classmethod and fix names"},{"line_number":135,"context_line":"        for name, attr in six.iteritems(extra_attributes):"},{"line_number":136,"context_line":"            try:"},{"line_number":137,"context_line":"                attr.__func__.__name__ \u003d name"}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_a7058d14","line":134,"range":{"start_line":134,"start_character":30,"end_line":134,"end_character":41},"updated":"2017-01-24 13:53:38.000000000","message":"Will remove","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"8d5785ba68907be00786567d5319407cc800e3d0","unresolved":false,"context_lines":[{"line_number":132,"context_line":"            extra_attributes[\u0027emit_{0}\u0027.format(event)] \u003d emit_event"},{"line_number":133,"context_line":""},{"line_number":134,"context_line":"        # Wrap all methods in classmethod and fix names"},{"line_number":135,"context_line":"        for name, attr in six.iteritems(extra_attributes):"},{"line_number":136,"context_line":"            try:"},{"line_number":137,"context_line":"                attr.__func__.__name__ \u003d name"},{"line_number":138,"context_line":"            except AttributeError:"},{"line_number":139,"context_line":"                attr.__name__ \u003d name"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"        return type(cls_.__name__, (cls_,), extra_attributes)"},{"line_number":142,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_5bb953cb","line":139,"range":{"start_line":135,"start_character":0,"end_line":139,"end_character":36},"updated":"2017-01-23 17:20:44.000000000","message":"Wouldn\u0027t it be clearer to do this inline? i.e. when you add get_indexes to extra_attributes, or when you define get_index, also say get_indexes.__func__.__name__ \u003d \u0027get_indexes\u0027?\n\nOr (possibly less clear) do this as a decorator that gets the name?","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b666cd0d040cd41bd5a04c8d4193b6d3efe9583c","unresolved":false,"context_lines":[{"line_number":132,"context_line":"            extra_attributes[\u0027emit_{0}\u0027.format(event)] \u003d emit_event"},{"line_number":133,"context_line":""},{"line_number":134,"context_line":"        # Wrap all methods in classmethod and fix names"},{"line_number":135,"context_line":"        for name, attr in six.iteritems(extra_attributes):"},{"line_number":136,"context_line":"            try:"},{"line_number":137,"context_line":"                attr.__func__.__name__ \u003d name"},{"line_number":138,"context_line":"            except AttributeError:"},{"line_number":139,"context_line":"                attr.__name__ \u003d name"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"        return type(cls_.__name__, (cls_,), extra_attributes)"},{"line_number":142,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_e787945e","line":139,"range":{"start_line":135,"start_character":0,"end_line":139,"end_character":36},"in_reply_to":"5a3905b3_5bb953cb","updated":"2017-01-24 13:53:38.000000000","message":"I don\u0027t really like it, for event methods we\u0027ll make this code few lines longer and I don\u0027t think it adds greatly to readability, I prefer adding a more elaborate code to this loop.","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"8d5785ba68907be00786567d5319407cc800e3d0","unresolved":false,"context_lines":[{"line_number":149,"context_line":"_lookup_by_table_name \u003d {}"},{"line_number":150,"context_line":""},{"line_number":151,"context_line":""},{"line_number":152,"context_line":"def register_model(cls):"},{"line_number":153,"context_line":"    _lookup_by_class_name[cls.__name__] \u003d cls"},{"line_number":154,"context_line":"    try:"},{"line_number":155,"context_line":"        _lookup_by_table_name[cls.table_name] \u003d cls"}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_1be50ba7","line":152,"range":{"start_line":152,"start_character":4,"end_line":152,"end_character":18},"updated":"2017-01-23 17:20:44.000000000","message":"nit: I think this method isn\u0027t tested. A nit, since this method will be heavily used anyway, so testing will be implicit.","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b666cd0d040cd41bd5a04c8d4193b6d3efe9583c","unresolved":false,"context_lines":[{"line_number":149,"context_line":"_lookup_by_table_name \u003d {}"},{"line_number":150,"context_line":""},{"line_number":151,"context_line":""},{"line_number":152,"context_line":"def register_model(cls):"},{"line_number":153,"context_line":"    _lookup_by_class_name[cls.__name__] \u003d cls"},{"line_number":154,"context_line":"    try:"},{"line_number":155,"context_line":"        _lookup_by_table_name[cls.table_name] \u003d cls"}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_07cd8130","line":152,"range":{"start_line":152,"start_character":4,"end_line":152,"end_character":18},"in_reply_to":"5a3905b3_1be50ba7","updated":"2017-01-24 13:53:38.000000000","message":"This method is tested at https://review.openstack.org/#/c/417820/14/dragonflow/tests/unit/test_model_framework.py L80 (get_model)","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"8d5785ba68907be00786567d5319407cc800e3d0","unresolved":false,"context_lines":[{"line_number":169,"context_line":"    if type(arg) \u003d\u003d type:"},{"line_number":170,"context_line":"        return arg"},{"line_number":171,"context_line":""},{"line_number":172,"context_line":"    for lookup in ("},{"line_number":173,"context_line":"        _lookup_by_class_name,"},{"line_number":174,"context_line":"        _lookup_by_table_name,"},{"line_number":175,"context_line":"        df_models.table_class_mapping,"},{"line_number":176,"context_line":"    ):"},{"line_number":177,"context_line":"        try:"},{"line_number":178,"context_line":"            return lookup[arg]"},{"line_number":179,"context_line":"        except KeyError:"},{"line_number":180,"context_line":"            pass"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":"    raise KeyError(arg)"},{"line_number":183,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_7b052f0f","line":180,"range":{"start_line":172,"start_character":0,"end_line":180,"end_character":16},"updated":"2017-01-23 17:20:44.000000000","message":"Would this code be more clear if the loop was unrolled?","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b666cd0d040cd41bd5a04c8d4193b6d3efe9583c","unresolved":false,"context_lines":[{"line_number":169,"context_line":"    if type(arg) \u003d\u003d type:"},{"line_number":170,"context_line":"        return arg"},{"line_number":171,"context_line":""},{"line_number":172,"context_line":"    for lookup in ("},{"line_number":173,"context_line":"        _lookup_by_class_name,"},{"line_number":174,"context_line":"        _lookup_by_table_name,"},{"line_number":175,"context_line":"        df_models.table_class_mapping,"},{"line_number":176,"context_line":"    ):"},{"line_number":177,"context_line":"        try:"},{"line_number":178,"context_line":"            return lookup[arg]"},{"line_number":179,"context_line":"        except KeyError:"},{"line_number":180,"context_line":"            pass"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":"    raise KeyError(arg)"},{"line_number":183,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_476f89fb","line":180,"range":{"start_line":172,"start_character":0,"end_line":180,"end_character":16},"in_reply_to":"5a3905b3_7b052f0f","updated":"2017-01-24 13:53:38.000000000","message":"I don\u0027t mind it you think it looks better\n\n x \u003d lookup1.get(key)\n if x is not None:\n     return x\n\n x \u003d lookup2.get(key)\n if x is not None:\n     return x\n\n x \u003d lookup3.get(key)\n if x is not None:\n     return x\n\n raise KeyError(x)","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"0834ad0d7ada28caafe333dc941b418b5715d817","unresolved":false,"context_lines":[{"line_number":39,"context_line":""},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"class _CommonBase(models.Base):"},{"line_number":42,"context_line":"    def __init__(self, **kwargs):"},{"line_number":43,"context_line":"        super(_CommonBase, self).__init__(**kwargs)"},{"line_number":44,"context_line":"        self._set_fields \u003d self._field_names.intersection(set(kwargs.keys()))"},{"line_number":45,"context_line":""}],"source_content_type":"text/x-python","patch_set":17,"id":"3a461143_5745d4b0","line":42,"range":{"start_line":42,"start_character":8,"end_line":42,"end_character":16},"updated":"2017-01-29 13:37:12.000000000","message":"docstring missing.","commit_id":"f7e9d6f6907ff5dec8f0b9e1f8e9c1aee3ba4d47"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"0834ad0d7ada28caafe333dc941b418b5715d817","unresolved":false,"context_lines":[{"line_number":108,"context_line":"        if key in self._field_names:"},{"line_number":109,"context_line":"            if value is not None:"},{"line_number":110,"context_line":"                self._set_fields.add(key)"},{"line_number":111,"context_line":"            else:"},{"line_number":112,"context_line":"                self._set_fields.discard(key)"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":"    def iterate_over_set_fields(self):"}],"source_content_type":"text/x-python","patch_set":17,"id":"3a461143_d70f0486","line":111,"updated":"2017-01-29 13:37:12.000000000","message":"So, if I say x.y \u003d None, y is removed from the x\u0027s fields? Maybe we want to reset the field to None? What does it mean if we remove the field - that it is ignored by NbApi\u0027s update? Maybe implement as __delattr__ instead?","commit_id":"f7e9d6f6907ff5dec8f0b9e1f8e9c1aee3ba4d47"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"643f21aa07204dd1dca91d42383a020677cc9fc8","unresolved":false,"context_lines":[{"line_number":38,"context_line":"    return tuple(v)"},{"line_number":39,"context_line":""},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"class _CommonBase(models.Base):"},{"line_number":42,"context_line":"    def __init__(self, **kwargs):"},{"line_number":43,"context_line":"        super(_CommonBase, self).__init__(**kwargs)"},{"line_number":44,"context_line":"        self._set_fields \u003d self._field_names.intersection(set(kwargs.keys()))"}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_8b9d54be","line":41,"range":{"start_line":41,"start_character":6,"end_line":41,"end_character":17},"updated":"2017-01-30 03:46:02.000000000","message":"docstring still missing. This class is central to the framework. Something explaining kwargs in the constructor, and what it adds on top of jsonmodels Base has to be mentioned.","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"5a047412592093ca0b5b438ffe5b41134e746c66","unresolved":false,"context_lines":[{"line_number":38,"context_line":"    return tuple(v)"},{"line_number":39,"context_line":""},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"class _CommonBase(models.Base):"},{"line_number":42,"context_line":"    def __init__(self, **kwargs):"},{"line_number":43,"context_line":"        super(_CommonBase, self).__init__(**kwargs)"},{"line_number":44,"context_line":"        self._set_fields \u003d self._field_names.intersection(set(kwargs.keys()))"}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_43742c67","line":41,"range":{"start_line":41,"start_character":6,"end_line":41,"end_character":17},"in_reply_to":"3a461143_8b9d54be","updated":"2017-01-30 13:40:18.000000000","message":"Done","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"643f21aa07204dd1dca91d42383a020677cc9fc8","unresolved":false,"context_lines":[{"line_number":108,"context_line":"        if key in self._field_names:"},{"line_number":109,"context_line":"            if value is not None:"},{"line_number":110,"context_line":"                self._set_fields.add(key)"},{"line_number":111,"context_line":"            else:"},{"line_number":112,"context_line":"                self._set_fields.discard(key)"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":"    def iterate_over_set_fields(self):"}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_aba210fb","line":111,"updated":"2017-01-30 03:46:02.000000000","message":"The comment from PS17 wasn\u0027t addressed:\n\n\u003e So, if I say x.y \u003d None, y is removed from the x\u0027s fields? Maybe we want to reset the field to None? What does it mean if we remove the field - that it is ignored by NbApi\u0027s update? Maybe implement as __delattr__ instead?","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"5a047412592093ca0b5b438ffe5b41134e746c66","unresolved":false,"context_lines":[{"line_number":108,"context_line":"        if key in self._field_names:"},{"line_number":109,"context_line":"            if value is not None:"},{"line_number":110,"context_line":"                self._set_fields.add(key)"},{"line_number":111,"context_line":"            else:"},{"line_number":112,"context_line":"                self._set_fields.discard(key)"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":"    def iterate_over_set_fields(self):"}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_c7e3c1d7","line":111,"in_reply_to":"3a461143_aba210fb","updated":"2017-01-30 13:40:18.000000000","message":"Added __delattr__ to unset fields, so now setting a field to None makes it set, and del model.field unsets it.\n\nA thing that bothers me is that jsonmodels treats none-fields as fields without value (i.e. gettattr on non-initialized field yields None).\n\nAlso, in order to allow un-setting fields in Model.update, a None value in update object is treated as sign to unset the field:\n\n \u003e\u003e\u003e obj.update(Model(field\u003dNone))\n \u003e\u003e\u003e obj.field_is_set(\u0027field\u0027)\n False\n\nIt works for now, but I\u0027m trying to figure out what makes the most sense.","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"cec37be3ebf155168961efc5d2f8319347da84b2","unresolved":false,"context_lines":[{"line_number":108,"context_line":"        if key in self._field_names:"},{"line_number":109,"context_line":"            if value is not None:"},{"line_number":110,"context_line":"                self._set_fields.add(key)"},{"line_number":111,"context_line":"            else:"},{"line_number":112,"context_line":"                self._set_fields.discard(key)"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":"    def iterate_over_set_fields(self):"}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_9912ee55","line":111,"in_reply_to":"3a461143_c7e3c1d7","updated":"2017-01-30 19:59:11.000000000","message":"You could use an \u0027unset value\u0027 to remove values. e.g.\nx.y \u003d mf.UnsetValue\nis equivalent to:\ndel x.y\n\nBecause setting a field to None should be allowed. There are workarounds (e.g. empty strings), but I would prefer things to be more explicit.","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"643f21aa07204dd1dca91d42383a020677cc9fc8","unresolved":false,"context_lines":[{"line_number":178,"context_line":"        # Add non-method attributes after we set names"},{"line_number":179,"context_line":"        cls_._event_callbacks \u003d event_callbacks"},{"line_number":180,"context_line":""},{"line_number":181,"context_line":"        fields \u003d set(n for n, _ in cls_.iterate_over_fields())"},{"line_number":182,"context_line":"        cls_._field_names \u003d fields"},{"line_number":183,"context_line":""},{"line_number":184,"context_line":"        return cls_"}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_0be08428","line":181,"updated":"2017-01-30 03:46:02.000000000","message":"Is _field_names allowed to be modified by reference? If not, maybe use frozenset?","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"5a047412592093ca0b5b438ffe5b41134e746c66","unresolved":false,"context_lines":[{"line_number":178,"context_line":"        # Add non-method attributes after we set names"},{"line_number":179,"context_line":"        cls_._event_callbacks \u003d event_callbacks"},{"line_number":180,"context_line":""},{"line_number":181,"context_line":"        fields \u003d set(n for n, _ in cls_.iterate_over_fields())"},{"line_number":182,"context_line":"        cls_._field_names \u003d fields"},{"line_number":183,"context_line":""},{"line_number":184,"context_line":"        return cls_"}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_7440fc34","line":181,"in_reply_to":"3a461143_0be08428","updated":"2017-01-30 13:40:18.000000000","message":"Agree, done","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"643f21aa07204dd1dca91d42383a020677cc9fc8","unresolved":false,"context_lines":[{"line_number":192,"context_line":"_lookup_by_table_name \u003d {}"},{"line_number":193,"context_line":""},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"@construct_nb_db_model(indexes\u003d{\u0027all\u0027: (), \u0027id\u0027: (\u0027id\u0027,)})"},{"line_number":196,"context_line":"class ModelBase(_CommonBase):"},{"line_number":197,"context_line":"    id \u003d fields.StringField(required\u003dTrue)"},{"line_number":198,"context_line":""}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_cbc83cab","line":195,"updated":"2017-01-30 03:46:02.000000000","message":"maybe also add the base events here? create, update, delete?","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"5a047412592093ca0b5b438ffe5b41134e746c66","unresolved":false,"context_lines":[{"line_number":192,"context_line":"_lookup_by_table_name \u003d {}"},{"line_number":193,"context_line":""},{"line_number":194,"context_line":""},{"line_number":195,"context_line":"@construct_nb_db_model(indexes\u003d{\u0027all\u0027: (), \u0027id\u0027: (\u0027id\u0027,)})"},{"line_number":196,"context_line":"class ModelBase(_CommonBase):"},{"line_number":197,"context_line":"    id \u003d fields.StringField(required\u003dTrue)"},{"line_number":198,"context_line":""}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_ef2c199b","line":195,"in_reply_to":"3a461143_cbc83cab","updated":"2017-01-30 13:40:18.000000000","message":"I\u0027ve moved it for now into BasicEventsMixin","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":7805,"name":"Li Ma","email":"skywalker.nick@gmail.com","username":"Nick"},"change_message_id":"7229ed2c61ccbe3e466edfc9317e6a91126bc102","unresolved":false,"context_lines":[{"line_number":151,"context_line":"            super(_CommonBase, self).__delattr__(key)"},{"line_number":152,"context_line":""},{"line_number":153,"context_line":"    def iterate_over_set_fields(self):"},{"line_number":154,"context_line":""},{"line_number":155,"context_line":"        for name, field in self:"},{"line_number":156,"context_line":"            if name in self._set_fields:"},{"line_number":157,"context_line":"                yield name, field"}],"source_content_type":"text/x-python","patch_set":23,"id":"1a430d35_c330b10a","line":154,"updated":"2017-02-03 09:07:17.000000000","message":"remove this blank line?","commit_id":"7ca4824f981a5ca72d627f3e4d2ff929203446c4"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"10b039569af6bb144235c1a7f4c2ddc0839a086a","unresolved":false,"context_lines":[{"line_number":151,"context_line":"            super(_CommonBase, self).__delattr__(key)"},{"line_number":152,"context_line":""},{"line_number":153,"context_line":"    def iterate_over_set_fields(self):"},{"line_number":154,"context_line":""},{"line_number":155,"context_line":"        for name, field in self:"},{"line_number":156,"context_line":"            if name in self._set_fields:"},{"line_number":157,"context_line":"                yield name, field"}],"source_content_type":"text/x-python","patch_set":23,"id":"1a430d35_237222ae","line":154,"in_reply_to":"1a430d35_c330b10a","updated":"2017-02-05 09:26:35.000000000","message":"Done","commit_id":"7ca4824f981a5ca72d627f3e4d2ff929203446c4"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"573566b82fd2775dcf44a1d84b53ebe802ea5b91","unresolved":false,"context_lines":[{"line_number":161,"context_line":"        return name in self._set_fields"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":""},{"line_number":164,"context_line":"def _get_emit_func(event):"},{"line_number":165,"context_line":"    def emit_event(self, *args, **kwargs):"},{"line_number":166,"context_line":"        self._emit(event, *args, **kwargs)"},{"line_number":167,"context_line":"    return emit_event"}],"source_content_type":"text/x-python","patch_set":23,"id":"1a430d35_6088a523","line":164,"range":{"start_line":164,"start_character":0,"end_line":164,"end_character":26},"updated":"2017-02-04 18:42:06.000000000","message":"Where is this function used? Where would it be used?","commit_id":"7ca4824f981a5ca72d627f3e4d2ff929203446c4"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"10b039569af6bb144235c1a7f4c2ddc0839a086a","unresolved":false,"context_lines":[{"line_number":161,"context_line":"        return name in self._set_fields"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":""},{"line_number":164,"context_line":"def _get_emit_func(event):"},{"line_number":165,"context_line":"    def emit_event(self, *args, **kwargs):"},{"line_number":166,"context_line":"        self._emit(event, *args, **kwargs)"},{"line_number":167,"context_line":"    return emit_event"}],"source_content_type":"text/x-python","patch_set":23,"id":"1a430d35_4369eebd","line":164,"range":{"start_line":164,"start_character":0,"end_line":164,"end_character":26},"in_reply_to":"1a430d35_6088a523","updated":"2017-02-05 09:26:35.000000000","message":"Removing","commit_id":"7ca4824f981a5ca72d627f3e4d2ff929203446c4"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"573566b82fd2775dcf44a1d84b53ebe802ea5b91","unresolved":false,"context_lines":[{"line_number":184,"context_line":""},{"line_number":185,"context_line":"    def emit_event(self, *args, **kwargs):"},{"line_number":186,"context_line":"        return self._emit(event, *args, **kwargs)"},{"line_number":187,"context_line":""},{"line_number":188,"context_line":"    emit_event_name \u003d \u0027emit_{0}\u0027.format(event)"},{"line_number":189,"context_line":"    emit_event.__name__ \u003d emit_event_name"},{"line_number":190,"context_line":"    setattr(cls_, emit_event_name, emit_event)"}],"source_content_type":"text/x-python","patch_set":23,"id":"1a430d35_a0828dfe","line":187,"updated":"2017-02-04 18:42:06.000000000","message":"nit: Blank line","commit_id":"7ca4824f981a5ca72d627f3e4d2ff929203446c4"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"10b039569af6bb144235c1a7f4c2ddc0839a086a","unresolved":false,"context_lines":[{"line_number":184,"context_line":""},{"line_number":185,"context_line":"    def emit_event(self, *args, **kwargs):"},{"line_number":186,"context_line":"        return self._emit(event, *args, **kwargs)"},{"line_number":187,"context_line":""},{"line_number":188,"context_line":"    emit_event_name \u003d \u0027emit_{0}\u0027.format(event)"},{"line_number":189,"context_line":"    emit_event.__name__ \u003d emit_event_name"},{"line_number":190,"context_line":"    setattr(cls_, emit_event_name, emit_event)"}],"source_content_type":"text/x-python","patch_set":23,"id":"1a430d35_63642ae5","line":187,"in_reply_to":"1a430d35_a0828dfe","updated":"2017-02-05 09:26:35.000000000","message":"removing","commit_id":"7ca4824f981a5ca72d627f3e4d2ff929203446c4"},{"author":{"_account_id":7805,"name":"Li Ma","email":"skywalker.nick@gmail.com","username":"Nick"},"change_message_id":"7229ed2c61ccbe3e466edfc9317e6a91126bc102","unresolved":false,"context_lines":[{"line_number":278,"context_line":"    for lookup in ("},{"line_number":279,"context_line":"        _lookup_by_class_name,"},{"line_number":280,"context_line":"        _lookup_by_table_name,"},{"line_number":281,"context_line":"        df_models.table_class_mapping,"},{"line_number":282,"context_line":"    ):"},{"line_number":283,"context_line":"        try:"},{"line_number":284,"context_line":"            return lookup[arg]"}],"source_content_type":"text/x-python","patch_set":23,"id":"1a430d35_5e3e54b9","line":281,"range":{"start_line":281,"start_character":8,"end_line":281,"end_character":38},"updated":"2017-02-03 09:07:17.000000000","message":"why still using old models, if a table is registered based on this new model? is it a temporary solution before all old models are upgraded?","commit_id":"7ca4824f981a5ca72d627f3e4d2ff929203446c4"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"10b039569af6bb144235c1a7f4c2ddc0839a086a","unresolved":false,"context_lines":[{"line_number":278,"context_line":"    for lookup in ("},{"line_number":279,"context_line":"        _lookup_by_class_name,"},{"line_number":280,"context_line":"        _lookup_by_table_name,"},{"line_number":281,"context_line":"        df_models.table_class_mapping,"},{"line_number":282,"context_line":"    ):"},{"line_number":283,"context_line":"        try:"},{"line_number":284,"context_line":"            return lookup[arg]"}],"source_content_type":"text/x-python","patch_set":23,"id":"1a430d35_e3773a9d","line":281,"range":{"start_line":281,"start_character":8,"end_line":281,"end_character":38},"in_reply_to":"1a430d35_5e3e54b9","updated":"2017-02-05 09:26:35.000000000","message":"Yes, this is added for external code that wants to get model regardless of whether it is new or old style. Will drop once we migrate all models.","commit_id":"7ca4824f981a5ca72d627f3e4d2ff929203446c4"},{"author":{"_account_id":11159,"name":"Hong Hui Xiao","email":"honghui_xiao@yeah.net","username":"HongHuiXiao"},"change_message_id":"0bf7025d43647ed45442dd280497e171e15a7763","unresolved":false,"context_lines":[{"line_number":92,"context_line":"            try:"},{"line_number":93,"context_line":"                cb(self, *args, **kwargs)"},{"line_number":94,"context_line":"            except Exception:"},{"line_number":95,"context_line":"                LOG.exception("},{"line_number":96,"context_line":"                    _LE(\u0027Error while calling %(func)r(*%(_args)r, **%(kw)r)\u0027),"},{"line_number":97,"context_line":"                    extra\u003d{\u0027func\u0027: cb, \u0027_args\u0027: args, \u0027kw\u0027: kwargs},"},{"line_number":98,"context_line":"                )"},{"line_number":99,"context_line":""},{"line_number":100,"context_line":"    @classmethod"},{"line_number":101,"context_line":"    def register(cls, event, cb):"}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_0cbaaec0","line":98,"range":{"start_line":95,"start_character":0,"end_line":98,"end_character":17},"updated":"2017-02-06 02:38:19.000000000","message":"Does it make sense to add a flag to propagate the exception out? It could be default to false. While sometimes the caller might be interested in what is going wrong.","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"febe569e38972c51184eedca1f852006238aa100","unresolved":false,"context_lines":[{"line_number":92,"context_line":"            try:"},{"line_number":93,"context_line":"                cb(self, *args, **kwargs)"},{"line_number":94,"context_line":"            except Exception:"},{"line_number":95,"context_line":"                LOG.exception("},{"line_number":96,"context_line":"                    _LE(\u0027Error while calling %(func)r(*%(_args)r, **%(kw)r)\u0027),"},{"line_number":97,"context_line":"                    extra\u003d{\u0027func\u0027: cb, \u0027_args\u0027: args, \u0027kw\u0027: kwargs},"},{"line_number":98,"context_line":"                )"},{"line_number":99,"context_line":""},{"line_number":100,"context_line":"    @classmethod"},{"line_number":101,"context_line":"    def register(cls, event, cb):"}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_c0e86713","line":98,"range":{"start_line":95,"start_character":0,"end_line":98,"end_character":17},"in_reply_to":"1a430d35_0cbaaec0","updated":"2017-02-06 06:32:59.000000000","message":"I think its best to add it once we see that it is needed.\n\nThere are several ways (raise first, raise last, stop on exception, finish all then raise...) to do it and without a clear scenario, none is better than the others.","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"},{"author":{"_account_id":11159,"name":"Hong Hui Xiao","email":"honghui_xiao@yeah.net","username":"HongHuiXiao"},"change_message_id":"0bf7025d43647ed45442dd280497e171e15a7763","unresolved":false,"context_lines":[{"line_number":107,"context_line":"        \u0027\u0027\u0027Unregisters `cb` from being called each time `event` is emitted\u0027\u0027\u0027"},{"line_number":108,"context_line":"        cls._event_callbacks[event].remove(cb)"},{"line_number":109,"context_line":""},{"line_number":110,"context_line":"    @classmethod"},{"line_number":111,"context_line":"    def get_events(self):"},{"line_number":112,"context_line":"        \u0027\u0027\u0027Events defined for this model\u0027\u0027\u0027"},{"line_number":113,"context_line":"        return frozenset()"},{"line_number":114,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_2c83ea05","line":111,"range":{"start_line":110,"start_character":0,"end_line":111,"end_character":25},"updated":"2017-02-06 02:38:19.000000000","message":"Doesn\u0027t the classmethod need class object as its first parameter?","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"febe569e38972c51184eedca1f852006238aa100","unresolved":false,"context_lines":[{"line_number":107,"context_line":"        \u0027\u0027\u0027Unregisters `cb` from being called each time `event` is emitted\u0027\u0027\u0027"},{"line_number":108,"context_line":"        cls._event_callbacks[event].remove(cb)"},{"line_number":109,"context_line":""},{"line_number":110,"context_line":"    @classmethod"},{"line_number":111,"context_line":"    def get_events(self):"},{"line_number":112,"context_line":"        \u0027\u0027\u0027Events defined for this model\u0027\u0027\u0027"},{"line_number":113,"context_line":"        return frozenset()"},{"line_number":114,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_2513fd67","line":111,"range":{"start_line":110,"start_character":0,"end_line":111,"end_character":25},"in_reply_to":"1a430d35_2c83ea05","updated":"2017-02-06 06:32:59.000000000","message":"Oops, fixing.","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"},{"author":{"_account_id":11159,"name":"Hong Hui Xiao","email":"honghui_xiao@yeah.net","username":"HongHuiXiao"},"change_message_id":"0bf7025d43647ed45442dd280497e171e15a7763","unresolved":false,"context_lines":[{"line_number":112,"context_line":"        \u0027\u0027\u0027Events defined for this model\u0027\u0027\u0027"},{"line_number":113,"context_line":"        return frozenset()"},{"line_number":114,"context_line":""},{"line_number":115,"context_line":"    @classmethod"},{"line_number":116,"context_line":"    def get_indexes(self):"},{"line_number":117,"context_line":"        \u0027\u0027\u0027Indexes defined for this model\u0027\u0027\u0027"},{"line_number":118,"context_line":"        return {}"},{"line_number":119,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_4c867614","line":116,"range":{"start_line":115,"start_character":0,"end_line":116,"end_character":26},"updated":"2017-02-06 02:38:19.000000000","message":"ditto","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"},{"author":{"_account_id":11159,"name":"Hong Hui Xiao","email":"honghui_xiao@yeah.net","username":"HongHuiXiao"},"change_message_id":"0bf7025d43647ed45442dd280497e171e15a7763","unresolved":false,"context_lines":[{"line_number":147,"context_line":""},{"line_number":148,"context_line":"    def __delattr__(self, key):"},{"line_number":149,"context_line":"        if key in self._field_names:"},{"line_number":150,"context_line":"            setattr(self, key, None)"},{"line_number":151,"context_line":"            self._set_fields.discard(key)"},{"line_number":152,"context_line":"        else:"},{"line_number":153,"context_line":"            super(_CommonBase, self).__delattr__(key)"}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_acdc3a13","line":150,"range":{"start_line":150,"start_character":0,"end_line":150,"end_character":36},"updated":"2017-02-06 02:38:19.000000000","message":"Where was the \u0027key\u0027 set to self?","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"febe569e38972c51184eedca1f852006238aa100","unresolved":false,"context_lines":[{"line_number":147,"context_line":""},{"line_number":148,"context_line":"    def __delattr__(self, key):"},{"line_number":149,"context_line":"        if key in self._field_names:"},{"line_number":150,"context_line":"            setattr(self, key, None)"},{"line_number":151,"context_line":"            self._set_fields.discard(key)"},{"line_number":152,"context_line":"        else:"},{"line_number":153,"context_line":"            super(_CommonBase, self).__delattr__(key)"}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_c0ba2723","line":150,"range":{"start_line":150,"start_character":0,"end_line":150,"end_character":36},"in_reply_to":"1a430d35_acdc3a13","updated":"2017-02-06 06:32:59.000000000","message":"All fields are initialized by the constructor in jsonmodels.","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"},{"author":{"_account_id":11159,"name":"Hong Hui Xiao","email":"honghui_xiao@yeah.net","username":"HongHuiXiao"},"change_message_id":"0bf7025d43647ed45442dd280497e171e15a7763","unresolved":false,"context_lines":[{"line_number":166,"context_line":"    @classmethod"},{"line_number":167,"context_line":"    def register_event(cls, cb):"},{"line_number":168,"context_line":"        cls.register(event, cb)"},{"line_number":169,"context_line":"    register_event_name \u003d \u0027register_{0}\u0027.format(event)"},{"line_number":170,"context_line":"    register_event.__func__.__name__ \u003d register_event_name"},{"line_number":171,"context_line":"    setattr(cls_, register_event_name, register_event)"},{"line_number":172,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_0c09cedd","line":169,"updated":"2017-02-06 02:38:19.000000000","message":"nit: better to add an extra line after method defination.","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"febe569e38972c51184eedca1f852006238aa100","unresolved":false,"context_lines":[{"line_number":166,"context_line":"    @classmethod"},{"line_number":167,"context_line":"    def register_event(cls, cb):"},{"line_number":168,"context_line":"        cls.register(event, cb)"},{"line_number":169,"context_line":"    register_event_name \u003d \u0027register_{0}\u0027.format(event)"},{"line_number":170,"context_line":"    register_event.__func__.__name__ \u003d register_event_name"},{"line_number":171,"context_line":"    setattr(cls_, register_event_name, register_event)"},{"line_number":172,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_20868b65","line":169,"in_reply_to":"1a430d35_0c09cedd","updated":"2017-02-06 06:32:59.000000000","message":"Adding","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"},{"author":{"_account_id":11159,"name":"Hong Hui Xiao","email":"honghui_xiao@yeah.net","username":"HongHuiXiao"},"change_message_id":"0bf7025d43647ed45442dd280497e171e15a7763","unresolved":false,"context_lines":[{"line_number":173,"context_line":"    @classmethod"},{"line_number":174,"context_line":"    def unregister_event(cls, cb):"},{"line_number":175,"context_line":"        cls.unregister(event, cb)"},{"line_number":176,"context_line":"    unregister_event_name \u003d \u0027unregister_{0}\u0027.format(event)"},{"line_number":177,"context_line":"    unregister_event.__func__.__name__ \u003d unregister_event_name"},{"line_number":178,"context_line":"    setattr(cls_, unregister_event_name, unregister_event)"},{"line_number":179,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_2c104a01","line":176,"updated":"2017-02-06 02:38:19.000000000","message":"ditto","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"},{"author":{"_account_id":11159,"name":"Hong Hui Xiao","email":"honghui_xiao@yeah.net","username":"HongHuiXiao"},"change_message_id":"0bf7025d43647ed45442dd280497e171e15a7763","unresolved":false,"context_lines":[{"line_number":179,"context_line":""},{"line_number":180,"context_line":"    def emit_event(self, *args, **kwargs):"},{"line_number":181,"context_line":"        return self._emit(event, *args, **kwargs)"},{"line_number":182,"context_line":"    emit_event_name \u003d \u0027emit_{0}\u0027.format(event)"},{"line_number":183,"context_line":"    emit_event.__name__ \u003d emit_event_name"},{"line_number":184,"context_line":"    setattr(cls_, emit_event_name, emit_event)"},{"line_number":185,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_ac043ac0","line":182,"updated":"2017-02-06 02:38:19.000000000","message":"ditto","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"},{"author":{"_account_id":7805,"name":"Li Ma","email":"skywalker.nick@gmail.com","username":"Nick"},"change_message_id":"ba6361ebedc0352196b6d7eb2469fc8ff715a4fc","unresolved":false,"context_lines":[{"line_number":200,"context_line":"    if indexes is None:"},{"line_number":201,"context_line":"        indexes \u003d {}"},{"line_number":202,"context_line":""},{"line_number":203,"context_line":"    indexes \u003d {k: _normalize_tuple(v) for k, v in six.iteritems(indexes)}"},{"line_number":204,"context_line":""},{"line_number":205,"context_line":"    def decorator(cls_):"},{"line_number":206,"context_line":"        event_callbacks \u003d collections.defaultdict(set)"}],"source_content_type":"text/x-python","patch_set":25,"id":"1a430d35_d2d9b958","line":203,"range":{"start_line":203,"start_character":50,"end_line":203,"end_character":63},"updated":"2017-02-08 01:53:42.000000000","message":"https://review.openstack.org/#/c/429593/\nThis discussion happened in the openstack-dev mailing list.\nhttp://lists.openstack.org/pipermail/openstack-dev/2015-June/066397.html","commit_id":"b922bbc356e01b0c41b3cd53097c7bbc834dc05e"},{"author":{"_account_id":7805,"name":"Li Ma","email":"skywalker.nick@gmail.com","username":"Nick"},"change_message_id":"ba6361ebedc0352196b6d7eb2469fc8ff715a4fc","unresolved":false,"context_lines":[{"line_number":287,"context_line":""},{"line_number":288,"context_line":"def iter_models():"},{"line_number":289,"context_line":"    \u0027\u0027\u0027Iterate over all registered models\u0027\u0027\u0027"},{"line_number":290,"context_line":"    for model in six.itervalues(_lookup_by_class_name):"},{"line_number":291,"context_line":"        yield model"},{"line_number":292,"context_line":""},{"line_number":293,"context_line":""}],"source_content_type":"text/x-python","patch_set":25,"id":"1a430d35_72ef25e9","line":290,"range":{"start_line":290,"start_character":17,"end_line":290,"end_character":31},"updated":"2017-02-08 01:53:42.000000000","message":"ditto","commit_id":"b922bbc356e01b0c41b3cd53097c7bbc834dc05e"}],"dragonflow/tests/unit/test_model_framework.py":[{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"c21425b1ef1195828bf71220f02a6ac3411000e1","unresolved":false,"context_lines":[{"line_number":66,"context_line":"    foo \u003d fields.StringField()"},{"line_number":67,"context_line":"    bar \u003d fields.StringField()"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"@mf.construct_nb_db_model"},{"line_number":71,"context_line":"class ModelWithEventsMixin(ModelWithEvents, EventsMixin):"},{"line_number":72,"context_line":"    pass"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_127d61e7","line":69,"updated":"2017-01-15 17:04:10.000000000","message":"No register_model on this model?","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b0e52dd6607469512d87690f10d455b161bcc6e8","unresolved":false,"context_lines":[{"line_number":66,"context_line":"    foo \u003d fields.StringField()"},{"line_number":67,"context_line":"    bar \u003d fields.StringField()"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"@mf.construct_nb_db_model"},{"line_number":71,"context_line":"class ModelWithEventsMixin(ModelWithEvents, EventsMixin):"},{"line_number":72,"context_line":"    pass"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_7435a7d8","line":69,"in_reply_to":"7a3c09a3_127d61e7","updated":"2017-01-16 08:17:23.000000000","message":"Register is needed only for models we expect to find by table name.","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"c21425b1ef1195828bf71220f02a6ac3411000e1","unresolved":false,"context_lines":[{"line_number":71,"context_line":"class ModelWithEventsMixin(ModelWithEvents, EventsMixin):"},{"line_number":72,"context_line":"    pass"},{"line_number":73,"context_line":""},{"line_number":74,"context_line":""},{"line_number":75,"context_line":"@mf.construct_nb_db_model(indexes\u003dnamespace.Namespace(foo\u003d\u0027bar\u0027))"},{"line_number":76,"context_line":"class ModelWithIndexesMixin(ModelTestWithIndexes, IndexesMixin):"},{"line_number":77,"context_line":"    pass"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_726ea530","line":74,"updated":"2017-01-15 17:04:10.000000000","message":"Same here","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"c21425b1ef1195828bf71220f02a6ac3411000e1","unresolved":false,"context_lines":[{"line_number":92,"context_line":"                         dict(ModelTestWithMoreIndexes.get_indexes()))"},{"line_number":93,"context_line":""},{"line_number":94,"context_line":"    def test_events_inheritance(self):"},{"line_number":95,"context_line":"        self.assertEqual(set((\u0027event1\u0027, \u0027event2\u0027)),"},{"line_number":96,"context_line":"                         set(ModelWithEvents.get_events()))"},{"line_number":97,"context_line":"        self.assertEqual(set((\u0027event1\u0027, \u0027event2\u0027, \u0027event3\u0027)),"},{"line_number":98,"context_line":"                         set(ModelWithMoreEvents.get_events()))"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_d24af9ab","line":95,"range":{"start_line":95,"start_character":13,"end_line":95,"end_character":24},"updated":"2017-01-15 17:04:10.000000000","message":"I think assertItemsEqual is more suitable here.","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b0e52dd6607469512d87690f10d455b161bcc6e8","unresolved":false,"context_lines":[{"line_number":92,"context_line":"                         dict(ModelTestWithMoreIndexes.get_indexes()))"},{"line_number":93,"context_line":""},{"line_number":94,"context_line":"    def test_events_inheritance(self):"},{"line_number":95,"context_line":"        self.assertEqual(set((\u0027event1\u0027, \u0027event2\u0027)),"},{"line_number":96,"context_line":"                         set(ModelWithEvents.get_events()))"},{"line_number":97,"context_line":"        self.assertEqual(set((\u0027event1\u0027, \u0027event2\u0027, \u0027event3\u0027)),"},{"line_number":98,"context_line":"                         set(ModelWithMoreEvents.get_events()))"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_b44d4f74","line":95,"range":{"start_line":95,"start_character":13,"end_line":95,"end_character":24},"in_reply_to":"7a3c09a3_d24af9ab","updated":"2017-01-16 08:17:23.000000000","message":"Will change","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"c21425b1ef1195828bf71220f02a6ac3411000e1","unresolved":false,"context_lines":[{"line_number":94,"context_line":"    def test_events_inheritance(self):"},{"line_number":95,"context_line":"        self.assertEqual(set((\u0027event1\u0027, \u0027event2\u0027)),"},{"line_number":96,"context_line":"                         set(ModelWithEvents.get_events()))"},{"line_number":97,"context_line":"        self.assertEqual(set((\u0027event1\u0027, \u0027event2\u0027, \u0027event3\u0027)),"},{"line_number":98,"context_line":"                         set(ModelWithMoreEvents.get_events()))"},{"line_number":99,"context_line":""},{"line_number":100,"context_line":"    def test_event_register_emit(self):"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_f2c7f50f","line":97,"range":{"start_line":97,"start_character":13,"end_line":97,"end_character":24},"updated":"2017-01-15 17:04:10.000000000","message":"And here","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"c21425b1ef1195828bf71220f02a6ac3411000e1","unresolved":false,"context_lines":[{"line_number":121,"context_line":""},{"line_number":122,"context_line":"        m1.assert_not_called()"},{"line_number":123,"context_line":""},{"line_number":124,"context_line":"    def test_mixin_mro_events(self):"},{"line_number":125,"context_line":"        self.assertEqual(set((\u0027event1\u0027, \u0027event2\u0027, \u0027foo\u0027, \u0027bar\u0027)),"},{"line_number":126,"context_line":"                         set(ModelWithEventsMixin.get_events()))"},{"line_number":127,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_32d25dd3","line":124,"range":{"start_line":124,"start_character":19,"end_line":124,"end_character":22},"updated":"2017-01-15 17:04:10.000000000","message":"Maybe rename to \u0027test_mixin_aggregate_events\u0027","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b0e52dd6607469512d87690f10d455b161bcc6e8","unresolved":false,"context_lines":[{"line_number":121,"context_line":""},{"line_number":122,"context_line":"        m1.assert_not_called()"},{"line_number":123,"context_line":""},{"line_number":124,"context_line":"    def test_mixin_mro_events(self):"},{"line_number":125,"context_line":"        self.assertEqual(set((\u0027event1\u0027, \u0027event2\u0027, \u0027foo\u0027, \u0027bar\u0027)),"},{"line_number":126,"context_line":"                         set(ModelWithEventsMixin.get_events()))"},{"line_number":127,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_d4501b0d","line":124,"range":{"start_line":124,"start_character":19,"end_line":124,"end_character":22},"in_reply_to":"7a3c09a3_32d25dd3","updated":"2017-01-16 08:17:23.000000000","message":"Agree","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"c21425b1ef1195828bf71220f02a6ac3411000e1","unresolved":false,"context_lines":[{"line_number":122,"context_line":"        m1.assert_not_called()"},{"line_number":123,"context_line":""},{"line_number":124,"context_line":"    def test_mixin_mro_events(self):"},{"line_number":125,"context_line":"        self.assertEqual(set((\u0027event1\u0027, \u0027event2\u0027, \u0027foo\u0027, \u0027bar\u0027)),"},{"line_number":126,"context_line":"                         set(ModelWithEventsMixin.get_events()))"},{"line_number":127,"context_line":""},{"line_number":128,"context_line":"    def test_mixin_mro_indexes(self):"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_12cba11f","line":125,"range":{"start_line":125,"start_character":13,"end_line":125,"end_character":24},"updated":"2017-01-15 17:04:10.000000000","message":"And here","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"c21425b1ef1195828bf71220f02a6ac3411000e1","unresolved":false,"context_lines":[{"line_number":125,"context_line":"        self.assertEqual(set((\u0027event1\u0027, \u0027event2\u0027, \u0027foo\u0027, \u0027bar\u0027)),"},{"line_number":126,"context_line":"                         set(ModelWithEventsMixin.get_events()))"},{"line_number":127,"context_line":""},{"line_number":128,"context_line":"    def test_mixin_mro_indexes(self):"},{"line_number":129,"context_line":"        self.assertEqual({\u0027foo\u0027: \u0027bar\u0027, \u0027bar\u0027: \u0027bar\u0027, \u0027index1\u0027: \u0027field1\u0027,"},{"line_number":130,"context_line":"                          \u0027index2\u0027: (\u0027field2\u0027, \u0027field3\u0027)},"},{"line_number":131,"context_line":"                         dict(ModelWithIndexesMixin.get_indexes()))"}],"source_content_type":"text/x-python","patch_set":7,"id":"7a3c09a3_52d529b7","line":128,"range":{"start_line":128,"start_character":8,"end_line":128,"end_character":30},"updated":"2017-01-15 17:04:10.000000000","message":"Same here: test_mixin_aggregate_indexes","commit_id":"57ece8009f7e00a1970a78589ddfc5c5b6a7d114"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"8d5785ba68907be00786567d5319407cc800e3d0","unresolved":false,"context_lines":[{"line_number":105,"context_line":"    def test_callbacks_not_shared(self):"},{"line_number":106,"context_line":"        m1 \u003d mock.MagicMock()"},{"line_number":107,"context_line":"        m2 \u003d mock.MagicMock()"},{"line_number":108,"context_line":"        ModelWithEvents.register_event1(m1)"},{"line_number":109,"context_line":"        ModelWithMoreEvents().register_event1(m2)"},{"line_number":110,"context_line":"        ModelWithMoreEvents().emit_event1()"},{"line_number":111,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_1b20abf6","line":108,"updated":"2017-01-23 17:20:44.000000000","message":"There is a bit of confusion here when to call register/emit on the class, and when on the instance. Is that intentional? Maybe it should be documented.","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"b666cd0d040cd41bd5a04c8d4193b6d3efe9583c","unresolved":false,"context_lines":[{"line_number":105,"context_line":"    def test_callbacks_not_shared(self):"},{"line_number":106,"context_line":"        m1 \u003d mock.MagicMock()"},{"line_number":107,"context_line":"        m2 \u003d mock.MagicMock()"},{"line_number":108,"context_line":"        ModelWithEvents.register_event1(m1)"},{"line_number":109,"context_line":"        ModelWithMoreEvents().register_event1(m2)"},{"line_number":110,"context_line":"        ModelWithMoreEvents().emit_event1()"},{"line_number":111,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"5a3905b3_a7990c7b","line":108,"in_reply_to":"5a3905b3_1b20abf6","updated":"2017-01-24 13:53:38.000000000","message":"I agree that we need a bit more documentation about events, this part was not spec\u0027d in NB refactor doc, and SB refactor spec is not up yet either.\n\nCurrent convention is that register/unregister are @classmethods and emit is an instance method..\n\nWhen you emit an event, each callback receives the instance the event was emitted from as its first argument. This was done because most (all) uses of event emit did this:\n\n obj.emit_something_happened(obj)\n\nI though it would make sense callbacks should have the following signature:\n\n def cb(source, *args, **kwargs):\n     pass","commit_id":"fefe19a2f840e6397d1fe2a1d2e2cc26dbe82a63"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"0834ad0d7ada28caafe333dc941b418b5715d817","unresolved":false,"context_lines":[{"line_number":108,"context_line":"        m1 \u003d mock.MagicMock()"},{"line_number":109,"context_line":"        m2 \u003d mock.MagicMock()"},{"line_number":110,"context_line":"        ModelWithEvents.register_event1(m1)"},{"line_number":111,"context_line":"        ModelWithMoreEvents().register_event1(m2)"},{"line_number":112,"context_line":"        ModelWithMoreEvents().emit_event1()"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":"        m1.assert_not_called()"}],"source_content_type":"text/x-python","patch_set":17,"id":"3a461143_571cf4c0","line":111,"range":{"start_line":111,"start_character":0,"end_line":111,"end_character":49},"updated":"2017-01-29 13:37:12.000000000","message":"In that case, this should be renamed to:\nModelWithMoreEvents.register_event1(m2)","commit_id":"f7e9d6f6907ff5dec8f0b9e1f8e9c1aee3ba4d47"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"0834ad0d7ada28caafe333dc941b418b5715d817","unresolved":false,"context_lines":[{"line_number":111,"context_line":"        ModelWithMoreEvents().register_event1(m2)"},{"line_number":112,"context_line":"        ModelWithMoreEvents().emit_event1()"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":"        m1.assert_not_called()"},{"line_number":115,"context_line":"        m2.assert_called()"},{"line_number":116,"context_line":""},{"line_number":117,"context_line":"    def test_register_unregister(self):"}],"source_content_type":"text/x-python","patch_set":17,"id":"3a461143_777bb0f5","line":114,"range":{"start_line":114,"start_character":0,"end_line":114,"end_character":30},"updated":"2017-01-29 13:37:12.000000000","message":"Why is m1 not called? It was registered to event1, event1 was emitted, and m1 was never unregistered?","commit_id":"f7e9d6f6907ff5dec8f0b9e1f8e9c1aee3ba4d47"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"0834ad0d7ada28caafe333dc941b418b5715d817","unresolved":false,"context_lines":[{"line_number":144,"context_line":"    def test_update(self):"},{"line_number":145,"context_line":"        m \u003d ModelTest(field1\u003d\u0027a\u0027, field2\u003d\u0027b\u0027)"},{"line_number":146,"context_line":""},{"line_number":147,"context_line":"        m.update(ModelTest(field3\u003d\u0027c\u0027))"},{"line_number":148,"context_line":"        self.assertItemsEqual((\u0027field1\u0027, \u0027field2\u0027, \u0027field3\u0027),"},{"line_number":149,"context_line":"                              (n for n, _ in m.iterate_over_set_fields()))"},{"line_number":150,"context_line":""}],"source_content_type":"text/x-python","patch_set":17,"id":"3a461143_97801cc2","line":147,"updated":"2017-01-29 13:37:12.000000000","message":"Maybe also verify the return value is as expected?","commit_id":"f7e9d6f6907ff5dec8f0b9e1f8e9c1aee3ba4d47"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"643f21aa07204dd1dca91d42383a020677cc9fc8","unresolved":false,"context_lines":[{"line_number":111,"context_line":"        m1 \u003d mock.MagicMock()"},{"line_number":112,"context_line":"        m2 \u003d mock.MagicMock()"},{"line_number":113,"context_line":"        ModelWithEvents.register_event1(m1)"},{"line_number":114,"context_line":"        ModelWithMoreEvents().register_event1(m2)"},{"line_number":115,"context_line":"        ModelWithMoreEvents().emit_event1()"},{"line_number":116,"context_line":""},{"line_number":117,"context_line":"        m1.assert_not_called()"}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_4bbd2c01","line":114,"range":{"start_line":114,"start_character":27,"end_line":114,"end_character":29},"updated":"2017-01-30 03:46:02.000000000","message":"This is still confusing. Is it here on purpose?","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"5a047412592093ca0b5b438ffe5b41134e746c66","unresolved":false,"context_lines":[{"line_number":111,"context_line":"        m1 \u003d mock.MagicMock()"},{"line_number":112,"context_line":"        m2 \u003d mock.MagicMock()"},{"line_number":113,"context_line":"        ModelWithEvents.register_event1(m1)"},{"line_number":114,"context_line":"        ModelWithMoreEvents().register_event1(m2)"},{"line_number":115,"context_line":"        ModelWithMoreEvents().emit_event1()"},{"line_number":116,"context_line":""},{"line_number":117,"context_line":"        m1.assert_not_called()"}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_4f436d42","line":114,"range":{"start_line":114,"start_character":27,"end_line":114,"end_character":29},"in_reply_to":"3a461143_4bbd2c01","updated":"2017-01-30 13:40:18.000000000","message":"Actually I don\u0027t think its needed, removing","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"643f21aa07204dd1dca91d42383a020677cc9fc8","unresolved":false,"context_lines":[{"line_number":114,"context_line":"        ModelWithMoreEvents().register_event1(m2)"},{"line_number":115,"context_line":"        ModelWithMoreEvents().emit_event1()"},{"line_number":116,"context_line":""},{"line_number":117,"context_line":"        m1.assert_not_called()"},{"line_number":118,"context_line":"        m2.assert_called()"},{"line_number":119,"context_line":""},{"line_number":120,"context_line":"    def test_register_unregister(self):"}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_2bc4608f","line":117,"range":{"start_line":117,"start_character":0,"end_line":117,"end_character":30},"updated":"2017-01-30 03:46:02.000000000","message":"No matter. Now I see it.","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"643f21aa07204dd1dca91d42383a020677cc9fc8","unresolved":false,"context_lines":[{"line_number":149,"context_line":"    def test_update(self):"},{"line_number":150,"context_line":"        m \u003d ModelTest(field1\u003d\u0027a\u0027, field2\u003d\u0027b\u0027)"},{"line_number":151,"context_line":""},{"line_number":152,"context_line":"        m.update(ModelTest(field3\u003d\u0027c\u0027))"},{"line_number":153,"context_line":"        self.assertItemsEqual((\u0027field1\u0027, \u0027field2\u0027, \u0027field3\u0027),"},{"line_number":154,"context_line":"                              (n for n, _ in m.iterate_over_set_fields()))"},{"line_number":155,"context_line":""}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_8b39d4a6","line":152,"updated":"2017-01-30 03:46:02.000000000","message":"Please answer the comment from PS17:\n\n\u003e Maybe also verify the return value is as expected?","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"5a047412592093ca0b5b438ffe5b41134e746c66","unresolved":false,"context_lines":[{"line_number":149,"context_line":"    def test_update(self):"},{"line_number":150,"context_line":"        m \u003d ModelTest(field1\u003d\u0027a\u0027, field2\u003d\u0027b\u0027)"},{"line_number":151,"context_line":""},{"line_number":152,"context_line":"        m.update(ModelTest(field3\u003d\u0027c\u0027))"},{"line_number":153,"context_line":"        self.assertItemsEqual((\u0027field1\u0027, \u0027field2\u0027, \u0027field3\u0027),"},{"line_number":154,"context_line":"                              (n for n, _ in m.iterate_over_set_fields()))"},{"line_number":155,"context_line":""}],"source_content_type":"text/x-python","patch_set":20,"id":"3a461143_efa179f9","line":152,"in_reply_to":"3a461143_8b39d4a6","updated":"2017-01-30 13:40:18.000000000","message":"Done","commit_id":"61cdd47d523bc52d38d8c22e989c4a1c3a5d86ad"},{"author":{"_account_id":11159,"name":"Hong Hui Xiao","email":"honghui_xiao@yeah.net","username":"HongHuiXiao"},"change_message_id":"0bf7025d43647ed45442dd280497e171e15a7763","unresolved":false,"context_lines":[{"line_number":12,"context_line":"from jsonmodels import fields"},{"line_number":13,"context_line":"import mock"},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"import dragonflow.db.model_framework as mf"},{"line_number":16,"context_line":"from dragonflow.tests import base as tests_base"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_8cf4de87","line":15,"range":{"start_line":15,"start_character":0,"end_line":15,"end_character":42},"updated":"2017-02-06 02:38:19.000000000","message":"why using such pattern of import","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"},{"author":{"_account_id":23766,"name":"Dima Kuznetsov","email":"dima.kuznetsov@toganetworks.com","username":"dimak"},"change_message_id":"febe569e38972c51184eedca1f852006238aa100","unresolved":false,"context_lines":[{"line_number":12,"context_line":"from jsonmodels import fields"},{"line_number":13,"context_line":"import mock"},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"import dragonflow.db.model_framework as mf"},{"line_number":16,"context_line":"from dragonflow.tests import base as tests_base"},{"line_number":17,"context_line":""},{"line_number":18,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"1a430d35_60e173fe","line":15,"range":{"start_line":15,"start_character":0,"end_line":15,"end_character":42},"in_reply_to":"1a430d35_8cf4de87","updated":"2017-02-06 06:32:59.000000000","message":"Personal preference, as long as the new name is an abbreviation, I think it doesn\u0027t hurt readability.","commit_id":"0b5fd6595cfc4378818e71ef086907899a00f50b"}],"requirements.txt":[{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"0834ad0d7ada28caafe333dc941b418b5715d817","unresolved":false,"context_lines":[{"line_number":11,"context_line":"pyzmq\u003e\u003d14.3.1 # LGPL+BSD"},{"line_number":12,"context_line":"ryu\u003e\u003d4.9 # Apache-2.0"},{"line_number":13,"context_line":"SQLAlchemy\u003c1.1.0,\u003e\u003d1.0.10 # MIT"},{"line_number":14,"context_line":"alembic\u003e\u003d0.8.10 # MIT"},{"line_number":15,"context_line":"neutron-lib\u003e\u003d1.1.0 # Apache-2.0"},{"line_number":16,"context_line":"oslo.config!\u003d3.18.0,\u003e\u003d3.14.0 # Apache-2.0"},{"line_number":17,"context_line":"oslo.db\u003e\u003d4.15.0 # Apache-2.0"}],"source_content_type":"text/plain","patch_set":17,"id":"3a461143_b78198c5","line":14,"range":{"start_line":14,"start_character":13,"end_line":14,"end_character":15},"updated":"2017-01-29 13:37:12.000000000","message":"Why are you doing this manually?","commit_id":"f7e9d6f6907ff5dec8f0b9e1f8e9c1aee3ba4d47"},{"author":{"_account_id":20229,"name":"Omer Anson","email":"omer.anson@toganetworks.com","username":"oanson"},"change_message_id":"1b821b34eaa9513a8c9d958960790062c349d949","unresolved":false,"context_lines":[{"line_number":20,"context_line":"oslo.reports\u003e\u003d0.6.0 # Apache-2.0"},{"line_number":21,"context_line":"oslo.serialization\u003e\u003d1.10.0 # Apache-2.0"},{"line_number":22,"context_line":"crc16\u003e\u003d0.1.1 # LGPLv3+"},{"line_number":23,"context_line":"jsonmodels\u003e\u003d2.1.4 # BSD License (3 clause)"},{"line_number":24,"context_line":""}],"source_content_type":"text/plain","patch_set":21,"id":"3a461143_794d423d","line":23,"range":{"start_line":23,"start_character":0,"end_line":23,"end_character":42},"updated":"2017-01-30 20:04:29.000000000","message":"This has to be done in the requirements project first.","commit_id":"4dfe1c885aac2e7ddfdfcdbf3e1d470e3fa8d9cf"}]}
