)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":8106,"name":"Haomeng,Wang","email":"wanghaomeng@gmail.com","username":"whaom"},"change_message_id":"7d08d2f526611c4a6334bba9457ff722786afc20","unresolved":false,"context_lines":[{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Add Tag, TagList objects and a new tags field to Node"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Implements: blueprint nodes-tagging"},{"line_number":10,"context_line":"Change-Id: Ie0ff6ad6f83b4ae1029e57a0c55678ea9a525ba4"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":18,"id":"9a68dd71_bd91699b","line":9,"range":{"start_line":9,"start_character":0,"end_line":9,"end_character":35},"updated":"2016-01-22 05:23:32.000000000","message":"nit: We track features with RFE bugs from recently days, so can you remove this bp and add Partial-Bug or Related-Bug in commit messages, thanks.","commit_id":"a8b4d802f34488ee021f869b324c866fac72c0de"},{"author":{"_account_id":6773,"name":"Lucas Alvares Gomes","email":"lucasagomes@gmail.com","username":"lucasagomes"},"change_message_id":"5261c746807e63414f7adb59d2481a479e0f0e21","unresolved":false,"context_lines":[{"line_number":5,"context_line":"CommitDate: 2016-01-23 11:25:49 +0800"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Add Tag, TagList objects and a new tags field to Node"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Partial-bug: #1526266"},{"line_number":10,"context_line":"Change-Id: Ie0ff6ad6f83b4ae1029e57a0c55678ea9a525ba4"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":19,"id":"9a68dd71_e5d4c8ec","line":8,"updated":"2016-01-25 11:41:40.000000000","message":"The commit message needs a bit more information. For example:\n\n1- Version of the Nodes RPC object bumped to 1.5\n\n2- This patch do not include the tags field in the Node API object (this is going to be done in a subsequent patch)","commit_id":"9d99e4044f2945d907b7dfa36ee22ac3dfe6181f"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"98e82dd85340a107cb07177f91696b96a3b8ada5","unresolved":false,"context_lines":[{"line_number":5,"context_line":"CommitDate: 2016-01-23 11:25:49 +0800"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Add Tag, TagList objects and a new tags field to Node"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Partial-bug: #1526266"},{"line_number":10,"context_line":"Change-Id: Ie0ff6ad6f83b4ae1029e57a0c55678ea9a525ba4"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":19,"id":"9a68dd71_4da26d9c","line":8,"in_reply_to":"9a68dd71_e5d4c8ec","updated":"2016-01-26 08:30:55.000000000","message":"thanks Lucas, have done.","commit_id":"9d99e4044f2945d907b7dfa36ee22ac3dfe6181f"},{"author":{"_account_id":23883,"name":"Joanna Taryma","email":"joanna.taryma@intel.com","username":"jtaryma"},"change_message_id":"398a42d63e6abbe755c42fa7a95b36b60fad5157","unresolved":false,"context_lines":[{"line_number":4,"context_line":"Commit:     Zhenguo Niu \u003cNiu.ZGlinux@gmail.com\u003e"},{"line_number":5,"context_line":"CommitDate: 2017-01-25 11:41:38 +0800"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Add nodes tagging support - objs"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"- Version of the Nodes RPC object bumped to 1.22"},{"line_number":10,"context_line":"- This patch do not include the tags field in the Node"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":51,"id":"3a461143_08f066fd","line":7,"updated":"2017-01-30 22:44:25.000000000","message":"/objs/RPC objects/","commit_id":"f162914c7808677e7ab7faf6e612bc3e4ae25edf"},{"author":{"_account_id":14760,"name":"John L. Villalovos","email":"openstack.org@sodarock.com","username":"jlvillal"},"change_message_id":"6d0e269630c12326844f4035f08882d19b112134","unresolved":false,"context_lines":[{"line_number":7,"context_line":"Add nodes tagging support - RPC objects"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"- Version of the Nodes RPC object bumped to 1.22"},{"line_number":10,"context_line":"- This patch do not include the tags field in the Node"},{"line_number":11,"context_line":"API object (this is going to be done in a subsequent patch)"},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"Partial-bug: #1526266"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":52,"id":"fa31d9ce_2d517963","line":10,"range":{"start_line":10,"start_character":13,"end_line":10,"end_character":15},"updated":"2017-02-09 21:39:35.000000000","message":"nit:  s/do/does/","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"b847272f14615d404c21032a1aaf220b3bf359bf","unresolved":false,"context_lines":[{"line_number":7,"context_line":"Add nodes tagging support - RPC objects"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"- Version of the Nodes RPC object bumped to 1.22"},{"line_number":10,"context_line":"- This patch do not include the tags field in the Node"},{"line_number":11,"context_line":"API object (this is going to be done in a subsequent patch)"},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"Partial-bug: #1526266"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":52,"id":"fa31d9ce_8dc6e514","line":10,"range":{"start_line":10,"start_character":13,"end_line":10,"end_character":15},"updated":"2017-02-09 21:34:46.000000000","message":"nit: s/do/does","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"5333b4c10b0440ba9b68c8c0c98ec982329eacf6","unresolved":false,"context_lines":[{"line_number":7,"context_line":"Add nodes tagging support - RPC objects"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"- Version of the Nodes RPC object bumped to 1.22"},{"line_number":10,"context_line":"- This patch do not include the tags field in the Node"},{"line_number":11,"context_line":"API object (this is going to be done in a subsequent patch)"},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"Partial-bug: #1526266"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":52,"id":"fa31d9ce_74c41540","line":10,"range":{"start_line":10,"start_character":13,"end_line":10,"end_character":15},"in_reply_to":"fa31d9ce_2d517963","updated":"2017-02-10 02:48:39.000000000","message":"Done","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"5333b4c10b0440ba9b68c8c0c98ec982329eacf6","unresolved":false,"context_lines":[{"line_number":7,"context_line":"Add nodes tagging support - RPC objects"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"- Version of the Nodes RPC object bumped to 1.22"},{"line_number":10,"context_line":"- This patch do not include the tags field in the Node"},{"line_number":11,"context_line":"API object (this is going to be done in a subsequent patch)"},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"Partial-bug: #1526266"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":52,"id":"fa31d9ce_34ca9d50","line":10,"range":{"start_line":10,"start_character":13,"end_line":10,"end_character":15},"in_reply_to":"fa31d9ce_8dc6e514","updated":"2017-02-10 02:48:39.000000000","message":"Done","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"}],"ironic/common/release_mappings.py":[{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"cc2981e77f3f0153a085d0978d8d042bf3adaa64","unresolved":false,"context_lines":[{"line_number":73,"context_line":"        \u0027rpc\u0027: \u00271.41\u0027,"},{"line_number":74,"context_line":"        \u0027objects\u0027: {"},{"line_number":75,"context_line":"            \u0027Node\u0027: \u00271.22\u0027,"},{"line_number":76,"context_line":"            \u0027NodeTag\u0027: \u00271.0\u0027,"},{"line_number":77,"context_line":"            \u0027Conductor\u0027: \u00271.2\u0027,"},{"line_number":78,"context_line":"            \u0027Chassis\u0027: \u00271.3\u0027,"},{"line_number":79,"context_line":"            \u0027Port\u0027: \u00271.7\u0027,"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_8a351b49","line":76,"updated":"2017-07-14 02:07:48.000000000","message":"I think we should add NodeTagList too; I think they are both serialized/deserialized.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"2ecbee1294fba350c79e2fc53666df84901b877d","unresolved":false,"context_lines":[{"line_number":73,"context_line":"        \u0027rpc\u0027: \u00271.41\u0027,"},{"line_number":74,"context_line":"        \u0027objects\u0027: {"},{"line_number":75,"context_line":"            \u0027Node\u0027: \u00271.22\u0027,"},{"line_number":76,"context_line":"            \u0027NodeTag\u0027: \u00271.0\u0027,"},{"line_number":77,"context_line":"            \u0027Conductor\u0027: \u00271.2\u0027,"},{"line_number":78,"context_line":"            \u0027Chassis\u0027: \u00271.3\u0027,"},{"line_number":79,"context_line":"            \u0027Port\u0027: \u00271.7\u0027,"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_68bd0bd7","line":76,"in_reply_to":"1f1a1f67_4f381e3c","updated":"2017-07-14 14:13:04.000000000","message":"Seems like you\u0027re correct, we\u0027ll be calling convert_to_version if the object is an instance of IronicObject, NodeTagList is.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"a88ac43ccef3d546f15ef854ce63825b5cc0f127","unresolved":false,"context_lines":[{"line_number":73,"context_line":"        \u0027rpc\u0027: \u00271.41\u0027,"},{"line_number":74,"context_line":"        \u0027objects\u0027: {"},{"line_number":75,"context_line":"            \u0027Node\u0027: \u00271.22\u0027,"},{"line_number":76,"context_line":"            \u0027NodeTag\u0027: \u00271.0\u0027,"},{"line_number":77,"context_line":"            \u0027Conductor\u0027: \u00271.2\u0027,"},{"line_number":78,"context_line":"            \u0027Chassis\u0027: \u00271.3\u0027,"},{"line_number":79,"context_line":"            \u0027Port\u0027: \u00271.7\u0027,"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_4c2a082c","line":76,"in_reply_to":"1f1a1f67_4f381e3c","updated":"2017-07-18 14:33:35.000000000","message":"You scared me; I looked and we don\u0027t have a NodeList object :)","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"f3fb7f1cf8a6dd896290d03e3e28664560bdeabc","unresolved":false,"context_lines":[{"line_number":73,"context_line":"        \u0027rpc\u0027: \u00271.41\u0027,"},{"line_number":74,"context_line":"        \u0027objects\u0027: {"},{"line_number":75,"context_line":"            \u0027Node\u0027: \u00271.22\u0027,"},{"line_number":76,"context_line":"            \u0027NodeTag\u0027: \u00271.0\u0027,"},{"line_number":77,"context_line":"            \u0027Conductor\u0027: \u00271.2\u0027,"},{"line_number":78,"context_line":"            \u0027Chassis\u0027: \u00271.3\u0027,"},{"line_number":79,"context_line":"            \u0027Port\u0027: \u00271.7\u0027,"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_4f381e3c","line":76,"in_reply_to":"1f1a1f67_8a351b49","updated":"2017-07-14 13:23:38.000000000","message":"Not really sure here. I thought that the list object does not have any logic, only its items are serialized. otherwise we\u0027d have NodeList here?","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"}],"ironic/db/sqlalchemy/api.py":[{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"3befc71936a87ea082d2db505e23018fd22a92d6","unresolved":false,"context_lines":[{"line_number":256,"context_line":"        if \u0027provision_state\u0027 not in values:"},{"line_number":257,"context_line":"            values[\u0027provision_state\u0027] \u003d states.ENROLL"},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"        # TODO(zhenguo): Support creating node with tags"},{"line_number":260,"context_line":"        if \u0027tags\u0027 in values:"},{"line_number":261,"context_line":"            del values[\u0027tags\u0027]"},{"line_number":262,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_88e1f39c","line":259,"updated":"2016-01-28 16:21:43.000000000","message":"I think this should to to dbapi change. Also, not sure that we should just ignore this, maybe log something or throw an exception?","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"0eb4a21c1125c245e85dc77bc42ac2ac60f44cac","unresolved":false,"context_lines":[{"line_number":236,"context_line":"        else:"},{"line_number":237,"context_line":"            columns \u003d [getattr(models.Node, c) for c in columns]"},{"line_number":238,"context_line":""},{"line_number":239,"context_line":"        query \u003d model_query(*columns, base_model\u003dmodels.Node)"},{"line_number":240,"context_line":"        query \u003d self._add_nodes_filters(query, filters)"},{"line_number":241,"context_line":"        return _paginate_query(models.Node, limit, marker,"},{"line_number":242,"context_line":"                               sort_key, sort_dir, query)"}],"source_content_type":"text/x-python","patch_set":45,"id":"1a6eadb0_6f25e85a","line":239,"updated":"2016-12-19 18:01:35.000000000","message":"We don\u0027t want/need tags here?","commit_id":"914ed07d4f14fbe9f28a1a3478f80270b83fbc2a"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"04704727566b0842d5b8fea6c3f6d2505f75eb4d","unresolved":false,"context_lines":[{"line_number":246,"context_line":"        else:"},{"line_number":247,"context_line":"            columns \u003d [getattr(models.Node, c) for c in columns]"},{"line_number":248,"context_line":""},{"line_number":249,"context_line":"        query \u003d model_query(*columns, base_model\u003dmodels.Node)"},{"line_number":250,"context_line":"        query \u003d self._add_nodes_filters(query, filters)"},{"line_number":251,"context_line":"        return _paginate_query(models.Node, limit, marker,"},{"line_number":252,"context_line":"                               sort_key, sort_dir, query)"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_36570c59","line":249,"updated":"2017-01-24 15:26:34.000000000","message":"if we\u0027re getting a list of nodes and returning the specified node columns, doesn\u0027t this include tags? And if not, maybe we should add a comment about why not...","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"7712c9e38ef69ba08a03307e7ef7211ef7ba2bb8","unresolved":false,"context_lines":[{"line_number":246,"context_line":"        else:"},{"line_number":247,"context_line":"            columns \u003d [getattr(models.Node, c) for c in columns]"},{"line_number":248,"context_line":""},{"line_number":249,"context_line":"        query \u003d model_query(*columns, base_model\u003dmodels.Node)"},{"line_number":250,"context_line":"        query \u003d self._add_nodes_filters(query, filters)"},{"line_number":251,"context_line":"        return _paginate_query(models.Node, limit, marker,"},{"line_number":252,"context_line":"                               sort_key, sort_dir, query)"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_35a36251","line":249,"in_reply_to":"5a3905b3_10adb39a","updated":"2017-01-25 03:43:17.000000000","message":"yes, the comments is in next patch ;)","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"4695993a9305ee85606a6f127c4059d02e8f0514","unresolved":false,"context_lines":[{"line_number":246,"context_line":"        else:"},{"line_number":247,"context_line":"            columns \u003d [getattr(models.Node, c) for c in columns]"},{"line_number":248,"context_line":""},{"line_number":249,"context_line":"        query \u003d model_query(*columns, base_model\u003dmodels.Node)"},{"line_number":250,"context_line":"        query \u003d self._add_nodes_filters(query, filters)"},{"line_number":251,"context_line":"        return _paginate_query(models.Node, limit, marker,"},{"line_number":252,"context_line":"                               sort_key, sort_dir, query)"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_10adb39a","line":249,"in_reply_to":"5a3905b3_36570c59","updated":"2017-01-24 15:49:14.000000000","message":"Zhenguo has added a note on that in the next patch, as actual filtering is added there.","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"b847272f14615d404c21032a1aaf220b3bf359bf","unresolved":false,"context_lines":[{"line_number":918,"context_line":"        return model_query(q.exists()).scalar()"},{"line_number":919,"context_line":""},{"line_number":920,"context_line":"    def get_node_by_port_addresses(self, addresses):"},{"line_number":921,"context_line":"        q \u003d _get_node_query_with_tags()"},{"line_number":922,"context_line":"        q \u003d q.distinct().join(models.Port)"},{"line_number":923,"context_line":"        q \u003d q.filter(models.Port.address.in_(addresses))"},{"line_number":924,"context_line":""}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_2dadf931","line":921,"updated":"2017-02-09 21:34:46.000000000","message":"This is so we return node tags with the node, right?","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"5333b4c10b0440ba9b68c8c0c98ec982329eacf6","unresolved":false,"context_lines":[{"line_number":918,"context_line":"        return model_query(q.exists()).scalar()"},{"line_number":919,"context_line":""},{"line_number":920,"context_line":"    def get_node_by_port_addresses(self, addresses):"},{"line_number":921,"context_line":"        q \u003d _get_node_query_with_tags()"},{"line_number":922,"context_line":"        q \u003d q.distinct().join(models.Port)"},{"line_number":923,"context_line":"        q \u003d q.filter(models.Port.address.in_(addresses))"},{"line_number":924,"context_line":""}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_34261d17","line":921,"in_reply_to":"fa31d9ce_2dadf931","updated":"2017-02-10 02:48:39.000000000","message":"yes, this will joined load the tags.","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"e38aa18c034ba81039447a5f0936078d4250fb0d","unresolved":false,"context_lines":[{"line_number":433,"context_line":"    @oslo_db_api.retry_on_deadlock"},{"line_number":434,"context_line":"    def _do_update_node(self, node_id, values):"},{"line_number":435,"context_line":"        with _session_for_write():"},{"line_number":436,"context_line":"            query \u003d _get_node_query_with_tags()"},{"line_number":437,"context_line":"            query \u003d add_identity_filter(query, node_id)"},{"line_number":438,"context_line":"            try:"},{"line_number":439,"context_line":"                ref \u003d query.with_lockmode(\u0027update\u0027).one()"}],"source_content_type":"text/x-python","patch_set":58,"id":"bf091321_e761973b","line":436,"updated":"2017-06-08 11:26:47.000000000","message":"Had to change this as unittests started to fail whenever doing node.save, saying:\n\n Parent instance is not bound to a Session\n\nThis makes me wonder do we really want to join the tags lasily? We could just change to lazy\u003dFalse in models.py relationship definition and forget about inserting options(joinedload(\u0027tags\u0027)) everywhere IIUC.","commit_id":"098c66e18c83252506217ffdec0a6bbaa52ae082"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"cc2981e77f3f0153a085d0978d8d042bf3adaa64","unresolved":false,"context_lines":[{"line_number":330,"context_line":"                        node\u003dvalues[\u0027uuid\u0027])"},{"line_number":331,"context_line":"                raise exception.NodeAlreadyExists(uuid\u003dvalues[\u0027uuid\u0027])"},{"line_number":332,"context_line":"            # Set tags to [] for new created node"},{"line_number":333,"context_line":"            node[\u0027tags\u0027] \u003d []"},{"line_number":334,"context_line":"            return node"},{"line_number":335,"context_line":""},{"line_number":336,"context_line":"    def get_node_by_id(self, node_id):"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_da375cb0","line":333,"updated":"2017-07-14 02:07:48.000000000","message":"I think this is wrong, even though we merged that code. models.Node() has no tags field. It seems to me that the abstraction (or whatever you call it) should be at the level where tags exists; in the VersionedObject layer. This seems to be a bit of a \u0027hack\u0027 and not very obvious.\n\nIt was confusing me, because I knew that \u0027tags\u0027 wasn\u0027t in the model, yet in objects.node.Node._set_from_db_object() it looked like it did exist. It seems to me that db_node[\u0027tags\u0027] will always be an empty list since we never save that in the DB. So maybe it would be better to change the _set_from_db_object() to do self.tags \u003d None if None is allowed, or \u003d tags.NodeTagList() (or whatever an empty list is).","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"d2d39fa7e5f284c2d180baaaa76cb57efb53d2dd","unresolved":false,"context_lines":[{"line_number":330,"context_line":"                        node\u003dvalues[\u0027uuid\u0027])"},{"line_number":331,"context_line":"                raise exception.NodeAlreadyExists(uuid\u003dvalues[\u0027uuid\u0027])"},{"line_number":332,"context_line":"            # Set tags to [] for new created node"},{"line_number":333,"context_line":"            node[\u0027tags\u0027] \u003d []"},{"line_number":334,"context_line":"            return node"},{"line_number":335,"context_line":""},{"line_number":336,"context_line":"    def get_node_by_id(self, node_id):"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_084a177f","line":333,"in_reply_to":"1f1a1f67_da375cb0","updated":"2017-07-14 15:15:50.000000000","message":"As I said replying to another comment, tags are joined by joinedload on the dbapi level, so it might make sense to do it here. and we should only set None (or empty list or whatever) to tags in create case, so I guess we won\u0027t be able to do this in _set_from_db_object, otherwise this would affect all the calls to get the node.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"cc2981e77f3f0153a085d0978d8d042bf3adaa64","unresolved":false,"context_lines":[{"line_number":415,"context_line":"        if \u0027uuid\u0027 in values:"},{"line_number":416,"context_line":"            msg \u003d _(\"Cannot overwrite UUID for an existing Node.\")"},{"line_number":417,"context_line":"            raise exception.InvalidParameterValue(err\u003dmsg)"},{"line_number":418,"context_line":""},{"line_number":419,"context_line":"        try:"},{"line_number":420,"context_line":"            return self._do_update_node(node_id, values)"},{"line_number":421,"context_line":"        except db_exc.DBDuplicateEntry as e:"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_da051cc4","line":418,"updated":"2017-07-14 02:07:48.000000000","message":"Do we know whether it is impossible for \u0027tags\u0027 to be in values? And/or maybe we should guard against it anyway, like create_node() does.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"d2d39fa7e5f284c2d180baaaa76cb57efb53d2dd","unresolved":false,"context_lines":[{"line_number":415,"context_line":"        if \u0027uuid\u0027 in values:"},{"line_number":416,"context_line":"            msg \u003d _(\"Cannot overwrite UUID for an existing Node.\")"},{"line_number":417,"context_line":"            raise exception.InvalidParameterValue(err\u003dmsg)"},{"line_number":418,"context_line":""},{"line_number":419,"context_line":"        try:"},{"line_number":420,"context_line":"            return self._do_update_node(node_id, values)"},{"line_number":421,"context_line":"        except db_exc.DBDuplicateEntry as e:"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_2815d34a","line":418,"in_reply_to":"1f1a1f67_cf430eaf","updated":"2017-07-14 15:15:50.000000000","message":"Yup, we should ignore it here.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"f3fb7f1cf8a6dd896290d03e3e28664560bdeabc","unresolved":false,"context_lines":[{"line_number":415,"context_line":"        if \u0027uuid\u0027 in values:"},{"line_number":416,"context_line":"            msg \u003d _(\"Cannot overwrite UUID for an existing Node.\")"},{"line_number":417,"context_line":"            raise exception.InvalidParameterValue(err\u003dmsg)"},{"line_number":418,"context_line":""},{"line_number":419,"context_line":"        try:"},{"line_number":420,"context_line":"            return self._do_update_node(node_id, values)"},{"line_number":421,"context_line":"        except db_exc.DBDuplicateEntry as e:"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_cf430eaf","line":418,"in_reply_to":"1f1a1f67_da051cc4","updated":"2017-07-14 13:23:38.000000000","message":"hrm, maybe.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"39d604312cd2814942154eab571d8b00d11a4416","unresolved":false,"context_lines":[{"line_number":418,"context_line":""},{"line_number":419,"context_line":"        # NOTE(vdrok): Ignore the tags here, set_node_tags should be used to"},{"line_number":420,"context_line":"        # update them"},{"line_number":421,"context_line":"        values.pop(\u0027tags\u0027, None)"},{"line_number":422,"context_line":""},{"line_number":423,"context_line":"        try:"},{"line_number":424,"context_line":"            return self._do_update_node(node_id, values)"}],"source_content_type":"text/x-python","patch_set":66,"id":"1f1a1f67_6c8144fb","line":421,"updated":"2017-07-18 14:30:58.000000000","message":"in create_node(), we raise an exception. I am not sure whether we should do the same, but we might want to log something? (I\u0027m not sure how tags would get here...)","commit_id":"35ddc67bdc6d28692a26ece6d5b555ea8b27cf49"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"00d31f6a5fed8033f89fef1de5e4005d451ec47a","unresolved":false,"context_lines":[{"line_number":418,"context_line":""},{"line_number":419,"context_line":"        # NOTE(vdrok): Ignore the tags here, set_node_tags should be used to"},{"line_number":420,"context_line":"        # update them"},{"line_number":421,"context_line":"        values.pop(\u0027tags\u0027, None)"},{"line_number":422,"context_line":""},{"line_number":423,"context_line":"        try:"},{"line_number":424,"context_line":"            return self._do_update_node(node_id, values)"}],"source_content_type":"text/x-python","patch_set":66,"id":"ff346bd7_25790f93","line":421,"in_reply_to":"1f1a1f67_6c8144fb","updated":"2017-07-28 15:53:45.000000000","message":"right, tags is an internal attr in the api object, so should not be writeable.","commit_id":"35ddc67bdc6d28692a26ece6d5b555ea8b27cf49"}],"ironic/objects/base.py":[{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"39d604312cd2814942154eab571d8b00d11a4416","unresolved":false,"context_lines":[{"line_number":154,"context_line":"            self.VERSION !\u003d self.__class__.VERSION):"},{"line_number":155,"context_line":"            self.VERSION \u003d target_version"},{"line_number":156,"context_line":""},{"line_number":157,"context_line":"    @classmethod"},{"line_number":158,"context_line":"    def get_target_version(cls):"},{"line_number":159,"context_line":"        \"\"\"Returns the target version for this object."},{"line_number":160,"context_line":""}],"source_content_type":"text/x-python","patch_set":66,"id":"1f1a1f67_ac2cfc01","line":157,"updated":"2017-07-18 14:30:58.000000000","message":"funny, i was just wondering about this yesterday. I\u0027ll submit a separate patch to do this, because we don\u0027t know when this patch might land and this will be useful for other features (like the port.physical_network addition).","commit_id":"35ddc67bdc6d28692a26ece6d5b555ea8b27cf49"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"4c2b3abb691cfebcb2df03a8948fc4ee9c342217","unresolved":false,"context_lines":[{"line_number":154,"context_line":"            self.VERSION !\u003d self.__class__.VERSION):"},{"line_number":155,"context_line":"            self.VERSION \u003d target_version"},{"line_number":156,"context_line":""},{"line_number":157,"context_line":"    @classmethod"},{"line_number":158,"context_line":"    def get_target_version(cls):"},{"line_number":159,"context_line":"        \"\"\"Returns the target version for this object."},{"line_number":160,"context_line":""}],"source_content_type":"text/x-python","patch_set":66,"id":"1f1a1f67_b4e4390e","line":157,"in_reply_to":"1f1a1f67_ac2cfc01","updated":"2017-07-18 17:55:26.000000000","message":"I moved this to a separate patch: https://review.openstack.org/#/c/484890/","commit_id":"35ddc67bdc6d28692a26ece6d5b555ea8b27cf49"}],"ironic/objects/fields.py":[{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"09f1a60560c5ed10260170b37c33751dd67743fc","unresolved":false,"context_lines":[{"line_number":42,"context_line":""},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"class ObjectField(object_fields.ObjectField):"},{"line_number":45,"context_line":"    pass"},{"line_number":46,"context_line":""},{"line_number":47,"context_line":""},{"line_number":48,"context_line":"class ListOfStringsField(object_fields.ListOfStringsField):"}],"source_content_type":"text/x-python","patch_set":5,"id":"da85f559_6d12b9b6","line":45,"updated":"2015-11-09 07:21:54.000000000","message":"Why don\u0027t use object_fields.ObjectField directly or do you have a future plan to customized?","commit_id":"040109c0df11e60c98ce26c1aa6e2a4087646d68"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"4c263db367a4244e594db587011ec8ffed5943c2","unresolved":false,"context_lines":[{"line_number":42,"context_line":""},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"class ObjectField(object_fields.ObjectField):"},{"line_number":45,"context_line":"    pass"},{"line_number":46,"context_line":""},{"line_number":47,"context_line":""},{"line_number":48,"context_line":"class ListOfStringsField(object_fields.ListOfStringsField):"}],"source_content_type":"text/x-python","patch_set":5,"id":"da85f559_13aeb02e","line":45,"in_reply_to":"da85f559_6d12b9b6","updated":"2015-11-09 08:41:55.000000000","message":"I find Ironic doesn\u0027t use object_fields directly even if there\u0027s no customized, so keep consistent with others.  please see ItegerField, StringField ...","commit_id":"040109c0df11e60c98ce26c1aa6e2a4087646d68"},{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"09f1a60560c5ed10260170b37c33751dd67743fc","unresolved":false,"context_lines":[{"line_number":50,"context_line":""},{"line_number":51,"context_line":""},{"line_number":52,"context_line":"class ListOfObjectsField(object_fields.ListOfObjectsField):"},{"line_number":53,"context_line":"    pass"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":""},{"line_number":56,"context_line":"class FlexibleDict(object_fields.FieldType):"}],"source_content_type":"text/x-python","patch_set":5,"id":"da85f559_4d11f5ab","line":53,"updated":"2015-11-09 07:21:54.000000000","message":"ditto","commit_id":"040109c0df11e60c98ce26c1aa6e2a4087646d68"}],"ironic/objects/node.py":[{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"09f1a60560c5ed10260170b37c33751dd67743fc","unresolved":false,"context_lines":[{"line_number":107,"context_line":"        for field in node.fields:"},{"line_number":108,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":109,"context_line":"                if db_node.get(field) is not None:"},{"line_number":110,"context_line":"                    node[\u0027tags\u0027] \u003d tags.TagList.get(context, db_node[\u0027id\u0027])"},{"line_number":111,"context_line":"                else:"},{"line_number":112,"context_line":"                    node[\u0027tags\u0027] \u003d None"},{"line_number":113,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":5,"id":"da85f559_938dc033","line":110,"updated":"2015-11-09 07:21:54.000000000","message":"Do we have to query db for tags one more time? I think we can get db_node and db_tag in one sql query by adding columns_to_join in node db_api.","commit_id":"040109c0df11e60c98ce26c1aa6e2a4087646d68"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"4c263db367a4244e594db587011ec8ffed5943c2","unresolved":false,"context_lines":[{"line_number":107,"context_line":"        for field in node.fields:"},{"line_number":108,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":109,"context_line":"                if db_node.get(field) is not None:"},{"line_number":110,"context_line":"                    node[\u0027tags\u0027] \u003d tags.TagList.get(context, db_node[\u0027id\u0027])"},{"line_number":111,"context_line":"                else:"},{"line_number":112,"context_line":"                    node[\u0027tags\u0027] \u003d None"},{"line_number":113,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":5,"id":"da85f559_76884a23","line":110,"in_reply_to":"da85f559_938dc033","updated":"2015-11-09 08:41:55.000000000","message":"thanks Tan, will try to use join columns later.","commit_id":"040109c0df11e60c98ce26c1aa6e2a4087646d68"},{"author":{"_account_id":6773,"name":"Lucas Alvares Gomes","email":"lucasagomes@gmail.com","username":"lucasagomes"},"change_message_id":"5261c746807e63414f7adb59d2481a479e0f0e21","unresolved":false,"context_lines":[{"line_number":107,"context_line":"    }"},{"line_number":108,"context_line":""},{"line_number":109,"context_line":"    @staticmethod"},{"line_number":110,"context_line":"    def _from_db_object(context, node, db_node, expected_tags\u003dFalse):"},{"line_number":111,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":112,"context_line":"        for field in node.fields:"},{"line_number":113,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"}],"source_content_type":"text/x-python","patch_set":19,"id":"9a68dd71_85f4ec5a","line":110,"updated":"2016-01-25 11:41:40.000000000","message":"mostly nit, but \"expected_tags\" sounds like you are passing a list of tags that is expected to be in the object.\n\nMaybe naming it \"include_tags\u003dTrue/False\" or \"with_tags\u003dTrue/False\" ? Meaning that the object will include the tags?\n\n( I also think that we may always want to include the tags, why wouldn\u0027t we?)","commit_id":"9d99e4044f2945d907b7dfa36ee22ac3dfe6181f"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"98e82dd85340a107cb07177f91696b96a3b8ada5","unresolved":false,"context_lines":[{"line_number":107,"context_line":"    }"},{"line_number":108,"context_line":""},{"line_number":109,"context_line":"    @staticmethod"},{"line_number":110,"context_line":"    def _from_db_object(context, node, db_node, expected_tags\u003dFalse):"},{"line_number":111,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":112,"context_line":"        for field in node.fields:"},{"line_number":113,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"}],"source_content_type":"text/x-python","patch_set":19,"id":"9a68dd71_8dae2580","line":110,"in_reply_to":"9a68dd71_85f4ec5a","updated":"2016-01-26 08:30:55.000000000","message":"thanks Lucas, have changed to always include tags :)","commit_id":"9d99e4044f2945d907b7dfa36ee22ac3dfe6181f"},{"author":{"_account_id":6773,"name":"Lucas Alvares Gomes","email":"lucasagomes@gmail.com","username":"lucasagomes"},"change_message_id":"5261c746807e63414f7adb59d2481a479e0f0e21","unresolved":false,"context_lines":[{"line_number":111,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":112,"context_line":"        for field in node.fields:"},{"line_number":113,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":114,"context_line":"                if expected_tags:"},{"line_number":115,"context_line":"                    node[\u0027tags\u0027] \u003d object_base.obj_make_list("},{"line_number":116,"context_line":"                        context, tags.NodeTagList(context),"},{"line_number":117,"context_line":"                        tags.NodeTag, db_node[\u0027tags\u0027]"}],"source_content_type":"text/x-python","patch_set":19,"id":"9a68dd71_65bf7861","line":114,"updated":"2016-01-25 11:41:40.000000000","message":"nit:\n\n if field \u003d\u003d \u0027tags\u0027 and expected_tags:\n   ...","commit_id":"9d99e4044f2945d907b7dfa36ee22ac3dfe6181f"},{"author":{"_account_id":6773,"name":"Lucas Alvares Gomes","email":"lucasagomes@gmail.com","username":"lucasagomes"},"change_message_id":"5261c746807e63414f7adb59d2481a479e0f0e21","unresolved":false,"context_lines":[{"line_number":311,"context_line":"        values \u003d self.obj_get_changes()"},{"line_number":312,"context_line":"        self._validate_property_values(values.get(\u0027properties\u0027))"},{"line_number":313,"context_line":"        db_node \u003d self.dbapi.create_node(values)"},{"line_number":314,"context_line":"        self._from_db_object(context, self, db_node)"},{"line_number":315,"context_line":""},{"line_number":316,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"},{"line_number":317,"context_line":"    # methods can be used in the future to replace current explicit RPC calls."}],"source_content_type":"text/x-python","patch_set":19,"id":"9a68dd71_0588fcc3","line":314,"updated":"2016-01-25 11:41:40.000000000","message":"Do we plan to allow people to enroll the node already containg the tags? If so, you may want to pass expected_tags\u003dTrue here","commit_id":"9d99e4044f2945d907b7dfa36ee22ac3dfe6181f"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"0eb4a21c1125c245e85dc77bc42ac2ac60f44cac","unresolved":false,"context_lines":[{"line_number":139,"context_line":"        for field in node.fields:"},{"line_number":140,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":141,"context_line":"                node[\u0027tags\u0027] \u003d object_base.obj_make_list("},{"line_number":142,"context_line":"                    context, tags.NodeTagList(context),"},{"line_number":143,"context_line":"                    tags.NodeTag, db_node[\u0027tags\u0027]"},{"line_number":144,"context_line":"                )"},{"line_number":145,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":45,"id":"1a6eadb0_5258cc56","line":142,"range":{"start_line":142,"start_character":20,"end_line":142,"end_character":27},"updated":"2016-12-19 18:01:35.000000000","message":"Hmm, we could use node._context instead of introducing another parameter, but that\u0027s private so yeah, seems we have to do that.","commit_id":"914ed07d4f14fbe9f28a1a3478f80270b83fbc2a"},{"author":{"_account_id":7711,"name":"Yuriy Zveryanskyy","email":"yzveryanskyy@mirantis.com","username":"yuriyz"},"change_message_id":"b7bd0c61d06107adc4ca05d26d287cce87274700","unresolved":false,"context_lines":[{"line_number":140,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":141,"context_line":"        for field in node.fields:"},{"line_number":142,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":143,"context_line":"                node[\u0027tags\u0027] \u003d object_base.obj_make_list("},{"line_number":144,"context_line":"                    context, tags.NodeTagList(context),"},{"line_number":145,"context_line":"                    tags.NodeTag, db_node[\u0027tags\u0027]"},{"line_number":146,"context_line":"                )"}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_cd565c05","line":143,"range":{"start_line":143,"start_character":16,"end_line":143,"end_character":28},"updated":"2017-01-23 21:10:23.000000000","message":"Please use attr access to field for new code (node.tags).","commit_id":"ca7effda782796626a48531bc69c1be71edb04d1"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"65eb058e4be881c357ed7ec6d7197c750536e287","unresolved":false,"context_lines":[{"line_number":140,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":141,"context_line":"        for field in node.fields:"},{"line_number":142,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":143,"context_line":"                node[\u0027tags\u0027] \u003d object_base.obj_make_list("},{"line_number":144,"context_line":"                    context, tags.NodeTagList(context),"},{"line_number":145,"context_line":"                    tags.NodeTag, db_node[\u0027tags\u0027]"},{"line_number":146,"context_line":"                )"}],"source_content_type":"text/x-python","patch_set":48,"id":"5a3905b3_785c3f7d","line":143,"range":{"start_line":143,"start_character":16,"end_line":143,"end_character":28},"in_reply_to":"5a3905b3_cd565c05","updated":"2017-01-24 02:45:02.000000000","message":"Done","commit_id":"ca7effda782796626a48531bc69c1be71edb04d1"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"04704727566b0842d5b8fea6c3f6d2505f75eb4d","unresolved":false,"context_lines":[{"line_number":133,"context_line":"    def as_dict(self):"},{"line_number":134,"context_line":"        return dict((k, getattr(self, k))"},{"line_number":135,"context_line":"                    for k in self.fields"},{"line_number":136,"context_line":"                    if k !\u003d \u0027tags\u0027 and hasattr(self, k))"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":"    @staticmethod"},{"line_number":139,"context_line":"    def _from_db_object(context, node, db_node):"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_7be41dab","line":136,"updated":"2017-01-24 15:26:34.000000000","message":"it would be good to have a comment as to why we\u0027re excluding tags.","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"4695993a9305ee85606a6f127c4059d02e8f0514","unresolved":false,"context_lines":[{"line_number":133,"context_line":"    def as_dict(self):"},{"line_number":134,"context_line":"        return dict((k, getattr(self, k))"},{"line_number":135,"context_line":"                    for k in self.fields"},{"line_number":136,"context_line":"                    if k !\u003d \u0027tags\u0027 and hasattr(self, k))"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":"    @staticmethod"},{"line_number":139,"context_line":"    def _from_db_object(context, node, db_node):"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_904363ae","line":136,"in_reply_to":"5a3905b3_7be41dab","updated":"2017-01-24 15:49:14.000000000","message":"I think it\u0027s because we cannot create a node with tags, like Node(**{..., \u0027tags\u0027: [\u0027abc\u0027]}). We can always get the node\u0027s tags if needed separately. Also tags are not actually part of the node, it\u0027s a separate entity, we\u0027re joining them only to speed up some operations I suppose. as_dict OTOH is just an utility function, used only in API (and also in agent_client, which can be considered an API in some sense:))","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"7712c9e38ef69ba08a03307e7ef7211ef7ba2bb8","unresolved":false,"context_lines":[{"line_number":133,"context_line":"    def as_dict(self):"},{"line_number":134,"context_line":"        return dict((k, getattr(self, k))"},{"line_number":135,"context_line":"                    for k in self.fields"},{"line_number":136,"context_line":"                    if k !\u003d \u0027tags\u0027 and hasattr(self, k))"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":"    @staticmethod"},{"line_number":139,"context_line":"    def _from_db_object(context, node, db_node):"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_75732ae8","line":136,"in_reply_to":"5a3905b3_904363ae","updated":"2017-01-25 03:43:17.000000000","message":"yes, thanks vdrok for the explanation, will add a comment for this in the coming patch set!","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"04704727566b0842d5b8fea6c3f6d2505f75eb4d","unresolved":false,"context_lines":[{"line_number":134,"context_line":"        return dict((k, getattr(self, k))"},{"line_number":135,"context_line":"                    for k in self.fields"},{"line_number":136,"context_line":"                    if k !\u003d \u0027tags\u0027 and hasattr(self, k))"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":"    @staticmethod"},{"line_number":139,"context_line":"    def _from_db_object(context, node, db_node):"},{"line_number":140,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_5b23e1bc","line":137,"updated":"2017-01-24 15:26:34.000000000","message":"I suppose you could also just call the inherited.as_dict(), and delete \u0027tags\u0027 entry.","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"4695993a9305ee85606a6f127c4059d02e8f0514","unresolved":false,"context_lines":[{"line_number":134,"context_line":"        return dict((k, getattr(self, k))"},{"line_number":135,"context_line":"                    for k in self.fields"},{"line_number":136,"context_line":"                    if k !\u003d \u0027tags\u0027 and hasattr(self, k))"},{"line_number":137,"context_line":""},{"line_number":138,"context_line":"    @staticmethod"},{"line_number":139,"context_line":"    def _from_db_object(context, node, db_node):"},{"line_number":140,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_50757bc8","line":137,"in_reply_to":"5a3905b3_5b23e1bc","updated":"2017-01-24 15:49:14.000000000","message":"Yup, that should be a bit better.","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"04704727566b0842d5b8fea6c3f6d2505f75eb4d","unresolved":false,"context_lines":[{"line_number":206,"context_line":"        :returns: a :class:`Node` object."},{"line_number":207,"context_line":"        \"\"\""},{"line_number":208,"context_line":"        db_node \u003d cls.dbapi.get_node_by_id(node_id)"},{"line_number":209,"context_line":"        node \u003d Node._from_db_object(context, cls(context), db_node)"},{"line_number":210,"context_line":"        return node"},{"line_number":211,"context_line":""},{"line_number":212,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_d69a4813","line":209,"updated":"2017-01-24 15:26:34.000000000","message":"won\u0027t cls also work? it should be \u003d\u003d to Node.","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"4695993a9305ee85606a6f127c4059d02e8f0514","unresolved":false,"context_lines":[{"line_number":206,"context_line":"        :returns: a :class:`Node` object."},{"line_number":207,"context_line":"        \"\"\""},{"line_number":208,"context_line":"        db_node \u003d cls.dbapi.get_node_by_id(node_id)"},{"line_number":209,"context_line":"        node \u003d Node._from_db_object(context, cls(context), db_node)"},{"line_number":210,"context_line":"        return node"},{"line_number":211,"context_line":""},{"line_number":212,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_f03907f3","line":209,"in_reply_to":"5a3905b3_d69a4813","updated":"2017-01-24 15:49:14.000000000","message":"yup, it will","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"7712c9e38ef69ba08a03307e7ef7211ef7ba2bb8","unresolved":false,"context_lines":[{"line_number":206,"context_line":"        :returns: a :class:`Node` object."},{"line_number":207,"context_line":"        \"\"\""},{"line_number":208,"context_line":"        db_node \u003d cls.dbapi.get_node_by_id(node_id)"},{"line_number":209,"context_line":"        node \u003d Node._from_db_object(context, cls(context), db_node)"},{"line_number":210,"context_line":"        return node"},{"line_number":211,"context_line":""},{"line_number":212,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_550b8e2b","line":209,"in_reply_to":"5a3905b3_f03907f3","updated":"2017-01-25 03:43:17.000000000","message":"Done","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"04704727566b0842d5b8fea6c3f6d2505f75eb4d","unresolved":false,"context_lines":[{"line_number":276,"context_line":"                                           marker\u003dmarker, sort_key\u003dsort_key,"},{"line_number":277,"context_line":"                                           sort_dir\u003dsort_dir)"},{"line_number":278,"context_line":"        return [Node._from_db_object(context, cls(context), obj)"},{"line_number":279,"context_line":"                for obj in db_nodes]"},{"line_number":280,"context_line":""},{"line_number":281,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"},{"line_number":282,"context_line":"    # methods can be used in the future to replace current explicit RPC calls."}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_d66888f7","line":279,"updated":"2017-01-24 15:26:34.000000000","message":"it seems like the original code should work here. (the original code has changed since you started this patch.)","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"4695993a9305ee85606a6f127c4059d02e8f0514","unresolved":false,"context_lines":[{"line_number":276,"context_line":"                                           marker\u003dmarker, sort_key\u003dsort_key,"},{"line_number":277,"context_line":"                                           sort_dir\u003dsort_dir)"},{"line_number":278,"context_line":"        return [Node._from_db_object(context, cls(context), obj)"},{"line_number":279,"context_line":"                for obj in db_nodes]"},{"line_number":280,"context_line":""},{"line_number":281,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"},{"line_number":282,"context_line":"    # methods can be used in the future to replace current explicit RPC calls."}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_b34f8969","line":279,"in_reply_to":"5a3905b3_d66888f7","updated":"2017-01-24 15:49:14.000000000","message":"Hm, I don\u0027t think so, we pass an additional context as first argument. We\u0027d have to change the *list function too to have it.","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"04704727566b0842d5b8fea6c3f6d2505f75eb4d","unresolved":false,"context_lines":[{"line_number":355,"context_line":"                        A context should be set when instantiating the"},{"line_number":356,"context_line":"                        object, e.g.: Node(context)"},{"line_number":357,"context_line":"        \"\"\""},{"line_number":358,"context_line":"        self.dbapi.destroy_node(self.uuid)"},{"line_number":359,"context_line":"        self.obj_reset_changes()"},{"line_number":360,"context_line":""},{"line_number":361,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_bcbe7b62","line":358,"updated":"2017-01-24 15:26:34.000000000","message":"the asymmetry of how tags are being handled bothers me.\n\nThis node object has a tags (list). This tags list/object is generated at this level (above _from_db_object()). Doesn\u0027t that mean that when this destroy() is called, self.tags exists, and if so, I would think we\u0027d call destroy on that list.","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"4695993a9305ee85606a6f127c4059d02e8f0514","unresolved":false,"context_lines":[{"line_number":355,"context_line":"                        A context should be set when instantiating the"},{"line_number":356,"context_line":"                        object, e.g.: Node(context)"},{"line_number":357,"context_line":"        \"\"\""},{"line_number":358,"context_line":"        self.dbapi.destroy_node(self.uuid)"},{"line_number":359,"context_line":"        self.obj_reset_changes()"},{"line_number":360,"context_line":""},{"line_number":361,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_33b2b94c","line":358,"in_reply_to":"5a3905b3_bcbe7b62","updated":"2017-01-24 15:49:14.000000000","message":"It\u0027s done in dbapi.destroy_node. They are not created in _from_db_object, but joined to nodes from tags table.","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":23883,"name":"Joanna Taryma","email":"joanna.taryma@intel.com","username":"jtaryma"},"change_message_id":"398a42d63e6abbe755c42fa7a95b36b60fad5157","unresolved":false,"context_lines":[{"line_number":135,"context_line":"                    for k in self.fields"},{"line_number":136,"context_line":"                    # As we cannot create a node with tags now, just"},{"line_number":137,"context_line":"                    # exclude it here."},{"line_number":138,"context_line":"                    if k !\u003d \u0027tags\u0027 and hasattr(self, k))"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    @staticmethod"},{"line_number":141,"context_line":"    def _from_db_object(context, node, db_node):"}],"source_content_type":"text/x-python","patch_set":51,"id":"3a461143_c8c3be55","line":138,"updated":"2017-01-30 22:44:25.000000000","message":"if so, shouldn\u0027t \u0027tags\u0027 be omitted by hasattr(self,k)?","commit_id":"f162914c7808677e7ab7faf6e612bc3e4ae25edf"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"16fbf152b32b94a2152e4f7b09dc0814fff4d108","unresolved":false,"context_lines":[{"line_number":135,"context_line":"                    for k in self.fields"},{"line_number":136,"context_line":"                    # As we cannot create a node with tags now, just"},{"line_number":137,"context_line":"                    # exclude it here."},{"line_number":138,"context_line":"                    if k !\u003d \u0027tags\u0027 and hasattr(self, k))"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    @staticmethod"},{"line_number":141,"context_line":"    def _from_db_object(context, node, db_node):"}],"source_content_type":"text/x-python","patch_set":51,"id":"1a430d35_34787fc4","line":138,"in_reply_to":"3a461143_c8c3be55","updated":"2017-02-06 12:14:06.000000000","message":"No, we just not support creating with tags now.","commit_id":"f162914c7808677e7ab7faf6e612bc3e4ae25edf"},{"author":{"_account_id":23883,"name":"Joanna Taryma","email":"joanna.taryma@intel.com","username":"jtaryma"},"change_message_id":"cd8f942b7060588b68ecc002c09fac2bb9166d2d","unresolved":false,"context_lines":[{"line_number":56,"context_line":"    #               power_interface, raid_interface, vendor_interface"},{"line_number":57,"context_line":"    # Version 1.20: Type of network_interface changed to just nullable string"},{"line_number":58,"context_line":"    # Version 1.21: Add storage_interface field"},{"line_number":59,"context_line":"    # Version 1.22: Add tags"},{"line_number":60,"context_line":"    VERSION \u003d \u00271.22\u0027"},{"line_number":61,"context_line":""},{"line_number":62,"context_line":"    dbapi \u003d db_api.get_instance()"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_705268df","line":59,"updated":"2017-02-09 21:41:59.000000000","message":"maybe Add node field?","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":14760,"name":"John L. Villalovos","email":"openstack.org@sodarock.com","username":"jlvillal"},"change_message_id":"6d0e269630c12326844f4035f08882d19b112134","unresolved":false,"context_lines":[{"line_number":131,"context_line":"    }"},{"line_number":132,"context_line":""},{"line_number":133,"context_line":"    def as_dict(self):"},{"line_number":134,"context_line":"        return dict((k, getattr(self, k))"},{"line_number":135,"context_line":"                    for k in self.fields"},{"line_number":136,"context_line":"                    # As we cannot create a node with tags now, just"},{"line_number":137,"context_line":"                    # exclude it here."}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_90fefc03","line":134,"updated":"2017-02-09 21:39:35.000000000","message":"Would this be better to call the base class version and then remove the ones that are named \u0027tags\u0027? Feel free to disagree.\n\nMaybe:\n\n result \u003d super(base.IronicObject, self).as_dict()\n return dict((k, v)\n             for k, v in result.items()\n             if k!\u003d \u0027tags\u0027)","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"5333b4c10b0440ba9b68c8c0c98ec982329eacf6","unresolved":false,"context_lines":[{"line_number":131,"context_line":"    }"},{"line_number":132,"context_line":""},{"line_number":133,"context_line":"    def as_dict(self):"},{"line_number":134,"context_line":"        return dict((k, getattr(self, k))"},{"line_number":135,"context_line":"                    for k in self.fields"},{"line_number":136,"context_line":"                    # As we cannot create a node with tags now, just"},{"line_number":137,"context_line":"                    # exclude it here."}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_548631ba","line":134,"in_reply_to":"fa31d9ce_90fefc03","updated":"2017-02-10 02:48:39.000000000","message":"seems better, thanks for the suggestion. but it should be \u0027Node\u0027 intead of \u0027base.IronicObject\u0027","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":14760,"name":"John L. Villalovos","email":"openstack.org@sodarock.com","username":"jlvillal"},"change_message_id":"6d0e269630c12326844f4035f08882d19b112134","unresolved":false,"context_lines":[{"line_number":138,"context_line":"                    if k !\u003d \u0027tags\u0027 and hasattr(self, k))"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    @staticmethod"},{"line_number":141,"context_line":"    def _from_db_object(context, node, db_node):"},{"line_number":142,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":143,"context_line":"        for field in node.fields:"},{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_d040740a","line":141,"updated":"2017-02-09 21:39:35.000000000","message":"This makes sense to NOT call the base class though.","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"28d3e90dce4f3bc601fa138ef2b4d417515babf5","unresolved":false,"context_lines":[{"line_number":138,"context_line":"                    if k !\u003d \u0027tags\u0027 and hasattr(self, k))"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    @staticmethod"},{"line_number":141,"context_line":"    def _from_db_object(context, node, db_node):"},{"line_number":142,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":143,"context_line":"        for field in node.fields:"},{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_f0e1f8ff","line":141,"range":{"start_line":141,"start_character":24,"end_line":141,"end_character":31},"updated":"2017-02-09 21:36:31.000000000","message":"why is context needed here?","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"5333b4c10b0440ba9b68c8c0c98ec982329eacf6","unresolved":false,"context_lines":[{"line_number":138,"context_line":"                    if k !\u003d \u0027tags\u0027 and hasattr(self, k))"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    @staticmethod"},{"line_number":141,"context_line":"    def _from_db_object(context, node, db_node):"},{"line_number":142,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":143,"context_line":"        for field in node.fields:"},{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_7481758f","line":141,"range":{"start_line":141,"start_character":24,"end_line":141,"end_character":31},"in_reply_to":"fa31d9ce_f0e1f8ff","updated":"2017-02-10 02:48:39.000000000","message":"as the oslo versionobject obj_make_list below needs the context.","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"b847272f14615d404c21032a1aaf220b3bf359bf","unresolved":false,"context_lines":[{"line_number":142,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":143,"context_line":"        for field in node.fields:"},{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":145,"context_line":"                node.tags \u003d object_base.obj_make_list("},{"line_number":146,"context_line":"                    context, tags.NodeTagList(context),"},{"line_number":147,"context_line":"                    tags.NodeTag, db_node[\u0027tags\u0027]"},{"line_number":148,"context_line":"                )"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_b003000d","line":145,"updated":"2017-02-09 21:34:46.000000000","message":"do we have to do obj_reset_changes on each tag in node.tags, as well?\n\nedit: never mind, oslo.versionedobjects will do that for us https://github.com/openstack/oslo.versionedobjects/blob/master/oslo_versionedobjects/base.py#L1121","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"b847272f14615d404c21032a1aaf220b3bf359bf","unresolved":false,"context_lines":[{"line_number":277,"context_line":"        db_nodes \u003d cls.dbapi.get_node_list(filters\u003dfilters, limit\u003dlimit,"},{"line_number":278,"context_line":"                                           marker\u003dmarker, sort_key\u003dsort_key,"},{"line_number":279,"context_line":"                                           sort_dir\u003dsort_dir)"},{"line_number":280,"context_line":"        return [Node._from_db_object(context, cls(context), obj)"},{"line_number":281,"context_line":"                for obj in db_nodes]"},{"line_number":282,"context_line":""},{"line_number":283,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_ad1c8978","line":280,"range":{"start_line":280,"start_character":60,"end_line":280,"end_character":63},"updated":"2017-02-09 21:34:46.000000000","message":"nit: this would be more readable if it was called db_obj","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"5333b4c10b0440ba9b68c8c0c98ec982329eacf6","unresolved":false,"context_lines":[{"line_number":277,"context_line":"        db_nodes \u003d cls.dbapi.get_node_list(filters\u003dfilters, limit\u003dlimit,"},{"line_number":278,"context_line":"                                           marker\u003dmarker, sort_key\u003dsort_key,"},{"line_number":279,"context_line":"                                           sort_dir\u003dsort_dir)"},{"line_number":280,"context_line":"        return [Node._from_db_object(context, cls(context), obj)"},{"line_number":281,"context_line":"                for obj in db_nodes]"},{"line_number":282,"context_line":""},{"line_number":283,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_4765a1df","line":280,"range":{"start_line":280,"start_character":60,"end_line":280,"end_character":63},"in_reply_to":"fa31d9ce_ad1c8978","updated":"2017-02-10 02:48:39.000000000","message":"Done","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"b847272f14615d404c21032a1aaf220b3bf359bf","unresolved":false,"context_lines":[{"line_number":432,"context_line":"        db_node \u003d cls.dbapi.get_node_by_port_addresses(addresses)"},{"line_number":433,"context_line":"        node \u003d Node._from_db_object(context, cls(context), db_node)"},{"line_number":434,"context_line":"        return node"},{"line_number":435,"context_line":""},{"line_number":436,"context_line":""},{"line_number":437,"context_line":"@base.IronicObjectRegistry.register"},{"line_number":438,"context_line":"class NodePayload(notification.NotificationPayloadBase):"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_d06dd4cd","line":435,"updated":"2017-02-09 21:34:46.000000000","message":"Don\u0027t we need a get_by_tags method?","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"5333b4c10b0440ba9b68c8c0c98ec982329eacf6","unresolved":false,"context_lines":[{"line_number":432,"context_line":"        db_node \u003d cls.dbapi.get_node_by_port_addresses(addresses)"},{"line_number":433,"context_line":"        node \u003d Node._from_db_object(context, cls(context), db_node)"},{"line_number":434,"context_line":"        return node"},{"line_number":435,"context_line":""},{"line_number":436,"context_line":""},{"line_number":437,"context_line":"@base.IronicObjectRegistry.register"},{"line_number":438,"context_line":"class NodePayload(notification.NotificationPayloadBase):"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_67b9c52e","line":435,"in_reply_to":"fa31d9ce_d06dd4cd","updated":"2017-02-10 02:48:39.000000000","message":"in fact, we have many ways to query instance by tags, you can read the API patch. but for get_by_tags, I think we can add later if it needed.","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":6773,"name":"Lucas Alvares Gomes","email":"lucasagomes@gmail.com","username":"lucasagomes"},"change_message_id":"5a232d69fbef4091e9d1ef96f1f9ff105c9fa68d","unresolved":false,"context_lines":[{"line_number":132,"context_line":""},{"line_number":133,"context_line":"    def as_dict(self):"},{"line_number":134,"context_line":"        result \u003d super(Node, self).as_dict()"},{"line_number":135,"context_line":"        return dict((k, v)"},{"line_number":136,"context_line":"                    for k, v in result.items()"},{"line_number":137,"context_line":"                    # As we cannot create a node with tags now, just"},{"line_number":138,"context_line":"                    # exclude it here."},{"line_number":139,"context_line":"                    if k !\u003d \u0027tags\u0027)"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"    @staticmethod"},{"line_number":142,"context_line":"    def _from_db_object(context, node, db_node):"}],"source_content_type":"text/x-python","patch_set":53,"id":"da36d5c6_e38137c4","line":139,"range":{"start_line":135,"start_character":0,"end_line":139,"end_character":35},"updated":"2017-02-27 12:08:31.000000000","message":"This is not being unittested.\n\nAlso, it\u0027s more efficient to just pop() the \u0027tags\u0027 key instead of looping through all the items in order to remove one item, e.g:\n\n result \u003d super(Node, self).as_dict()\n result.pop(\u0027tags\u0027, None)\n return result","commit_id":"e9a7cef318169b5be9b0707d2695d5845a846eca"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"5c5ab8007432f636190bfe79a70725d236bcbc7f","unresolved":false,"context_lines":[{"line_number":132,"context_line":""},{"line_number":133,"context_line":"    def as_dict(self):"},{"line_number":134,"context_line":"        result \u003d super(Node, self).as_dict()"},{"line_number":135,"context_line":"        return dict((k, v)"},{"line_number":136,"context_line":"                    for k, v in result.items()"},{"line_number":137,"context_line":"                    # As we cannot create a node with tags now, just"},{"line_number":138,"context_line":"                    # exclude it here."},{"line_number":139,"context_line":"                    if k !\u003d \u0027tags\u0027)"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"    @staticmethod"},{"line_number":142,"context_line":"    def _from_db_object(context, node, db_node):"}],"source_content_type":"text/x-python","patch_set":53,"id":"9a30ddce_1c95c13f","line":139,"range":{"start_line":135,"start_character":0,"end_line":139,"end_character":35},"in_reply_to":"da36d5c6_e38137c4","updated":"2017-03-07 01:53:58.000000000","message":"Done","commit_id":"e9a7cef318169b5be9b0707d2695d5845a846eca"},{"author":{"_account_id":6773,"name":"Lucas Alvares Gomes","email":"lucasagomes@gmail.com","username":"lucasagomes"},"change_message_id":"5a232d69fbef4091e9d1ef96f1f9ff105c9fa68d","unresolved":false,"context_lines":[{"line_number":139,"context_line":"                    if k !\u003d \u0027tags\u0027)"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"    @staticmethod"},{"line_number":142,"context_line":"    def _from_db_object(context, node, db_node):"},{"line_number":143,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":144,"context_line":"        for field in node.fields:"},{"line_number":145,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"}],"source_content_type":"text/x-python","patch_set":53,"id":"da36d5c6_7ee15e29","line":142,"range":{"start_line":142,"start_character":4,"end_line":142,"end_character":48},"updated":"2017-02-27 12:08:31.000000000","message":"Most a nit, but I don\u0027t really like the idea of having the same name of the method in the base class but overwriting it with more parameters. Kinda changes the method definition here.\n\nPerhaps, this would be more appropriated:\n\ndef _from_db_object_with_tags(...) \n\n?","commit_id":"e9a7cef318169b5be9b0707d2695d5845a846eca"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"2d8caec53dbdf3ef5a5c59e4018245cd4e5befe8","unresolved":false,"context_lines":[{"line_number":139,"context_line":"                    if k !\u003d \u0027tags\u0027)"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"    @staticmethod"},{"line_number":142,"context_line":"    def _from_db_object(context, node, db_node):"},{"line_number":143,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":144,"context_line":"        for field in node.fields:"},{"line_number":145,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"}],"source_content_type":"text/x-python","patch_set":53,"id":"9a30ddce_f3d01bcc","line":142,"range":{"start_line":142,"start_character":4,"end_line":142,"end_character":48},"in_reply_to":"9a30ddce_bc991522","updated":"2017-03-07 02:49:22.000000000","message":"seems we want to include tags always, and there are some tools in ovo call _from_db_object directly, so maybe should keep the name.","commit_id":"e9a7cef318169b5be9b0707d2695d5845a846eca"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"5c5ab8007432f636190bfe79a70725d236bcbc7f","unresolved":false,"context_lines":[{"line_number":139,"context_line":"                    if k !\u003d \u0027tags\u0027)"},{"line_number":140,"context_line":""},{"line_number":141,"context_line":"    @staticmethod"},{"line_number":142,"context_line":"    def _from_db_object(context, node, db_node):"},{"line_number":143,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":144,"context_line":"        for field in node.fields:"},{"line_number":145,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"}],"source_content_type":"text/x-python","patch_set":53,"id":"9a30ddce_bc991522","line":142,"range":{"start_line":142,"start_character":4,"end_line":142,"end_character":48},"in_reply_to":"da36d5c6_7ee15e29","updated":"2017-03-07 01:53:58.000000000","message":"yes, seems better, will update soon, thanks!","commit_id":"e9a7cef318169b5be9b0707d2695d5845a846eca"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":132,"context_line":""},{"line_number":133,"context_line":"    def as_dict(self):"},{"line_number":134,"context_line":"        result \u003d super(Node, self).as_dict()"},{"line_number":135,"context_line":"        # As we cannot create a node with tags now, just"},{"line_number":136,"context_line":"        # exclude it here."},{"line_number":137,"context_line":"        result.pop(\u0027tags\u0027, None)"},{"line_number":138,"context_line":"        return result"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_053705b1","line":135,"updated":"2017-03-07 18:42:14.000000000","message":"i don\u0027t think we\u0027re ever going to allow creation of nodes with tags (or are we?), so maybe s/ now,//","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"8b467dca7078b8a1be1365df0b7dcba90a0ce263","unresolved":false,"context_lines":[{"line_number":132,"context_line":""},{"line_number":133,"context_line":"    def as_dict(self):"},{"line_number":134,"context_line":"        result \u003d super(Node, self).as_dict()"},{"line_number":135,"context_line":"        # As we cannot create a node with tags now, just"},{"line_number":136,"context_line":"        # exclude it here."},{"line_number":137,"context_line":"        result.pop(\u0027tags\u0027, None)"},{"line_number":138,"context_line":"        return result"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_f4f53383","line":135,"in_reply_to":"9a30ddce_053705b1","updated":"2017-03-07 21:37:25.000000000","message":"a nit, but +1 if this is true","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"7dc4709a7b482c9ef0c9203c113ef178245966e6","unresolved":false,"context_lines":[{"line_number":132,"context_line":""},{"line_number":133,"context_line":"    def as_dict(self):"},{"line_number":134,"context_line":"        result \u003d super(Node, self).as_dict()"},{"line_number":135,"context_line":"        # As we cannot create a node with tags now, just"},{"line_number":136,"context_line":"        # exclude it here."},{"line_number":137,"context_line":"        result.pop(\u0027tags\u0027, None)"},{"line_number":138,"context_line":"        return result"}],"source_content_type":"text/x-python","patch_set":54,"id":"1a1ced50_d717a342","line":135,"in_reply_to":"9a30ddce_ddabbdd4","updated":"2017-03-23 12:20:10.000000000","message":"I\u0027ve removed this completely. as_dict can be called in multiple places, not only after we create the node and show it in api.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":132,"context_line":""},{"line_number":133,"context_line":"    def as_dict(self):"},{"line_number":134,"context_line":"        result \u003d super(Node, self).as_dict()"},{"line_number":135,"context_line":"        # As we cannot create a node with tags now, just"},{"line_number":136,"context_line":"        # exclude it here."},{"line_number":137,"context_line":"        result.pop(\u0027tags\u0027, None)"},{"line_number":138,"context_line":"        return result"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_ddabbdd4","line":135,"in_reply_to":"9a30ddce_f4f53383","updated":"2017-03-09 01:59:48.000000000","message":"but seems create node with tags is a reasonable use case, but anyhow we don\u0027t support it with this patch, so I agree with removing \"now\".","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":145,"context_line":"                node.tags \u003d object_base.obj_make_list("},{"line_number":146,"context_line":"                    context, tags.NodeTagList(context),"},{"line_number":147,"context_line":"                    tags.NodeTag, db_node[\u0027tags\u0027]"},{"line_number":148,"context_line":"                )"},{"line_number":149,"context_line":"            else:"},{"line_number":150,"context_line":"                node[field] \u003d db_node[field]"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_3be8a110","line":147,"updated":"2017-03-07 18:42:14.000000000","message":"I feel like it might be better to have some sort of helper method in tags.py, maybe in NodeTagList that will return the list. That\u0027s what node.tags is, right? a tags.NodeTagList?","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"8b467dca7078b8a1be1365df0b7dcba90a0ce263","unresolved":false,"context_lines":[{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":145,"context_line":"                node.tags \u003d object_base.obj_make_list("},{"line_number":146,"context_line":"                    context, tags.NodeTagList(context),"},{"line_number":147,"context_line":"                    tags.NodeTag, db_node[\u0027tags\u0027]"},{"line_number":148,"context_line":"                )"},{"line_number":149,"context_line":"            else:"},{"line_number":150,"context_line":"                node[field] \u003d db_node[field]"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_f4237303","line":147,"in_reply_to":"9a30ddce_3be8a110","updated":"2017-03-07 21:37:25.000000000","message":"I wonder how we do this for other top-level lists in the DB....\n\n+1 to helper iff this block of code is used more than once, otherwise it\u0027s small enough to keep here, I think","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"7dc4709a7b482c9ef0c9203c113ef178245966e6","unresolved":false,"context_lines":[{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":145,"context_line":"                node.tags \u003d object_base.obj_make_list("},{"line_number":146,"context_line":"                    context, tags.NodeTagList(context),"},{"line_number":147,"context_line":"                    tags.NodeTag, db_node[\u0027tags\u0027]"},{"line_number":148,"context_line":"                )"},{"line_number":149,"context_line":"            else:"},{"line_number":150,"context_line":"                node[field] \u003d db_node[field]"}],"source_content_type":"text/x-python","patch_set":54,"id":"1a1ced50_72751d62","line":147,"in_reply_to":"9a30ddce_9d806548","updated":"2017-03-23 12:20:10.000000000","message":"Done","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":145,"context_line":"                node.tags \u003d object_base.obj_make_list("},{"line_number":146,"context_line":"                    context, tags.NodeTagList(context),"},{"line_number":147,"context_line":"                    tags.NodeTag, db_node[\u0027tags\u0027]"},{"line_number":148,"context_line":"                )"},{"line_number":149,"context_line":"            else:"},{"line_number":150,"context_line":"                node[field] \u003d db_node[field]"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_9d806548","line":147,"in_reply_to":"9a30ddce_f4237303","updated":"2017-03-09 01:59:48.000000000","message":"Thanks for the suggestion, will try to find a better way.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":253,"context_line":"        :returns: a :class:`Node` object."},{"line_number":254,"context_line":"        \"\"\""},{"line_number":255,"context_line":"        db_node \u003d cls.dbapi.get_node_by_instance(instance_uuid)"},{"line_number":256,"context_line":"        node \u003d cls._from_db_object(context, cls(context), db_node)"},{"line_number":257,"context_line":"        return node"},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_f61aa56d","line":256,"updated":"2017-03-07 18:42:14.000000000","message":"Sigh. I think this is confusing. By \u0027this\u0027, this line vs L281 \u0026 L302.\n\nOK, I think I see what the problem is. base.IronicObject._from_db_object() should have context as its first argument, because some code in OVO expects it, even though that isn\u0027t documented very well. Zhenguo mentions it in a comment in the tags.py file: https://github.com/openstack/oslo.versionedobjects/blob/master/oslo_versionedobjects/base.py#L1117.\n\nI don\u0027t want to hold back this patch because of that, but we should fix it in base.py. To track this work: https://bugs.launchpad.net/ironic/+bug/1670778","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"7dc4709a7b482c9ef0c9203c113ef178245966e6","unresolved":false,"context_lines":[{"line_number":253,"context_line":"        :returns: a :class:`Node` object."},{"line_number":254,"context_line":"        \"\"\""},{"line_number":255,"context_line":"        db_node \u003d cls.dbapi.get_node_by_instance(instance_uuid)"},{"line_number":256,"context_line":"        node \u003d cls._from_db_object(context, cls(context), db_node)"},{"line_number":257,"context_line":"        return node"},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":54,"id":"1a1ced50_f28aed19","line":256,"in_reply_to":"9a30ddce_5dd42d46","updated":"2017-03-23 12:20:10.000000000","message":"Done","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"8b467dca7078b8a1be1365df0b7dcba90a0ce263","unresolved":false,"context_lines":[{"line_number":253,"context_line":"        :returns: a :class:`Node` object."},{"line_number":254,"context_line":"        \"\"\""},{"line_number":255,"context_line":"        db_node \u003d cls.dbapi.get_node_by_instance(instance_uuid)"},{"line_number":256,"context_line":"        node \u003d cls._from_db_object(context, cls(context), db_node)"},{"line_number":257,"context_line":"        return node"},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_d46d8f33","line":256,"in_reply_to":"9a30ddce_f61aa56d","updated":"2017-03-07 21:37:25.000000000","message":"Agreed, this is really confusing","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":253,"context_line":"        :returns: a :class:`Node` object."},{"line_number":254,"context_line":"        \"\"\""},{"line_number":255,"context_line":"        db_node \u003d cls.dbapi.get_node_by_instance(instance_uuid)"},{"line_number":256,"context_line":"        node \u003d cls._from_db_object(context, cls(context), db_node)"},{"line_number":257,"context_line":"        return node"},{"line_number":258,"context_line":""},{"line_number":259,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_5dd42d46","line":256,"in_reply_to":"9a30ddce_f61aa56d","updated":"2017-03-09 01:59:48.000000000","message":"ok, thanks Ruby, will assign it to me if there\u0027s no one like to take it.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":299,"context_line":""},{"line_number":300,"context_line":"        \"\"\""},{"line_number":301,"context_line":"        db_node \u003d cls.dbapi.reserve_node(tag, node_id)"},{"line_number":302,"context_line":"        node \u003d Node._from_db_object(context, cls(context), db_node)"},{"line_number":303,"context_line":"        return node"},{"line_number":304,"context_line":""},{"line_number":305,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_bb5bb653","line":302,"updated":"2017-03-07 18:42:14.000000000","message":"this isn\u0027t consistent with other calls to ._from_db_object. Sigh.\n\nIn this file, you only want to use Node._from_db_object() (because it is different from base.IronicObject._from_db_object()) so (sorry, I think I asked you change it), maybe we should be explicit and make all the calls to Node._from_db_object() until we fix base.Ironic_object._from_db_object() to be consistent.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"7dc4709a7b482c9ef0c9203c113ef178245966e6","unresolved":false,"context_lines":[{"line_number":299,"context_line":""},{"line_number":300,"context_line":"        \"\"\""},{"line_number":301,"context_line":"        db_node \u003d cls.dbapi.reserve_node(tag, node_id)"},{"line_number":302,"context_line":"        node \u003d Node._from_db_object(context, cls(context), db_node)"},{"line_number":303,"context_line":"        return node"},{"line_number":304,"context_line":""},{"line_number":305,"context_line":"    # NOTE(xek): We don\u0027t want to enable RPC on this call just yet. Remotable"}],"source_content_type":"text/x-python","patch_set":54,"id":"1a1ced50_3281e5fb","line":302,"in_reply_to":"9a30ddce_bb5bb653","updated":"2017-03-23 12:20:10.000000000","message":"Done","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":447,"context_line":"    #   external services"},{"line_number":448,"context_line":"    # - being internal-only or hardware-related fields"},{"line_number":449,"context_line":"    SCHEMA \u003d {"},{"line_number":450,"context_line":"        \u0027clean_step\u0027: (\u0027node\u0027, \u0027clean_step\u0027),"},{"line_number":451,"context_line":"        \u0027console_enabled\u0027: (\u0027node\u0027, \u0027console_enabled\u0027),"},{"line_number":452,"context_line":"        \u0027created_at\u0027: (\u0027node\u0027, \u0027created_at\u0027),"},{"line_number":453,"context_line":"        \u0027driver\u0027: (\u0027node\u0027, \u0027driver\u0027),"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_760eb535","line":450,"updated":"2017-03-07 18:42:14.000000000","message":"@Yuriy. Are the notification payloads going to include the tags info? If so, I think we should put a TODO comment here (or someone note it down somewhere; otherwise i think we may forget).","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"c8392df6e3eab4e5599584ded7360e5dd04c5dea","unresolved":false,"context_lines":[{"line_number":447,"context_line":"    #   external services"},{"line_number":448,"context_line":"    # - being internal-only or hardware-related fields"},{"line_number":449,"context_line":"    SCHEMA \u003d {"},{"line_number":450,"context_line":"        \u0027clean_step\u0027: (\u0027node\u0027, \u0027clean_step\u0027),"},{"line_number":451,"context_line":"        \u0027console_enabled\u0027: (\u0027node\u0027, \u0027console_enabled\u0027),"},{"line_number":452,"context_line":"        \u0027created_at\u0027: (\u0027node\u0027, \u0027created_at\u0027),"},{"line_number":453,"context_line":"        \u0027driver\u0027: (\u0027node\u0027, \u0027driver\u0027),"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_6c6ea102","line":450,"in_reply_to":"9a30ddce_1d52b5dd","updated":"2017-03-09 06:36:47.000000000","message":"I think we should not change the notifications until we expose it in the API.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"7dc4709a7b482c9ef0c9203c113ef178245966e6","unresolved":false,"context_lines":[{"line_number":447,"context_line":"    #   external services"},{"line_number":448,"context_line":"    # - being internal-only or hardware-related fields"},{"line_number":449,"context_line":"    SCHEMA \u003d {"},{"line_number":450,"context_line":"        \u0027clean_step\u0027: (\u0027node\u0027, \u0027clean_step\u0027),"},{"line_number":451,"context_line":"        \u0027console_enabled\u0027: (\u0027node\u0027, \u0027console_enabled\u0027),"},{"line_number":452,"context_line":"        \u0027created_at\u0027: (\u0027node\u0027, \u0027created_at\u0027),"},{"line_number":453,"context_line":"        \u0027driver\u0027: (\u0027node\u0027, \u0027driver\u0027),"}],"source_content_type":"text/x-python","patch_set":54,"id":"1a1ced50_727fdd14","line":450,"in_reply_to":"9a30ddce_515404fe","updated":"2017-03-23 12:20:10.000000000","message":"Done","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":10342,"name":"Jay Faulkner","display_name":"JayF","email":"jay@jvf.cc","username":"JayF","status":"youtube.com/@oss-gr / podcast.gr-oss.io"},"change_message_id":"1a915713f6b3d81d0628fc5207d2de5e3bd0f2a9","unresolved":false,"context_lines":[{"line_number":447,"context_line":"    #   external services"},{"line_number":448,"context_line":"    # - being internal-only or hardware-related fields"},{"line_number":449,"context_line":"    SCHEMA \u003d {"},{"line_number":450,"context_line":"        \u0027clean_step\u0027: (\u0027node\u0027, \u0027clean_step\u0027),"},{"line_number":451,"context_line":"        \u0027console_enabled\u0027: (\u0027node\u0027, \u0027console_enabled\u0027),"},{"line_number":452,"context_line":"        \u0027created_at\u0027: (\u0027node\u0027, \u0027created_at\u0027),"},{"line_number":453,"context_line":"        \u0027driver\u0027: (\u0027node\u0027, \u0027driver\u0027),"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_a8f40ef2","line":450,"in_reply_to":"9a30ddce_5460bf35","updated":"2017-03-08 23:06:30.000000000","message":"Are we certain we\u0027re OK wth this landing without notification support in the same patch? Seems like a bad precedent to set...","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"a866f0f23f7303b16dba0440d99f8ce7f957a546","unresolved":false,"context_lines":[{"line_number":447,"context_line":"    #   external services"},{"line_number":448,"context_line":"    # - being internal-only or hardware-related fields"},{"line_number":449,"context_line":"    SCHEMA \u003d {"},{"line_number":450,"context_line":"        \u0027clean_step\u0027: (\u0027node\u0027, \u0027clean_step\u0027),"},{"line_number":451,"context_line":"        \u0027console_enabled\u0027: (\u0027node\u0027, \u0027console_enabled\u0027),"},{"line_number":452,"context_line":"        \u0027created_at\u0027: (\u0027node\u0027, \u0027created_at\u0027),"},{"line_number":453,"context_line":"        \u0027driver\u0027: (\u0027node\u0027, \u0027driver\u0027),"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_515404fe","line":450,"in_reply_to":"9a30ddce_6c6ea102","updated":"2017-03-09 14:18:54.000000000","message":"I agree with vdrok. It makes no sense to emit notifications with tags at this point, because there\u0027s no way yet, to have any tags specified. It is only when the API part lands, that it makes sense to add tags.\n\nI\u0027m OK with a TODO, or a bug, or a patch in this series, or something that indicates that this needs to be done. (We don\u0027t have a formal process for this.)","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"8b467dca7078b8a1be1365df0b7dcba90a0ce263","unresolved":false,"context_lines":[{"line_number":447,"context_line":"    #   external services"},{"line_number":448,"context_line":"    # - being internal-only or hardware-related fields"},{"line_number":449,"context_line":"    SCHEMA \u003d {"},{"line_number":450,"context_line":"        \u0027clean_step\u0027: (\u0027node\u0027, \u0027clean_step\u0027),"},{"line_number":451,"context_line":"        \u0027console_enabled\u0027: (\u0027node\u0027, \u0027console_enabled\u0027),"},{"line_number":452,"context_line":"        \u0027created_at\u0027: (\u0027node\u0027, \u0027created_at\u0027),"},{"line_number":453,"context_line":"        \u0027driver\u0027: (\u0027node\u0027, \u0027driver\u0027),"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_5460bf35","line":450,"in_reply_to":"9a30ddce_760eb535","updated":"2017-03-07 21:37:25.000000000","message":"+1, please modify notifications in this patch or add a TODO for someone else to look at it","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":447,"context_line":"    #   external services"},{"line_number":448,"context_line":"    # - being internal-only or hardware-related fields"},{"line_number":449,"context_line":"    SCHEMA \u003d {"},{"line_number":450,"context_line":"        \u0027clean_step\u0027: (\u0027node\u0027, \u0027clean_step\u0027),"},{"line_number":451,"context_line":"        \u0027console_enabled\u0027: (\u0027node\u0027, \u0027console_enabled\u0027),"},{"line_number":452,"context_line":"        \u0027created_at\u0027: (\u0027node\u0027, \u0027created_at\u0027),"},{"line_number":453,"context_line":"        \u0027driver\u0027: (\u0027node\u0027, \u0027driver\u0027),"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_1d52b5dd","line":450,"in_reply_to":"9a30ddce_760eb535","updated":"2017-03-09 01:59:48.000000000","message":"OK, will figure out how to add tags info here.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"bd8c77d53c628ac3606aa3aabffee308c12b3a65","unresolved":false,"context_lines":[{"line_number":135,"context_line":"        target_version \u003d versionutils.convert_version_to_tuple(target_version)"},{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                delattr(self, \u0027tags\u0027)"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    @staticmethod"},{"line_number":141,"context_line":"    def _from_db_object(context, node, db_node):"}],"source_content_type":"text/x-python","patch_set":61,"id":"7f231b9d_f43e6a89","line":138,"updated":"2017-06-14 22:06:32.000000000","message":"We need the object to know that self.tags was changed, so I think this should be self.tags \u003d None","commit_id":"a53a0d6f45f5b1052c6295aded1c5a4f086995ff"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"2abf4a1b448eeff50e10ceb3a07c4d37fa8d2dcf","unresolved":false,"context_lines":[{"line_number":135,"context_line":"        target_version \u003d versionutils.convert_version_to_tuple(target_version)"},{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                delattr(self, \u0027tags\u0027)"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    @staticmethod"},{"line_number":141,"context_line":"    def _from_db_object(context, node, db_node):"}],"source_content_type":"text/x-python","patch_set":61,"id":"7f231b9d_99bd1bda","line":138,"in_reply_to":"7f231b9d_4078a98e","updated":"2017-06-15 13:35:13.000000000","message":"_convert_to_version() is used in serialization/deserialization as well as in saving to the DB. For saving to the DB, we definitely need the object\u0027s changed fields to be accurate, otherwise it won\u0027t get saved in the DB. Eg, let\u0027s say node had been saved in DB in version 1.22, and now some pinned conductor is saving it in version 1.21, I don\u0027t think delattr() will cause the node object to know that node.tags was changed and it won\u0027t get set to None in the DB. In this case (wrt node.tags) it may not matter, but it does matter in other cases, so it would be good to be consistent. I think for serialization/deserialization, it is fine for self.tags\u003dNone but I will make a point of confirming.","commit_id":"a53a0d6f45f5b1052c6295aded1c5a4f086995ff"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"35c6b3855aefc377a3a8aefe5417328f85154909","unresolved":false,"context_lines":[{"line_number":135,"context_line":"        target_version \u003d versionutils.convert_version_to_tuple(target_version)"},{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                delattr(self, \u0027tags\u0027)"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    @staticmethod"},{"line_number":141,"context_line":"    def _from_db_object(context, node, db_node):"}],"source_content_type":"text/x-python","patch_set":61,"id":"7f231b9d_df27ccc9","line":138,"in_reply_to":"7f231b9d_99bd1bda","updated":"2017-06-16 16:26:43.000000000","message":"Had a look at the deserialization in the ovo, it seems like we don\u0027t actually need to do anything  with tags at all, as an object of older version will only be considering fields it knows about during deserialization (might be wrong though). But setting to None at least will save some bytes from being sent over the wire :)","commit_id":"a53a0d6f45f5b1052c6295aded1c5a4f086995ff"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"db024af6a9b3977af5c8a209b775be89eb662c9d","unresolved":false,"context_lines":[{"line_number":135,"context_line":"        target_version \u003d versionutils.convert_version_to_tuple(target_version)"},{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                delattr(self, \u0027tags\u0027)"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    @staticmethod"},{"line_number":141,"context_line":"    def _from_db_object(context, node, db_node):"}],"source_content_type":"text/x-python","patch_set":61,"id":"7f231b9d_4078a98e","line":138,"in_reply_to":"7f231b9d_f43e6a89","updated":"2017-06-15 11:59:49.000000000","message":"Hrm, I\u0027m not sure about this one, during serialization, iiuc obj_attr_is_set is used to determine if we send a field or not, and if we do self.tags\u003dNone, it will be set?","commit_id":"a53a0d6f45f5b1052c6295aded1c5a4f086995ff"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"bd8c77d53c628ac3606aa3aabffee308c12b3a65","unresolved":false,"context_lines":[{"line_number":138,"context_line":"                delattr(self, \u0027tags\u0027)"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    @staticmethod"},{"line_number":141,"context_line":"    def _from_db_object(context, node, db_node):"},{"line_number":142,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":143,"context_line":"        for field in node.fields:"},{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"}],"source_content_type":"text/x-python","patch_set":61,"id":"7f231b9d_f2667dc1","line":141,"updated":"2017-06-14 22:06:32.000000000","message":"Oh, ugh, I didn\u0027t think of this wrt rolling upgrades and handling different versions of objects. base.py\u0027s IronicObject._from_db_object() has logic for dealing with conversion of object versions. Doing this means the conversion between object versions is lost. Let me think about this...\n\nOk, I think I need to change IronicObject._from_db_object() so that it calls a helper function, eg IronicObject._set_from_db_object(context, db_object). This function would be renamed to that helper function and would only include L143-148. And/or include up to L150.\n\nNot sure if the helper should be a static method or not. I will try to catch you on IRC to discuss, need to think about the ordering. Probably the right thing to do is change base.py first.","commit_id":"a53a0d6f45f5b1052c6295aded1c5a4f086995ff"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"2abf4a1b448eeff50e10ceb3a07c4d37fa8d2dcf","unresolved":false,"context_lines":[{"line_number":138,"context_line":"                delattr(self, \u0027tags\u0027)"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    @staticmethod"},{"line_number":141,"context_line":"    def _from_db_object(context, node, db_node):"},{"line_number":142,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":143,"context_line":"        for field in node.fields:"},{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"}],"source_content_type":"text/x-python","patch_set":61,"id":"7f231b9d_d99b9370","line":141,"in_reply_to":"7f231b9d_10232058","updated":"2017-06-15 13:35:13.000000000","message":"ok, you mean object fields, right, not the DB fields. I\u0027m not sure I see a usecase for it but if you ask there must be one :-)","commit_id":"a53a0d6f45f5b1052c6295aded1c5a4f086995ff"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"db024af6a9b3977af5c8a209b775be89eb662c9d","unresolved":false,"context_lines":[{"line_number":138,"context_line":"                delattr(self, \u0027tags\u0027)"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    @staticmethod"},{"line_number":141,"context_line":"    def _from_db_object(context, node, db_node):"},{"line_number":142,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":143,"context_line":"        for field in node.fields:"},{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"}],"source_content_type":"text/x-python","patch_set":61,"id":"7f231b9d_10232058","line":141,"in_reply_to":"7f231b9d_f2667dc1","updated":"2017-06-15 11:59:49.000000000","message":"I\u0027d also allow for that base _set_from_db_object method to have an arg being a list of fields to set. Others can be added by children methods.","commit_id":"a53a0d6f45f5b1052c6295aded1c5a4f086995ff"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"bd8c77d53c628ac3606aa3aabffee308c12b3a65","unresolved":false,"context_lines":[{"line_number":143,"context_line":"        for field in node.fields:"},{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":145,"context_line":"                node.tags \u003d tags.NodeTagList.from_db_tags_list(context,"},{"line_number":146,"context_line":"                                                               db_node[\u0027tags\u0027])"},{"line_number":147,"context_line":"            else:"},{"line_number":148,"context_line":"                node[field] \u003d db_node[field]"},{"line_number":149,"context_line":"        node._context \u003d context"}],"source_content_type":"text/x-python","patch_set":61,"id":"7f231b9d_d46feef9","line":146,"updated":"2017-06-14 22:06:32.000000000","message":"Sigh, it has been awhile since I looked at the tags code, I need to refresh my memory. What is the value of db_node[\u0027tags\u0027]? If there are no tags, is this .from_db_tags_list() call pretty fast?","commit_id":"a53a0d6f45f5b1052c6295aded1c5a4f086995ff"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"2abf4a1b448eeff50e10ceb3a07c4d37fa8d2dcf","unresolved":false,"context_lines":[{"line_number":143,"context_line":"        for field in node.fields:"},{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":145,"context_line":"                node.tags \u003d tags.NodeTagList.from_db_tags_list(context,"},{"line_number":146,"context_line":"                                                               db_node[\u0027tags\u0027])"},{"line_number":147,"context_line":"            else:"},{"line_number":148,"context_line":"                node[field] \u003d db_node[field]"},{"line_number":149,"context_line":"        node._context \u003d context"}],"source_content_type":"text/x-python","patch_set":61,"id":"7f231b9d_99de3b0f","line":146,"in_reply_to":"7f231b9d_b067ccb7","updated":"2017-06-15 13:35:13.000000000","message":"Thx. This is the first time we have an object consist of other objects I think... we normally use IDs to refer to other objects. Well, I guess node-tags are different, they don\u0027t exist as such outside of the node.","commit_id":"a53a0d6f45f5b1052c6295aded1c5a4f086995ff"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"db024af6a9b3977af5c8a209b775be89eb662c9d","unresolved":false,"context_lines":[{"line_number":143,"context_line":"        for field in node.fields:"},{"line_number":144,"context_line":"            if field \u003d\u003d \u0027tags\u0027:"},{"line_number":145,"context_line":"                node.tags \u003d tags.NodeTagList.from_db_tags_list(context,"},{"line_number":146,"context_line":"                                                               db_node[\u0027tags\u0027])"},{"line_number":147,"context_line":"            else:"},{"line_number":148,"context_line":"                node[field] \u003d db_node[field]"},{"line_number":149,"context_line":"        node._context \u003d context"}],"source_content_type":"text/x-python","patch_set":61,"id":"7f231b9d_b067ccb7","line":146,"in_reply_to":"7f231b9d_d46feef9","updated":"2017-06-15 11:59:49.000000000","message":"It\u0027s a list of NodeTag db model objects, basically received by calling get_node_tags_by_node_id dbapi method.","commit_id":"a53a0d6f45f5b1052c6295aded1c5a4f086995ff"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"a587824ddd85ffef359b1f8358572fb56c7cbbef","unresolved":false,"context_lines":[{"line_number":135,"context_line":"        target_version \u003d versionutils.convert_version_to_tuple(target_version)"},{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                self.tags \u003d []"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"},{"line_number":141,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"}],"source_content_type":"text/x-python","patch_set":64,"id":"5f201791_a394b9e9","line":138,"updated":"2017-06-20 21:23:41.000000000","message":"So it does not seem to work, neither list nor None. As during deserialization coerce is called that enforces the type, and then obj_from_primitive is called, which requires a proper object inside.","commit_id":"32ebb275ec0fc1c974ce2dcaa919cadc5f71e5a0"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"1b79cfc2d7caf55a76314c2abb28dc20c8804a02","unresolved":false,"context_lines":[{"line_number":135,"context_line":"        target_version \u003d versionutils.convert_version_to_tuple(target_version)"},{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                self.tags \u003d []"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"},{"line_number":141,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"}],"source_content_type":"text/x-python","patch_set":64,"id":"3f1d235d_89fdbb6f","line":138,"in_reply_to":"3f1d235d_c9d3b35f","updated":"2017-07-05 18:15:31.000000000","message":"By the way I\u0027ve finally setup an environment to test this, with tags and your change, so can check things if you want something checked :)","commit_id":"32ebb275ec0fc1c974ce2dcaa919cadc5f71e5a0"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"b3a6078d90f7f6fbbf264fce36808d7c9b16ab5f","unresolved":false,"context_lines":[{"line_number":135,"context_line":"        target_version \u003d versionutils.convert_version_to_tuple(target_version)"},{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                self.tags \u003d []"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"},{"line_number":141,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"}],"source_content_type":"text/x-python","patch_set":64,"id":"1f1a1f67_1a7aa723","line":138,"in_reply_to":"3f1d235d_c9d3b35f","updated":"2017-07-12 18:36:13.000000000","message":"Good question.\n\nThis method is used when serializing/deserializing, as well as when saving the object to the DB.\n\nWhen serializing/deserializing, we want to remove the tags with delattr.\n\nWhen saving the object to the DB, IF we remove the tags with delattr, I believe the node object will not know that node.tags was modified, and so node.tags will not be saved/replaced in the DB. There is a \u0027corner\u0027 case, when all services are running the new version, but ironic-api are pinned-to-old; some ironic-conductor C1 pinned-to-old and some conductor C2 not pinned (in the process of unpinning all conductors...) IF C2 saves node.tags\u003d\u0027foo\u0027 (for example), then a new API request causes C1 to save node (without tags cuz it is pinned), if we don\u0027t set self.tags \u003d None, the DB will have node.tags\u003d\u0027foo\u0027 instead of None. In your/this particular case I don\u0027t think it matters. However, in the general \u0027some-object-has-changes-between-versions\u0027, this could be a problem and result in an inconsistent object (e.g., if we are replacing node.foo with new node.bar).\n\nDoes that make sense to you? Maybe I need to add more documentation/comments somewhere, maybe more docstring for _convert_to_version().","commit_id":"32ebb275ec0fc1c974ce2dcaa919cadc5f71e5a0"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"6620a4a6afe290cbf56069f10ffb99b41944a8e0","unresolved":false,"context_lines":[{"line_number":135,"context_line":"        target_version \u003d versionutils.convert_version_to_tuple(target_version)"},{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                self.tags \u003d []"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"},{"line_number":141,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"}],"source_content_type":"text/x-python","patch_set":64,"id":"5f201791_436964bc","line":138,"in_reply_to":"5f201791_232429c6","updated":"2017-06-20 21:34:54.000000000","message":"sure, thanks for that. I plan to do some proper testing tomorrow too.","commit_id":"32ebb275ec0fc1c974ce2dcaa919cadc5f71e5a0"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"cdebae87ab2e05a857250542b8525f88fda0c6b8","unresolved":false,"context_lines":[{"line_number":135,"context_line":"        target_version \u003d versionutils.convert_version_to_tuple(target_version)"},{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                self.tags \u003d []"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"},{"line_number":141,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"}],"source_content_type":"text/x-python","patch_set":64,"id":"5f201791_e7414a3b","line":138,"in_reply_to":"5f201791_436964bc","updated":"2017-06-23 05:08:42.000000000","message":"I didn\u0027t get a chance yet to test the nodes-tags stuff wrt rolling upgrades. I am working on some changes though, which will affect this method, see [1]. I\u0027m adding another parameter (might change its name); used to either change the value of object fields or to delete the fields.\n\nMy changes may not address your particular issue, so there may be more changes in the works...\n\n[1] https://review.openstack.org/#/c/476779/. I","commit_id":"32ebb275ec0fc1c974ce2dcaa919cadc5f71e5a0"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"40192be0fee24c6f044189d63dd351b558550818","unresolved":false,"context_lines":[{"line_number":135,"context_line":"        target_version \u003d versionutils.convert_version_to_tuple(target_version)"},{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                self.tags \u003d []"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"},{"line_number":141,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"}],"source_content_type":"text/x-python","patch_set":64,"id":"3f1d235d_c9d3b35f","line":138,"in_reply_to":"5f201791_4c1d5a72","updated":"2017-07-05 18:05:54.000000000","message":"I\u0027m not sure how I feel about this change. Maybe I\u0027m missing something, but when we have the tags set and target version is \u003c 1.22, don\u0027t we know that we\u0027re doing the downgrade? which means that we\u0027re talking to the older service, and because of this, we need to remove the tags with delattr?","commit_id":"32ebb275ec0fc1c974ce2dcaa919cadc5f71e5a0"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"acf2682d7b86cbd3103c06d5e00e4ec4d75c6c2c","unresolved":false,"context_lines":[{"line_number":135,"context_line":"        target_version \u003d versionutils.convert_version_to_tuple(target_version)"},{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                self.tags \u003d []"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"},{"line_number":141,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"}],"source_content_type":"text/x-python","patch_set":64,"id":"5f201791_232429c6","line":138,"in_reply_to":"5f201791_a394b9e9","updated":"2017-06-20 21:28:53.000000000","message":"Hmm, but tags is nullable, so that seems odd. I can (I hope) take a look tomorrow.","commit_id":"32ebb275ec0fc1c974ce2dcaa919cadc5f71e5a0"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"fda6e1cf5517324bd0e1d89e3c1e11e62c155471","unresolved":false,"context_lines":[{"line_number":135,"context_line":"        target_version \u003d versionutils.convert_version_to_tuple(target_version)"},{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                self.tags \u003d []"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"},{"line_number":141,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"}],"source_content_type":"text/x-python","patch_set":64,"id":"5f201791_4c1d5a72","line":138,"in_reply_to":"5f201791_e7414a3b","updated":"2017-06-27 15:36:27.000000000","message":"Ok, I rebased this patch on top of https://review.openstack.org/#/c/476779/ and changed this method and it passes the unit tests (you\u0027ll have to update a test):\n\ndiff --git a/ironic/objects/node.py b/ironic/objects/node.py\nindex 4087ea2..9e62a46 100644\n--- a/ironic/objects/node.py\n+++ b/ironic/objects/node.py\n@@ -131,11 +131,14 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):\n         \u0027tags\u0027: object_fields.ObjectField(\u0027NodeTagList\u0027, nullable\u003dTrue),\n     }\n \n-    def _convert_to_version(self, target_version):\n+    def _convert_to_version(self, target_version, change_fields\u003dTrue):\n         target_version \u003d versionutils.convert_version_to_tuple(target_version)\n         if target_version \u003c (1, 22):\n             if self.obj_attr_is_set(\u0027tags\u0027):\n-                self.tags \u003d []\n+                if change_fields:\n+                    self.tags \u003d None\n+                else:\n+                    delattr(self, \u0027tags\u0027)","commit_id":"32ebb275ec0fc1c974ce2dcaa919cadc5f71e5a0"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"cc2981e77f3f0153a085d0978d8d042bf3adaa64","unresolved":false,"context_lines":[{"line_number":57,"context_line":"    #               power_interface, raid_interface, vendor_interface"},{"line_number":58,"context_line":"    # Version 1.20: Type of network_interface changed to just nullable string"},{"line_number":59,"context_line":"    # Version 1.21: Add storage_interface field"},{"line_number":60,"context_line":"    # Version 1.22: Add tags field"},{"line_number":61,"context_line":"    VERSION \u003d \u00271.22\u0027"},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"    dbapi \u003d db_api.get_instance()"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_69a3e49f","line":60,"updated":"2017-07-14 02:07:48.000000000","message":"and _convert_to_version()","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"f3fb7f1cf8a6dd896290d03e3e28664560bdeabc","unresolved":false,"context_lines":[{"line_number":57,"context_line":"    #               power_interface, raid_interface, vendor_interface"},{"line_number":58,"context_line":"    # Version 1.20: Type of network_interface changed to just nullable string"},{"line_number":59,"context_line":"    # Version 1.21: Add storage_interface field"},{"line_number":60,"context_line":"    # Version 1.22: Add tags field"},{"line_number":61,"context_line":"    VERSION \u003d \u00271.22\u0027"},{"line_number":62,"context_line":""},{"line_number":63,"context_line":"    dbapi \u003d db_api.get_instance()"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_42a590b4","line":60,"in_reply_to":"1f1a1f67_69a3e49f","updated":"2017-07-14 13:23:38.000000000","message":"Done","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"cc2981e77f3f0153a085d0978d8d042bf3adaa64","unresolved":false,"context_lines":[{"line_number":138,"context_line":"                if remove_unavail_fields:"},{"line_number":139,"context_line":"                    delattr(self, \u0027tags\u0027)"},{"line_number":140,"context_line":"                else:"},{"line_number":141,"context_line":"                    self.tags \u003d None"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"},{"line_number":144,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_7ab5e8cc","line":141,"updated":"2017-07-14 02:07:48.000000000","message":"I tested this, and I see that when deserializing from a node in v1.21 to v1.22, tags is unset. [Eg api with old release, conductor with new release+pinned.] All the other node fields are set, and I think this should be set too. (Or do we not always do this; seems like if we don\u0027t, we\u0027d have a lot of places in conductor code where we have to check if the attr is set, before actually accessing it.) Maybe add something like \n\nif target_version \u003c (1, 22):\n   ...\nelif not self.obj_attr_is_set(\u0027tags\u0027):\n    self.tags  \u003d None\n\nAlthough I tried that and well, it requires some changes at the db/sqlalchemy layer too.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"f3fb7f1cf8a6dd896290d03e3e28664560bdeabc","unresolved":false,"context_lines":[{"line_number":138,"context_line":"                if remove_unavail_fields:"},{"line_number":139,"context_line":"                    delattr(self, \u0027tags\u0027)"},{"line_number":140,"context_line":"                else:"},{"line_number":141,"context_line":"                    self.tags \u003d None"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"},{"line_number":144,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_7f46e351","line":141,"in_reply_to":"1f1a1f67_7ab5e8cc","updated":"2017-07-14 13:23:38.000000000","message":"This upsets all the update node calls to the api. if the api is pinned, after applying the json patch, tags are present. then pinned api sets self.tags to None and sends them to the conductor. conductor then passes the values, including tags all the way down to the sqlalchemy.api._do_update_node, which complains about tags being None instead of list.\n\nThe more I look at it, the more I think we\u0027re trying to solve the non-existing problem here :) In the api, tags are set using the NodeTag objects, node\u0027s /tags path is blocked from updating from the api. If we need to update the tags in code, we can do the same thing, if we have node with tags, instead of doing node.save to save the updated tags, one can just do node.tags.create(). And in fact, this is what happens in nova with instance tags - it is also a TagList object there, and this is what happens during instance.save call -- https://github.com/openstack/nova/blob/d955eb1db753f191acb02eb9758080329da5b866/nova/objects/instance.py#L620","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"a88ac43ccef3d546f15ef854ce63825b5cc0f127","unresolved":false,"context_lines":[{"line_number":138,"context_line":"                if remove_unavail_fields:"},{"line_number":139,"context_line":"                    delattr(self, \u0027tags\u0027)"},{"line_number":140,"context_line":"                else:"},{"line_number":141,"context_line":"                    self.tags \u003d None"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"},{"line_number":144,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_2cb34c9a","line":141,"in_reply_to":"1f1a1f67_7f46e351","updated":"2017-07-18 14:33:35.000000000","message":"What you say is true for these tags, for the way it is being used/coded. What will break is some possible future case that may never happen.\n\nMy preference is to generalize this to \n\n1. deal with any future changes that don\u0027t make the assumptions you describe and \n\n2. as a \u0027model\u0027 for other features that need to add a _convert_to_version() method. Perhaps there is no way to come up with a generalized/template of _convert_to_version() right now, and it will evolve (or maybe just be different) depending on the feature/use case.\n\nSo if we decide not to do the above, we should make sure we add lots of comments about it.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"cc2981e77f3f0153a085d0978d8d042bf3adaa64","unresolved":false,"context_lines":[{"line_number":144,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"},{"line_number":145,"context_line":"        super(Node, self)._set_from_db_object(context, db_node, fields)"},{"line_number":146,"context_line":"        self.tags \u003d tags.NodeTagList.from_db_tags_list("},{"line_number":147,"context_line":"            context, db_node[\u0027tags\u0027])"},{"line_number":148,"context_line":""},{"line_number":149,"context_line":"    def _validate_property_values(self, properties):"},{"line_number":150,"context_line":"        \"\"\"Check if the input of local_gb, cpus and memory_mb are valid."}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_895f6071","line":147,"updated":"2017-07-14 02:07:48.000000000","message":"I commented elsewhere about this, but will mention it again :-)\n\ndb_node[\u0027tags\u0027] is misleading to me. It made me think that the nodes DB table had a \u0027tags\u0027 column. Which it doesn\u0027t. I think the code would be cleaner if we just set self.tags \u003d tags.NodeTagList() or None. Or why doesn\u0027t it call tags.NodeTagList.get_from_node_id()?\n\nTo be honest, I haven\u0027t gotten through all the code to understand where node.tags actually gets set. I was going to try to test it out but ran out of time. So it is quite possible that I don\u0027t understand how all this code works.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"f3fb7f1cf8a6dd896290d03e3e28664560bdeabc","unresolved":false,"context_lines":[{"line_number":144,"context_line":"        fields \u003d set(fields or self.fields) - {\u0027tags\u0027}"},{"line_number":145,"context_line":"        super(Node, self)._set_from_db_object(context, db_node, fields)"},{"line_number":146,"context_line":"        self.tags \u003d tags.NodeTagList.from_db_tags_list("},{"line_number":147,"context_line":"            context, db_node[\u0027tags\u0027])"},{"line_number":148,"context_line":""},{"line_number":149,"context_line":"    def _validate_property_values(self, properties):"},{"line_number":150,"context_line":"        \"\"\"Check if the input of local_gb, cpus and memory_mb are valid."}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_0a1d740e","line":147,"in_reply_to":"1f1a1f67_895f6071","updated":"2017-07-14 13:23:38.000000000","message":"We do the join on the db level, hence db_node contains tags already. We could do the get_from_node_id but it would mean one more DB call which is unnecessary.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"39d604312cd2814942154eab571d8b00d11a4416","unresolved":false,"context_lines":[{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                # NOTE(vdrok): We don\u0027t care about keeping tags changes, to"},{"line_number":139,"context_line":"                # update the tags NodeTagList create method should be used"},{"line_number":140,"context_line":"                delattr(self, \u0027tags\u0027)"},{"line_number":141,"context_line":""},{"line_number":142,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"}],"source_content_type":"text/x-python","patch_set":66,"id":"1f1a1f67_276b67b7","line":139,"updated":"2017-07-18 14:30:58.000000000","message":"I think we ought to also add a comment, maybe after L134: \n\nThis assumes that the conductor doesn\u0027t access node.tags without checking that it is set, because not keeping the tags changes (or setting its value if unset) means that it may be unset (a different behaviour from the other fields).","commit_id":"35ddc67bdc6d28692a26ece6d5b555ea8b27cf49"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"00d31f6a5fed8033f89fef1de5e4005d451ec47a","unresolved":false,"context_lines":[{"line_number":136,"context_line":"        if target_version \u003c (1, 22):"},{"line_number":137,"context_line":"            if self.obj_attr_is_set(\u0027tags\u0027):"},{"line_number":138,"context_line":"                # NOTE(vdrok): We don\u0027t care about keeping tags changes, to"},{"line_number":139,"context_line":"                # update the tags NodeTagList create method should be used"},{"line_number":140,"context_line":"                delattr(self, \u0027tags\u0027)"},{"line_number":141,"context_line":""},{"line_number":142,"context_line":"    def _set_from_db_object(self, context, db_node, fields\u003dNone):"}],"source_content_type":"text/x-python","patch_set":66,"id":"ff346bd7_456773b8","line":139,"in_reply_to":"1f1a1f67_276b67b7","updated":"2017-07-28 15:53:45.000000000","message":"Done","commit_id":"35ddc67bdc6d28692a26ece6d5b555ea8b27cf49"}],"ironic/objects/tags.py":[{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"09f1a60560c5ed10260170b37c33751dd67743fc","unresolved":false,"context_lines":[{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"@base.IronicObjectRegistry.register"},{"line_number":21,"context_line":"class Tag(base.IronicObject, object_base.VersionedObjectDictCompat):"},{"line_number":22,"context_line":"    fields \u003d {"},{"line_number":23,"context_line":"        \u0027tag\u0027: object_fields.StringField(),"},{"line_number":24,"context_line":"        \u0027node_id\u0027: object_fields.IntegerField(),"}],"source_content_type":"text/x-python","patch_set":5,"id":"da85f559_b020faf8","line":21,"updated":"2015-11-09 07:21:54.000000000","message":"From the chain of your patches, this should be NodeTag instead of a general tag object, right?","commit_id":"040109c0df11e60c98ce26c1aa6e2a4087646d68"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"4c263db367a4244e594db587011ec8ffed5943c2","unresolved":false,"context_lines":[{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"@base.IronicObjectRegistry.register"},{"line_number":21,"context_line":"class Tag(base.IronicObject, object_base.VersionedObjectDictCompat):"},{"line_number":22,"context_line":"    fields \u003d {"},{"line_number":23,"context_line":"        \u0027tag\u0027: object_fields.StringField(),"},{"line_number":24,"context_line":"        \u0027node_id\u0027: object_fields.IntegerField(),"}],"source_content_type":"text/x-python","patch_set":5,"id":"da85f559_41ca1ea3","line":21,"in_reply_to":"da85f559_b020faf8","updated":"2015-11-09 08:41:55.000000000","message":"yeah, you are right.","commit_id":"040109c0df11e60c98ce26c1aa6e2a4087646d68"},{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"09f1a60560c5ed10260170b37c33751dd67743fc","unresolved":false,"context_lines":[{"line_number":34,"context_line":"        return tag"},{"line_number":35,"context_line":""},{"line_number":36,"context_line":"    @classmethod"},{"line_number":37,"context_line":"    def get_obj(cls, context, tag):"},{"line_number":38,"context_line":"        return cls._from_db_object(cls(context), tag)"},{"line_number":39,"context_line":""},{"line_number":40,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"da85f559_1093065d","line":37,"updated":"2015-11-09 07:21:54.000000000","message":"1. rename tag to db_tag maybe better\n 2. I didn\u0027t see where you call this func.\n 3. are you sure this will work as you expect, you have change  _from_db_object() in Node object","commit_id":"040109c0df11e60c98ce26c1aa6e2a4087646d68"},{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"09f1a60560c5ed10260170b37c33751dd67743fc","unresolved":false,"context_lines":[{"line_number":39,"context_line":""},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"@base.IronicObjectRegistry.register"},{"line_number":42,"context_line":"class TagList(base.IronicObject, object_base.VersionedObjectDictCompat):"},{"line_number":43,"context_line":"    dbapi \u003d dbapi.get_instance()"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"    fields \u003d {"}],"source_content_type":"text/x-python","patch_set":5,"id":"da85f559_70ee128d","line":42,"updated":"2015-11-09 07:21:54.000000000","message":"ditto","commit_id":"040109c0df11e60c98ce26c1aa6e2a4087646d68"},{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"09f1a60560c5ed10260170b37c33751dd67743fc","unresolved":false,"context_lines":[{"line_number":47,"context_line":"    }"},{"line_number":48,"context_line":""},{"line_number":49,"context_line":"    @classmethod"},{"line_number":50,"context_line":"    def get(cls, context, node_id):"},{"line_number":51,"context_line":"        db_tags \u003d cls.dbapi.node_tags_get(node_id)"},{"line_number":52,"context_line":"        if db_tags:"},{"line_number":53,"context_line":"            return object_base.obj_make_list(context, cls(), Tag, db_tags)"}],"source_content_type":"text/x-python","patch_set":5,"id":"da85f559_93d5c044","line":50,"updated":"2015-11-09 07:21:54.000000000","message":"what about get_by_node_id?","commit_id":"040109c0df11e60c98ce26c1aa6e2a4087646d68"},{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"d6510b0d116ec8dd592f3004069b2f6b8cd94861","unresolved":false,"context_lines":[{"line_number":34,"context_line":"        tag.obj_reset_changes()"},{"line_number":35,"context_line":"        return tag"},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"    def create(self, context\u003dNone):"},{"line_number":38,"context_line":"        db_tag \u003d self.dbapi.node_tag_add(self.node_id, self.tag)"},{"line_number":39,"context_line":"        self._from_db_object(context, self, db_tag)"},{"line_number":40,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"da85f559_0bb5d52f","line":37,"updated":"2015-11-16 07:01:29.000000000","message":"Add doc please, like raises exception","commit_id":"19a199380c05a61f52f273ad2b03495aaffaa59e"},{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"d6510b0d116ec8dd592f3004069b2f6b8cd94861","unresolved":false,"context_lines":[{"line_number":36,"context_line":""},{"line_number":37,"context_line":"    def create(self, context\u003dNone):"},{"line_number":38,"context_line":"        db_tag \u003d self.dbapi.node_tag_add(self.node_id, self.tag)"},{"line_number":39,"context_line":"        self._from_db_object(context, self, db_tag)"},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    @classmethod"},{"line_number":42,"context_line":"    def destroy(cls, context, node_id, tag):"}],"source_content_type":"text/x-python","patch_set":6,"id":"da85f559_eb55f1c5","line":39,"updated":"2015-11-16 07:01:29.000000000","message":"I am wondering if you don\u0027t return the tag, why do we have to convert it to a formal object. This is useless.....","commit_id":"19a199380c05a61f52f273ad2b03495aaffaa59e"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"8405446402399173fb02a1933d9e4582d90ec6f5","unresolved":false,"context_lines":[{"line_number":36,"context_line":""},{"line_number":37,"context_line":"    def create(self, context\u003dNone):"},{"line_number":38,"context_line":"        db_tag \u003d self.dbapi.node_tag_add(self.node_id, self.tag)"},{"line_number":39,"context_line":"        self._from_db_object(context, self, db_tag)"},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    @classmethod"},{"line_number":42,"context_line":"    def destroy(cls, context, node_id, tag):"}],"source_content_type":"text/x-python","patch_set":6,"id":"ba8a016a_48463850","line":39,"in_reply_to":"da85f559_eb55f1c5","updated":"2015-11-19 02:16:01.000000000","message":"yes, thanks Tan, I meant to return the tag here.","commit_id":"19a199380c05a61f52f273ad2b03495aaffaa59e"},{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"d6510b0d116ec8dd592f3004069b2f6b8cd94861","unresolved":false,"context_lines":[{"line_number":39,"context_line":"        self._from_db_object(context, self, db_tag)"},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    @classmethod"},{"line_number":42,"context_line":"    def destroy(cls, context, node_id, tag):"},{"line_number":43,"context_line":"        cls.dbapi.node_tag_delete(node_id, tag)"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"da85f559_4b92fda0","line":42,"updated":"2015-11-16 07:01:29.000000000","message":"ditto","commit_id":"19a199380c05a61f52f273ad2b03495aaffaa59e"},{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"d6510b0d116ec8dd592f3004069b2f6b8cd94861","unresolved":false,"context_lines":[{"line_number":52,"context_line":"    }"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"    @classmethod"},{"line_number":55,"context_line":"    def get_by_node_id(cls, context, node_id):"},{"line_number":56,"context_line":"        db_tags \u003d cls.dbapi.node_tags_get(node_id)"},{"line_number":57,"context_line":"        if db_tags:"},{"line_number":58,"context_line":"            return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"}],"source_content_type":"text/x-python","patch_set":6,"id":"da85f559_6bf3410b","line":55,"updated":"2015-11-16 07:01:29.000000000","message":"ditto","commit_id":"19a199380c05a61f52f273ad2b03495aaffaa59e"},{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"d6510b0d116ec8dd592f3004069b2f6b8cd94861","unresolved":false,"context_lines":[{"line_number":58,"context_line":"            return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":59,"context_line":""},{"line_number":60,"context_line":"    @classmethod"},{"line_number":61,"context_line":"    def set(cls, context, node_id, tags):"},{"line_number":62,"context_line":"        db_tags \u003d cls.dbapi.node_tags_set(node_id, tags)"},{"line_number":63,"context_line":"        if db_tags:"},{"line_number":64,"context_line":"            return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"}],"source_content_type":"text/x-python","patch_set":6,"id":"da85f559_2bde996d","line":61,"updated":"2015-11-16 07:01:29.000000000","message":"ditto","commit_id":"19a199380c05a61f52f273ad2b03495aaffaa59e"},{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"d6510b0d116ec8dd592f3004069b2f6b8cd94861","unresolved":false,"context_lines":[{"line_number":64,"context_line":"            return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":65,"context_line":""},{"line_number":66,"context_line":"    @classmethod"},{"line_number":67,"context_line":"    def destroy(cls, context, node_id):"},{"line_number":68,"context_line":"        cls.dbapi.node_tags_delete(node_id)"}],"source_content_type":"text/x-python","patch_set":6,"id":"da85f559_ebe7313e","line":67,"updated":"2015-11-16 07:01:29.000000000","message":"ditto","commit_id":"19a199380c05a61f52f273ad2b03495aaffaa59e"},{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"a0be52979beef0b9fb08aba700b66716f4843393","unresolved":false,"context_lines":[{"line_number":42,"context_line":"                        Unfortunately, RPC requires context as the first"},{"line_number":43,"context_line":"                        argument, even though we don\u0027t use it."},{"line_number":44,"context_line":"                        A context should be set when instantiating the"},{"line_number":45,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":46,"context_line":"        \"\"\""},{"line_number":47,"context_line":"        db_tag \u003d self.dbapi.node_tag_add(self.node_id, self.tag)"},{"line_number":48,"context_line":"        return self._from_db_object(context, self, db_tag)"}],"source_content_type":"text/x-python","patch_set":10,"id":"9a8ffd7b_ebcfa826","line":45,"updated":"2015-11-30 05:54:29.000000000","message":"add returns parameter please, since you will return the tag","commit_id":"5861c0fd06a7530852ce23116e4f523cb22b7ac2"},{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"dfd713189a40295764d11b936487f6ffdf66da5d","unresolved":false,"context_lines":[{"line_number":76,"context_line":"        :param node_id: the id of a node."},{"line_number":77,"context_line":"        :returns: a :class:`NodeTagList` object."},{"line_number":78,"context_line":"        \"\"\""},{"line_number":79,"context_line":"        db_tags \u003d dbapi.get_instance().node_tags_get(node_id)"},{"line_number":80,"context_line":"        return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":81,"context_line":""},{"line_number":82,"context_line":"    @classmethod"}],"source_content_type":"text/x-python","patch_set":14,"id":"9a8ffd7b_ec56fd5a","line":79,"updated":"2015-12-03 13:59:46.000000000","message":"Any specific reason to not create a class attribute dbapi like NodeTag? At least they should be same.","commit_id":"50373eedf57799730a52c1709ae486b3335dd58b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"3e247ed30d82a90c00ed198060630970c3ec8b83","unresolved":false,"context_lines":[{"line_number":76,"context_line":"        :param node_id: the id of a node."},{"line_number":77,"context_line":"        :returns: a :class:`NodeTagList` object."},{"line_number":78,"context_line":"        \"\"\""},{"line_number":79,"context_line":"        db_tags \u003d dbapi.get_instance().node_tags_get(node_id)"},{"line_number":80,"context_line":"        return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":81,"context_line":""},{"line_number":82,"context_line":"    @classmethod"}],"source_content_type":"text/x-python","patch_set":14,"id":"7a740942_1836ea03","line":79,"in_reply_to":"9a8ffd7b_ec56fd5a","updated":"2015-12-03 17:00:49.000000000","message":"I tried to, but there\u0027s some problems when NodeTagList class inheris from ObjectListBase, I didn\u0027t figure out why, so not use dbapi as class attribute.","commit_id":"50373eedf57799730a52c1709ae486b3335dd58b"},{"author":{"_account_id":8106,"name":"Haomeng,Wang","email":"wanghaomeng@gmail.com","username":"whaom"},"change_message_id":"7d08d2f526611c4a6334bba9457ff722786afc20","unresolved":false,"context_lines":[{"line_number":83,"context_line":"    def set(cls, context, node_id, tags):"},{"line_number":84,"context_line":"        \"\"\"Set a list of tags to a node."},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"        :param node_id: the id of a node."},{"line_number":87,"context_line":"        :returns: a :class:`NodeTagList` object."},{"line_number":88,"context_line":"        \"\"\""},{"line_number":89,"context_line":"        db_tags \u003d dbapi.get_instance().node_tags_set(node_id, tags)"}],"source_content_type":"text/x-python","patch_set":18,"id":"9a68dd71_7d5f71e5","line":86,"range":{"start_line":86,"start_character":40,"end_line":86,"end_character":41},"updated":"2016-01-22 05:23:32.000000000","message":"nit: missing \":param tags: xxx\" here.","commit_id":"a8b4d802f34488ee021f869b324c866fac72c0de"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"3befc71936a87ea082d2db505e23018fd22a92d6","unresolved":false,"context_lines":[{"line_number":57,"context_line":"                        Unfortunately, RPC requires context as the first"},{"line_number":58,"context_line":"                        argument, even though we don\u0027t use it."},{"line_number":59,"context_line":"                        A context should be set when instantiating the"},{"line_number":60,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":61,"context_line":"        \"\"\""},{"line_number":62,"context_line":"        cls.dbapi.delete_node_tag(node_id, tag)"},{"line_number":63,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_642ffbf6","line":60,"updated":"2016-01-28 16:21:43.000000000","message":"Missing other params and returns here.","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"e6f1ad3d50610cb382402134a32127b151d40bc6","unresolved":false,"context_lines":[{"line_number":57,"context_line":"                        Unfortunately, RPC requires context as the first"},{"line_number":58,"context_line":"                        argument, even though we don\u0027t use it."},{"line_number":59,"context_line":"                        A context should be set when instantiating the"},{"line_number":60,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":61,"context_line":"        \"\"\""},{"line_number":62,"context_line":"        cls.dbapi.delete_node_tag(node_id, tag)"},{"line_number":63,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_dab54331","line":60,"in_reply_to":"7a5de9d1_642ffbf6","updated":"2016-01-29 07:36:06.000000000","message":"will add the other params but there\u0027s no returns.","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"3befc71936a87ea082d2db505e23018fd22a92d6","unresolved":false,"context_lines":[{"line_number":76,"context_line":"        :param node_id: the id of a node."},{"line_number":77,"context_line":"        :returns: a :class:`NodeTagList` object."},{"line_number":78,"context_line":"        \"\"\""},{"line_number":79,"context_line":"        db_tags \u003d dbapi.get_instance().get_node_tags(node_id)"},{"line_number":80,"context_line":"        return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":81,"context_line":""},{"line_number":82,"context_line":"    @classmethod"}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_c497cf8e","line":79,"updated":"2016-01-28 16:21:43.000000000","message":"Not sure why can\u0027t you add dbapi as a class attribute, seems it should work.","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"e6f1ad3d50610cb382402134a32127b151d40bc6","unresolved":false,"context_lines":[{"line_number":76,"context_line":"        :param node_id: the id of a node."},{"line_number":77,"context_line":"        :returns: a :class:`NodeTagList` object."},{"line_number":78,"context_line":"        \"\"\""},{"line_number":79,"context_line":"        db_tags \u003d dbapi.get_instance().get_node_tags(node_id)"},{"line_number":80,"context_line":"        return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":81,"context_line":""},{"line_number":82,"context_line":"    @classmethod"}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_1a867bb9","line":79,"in_reply_to":"7a5de9d1_c497cf8e","updated":"2016-01-29 07:36:06.000000000","message":"Done","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"3befc71936a87ea082d2db505e23018fd22a92d6","unresolved":false,"context_lines":[{"line_number":80,"context_line":"        return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":81,"context_line":""},{"line_number":82,"context_line":"    @classmethod"},{"line_number":83,"context_line":"    def set(cls, context, node_id, tags):"},{"line_number":84,"context_line":"        \"\"\"Set a list of tags to a node."},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"        :param node_id: the id of a node."}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_a4a9737d","line":83,"updated":"2016-01-28 16:21:43.000000000","message":"Would be good to come up with a different name as set is a reserved word.","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"e6f1ad3d50610cb382402134a32127b151d40bc6","unresolved":false,"context_lines":[{"line_number":80,"context_line":"        return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":81,"context_line":""},{"line_number":82,"context_line":"    @classmethod"},{"line_number":83,"context_line":"    def set(cls, context, node_id, tags):"},{"line_number":84,"context_line":"        \"\"\"Set a list of tags to a node."},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"        :param node_id: the id of a node."}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_9ac02be2","line":83,"in_reply_to":"7a5de9d1_a4a9737d","updated":"2016-01-29 07:36:06.000000000","message":"Done","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"0eb4a21c1125c245e85dc77bc42ac2ac60f44cac","unresolved":false,"context_lines":[{"line_number":22,"context_line":"    dbapi \u003d dbapi.get_instance()"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    fields \u003d {"},{"line_number":25,"context_line":"        \u0027tag\u0027: object_fields.StringField(),"},{"line_number":26,"context_line":"        \u0027node_id\u0027: object_fields.IntegerField(),"},{"line_number":27,"context_line":"    }"},{"line_number":28,"context_line":""}],"source_content_type":"text/x-python","patch_set":45,"id":"1a6eadb0_9de195d3","line":25,"range":{"start_line":25,"start_character":9,"end_line":25,"end_character":12},"updated":"2016-12-19 18:01:35.000000000","message":"Hm, I\u0027d prefer something like value here, as node.tags[0].tag reads strange. Not a big deal tho.","commit_id":"914ed07d4f14fbe9f28a1a3478f80270b83fbc2a"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"84879f20ce3c4d4c4dc78474361f073c97fdd317","unresolved":false,"context_lines":[{"line_number":22,"context_line":"    dbapi \u003d dbapi.get_instance()"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    fields \u003d {"},{"line_number":25,"context_line":"        \u0027tag\u0027: object_fields.StringField(),"},{"line_number":26,"context_line":"        \u0027node_id\u0027: object_fields.IntegerField(),"},{"line_number":27,"context_line":"    }"},{"line_number":28,"context_line":""}],"source_content_type":"text/x-python","patch_set":46,"id":"7a3c09a3_feecf1f4","line":25,"range":{"start_line":25,"start_character":9,"end_line":25,"end_character":12},"updated":"2017-01-16 18:55:11.000000000","message":"I would still like to have it as \u0027value\u0027, or something like that. So that we could do smth like:\n\n for tag in node.tags:\n   tag_value \u003d tag.value\n   ...\n\ninstead of:\n\n for tag in node.tags:\n   tag_value \u003d tag.tag\n   ...","commit_id":"55593008c270346a5a3bd9ad757e459f8e25c676"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"6642b0598a86749d6f7ea5873cb2071bfff44ec6","unresolved":false,"context_lines":[{"line_number":22,"context_line":"    dbapi \u003d dbapi.get_instance()"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    fields \u003d {"},{"line_number":25,"context_line":"        \u0027tag\u0027: object_fields.StringField(),"},{"line_number":26,"context_line":"        \u0027node_id\u0027: object_fields.IntegerField(),"},{"line_number":27,"context_line":"    }"},{"line_number":28,"context_line":""}],"source_content_type":"text/x-python","patch_set":46,"id":"7a3c09a3_6a3e6c8d","line":25,"range":{"start_line":25,"start_character":9,"end_line":25,"end_character":12},"in_reply_to":"7a3c09a3_cf74d269","updated":"2017-01-17 02:46:50.000000000","message":"hi vdrok, after browsing other projects code, seems they all use a tag instead of value, maybe better to leave this as is to keep consistent, wdyt?\n\nhttps://github.com/openstack/nova/blob/master/nova/objects/tag.py#L29","commit_id":"55593008c270346a5a3bd9ad757e459f8e25c676"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"068a688f9eed9c6f748e6335a6d397f964d2dce1","unresolved":false,"context_lines":[{"line_number":22,"context_line":"    dbapi \u003d dbapi.get_instance()"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    fields \u003d {"},{"line_number":25,"context_line":"        \u0027tag\u0027: object_fields.StringField(),"},{"line_number":26,"context_line":"        \u0027node_id\u0027: object_fields.IntegerField(),"},{"line_number":27,"context_line":"    }"},{"line_number":28,"context_line":""}],"source_content_type":"text/x-python","patch_set":46,"id":"7a3c09a3_cf74d269","line":25,"range":{"start_line":25,"start_character":9,"end_line":25,"end_character":12},"in_reply_to":"7a3c09a3_feecf1f4","updated":"2017-01-17 02:12:43.000000000","message":"ok, will update soon, thanks!","commit_id":"55593008c270346a5a3bd9ad757e459f8e25c676"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"04704727566b0842d5b8fea6c3f6d2505f75eb4d","unresolved":false,"context_lines":[{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"@base.IronicObjectRegistry.register"},{"line_number":21,"context_line":"class NodeTag(base.IronicObject, object_base.VersionedObjectDictCompat):"},{"line_number":22,"context_line":"    dbapi \u003d dbapi.get_instance()"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    fields \u003d {"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_8154f8c9","line":21,"updated":"2017-01-24 15:26:34.000000000","message":"Please add an explicit VERSION here. It will inherit 1.0, but to be consistent with the other objects (and so we don\u0027t forget to update it if this object changes) it is better to be explicit. E.g.\n\n    # Version 1.0: Initial version\n    VERSION \u003d \u00271.0\u0027","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"7712c9e38ef69ba08a03307e7ef7211ef7ba2bb8","unresolved":false,"context_lines":[{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"@base.IronicObjectRegistry.register"},{"line_number":21,"context_line":"class NodeTag(base.IronicObject, object_base.VersionedObjectDictCompat):"},{"line_number":22,"context_line":"    dbapi \u003d dbapi.get_instance()"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"    fields \u003d {"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_3013700f","line":21,"in_reply_to":"5a3905b3_8154f8c9","updated":"2017-01-25 03:43:17.000000000","message":"Done","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"04704727566b0842d5b8fea6c3f6d2505f75eb4d","unresolved":false,"context_lines":[{"line_number":32,"context_line":"        for field in tag.fields:"},{"line_number":33,"context_line":"            tag[field] \u003d db_tag[field]"},{"line_number":34,"context_line":"        tag.obj_reset_changes()"},{"line_number":35,"context_line":"        return tag"},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"    def create(self, context\u003dNone):"},{"line_number":38,"context_line":"        \"\"\"Create a NodeTag record in the DB."}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_01aac884","line":35,"updated":"2017-01-24 15:26:34.000000000","message":"this method isn\u0027t needed; it can use the one from base.py","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"7712c9e38ef69ba08a03307e7ef7211ef7ba2bb8","unresolved":false,"context_lines":[{"line_number":32,"context_line":"        for field in tag.fields:"},{"line_number":33,"context_line":"            tag[field] \u003d db_tag[field]"},{"line_number":34,"context_line":"        tag.obj_reset_changes()"},{"line_number":35,"context_line":"        return tag"},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"    def create(self, context\u003dNone):"},{"line_number":38,"context_line":"        \"\"\"Create a NodeTag record in the DB."}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_b0eda0f1","line":35,"in_reply_to":"5a3905b3_01aac884","updated":"2017-01-25 03:43:17.000000000","message":"we need to pass context as the first parameter, as oslo_versionedobjects.obj_make_list will call _from_db_object with context, unfortunately we don\u0027t have that parameter in base.py\n\n  https://github.com/openstack/oslo.versionedobjects/blob/master/oslo_versionedobjects/base.py#L1117","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"04704727566b0842d5b8fea6c3f6d2505f75eb4d","unresolved":false,"context_lines":[{"line_number":49,"context_line":"        return self._from_db_object(context, self, db_tag)"},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"    @classmethod"},{"line_number":52,"context_line":"    def destroy(cls, context, node_id, tag):"},{"line_number":53,"context_line":"        \"\"\"Delete the NodeTag from the DB."},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"        :param context: Security context. NOTE: This should only"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_9c5c5f1a","line":52,"updated":"2017-01-24 15:26:34.000000000","message":"I am concerned about making this a class method. This makes it inconsistent from the other objects we have. And if we ever enable RPC on the other object destroy\u0027s, it won\u0027t be available for this. I suspect we don\u0027t need that functionality but I think this deserves a comment to explain why this is a class method.","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"7712c9e38ef69ba08a03307e7ef7211ef7ba2bb8","unresolved":false,"context_lines":[{"line_number":49,"context_line":"        return self._from_db_object(context, self, db_tag)"},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"    @classmethod"},{"line_number":52,"context_line":"    def destroy(cls, context, node_id, tag):"},{"line_number":53,"context_line":"        \"\"\"Delete the NodeTag from the DB."},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"        :param context: Security context. NOTE: This should only"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_1082f4c8","line":52,"in_reply_to":"5a3905b3_5393c55a","updated":"2017-01-25 03:43:17.000000000","message":"seems yes, will change this to instance method.","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"4695993a9305ee85606a6f127c4059d02e8f0514","unresolved":false,"context_lines":[{"line_number":49,"context_line":"        return self._from_db_object(context, self, db_tag)"},{"line_number":50,"context_line":""},{"line_number":51,"context_line":"    @classmethod"},{"line_number":52,"context_line":"    def destroy(cls, context, node_id, tag):"},{"line_number":53,"context_line":"        \"\"\"Delete the NodeTag from the DB."},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"        :param context: Security context. NOTE: This should only"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_5393c55a","line":52,"in_reply_to":"5a3905b3_9c5c5f1a","updated":"2017-01-24 15:49:14.000000000","message":"Yeah, I don\u0027t like these methods myself. Some are classmethods, some instance methods... OVO base class does not define all these create/destroy methods, we don\u0027t have them in IronicBase, so I guess it\u0027s up to every particular object to decide what\u0027s needed here. And I don\u0027t know if insance method is better than class method in this case :)","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"04704727566b0842d5b8fea6c3f6d2505f75eb4d","unresolved":false,"context_lines":[{"line_number":59,"context_line":"                        A context should be set when instantiating the"},{"line_number":60,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":61,"context_line":"        :param node_id: the id of a node."},{"line_number":62,"context_line":"        :param tag: node tag."},{"line_number":63,"context_line":"        \"\"\""},{"line_number":64,"context_line":"        cls.dbapi.delete_node_tag(node_id, tag)"},{"line_number":65,"context_line":""}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_3c99abc4","line":62,"updated":"2017-01-24 15:26:34.000000000","message":"this is a string, right? Not even a \u0027node tag\u0027. It is just a tag that we associated with the node.","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"7712c9e38ef69ba08a03307e7ef7211ef7ba2bb8","unresolved":false,"context_lines":[{"line_number":59,"context_line":"                        A context should be set when instantiating the"},{"line_number":60,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":61,"context_line":"        :param node_id: the id of a node."},{"line_number":62,"context_line":"        :param tag: node tag."},{"line_number":63,"context_line":"        \"\"\""},{"line_number":64,"context_line":"        cls.dbapi.delete_node_tag(node_id, tag)"},{"line_number":65,"context_line":""}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_302450ae","line":62,"in_reply_to":"5a3905b3_3c99abc4","updated":"2017-01-25 03:43:17.000000000","message":"yes, it\u0027s actually a string","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"04704727566b0842d5b8fea6c3f6d2505f75eb4d","unresolved":false,"context_lines":[{"line_number":65,"context_line":""},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"@base.IronicObjectRegistry.register"},{"line_number":68,"context_line":"class NodeTagList(base.IronicObject, object_base.ObjectListBase):"},{"line_number":69,"context_line":"    dbapi \u003d dbapi.get_instance()"},{"line_number":70,"context_line":""},{"line_number":71,"context_line":"    fields \u003d {"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_fc3f2384","line":68,"updated":"2017-01-24 15:26:34.000000000","message":"ditto about VERSION","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"7712c9e38ef69ba08a03307e7ef7211ef7ba2bb8","unresolved":false,"context_lines":[{"line_number":65,"context_line":""},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"@base.IronicObjectRegistry.register"},{"line_number":68,"context_line":"class NodeTagList(base.IronicObject, object_base.ObjectListBase):"},{"line_number":69,"context_line":"    dbapi \u003d dbapi.get_instance()"},{"line_number":70,"context_line":""},{"line_number":71,"context_line":"    fields \u003d {"}],"source_content_type":"text/x-python","patch_set":50,"id":"5a3905b3_f02f283c","line":68,"in_reply_to":"5a3905b3_fc3f2384","updated":"2017-01-25 03:43:17.000000000","message":"Done","commit_id":"d9c3c19b308b0f4e53737f7d5a7e6d2abf28e26b"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"b847272f14615d404c21032a1aaf220b3bf359bf","unresolved":false,"context_lines":[{"line_number":30,"context_line":"    }"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"    @staticmethod"},{"line_number":33,"context_line":"    def _from_db_object(context, tag, db_tag):"},{"line_number":34,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":35,"context_line":"        for field in tag.fields:"},{"line_number":36,"context_line":"            tag[field] \u003d db_tag[field]"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_10af6ce4","line":33,"updated":"2017-02-09 21:34:46.000000000","message":"This is doing the exact same thing as base.IronicObject, so it\u0027s unnecessary: https://github.com/openstack/ironic/blob/master/ironic/objects/base.py#L78\n\nRight?","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":14760,"name":"John L. Villalovos","email":"openstack.org@sodarock.com","username":"jlvillal"},"change_message_id":"6d0e269630c12326844f4035f08882d19b112134","unresolved":false,"context_lines":[{"line_number":30,"context_line":"    }"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"    @staticmethod"},{"line_number":33,"context_line":"    def _from_db_object(context, tag, db_tag):"},{"line_number":34,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":35,"context_line":"        for field in tag.fields:"},{"line_number":36,"context_line":"            tag[field] \u003d db_tag[field]"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_90d27c33","line":33,"updated":"2017-02-09 21:39:35.000000000","message":"Why aren\u0027t we using the base class method? Via using super()\n\nIs it required to have \u0027context\u0027 in this signature?","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":23883,"name":"Joanna Taryma","email":"joanna.taryma@intel.com","username":"jtaryma"},"change_message_id":"cd8f942b7060588b68ecc002c09fac2bb9166d2d","unresolved":false,"context_lines":[{"line_number":30,"context_line":"    }"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"    @staticmethod"},{"line_number":33,"context_line":"    def _from_db_object(context, tag, db_tag):"},{"line_number":34,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":35,"context_line":"        for field in tag.fields:"},{"line_number":36,"context_line":"            tag[field] \u003d db_tag[field]"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_50c80475","line":33,"in_reply_to":"fa31d9ce_10af6ce4","updated":"2017-02-09 21:41:59.000000000","message":"The only difference is in parameters, but additional \u0027context\u0027 param seems unused","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"5333b4c10b0440ba9b68c8c0c98ec982329eacf6","unresolved":false,"context_lines":[{"line_number":30,"context_line":"    }"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"    @staticmethod"},{"line_number":33,"context_line":"    def _from_db_object(context, tag, db_tag):"},{"line_number":34,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":35,"context_line":"        for field in tag.fields:"},{"line_number":36,"context_line":"            tag[field] \u003d db_tag[field]"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_c78c3138","line":33,"in_reply_to":"fa31d9ce_50c80475","updated":"2017-02-10 02:48:39.000000000","message":"This is also because obj_make_list in also versionobject :(","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":14760,"name":"John L. Villalovos","email":"openstack.org@sodarock.com","username":"jlvillal"},"change_message_id":"6d0e269630c12326844f4035f08882d19b112134","unresolved":false,"context_lines":[{"line_number":49,"context_line":"        :returns: a :class:`NodeTag` object."},{"line_number":50,"context_line":"        \"\"\""},{"line_number":51,"context_line":"        db_tag \u003d self.dbapi.add_node_tag(self.node_id, self.tag)"},{"line_number":52,"context_line":"        return self._from_db_object(context, self, db_tag)"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"    def destroy(self, context, node_id, tag):"},{"line_number":55,"context_line":"        \"\"\"Delete the NodeTag from the DB."}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_f0865812","line":52,"updated":"2017-02-09 21:39:35.000000000","message":"Don\u0027t need to use context here. If use base class _from_db_object()","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"b847272f14615d404c21032a1aaf220b3bf359bf","unresolved":false,"context_lines":[{"line_number":49,"context_line":"        :returns: a :class:`NodeTag` object."},{"line_number":50,"context_line":"        \"\"\""},{"line_number":51,"context_line":"        db_tag \u003d self.dbapi.add_node_tag(self.node_id, self.tag)"},{"line_number":52,"context_line":"        return self._from_db_object(context, self, db_tag)"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"    def destroy(self, context, node_id, tag):"},{"line_number":55,"context_line":"        \"\"\"Delete the NodeTag from the DB."}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_b03b009c","line":52,"range":{"start_line":52,"start_character":36,"end_line":52,"end_character":43},"updated":"2017-02-09 21:34:46.000000000","message":"Not sure why the context is being passed here.","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"b847272f14615d404c21032a1aaf220b3bf359bf","unresolved":false,"context_lines":[{"line_number":51,"context_line":"        db_tag \u003d self.dbapi.add_node_tag(self.node_id, self.tag)"},{"line_number":52,"context_line":"        return self._from_db_object(context, self, db_tag)"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"    def destroy(self, context, node_id, tag):"},{"line_number":55,"context_line":"        \"\"\"Delete the NodeTag from the DB."},{"line_number":56,"context_line":""},{"line_number":57,"context_line":"        :param context: Security context. NOTE: This should only"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_50e72440","line":54,"range":{"start_line":54,"start_character":22,"end_line":54,"end_character":29},"updated":"2017-02-09 21:34:46.000000000","message":"Why not context\u003dNone here?","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"5333b4c10b0440ba9b68c8c0c98ec982329eacf6","unresolved":false,"context_lines":[{"line_number":51,"context_line":"        db_tag \u003d self.dbapi.add_node_tag(self.node_id, self.tag)"},{"line_number":52,"context_line":"        return self._from_db_object(context, self, db_tag)"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"    def destroy(self, context, node_id, tag):"},{"line_number":55,"context_line":"        \"\"\"Delete the NodeTag from the DB."},{"line_number":56,"context_line":""},{"line_number":57,"context_line":"        :param context: Security context. NOTE: This should only"}],"source_content_type":"text/x-python","patch_set":52,"id":"fa31d9ce_e7aa1585","line":54,"range":{"start_line":54,"start_character":22,"end_line":54,"end_character":29},"in_reply_to":"fa31d9ce_50e72440","updated":"2017-02-10 02:48:39.000000000","message":"Done","commit_id":"7ba6aa6fb6edfb14e827ba1e9203f204a020c81b"},{"author":{"_account_id":6773,"name":"Lucas Alvares Gomes","email":"lucasagomes@gmail.com","username":"lucasagomes"},"change_message_id":"5a232d69fbef4091e9d1ef96f1f9ff105c9fa68d","unresolved":false,"context_lines":[{"line_number":30,"context_line":"    }"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"    @staticmethod"},{"line_number":33,"context_line":"    def _from_db_object(context, tag, db_tag):"},{"line_number":34,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":35,"context_line":"        for field in tag.fields:"},{"line_number":36,"context_line":"            tag[field] \u003d db_tag[field]"}],"source_content_type":"text/x-python","patch_set":53,"id":"da36d5c6_1e75c262","line":33,"range":{"start_line":33,"start_character":24,"end_line":33,"end_character":31},"updated":"2017-02-27 12:08:31.000000000","message":"We don\u0027t need to overwrite it, the context parameter here is not being used","commit_id":"e9a7cef318169b5be9b0707d2695d5845a846eca"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"5c5ab8007432f636190bfe79a70725d236bcbc7f","unresolved":false,"context_lines":[{"line_number":30,"context_line":"    }"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"    @staticmethod"},{"line_number":33,"context_line":"    def _from_db_object(context, tag, db_tag):"},{"line_number":34,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":35,"context_line":"        for field in tag.fields:"},{"line_number":36,"context_line":"            tag[field] \u003d db_tag[field]"}],"source_content_type":"text/x-python","patch_set":53,"id":"9a30ddce_d09f8db2","line":33,"range":{"start_line":33,"start_character":24,"end_line":33,"end_character":31},"in_reply_to":"da36d5c6_1e75c262","updated":"2017-03-07 01:53:58.000000000","message":"This is because ovo obj_make_list need to call item_cls._from_db_object with context :(\n  https://github.com/openstack/oslo.versionedobjects/blob/master/oslo_versionedobjects/base.py#L1117","commit_id":"e9a7cef318169b5be9b0707d2695d5845a846eca"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"682007853067018c6241e93a8f5edf3daf65a4b7","unresolved":false,"context_lines":[{"line_number":30,"context_line":"    }"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"    @staticmethod"},{"line_number":33,"context_line":"    def _from_db_object(context, tag, db_tag):"},{"line_number":34,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":35,"context_line":"        for field in tag.fields:"},{"line_number":36,"context_line":"            tag[field] \u003d db_tag[field]"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_065398e2","line":33,"range":{"start_line":33,"start_character":24,"end_line":33,"end_character":31},"updated":"2017-03-07 13:49:23.000000000","message":"Would be good to add a comment on why it\u0027s needed, as several people already asked about it.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":30,"context_line":"    }"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"    @staticmethod"},{"line_number":33,"context_line":"    def _from_db_object(context, tag, db_tag):"},{"line_number":34,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":35,"context_line":"        for field in tag.fields:"},{"line_number":36,"context_line":"            tag[field] \u003d db_tag[field]"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_9830b358","line":33,"range":{"start_line":33,"start_character":24,"end_line":33,"end_character":31},"in_reply_to":"9a30ddce_065398e2","updated":"2017-03-07 18:42:14.000000000","message":"++","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":30,"context_line":"    }"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"    @staticmethod"},{"line_number":33,"context_line":"    def _from_db_object(context, tag, db_tag):"},{"line_number":34,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":35,"context_line":"        for field in tag.fields:"},{"line_number":36,"context_line":"            tag[field] \u003d db_tag[field]"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_9d5ce5ee","line":33,"range":{"start_line":33,"start_character":24,"end_line":33,"end_character":31},"in_reply_to":"9a30ddce_065398e2","updated":"2017-03-09 01:59:48.000000000","message":"Done","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":13295,"name":"Mario Villaplana","email":"mario.villaplana@gmail.com","username":"mariojv"},"change_message_id":"8b467dca7078b8a1be1365df0b7dcba90a0ce263","unresolved":false,"context_lines":[{"line_number":30,"context_line":"    }"},{"line_number":31,"context_line":""},{"line_number":32,"context_line":"    @staticmethod"},{"line_number":33,"context_line":"    def _from_db_object(context, tag, db_tag):"},{"line_number":34,"context_line":"        \"\"\"Converts a database entity to a formal object.\"\"\""},{"line_number":35,"context_line":"        for field in tag.fields:"},{"line_number":36,"context_line":"            tag[field] \u003d db_tag[field]"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_b45f3b71","line":33,"range":{"start_line":33,"start_character":24,"end_line":33,"end_character":31},"in_reply_to":"9a30ddce_9830b358","updated":"2017-03-07 21:37:25.000000000","message":"+1","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":57,"context_line":"        :param context: Security context. NOTE: This should only"},{"line_number":58,"context_line":"                        be used internally by the indirection_api."},{"line_number":59,"context_line":"                        Unfortunately, RPC requires context as the first"},{"line_number":60,"context_line":"                        argument, even though we don\u0027t use it."},{"line_number":61,"context_line":"                        A context should be set when instantiating the"},{"line_number":62,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":63,"context_line":"        :param node_id: the id of a node."}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_163739b1","line":60,"updated":"2017-03-07 18:42:14.000000000","message":"hmm. this is inconsistent with the context being the last argument above.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":57,"context_line":"        :param context: Security context. NOTE: This should only"},{"line_number":58,"context_line":"                        be used internally by the indirection_api."},{"line_number":59,"context_line":"                        Unfortunately, RPC requires context as the first"},{"line_number":60,"context_line":"                        argument, even though we don\u0027t use it."},{"line_number":61,"context_line":"                        A context should be set when instantiating the"},{"line_number":62,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":63,"context_line":"        :param node_id: the id of a node."}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_ddf57dcb","line":60,"in_reply_to":"9a30ddce_163739b1","updated":"2017-03-09 01:59:48.000000000","message":"Done","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":60,"context_line":"                        argument, even though we don\u0027t use it."},{"line_number":61,"context_line":"                        A context should be set when instantiating the"},{"line_number":62,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":63,"context_line":"        :param node_id: the id of a node."},{"line_number":64,"context_line":"        :param tag: a string tag that associated with the node."},{"line_number":65,"context_line":"        \"\"\""},{"line_number":66,"context_line":"        self.dbapi.delete_node_tag(node_id, tag)"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_165e59e9","line":63,"updated":"2017-03-07 18:42:14.000000000","message":"nit s/id/ID/","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":60,"context_line":"                        argument, even though we don\u0027t use it."},{"line_number":61,"context_line":"                        A context should be set when instantiating the"},{"line_number":62,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":63,"context_line":"        :param node_id: the id of a node."},{"line_number":64,"context_line":"        :param tag: a string tag that associated with the node."},{"line_number":65,"context_line":"        \"\"\""},{"line_number":66,"context_line":"        self.dbapi.delete_node_tag(node_id, tag)"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_fd0401c1","line":63,"in_reply_to":"9a30ddce_165e59e9","updated":"2017-03-09 01:59:48.000000000","message":"Done","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":61,"context_line":"                        A context should be set when instantiating the"},{"line_number":62,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":63,"context_line":"        :param node_id: the id of a node."},{"line_number":64,"context_line":"        :param tag: a string tag that associated with the node."},{"line_number":65,"context_line":"        \"\"\""},{"line_number":66,"context_line":"        self.dbapi.delete_node_tag(node_id, tag)"},{"line_number":67,"context_line":""}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_5658d1fa","line":64,"updated":"2017-03-07 18:42:14.000000000","message":"nit. s/that associated/that is associated/","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":61,"context_line":"                        A context should be set when instantiating the"},{"line_number":62,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":63,"context_line":"        :param node_id: the id of a node."},{"line_number":64,"context_line":"        :param tag: a string tag that associated with the node."},{"line_number":65,"context_line":"        \"\"\""},{"line_number":66,"context_line":"        self.dbapi.delete_node_tag(node_id, tag)"},{"line_number":67,"context_line":""}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_1d00f5a9","line":64,"in_reply_to":"9a30ddce_5658d1fa","updated":"2017-03-09 01:59:48.000000000","message":"Done","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":79,"context_line":""},{"line_number":80,"context_line":"    @classmethod"},{"line_number":81,"context_line":"    def get_by_node_id(cls, context, node_id):"},{"line_number":82,"context_line":"        \"\"\"Find node tag list based on its integer id."},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"        :param node_id: the id of a node."},{"line_number":85,"context_line":"        :returns: a :class:`NodeTagList` object."}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_1b3f5db5","line":82,"updated":"2017-03-07 18:42:14.000000000","message":"maybe \u0027Get list of tags for node.\u0027 (It took me a few seconds to understand what \u0027its\u0027 was, the node, not the tags.)","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":79,"context_line":""},{"line_number":80,"context_line":"    @classmethod"},{"line_number":81,"context_line":"    def get_by_node_id(cls, context, node_id):"},{"line_number":82,"context_line":"        \"\"\"Find node tag list based on its integer id."},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"        :param node_id: the id of a node."},{"line_number":85,"context_line":"        :returns: a :class:`NodeTagList` object."}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_5d30ad9e","line":82,"in_reply_to":"9a30ddce_1b3f5db5","updated":"2017-03-09 01:59:48.000000000","message":"Done","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"682007853067018c6241e93a8f5edf3daf65a4b7","unresolved":false,"context_lines":[{"line_number":81,"context_line":"    def get_by_node_id(cls, context, node_id):"},{"line_number":82,"context_line":"        \"\"\"Find node tag list based on its integer id."},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"        :param node_id: the id of a node."},{"line_number":85,"context_line":"        :returns: a :class:`NodeTagList` object."},{"line_number":86,"context_line":"        \"\"\""},{"line_number":87,"context_line":"        db_tags \u003d cls.dbapi.get_node_tags_by_node_id(node_id)"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_26ba5ce2","line":84,"updated":"2017-03-07 13:49:23.000000000","message":"missing context in docstring here and in the next one.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":81,"context_line":"    def get_by_node_id(cls, context, node_id):"},{"line_number":82,"context_line":"        \"\"\"Find node tag list based on its integer id."},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"        :param node_id: the id of a node."},{"line_number":85,"context_line":"        :returns: a :class:`NodeTagList` object."},{"line_number":86,"context_line":"        \"\"\""},{"line_number":87,"context_line":"        db_tags \u003d cls.dbapi.get_node_tags_by_node_id(node_id)"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_7d273164","line":84,"in_reply_to":"9a30ddce_26ba5ce2","updated":"2017-03-09 01:59:48.000000000","message":"Done","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":87,"context_line":"        db_tags \u003d cls.dbapi.get_node_tags_by_node_id(node_id)"},{"line_number":88,"context_line":"        return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"    @classmethod"},{"line_number":91,"context_line":"    def create(cls, context, node_id, tags):"},{"line_number":92,"context_line":"        \"\"\"Set a list of tags to a node."},{"line_number":93,"context_line":""}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_3bf341a0","line":90,"updated":"2017-03-07 18:42:14.000000000","message":"What is your reason for making this a class method? It is inconsistent with our other objects.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":87,"context_line":"        db_tags \u003d cls.dbapi.get_node_tags_by_node_id(node_id)"},{"line_number":88,"context_line":"        return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"    @classmethod"},{"line_number":91,"context_line":"    def create(cls, context, node_id, tags):"},{"line_number":92,"context_line":"        \"\"\"Set a list of tags to a node."},{"line_number":93,"context_line":""}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_3d905943","line":90,"in_reply_to":"9a30ddce_3bf341a0","updated":"2017-03-09 01:59:48.000000000","message":"not sure why this is not a class method in other objects, and will figure out the difference.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"7dc4709a7b482c9ef0c9203c113ef178245966e6","unresolved":false,"context_lines":[{"line_number":87,"context_line":"        db_tags \u003d cls.dbapi.get_node_tags_by_node_id(node_id)"},{"line_number":88,"context_line":"        return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"    @classmethod"},{"line_number":91,"context_line":"    def create(cls, context, node_id, tags):"},{"line_number":92,"context_line":"        \"\"\"Set a list of tags to a node."},{"line_number":93,"context_line":""}],"source_content_type":"text/x-python","patch_set":54,"id":"1a1ced50_3282c5c8","line":90,"in_reply_to":"9a30ddce_3d905943","updated":"2017-03-23 12:20:10.000000000","message":"I get confused by this too. My logic here is - if we don\u0027t need an actual object in this method, it should be a class method. So I\u0027m all for switching to class methods wherever possible. The ovo base class does not set any expectations on whether it\u0027s going to be a class or instance method, so here we are free to choose the one we need I think.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"7dc4709a7b482c9ef0c9203c113ef178245966e6","unresolved":false,"context_lines":[{"line_number":88,"context_line":"        return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"    @classmethod"},{"line_number":91,"context_line":"    def create(cls, context, node_id, tags):"},{"line_number":92,"context_line":"        \"\"\"Set a list of tags to a node."},{"line_number":93,"context_line":""},{"line_number":94,"context_line":"        :param node_id: the id of a node."}],"source_content_type":"text/x-python","patch_set":54,"id":"1a1ced50_cb91b748","line":91,"updated":"2017-03-23 12:20:10.000000000","message":"Here I think we can actually make node_id a field in NodeTagList, and remove it from these methods, and make them instance methods. It will work as we need to get the rpc node anyway in api, to get its ID, as dbapi only knows about node ID of tags. This will make the request to create node tags as follows:\n\n node \u003d get_rpc_node(uuid or name)\n node.tags.create([\"a\", \"b\", \"c\"])\n\nOTOH, this will bring some complexity here, so if people think it\u0027s fine to do\n\n node \u003d get_rpc_node(uuid or name)\n NodeTagList.create(node.id, [\"a\", \"b\", \"c\"])\n\nit looks not that bad too. Same applies for destroy, that can become just \"node.tags.destroy()\". Opinions welcome here, leaving as-is for now.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":98,"context_line":"        db_tags \u003d cls.dbapi.set_node_tags(node_id, tags)"},{"line_number":99,"context_line":"        return object_base.obj_make_list(context, cls(), NodeTag, db_tags)"},{"line_number":100,"context_line":""},{"line_number":101,"context_line":"    @classmethod"},{"line_number":102,"context_line":"    def destroy(cls, context, node_id):"},{"line_number":103,"context_line":"        \"\"\"Remove all tags from a node based on its integer id."},{"line_number":104,"context_line":""}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_7b2bf9eb","line":101,"updated":"2017-03-07 18:42:14.000000000","message":"ditto about class method.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":100,"context_line":""},{"line_number":101,"context_line":"    @classmethod"},{"line_number":102,"context_line":"    def destroy(cls, context, node_id):"},{"line_number":103,"context_line":"        \"\"\"Remove all tags from a node based on its integer id."},{"line_number":104,"context_line":""},{"line_number":105,"context_line":"        :param context: Security context."},{"line_number":106,"context_line":"        :param node_id: A node id or uuid."}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_db14e5f6","line":103,"updated":"2017-03-07 18:42:14.000000000","message":"this is not consistent with your description for node_id in L106.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":100,"context_line":""},{"line_number":101,"context_line":"    @classmethod"},{"line_number":102,"context_line":"    def destroy(cls, context, node_id):"},{"line_number":103,"context_line":"        \"\"\"Remove all tags from a node based on its integer id."},{"line_number":104,"context_line":""},{"line_number":105,"context_line":"        :param context: Security context."},{"line_number":106,"context_line":"        :param node_id: A node id or uuid."}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_bd21a94f","line":103,"in_reply_to":"9a30ddce_db14e5f6","updated":"2017-03-09 01:59:48.000000000","message":"Done","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"19925efeaa2dcf6d8effe4349b23ac6c0b21db7d","unresolved":false,"context_lines":[{"line_number":103,"context_line":"        \"\"\"Remove all tags from a node based on its integer id."},{"line_number":104,"context_line":""},{"line_number":105,"context_line":"        :param context: Security context."},{"line_number":106,"context_line":"        :param node_id: A node id or uuid."},{"line_number":107,"context_line":"        \"\"\""},{"line_number":108,"context_line":"        cls.dbapi.unset_node_tags(node_id)"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_7b05b9c0","line":106,"updated":"2017-03-07 18:42:14.000000000","message":"s/id/ID/\n\ns/uuid/UUID/","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"914ba9e1fba98935b1b92373ac2cefd809a14403","unresolved":false,"context_lines":[{"line_number":103,"context_line":"        \"\"\"Remove all tags from a node based on its integer id."},{"line_number":104,"context_line":""},{"line_number":105,"context_line":"        :param context: Security context."},{"line_number":106,"context_line":"        :param node_id: A node id or uuid."},{"line_number":107,"context_line":"        \"\"\""},{"line_number":108,"context_line":"        cls.dbapi.unset_node_tags(node_id)"}],"source_content_type":"text/x-python","patch_set":54,"id":"9a30ddce_fd1b2119","line":106,"in_reply_to":"9a30ddce_7b05b9c0","updated":"2017-03-09 01:59:48.000000000","message":"Done","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"7dc4709a7b482c9ef0c9203c113ef178245966e6","unresolved":false,"context_lines":[{"line_number":103,"context_line":"        \"\"\"Remove all tags from a node based on its integer id."},{"line_number":104,"context_line":""},{"line_number":105,"context_line":"        :param context: Security context."},{"line_number":106,"context_line":"        :param node_id: A node id or uuid."},{"line_number":107,"context_line":"        \"\"\""},{"line_number":108,"context_line":"        cls.dbapi.unset_node_tags(node_id)"}],"source_content_type":"text/x-python","patch_set":54,"id":"1a1ced50_3a7e176a","line":106,"in_reply_to":"9a30ddce_fd1b2119","updated":"2017-03-23 12:20:10.000000000","message":"good catch, it should be id.","commit_id":"de5bba898aad30772e2055150a7f4c4f122609df"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"2985b267f0956396289e8584dbea7e4c59f01d09","unresolved":false,"context_lines":[{"line_number":68,"context_line":""},{"line_number":69,"context_line":"@base.IronicObjectRegistry.register"},{"line_number":70,"context_line":"class NodeTagList(object_base.VersionedObject, object_base.ObjectListBase):"},{"line_number":71,"context_line":"    # We inherit from object_base.VersionedObject as we don\u0027t need anything"},{"line_number":72,"context_line":"    # from the base.IronicObject"},{"line_number":73,"context_line":"    # Version 1.0: Initial version"},{"line_number":74,"context_line":"    VERSION \u003d \u00271.0\u0027"}],"source_content_type":"text/x-python","patch_set":55,"id":"1a1ced50_46b3fe97","line":71,"updated":"2017-03-23 12:35:02.000000000","message":"The only thing that would be good to reuse from the base.IronicObject is OBJ_SERIAL_NAMESPACE/OBJ_PROJECT_NAMESPACE, but it should work as is, so not sure if it\u0027s worth it.","commit_id":"f9bda8f0348868db80882e605dc3056f4d6b1e6c"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"cc2981e77f3f0153a085d0978d8d042bf3adaa64","unresolved":false,"context_lines":[{"line_number":40,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":41,"context_line":"        :returns: a :class:`NodeTag` object."},{"line_number":42,"context_line":"        \"\"\""},{"line_number":43,"context_line":"        db_tag \u003d self.dbapi.add_node_tag(self.node_id, self.tag)"},{"line_number":44,"context_line":"        return self._from_db_object(context, self, db_tag)"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"    def destroy(self, context):"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_f51c70c2","line":43,"updated":"2017-07-14 02:07:48.000000000","message":"this is fine for now, but none of this code supports rolling upgrades. If we ever change the object (\u0026 version), we\u0027ll need to make sure we handle them properly wrt rolling upgrades.\n\nMaybe we should add a note about that.\n\nThe mechanism I am using for rolling upgrades assumes that when saving objects to the DB, they save the object\u0027s changed fields only. Which this doesn\u0027t do. Since this is a new object, it is fine for now, but if we ever change the object (\u0026 version), we\u0027ll need to make sure we handle them properly wrt rolling upgrades.\n\nMaybe we should add a note about that.\n\nI wonder if we need to put the mechanism in place *before* it gets changed though...","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"d2d39fa7e5f284c2d180baaaa76cb57efb53d2dd","unresolved":false,"context_lines":[{"line_number":40,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":41,"context_line":"        :returns: a :class:`NodeTag` object."},{"line_number":42,"context_line":"        \"\"\""},{"line_number":43,"context_line":"        db_tag \u003d self.dbapi.add_node_tag(self.node_id, self.tag)"},{"line_number":44,"context_line":"        return self._from_db_object(context, self, db_tag)"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"    def destroy(self, context):"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_335d447a","line":43,"in_reply_to":"1f1a1f67_02b678da","updated":"2017-07-14 15:15:50.000000000","message":"I\u0027m wondering if we should bother with versioning at all. The tag should be only a string, it is its only purpose. So I\u0027d think the data structure for this object should not change. We might add new methods here, but there would be no need in data manipulation (other than the possibility of renaming tag field?..) I think I\u0027ll just add the logic to set the version as well.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"a88ac43ccef3d546f15ef854ce63825b5cc0f127","unresolved":false,"context_lines":[{"line_number":40,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":41,"context_line":"        :returns: a :class:`NodeTag` object."},{"line_number":42,"context_line":"        \"\"\""},{"line_number":43,"context_line":"        db_tag \u003d self.dbapi.add_node_tag(self.node_id, self.tag)"},{"line_number":44,"context_line":"        return self._from_db_object(context, self, db_tag)"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"    def destroy(self, context):"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_c7983376","line":43,"in_reply_to":"1f1a1f67_335d447a","updated":"2017-07-18 14:33:35.000000000","message":"I really dislike adding a VersionedObject that is not consistent with the other VersionedObjects. We don\u0027t know what will happen in the future (and I don\u0027t know if we will be around...). If it is \u0027easy enough\u0027 to make things as consistent as possible now, I\u0027d rather we do that, than leave it as a future-thing-to-do-if-it-ever-has-a-new-version. Although, yeah, I\u0027d think that we wouldn\u0027t need to have a new version of this object but who knows :)\n\nThx for adding the logic to set the version!","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"f3fb7f1cf8a6dd896290d03e3e28664560bdeabc","unresolved":false,"context_lines":[{"line_number":40,"context_line":"                        object, e.g.: NodeTag(context)"},{"line_number":41,"context_line":"        :returns: a :class:`NodeTag` object."},{"line_number":42,"context_line":"        \"\"\""},{"line_number":43,"context_line":"        db_tag \u003d self.dbapi.add_node_tag(self.node_id, self.tag)"},{"line_number":44,"context_line":"        return self._from_db_object(context, self, db_tag)"},{"line_number":45,"context_line":""},{"line_number":46,"context_line":"    def destroy(self, context):"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_02b678da","line":43,"in_reply_to":"1f1a1f67_f51c70c2","updated":"2017-07-14 13:23:38.000000000","message":"I need to think about this. Also you\u0027ve asked somewhere about if the version is saved with tag objects, seems like it does not.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"cc2981e77f3f0153a085d0978d8d042bf3adaa64","unresolved":false,"context_lines":[{"line_number":102,"context_line":"    @classmethod"},{"line_number":103,"context_line":"    def create(cls, context, node_id, tags):"},{"line_number":104,"context_line":"        \"\"\"Set a list of tags to a node."},{"line_number":105,"context_line":""},{"line_number":106,"context_line":"        :param context: Security context. NOTE: This should only"},{"line_number":107,"context_line":"                        be used internally by the indirection_api."},{"line_number":108,"context_line":"                        Unfortunately, RPC requires context as the first"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_b598381b","line":105,"updated":"2017-07-14 02:07:48.000000000","message":"it would be useful to clarify that this replaces any existing tags associated with this node, to this new list.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"f3fb7f1cf8a6dd896290d03e3e28664560bdeabc","unresolved":false,"context_lines":[{"line_number":102,"context_line":"    @classmethod"},{"line_number":103,"context_line":"    def create(cls, context, node_id, tags):"},{"line_number":104,"context_line":"        \"\"\"Set a list of tags to a node."},{"line_number":105,"context_line":""},{"line_number":106,"context_line":"        :param context: Security context. NOTE: This should only"},{"line_number":107,"context_line":"                        be used internally by the indirection_api."},{"line_number":108,"context_line":"                        Unfortunately, RPC requires context as the first"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_82c16831","line":105,"in_reply_to":"1f1a1f67_b598381b","updated":"2017-07-14 13:23:38.000000000","message":"will do","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"},{"author":{"_account_id":6618,"name":"Ruby Loo","email":"opensrloo@gmail.com","username":"rloo"},"change_message_id":"cc2981e77f3f0153a085d0978d8d042bf3adaa64","unresolved":false,"context_lines":[{"line_number":113,"context_line":"        :param tags: list of tag strings."},{"line_number":114,"context_line":"        :returns: a :class:`NodeTagList` object."},{"line_number":115,"context_line":"        \"\"\""},{"line_number":116,"context_line":"        db_tags \u003d cls.dbapi.set_node_tags(node_id, tags)"},{"line_number":117,"context_line":"        return cls.from_db_tags_list(context, db_tags)"},{"line_number":118,"context_line":""},{"line_number":119,"context_line":"    @classmethod"}],"source_content_type":"text/x-python","patch_set":65,"id":"1f1a1f67_95eadc72","line":116,"updated":"2017-07-14 02:07:48.000000000","message":"ditto about rolling upgrades.","commit_id":"c8eeda0f2dc69e65ce750418c1b575f1061192f9"}],"ironic/tests/unit/api/utils.py":[{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"3befc71936a87ea082d2db505e23018fd22a92d6","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    node.pop(\u0027chassis_id\u0027)"},{"line_number":96,"context_line":"    node.pop(\u0027target_raid_config\u0027)"},{"line_number":97,"context_line":"    node.pop(\u0027raid_config\u0027)"},{"line_number":98,"context_line":"    node.pop(\u0027tags\u0027)"},{"line_number":99,"context_line":"    internal \u003d node_controller.NodePatchType.internal_attrs()"},{"line_number":100,"context_line":"    return remove_internal(node, internal)"},{"line_number":101,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_1a13020f","line":98,"updated":"2016-01-28 16:21:43.000000000","message":"This is a part of an API object, it\u0027s just internal right? (looking at the API patch)","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"e6f1ad3d50610cb382402134a32127b151d40bc6","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    node.pop(\u0027chassis_id\u0027)"},{"line_number":96,"context_line":"    node.pop(\u0027target_raid_config\u0027)"},{"line_number":97,"context_line":"    node.pop(\u0027raid_config\u0027)"},{"line_number":98,"context_line":"    node.pop(\u0027tags\u0027)"},{"line_number":99,"context_line":"    internal \u003d node_controller.NodePatchType.internal_attrs()"},{"line_number":100,"context_line":"    return remove_internal(node, internal)"},{"line_number":101,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_fa427f3d","line":98,"in_reply_to":"7a5de9d1_1a13020f","updated":"2016-01-29 07:36:06.000000000","message":"yeah, but with the version 0.8.0 WSME will raise HTTP 400 (BadRequest) when one attempt to create a node with nonexistent fields, please reference https://review.openstack.org/#/c/216802/2/ironic/tests/api/utils.py","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"eda0776bfd998cac9d84c123c6cba14c94cb4075","unresolved":false,"context_lines":[{"line_number":95,"context_line":"    node.pop(\u0027chassis_id\u0027)"},{"line_number":96,"context_line":"    node.pop(\u0027target_raid_config\u0027)"},{"line_number":97,"context_line":"    node.pop(\u0027raid_config\u0027)"},{"line_number":98,"context_line":"    node.pop(\u0027tags\u0027)"},{"line_number":99,"context_line":"    internal \u003d node_controller.NodePatchType.internal_attrs()"},{"line_number":100,"context_line":"    return remove_internal(node, internal)"},{"line_number":101,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_cc73467f","line":98,"in_reply_to":"7a5de9d1_fa427f3d","updated":"2016-01-29 10:29:17.000000000","message":"OK, then maybe you could remove this line in API patch? There you add it to internal_attrs, so it will be removed on L100","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"},{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"3befc71936a87ea082d2db505e23018fd22a92d6","unresolved":false,"context_lines":[{"line_number":96,"context_line":"    node.pop(\u0027target_raid_config\u0027)"},{"line_number":97,"context_line":"    node.pop(\u0027raid_config\u0027)"},{"line_number":98,"context_line":"    node.pop(\u0027tags\u0027)"},{"line_number":99,"context_line":"    internal \u003d node_controller.NodePatchType.internal_attrs()"},{"line_number":100,"context_line":"    return remove_internal(node, internal)"},{"line_number":101,"context_line":""},{"line_number":102,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_3abb5ee7","line":99,"updated":"2016-01-28 16:21:43.000000000","message":"\u0027tags\u0027 are added to internal attrs in the following patch, so will be removed anyway.","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"}],"ironic/tests/unit/db/utils.py":[{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"3befc71936a87ea082d2db505e23018fd22a92d6","unresolved":false,"context_lines":[{"line_number":351,"context_line":"    return {"},{"line_number":352,"context_line":"        \"tag\": kw.get(\"tag\", \"tag1\"),"},{"line_number":353,"context_line":"        \"node_id\": kw.get(\"node_id\", \"123\"),"},{"line_number":354,"context_line":"        \u0027created_at\u0027: kw.get(\u0027created_at\u0027, timeutils.utcnow()),"},{"line_number":355,"context_line":"        \u0027updated_at\u0027: kw.get(\u0027updated_at\u0027, timeutils.utcnow()),"},{"line_number":356,"context_line":"    }"}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_5af2da70","line":354,"updated":"2016-01-28 16:21:43.000000000","message":"There is no default for other objects, I think it\u0027s better to remove these. Also updated_at does not make much sense at all as you cannot update a tag, but idk what can be done about this.","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"e6f1ad3d50610cb382402134a32127b151d40bc6","unresolved":false,"context_lines":[{"line_number":351,"context_line":"    return {"},{"line_number":352,"context_line":"        \"tag\": kw.get(\"tag\", \"tag1\"),"},{"line_number":353,"context_line":"        \"node_id\": kw.get(\"node_id\", \"123\"),"},{"line_number":354,"context_line":"        \u0027created_at\u0027: kw.get(\u0027created_at\u0027, timeutils.utcnow()),"},{"line_number":355,"context_line":"        \u0027updated_at\u0027: kw.get(\u0027updated_at\u0027, timeutils.utcnow()),"},{"line_number":356,"context_line":"    }"}],"source_content_type":"text/x-python","patch_set":22,"id":"7a5de9d1_2f369752","line":354,"in_reply_to":"7a5de9d1_5af2da70","updated":"2016-01-29 07:36:06.000000000","message":"ok, will remove them in the coming patch set.","commit_id":"e551cff83ab720d2c961703d1e6dc949bb63d183"}],"ironic/tests/unit/objects/test_node.py":[{"author":{"_account_id":6773,"name":"Lucas Alvares Gomes","email":"lucasagomes@gmail.com","username":"lucasagomes"},"change_message_id":"5261c746807e63414f7adb59d2481a479e0f0e21","unresolved":false,"context_lines":[{"line_number":28,"context_line":"        super(TestNodeObject, self).setUp()"},{"line_number":29,"context_line":"        test_node \u003d utils.get_test_node()"},{"line_number":30,"context_line":"        test_node[\u0027tags\u0027] \u003d objects.NodeTagList(objects\u003d[])"},{"line_number":31,"context_line":"        self.fake_node \u003d test_node"},{"line_number":32,"context_line":""},{"line_number":33,"context_line":"    def test_get_by_id(self):"},{"line_number":34,"context_line":"        node_id \u003d self.fake_node[\u0027id\u0027]"}],"source_content_type":"text/x-python","patch_set":19,"id":"9a68dd71_4514b44b","line":31,"updated":"2016-01-25 11:41:40.000000000","message":"I would like to see a test where the node does actually have some tags and we assert that the tags are being returned in the object","commit_id":"9d99e4044f2945d907b7dfa36ee22ac3dfe6181f"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"98e82dd85340a107cb07177f91696b96a3b8ada5","unresolved":false,"context_lines":[{"line_number":28,"context_line":"        super(TestNodeObject, self).setUp()"},{"line_number":29,"context_line":"        test_node \u003d utils.get_test_node()"},{"line_number":30,"context_line":"        test_node[\u0027tags\u0027] \u003d objects.NodeTagList(objects\u003d[])"},{"line_number":31,"context_line":"        self.fake_node \u003d test_node"},{"line_number":32,"context_line":""},{"line_number":33,"context_line":"    def test_get_by_id(self):"},{"line_number":34,"context_line":"        node_id \u003d self.fake_node[\u0027id\u0027]"}],"source_content_type":"text/x-python","patch_set":19,"id":"9a68dd71_d0c5920a","line":31,"in_reply_to":"9a68dd71_4514b44b","updated":"2016-01-26 08:30:55.000000000","message":"Done","commit_id":"9d99e4044f2945d907b7dfa36ee22ac3dfe6181f"}],"ironic/tests/unit/objects/test_tag.py":[{"author":{"_account_id":13362,"name":"Tan Lin","email":"lin.tan@intel.com","username":"zero"},"change_message_id":"09f1a60560c5ed10260170b37c33751dd67743fc","unresolved":false,"context_lines":[{"line_number":17,"context_line":"from ironic.tests.unit.db import utils"},{"line_number":18,"context_line":""},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"class TestTagListObject(base.DbTestCase):"},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"    def setUp(self):"},{"line_number":23,"context_line":"        super(TestTagListObject, self).setUp()"}],"source_content_type":"text/x-python","patch_set":5,"id":"da85f559_b0623ad7","line":20,"updated":"2015-11-09 07:21:54.000000000","message":"Only TagLIst?  TagObject also need test","commit_id":"040109c0df11e60c98ce26c1aa6e2a4087646d68"}],"ironic/tests/unit/objects/test_tags.py":[{"author":{"_account_id":12356,"name":"Vladyslav Drok","email":"vdrok@mirantis.com","username":"vdrok"},"change_message_id":"0eb4a21c1125c245e85dc77bc42ac2ac60f44cac","unresolved":false,"context_lines":[{"line_number":59,"context_line":""},{"line_number":60,"context_line":"            tags \u003d objects.NodeTagList.create(self.context, node_id, [\u0027tag1\u0027])"},{"line_number":61,"context_line":"            mock_set_tags.assert_called_once_with(node_id, [\u0027tag1\u0027])"},{"line_number":62,"context_line":"            self.assertEqual(\u0027tag1\u0027, tags.objects[0].tag)"},{"line_number":63,"context_line":""},{"line_number":64,"context_line":"    def test_get_by_node_id(self):"},{"line_number":65,"context_line":"        node_id \u003d self.fake_tag[\u0027node_id\u0027]"}],"source_content_type":"text/x-python","patch_set":45,"id":"1a6eadb0_9d2fd5f5","line":62,"range":{"start_line":62,"start_character":37,"end_line":62,"end_character":52},"updated":"2016-12-19 18:01:35.000000000","message":"Tags should support indexing, so you can just do tags[0].tag (and I think it\u0027s the recommended way?)","commit_id":"914ed07d4f14fbe9f28a1a3478f80270b83fbc2a"}],"ironic/tests/unit/objects/utils.py":[{"author":{"_account_id":23883,"name":"Joanna Taryma","email":"joanna.taryma@intel.com","username":"jtaryma"},"change_message_id":"398a42d63e6abbe755c42fa7a95b36b60fad5157","unresolved":false,"context_lines":[{"line_number":58,"context_line":"        del db_node[\u0027id\u0027]"},{"line_number":59,"context_line":"    node \u003d objects.Node(ctxt)"},{"line_number":60,"context_line":"    for key in db_node:"},{"line_number":61,"context_line":"        if key !\u003d \u0027tags\u0027:"},{"line_number":62,"context_line":"            setattr(node, key, db_node[key])"},{"line_number":63,"context_line":"    return node"},{"line_number":64,"context_line":""}],"source_content_type":"text/x-python","patch_set":51,"id":"3a461143_e8c87a24","line":61,"updated":"2017-01-30 22:44:25.000000000","message":"wouldn\u0027t it be better to del/pop \u0027tags\u0027 from db_node, instead of applying this condition?","commit_id":"f162914c7808677e7ab7faf6e612bc3e4ae25edf"},{"author":{"_account_id":6610,"name":"Zhenguo Niu","email":"Niu.ZGlinux@gmail.com","username":"niu-zglinux"},"change_message_id":"16fbf152b32b94a2152e4f7b09dc0814fff4d108","unresolved":false,"context_lines":[{"line_number":58,"context_line":"        del db_node[\u0027id\u0027]"},{"line_number":59,"context_line":"    node \u003d objects.Node(ctxt)"},{"line_number":60,"context_line":"    for key in db_node:"},{"line_number":61,"context_line":"        if key !\u003d \u0027tags\u0027:"},{"line_number":62,"context_line":"            setattr(node, key, db_node[key])"},{"line_number":63,"context_line":"    return node"},{"line_number":64,"context_line":""}],"source_content_type":"text/x-python","patch_set":51,"id":"1a430d35_942bf393","line":61,"in_reply_to":"3a461143_e8c87a24","updated":"2017-02-06 12:14:06.000000000","message":"No, tags will be converted to TagList object, this is just for tests.","commit_id":"f162914c7808677e7ab7faf6e612bc3e4ae25edf"}]}
