)]}'
{"nova/db/api.py":[{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"a5af81d2ad2775e2ad5b22cb96d07c9c7ef45486","unresolved":false,"context_lines":[{"line_number":191,"context_line":""},{"line_number":192,"context_line":"# TODO(edleafe): remove once the compute node resource provider migration is"},{"line_number":193,"context_line":"# complete, and this distinction is no longer necessary."},{"line_number":194,"context_line":"def compute_node_get_model(context, compute_id):"},{"line_number":195,"context_line":"    \"\"\"Get a compute node sqlalchemy model object by its id."},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"    :param context: The security context"}],"source_content_type":"text/x-python","patch_set":6,"id":"9aed3d3a_32ebe879","line":194,"updated":"2016-02-29 21:00:39.000000000","message":"I don\u0027t think we need this exposed at all. However, maybe it\u0027s easiest to just leave it in case we need it for a backport or something after we see this all fly in the wild.","commit_id":"1a6fbb1a51a6b3217b6a2afe4fb53f42df822872"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"3201bb56fd0abc9efa20da0c3ccfd4a2c5831ac6","unresolved":false,"context_lines":[{"line_number":191,"context_line":""},{"line_number":192,"context_line":"# TODO(edleafe): remove once the compute node resource provider migration is"},{"line_number":193,"context_line":"# complete, and this distinction is no longer necessary."},{"line_number":194,"context_line":"def compute_node_get_model(context, compute_id):"},{"line_number":195,"context_line":"    \"\"\"Get a compute node sqlalchemy model object by its id."},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"    :param context: The security context"}],"source_content_type":"text/x-python","patch_set":8,"id":"7af24918_d394f6e9","line":194,"updated":"2016-03-01 12:38:31.000000000","message":"It was this new entry point I didn\u0027t see a new unit test for, although maybe thats a miss-read?","commit_id":"d3198af3388752753b1425fdcbde0200db3c4159"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"99fea0baeb7d18313eeee8b35b2fa417753a6f41","unresolved":false,"context_lines":[{"line_number":191,"context_line":""},{"line_number":192,"context_line":"# TODO(edleafe): remove once the compute node resource provider migration is"},{"line_number":193,"context_line":"# complete, and this distinction is no longer necessary."},{"line_number":194,"context_line":"def compute_node_get_model(context, compute_id):"},{"line_number":195,"context_line":"    \"\"\"Get a compute node sqlalchemy model object by its id."},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"    :param context: The security context"}],"source_content_type":"text/x-python","patch_set":8,"id":"7af24918_cf2a827e","line":194,"in_reply_to":"7af24918_d394f6e9","updated":"2016-03-01 14:14:11.000000000","message":"Ah, you\u0027re correct. This was more of a \"what do you think about this\" approach for handling updates. Since it looks like we\u0027re keeping it, I\u0027ll add a test.","commit_id":"d3198af3388752753b1425fdcbde0200db3c4159"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"8d184ffed6dcdbe4d17fe196b66d1ad72d1a30f2","unresolved":false,"context_lines":[{"line_number":191,"context_line":""},{"line_number":192,"context_line":"# TODO(edleafe): remove once the compute node resource provider migration is"},{"line_number":193,"context_line":"# complete, and this distinction is no longer necessary."},{"line_number":194,"context_line":"def compute_node_get_model(context, compute_id):"},{"line_number":195,"context_line":"    \"\"\"Get a compute node sqlalchemy model object by its id."},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"    :param context: The security context"}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_6b979890","line":194,"range":{"start_line":194,"start_character":4,"end_line":194,"end_character":26},"updated":"2016-03-02 13:10:23.000000000","message":"nit: you could have named it something like \"compute_node_get_legacy\" to make sure it doesn\u0027t make sense.","commit_id":"1f840f7583ffdbb141d288cd2279cc42e02e9b0c"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"8d184ffed6dcdbe4d17fe196b66d1ad72d1a30f2","unresolved":false,"context_lines":[{"line_number":191,"context_line":""},{"line_number":192,"context_line":"# TODO(edleafe): remove once the compute node resource provider migration is"},{"line_number":193,"context_line":"# complete, and this distinction is no longer necessary."},{"line_number":194,"context_line":"def compute_node_get_model(context, compute_id):"},{"line_number":195,"context_line":"    \"\"\"Get a compute node sqlalchemy model object by its id."},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"    :param context: The security context"}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_cb77cc9d","line":194,"updated":"2016-03-02 13:10:23.000000000","message":"not sure I get *why* you need to keep that legacy method for only accessing the ComputeNode SQLA object only if you don\u0027t want to use the inventories, particularly if you don\u0027t modify the callers to use this new method instead of the one new-style.\n\nAFAICS, there is only one DB SQLA method using that, so that could be kept internally in a private method, instead of exposing it in the DB API contract.","commit_id":"1f840f7583ffdbb141d288cd2279cc42e02e9b0c"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"a5c4553beaf62fcb002d083b20c67654b3693642","unresolved":false,"context_lines":[{"line_number":191,"context_line":""},{"line_number":192,"context_line":"# TODO(edleafe): remove once the compute node resource provider migration is"},{"line_number":193,"context_line":"# complete, and this distinction is no longer necessary."},{"line_number":194,"context_line":"def compute_node_get_model(context, compute_id):"},{"line_number":195,"context_line":"    \"\"\"Get a compute node sqlalchemy model object by its id."},{"line_number":196,"context_line":""},{"line_number":197,"context_line":"    :param context: The security context"}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_f55a6129","line":194,"in_reply_to":"7af24918_cb77cc9d","updated":"2016-03-02 14:20:45.000000000","message":"This method was *only* added if dansmith needed it for the compute_node object work he was doing. It can (and should) be removed if he determines it isn\u0027t needed.","commit_id":"1f840f7583ffdbb141d288cd2279cc42e02e9b0c"}],"nova/db/sqlalchemy/api.py":[{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"694001a596fd885d105e590a01eda9c568031995","unresolved":false,"context_lines":[{"line_number":577,"context_line":"VCPU \u003d fields.ResourceClass.index(fields.ResourceClass.VCPU)"},{"line_number":578,"context_line":"DISK_GB \u003d fields.ResourceClass.index(fields.ResourceClass.DISK_GB)"},{"line_number":579,"context_line":""},{"line_number":580,"context_line":"_CN_TABLE \u003d sa.alias(models.ComputeNode.__table__, name\u003d\u0027cn\u0027)"},{"line_number":581,"context_line":"_RP_TABLE \u003d sa.alias(models.ResourceProvider.__table__, name\u003d\u0027rp\u0027)"},{"line_number":582,"context_line":"_INV_TABLE \u003d models.Inventory.__table__"},{"line_number":583,"context_line":"_ALLOC_TABLE \u003d models.Allocation.__table__"}],"source_content_type":"text/x-python","patch_set":1,"id":"9aed3d3a_a8e1ffd2","line":580,"updated":"2016-02-25 17:45:37.000000000","message":"This is actually the only variable that is used outside of the _compute_node_select() function. Any way we can undo the move of all the other variables out of local function scope into the module-level scope? That would dramatically reduce the number of lines of code changed.","commit_id":"3d941c824d4408345495be812bb23d34468c185c"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"3ab0e7ad161939976f293af1e0ad217dfb04db10","unresolved":false,"context_lines":[{"line_number":577,"context_line":"VCPU \u003d fields.ResourceClass.index(fields.ResourceClass.VCPU)"},{"line_number":578,"context_line":"DISK_GB \u003d fields.ResourceClass.index(fields.ResourceClass.DISK_GB)"},{"line_number":579,"context_line":""},{"line_number":580,"context_line":"_CN_TABLE \u003d sa.alias(models.ComputeNode.__table__, name\u003d\u0027cn\u0027)"},{"line_number":581,"context_line":"_RP_TABLE \u003d sa.alias(models.ResourceProvider.__table__, name\u003d\u0027rp\u0027)"},{"line_number":582,"context_line":"_INV_TABLE \u003d models.Inventory.__table__"},{"line_number":583,"context_line":"_ALLOC_TABLE \u003d models.Allocation.__table__"}],"source_content_type":"text/x-python","patch_set":1,"id":"9aed3d3a_731a4870","line":580,"in_reply_to":"9aed3d3a_a8e1ffd2","updated":"2016-02-25 17:48:33.000000000","message":"Heh, that\u0027s what I did at first, but anticipated that since the others were of a similar nature, that they should be treated the same.","commit_id":"3d941c824d4408345495be812bb23d34468c185c"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"1a5fd3c76902c7725f47dfa6ee9a9048e207fe06","unresolved":false,"context_lines":[{"line_number":740,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":741,"context_line":"    if not results:"},{"line_number":742,"context_line":"        raise exception.ComputeHostNotFound(host\u003dcompute_id)"},{"line_number":743,"context_line":"    return results[0]"},{"line_number":744,"context_line":""},{"line_number":745,"context_line":""},{"line_number":746,"context_line":"@main_context_manager.reader"}],"source_content_type":"text/x-python","patch_set":4,"id":"9aed3d3a_7bb664dd","line":743,"updated":"2016-02-26 14:19:10.000000000","message":"please don\u0027t move when not necessary the methods, it makes the review very difficult","commit_id":"4d44e2fddb0461dc418f3a066605fc487cc376ce"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"c4d7e3a0e74a7d76adecacce2399d6fb8b572833","unresolved":false,"context_lines":[{"line_number":740,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":741,"context_line":"    if not results:"},{"line_number":742,"context_line":"        raise exception.ComputeHostNotFound(host\u003dcompute_id)"},{"line_number":743,"context_line":"    return results[0]"},{"line_number":744,"context_line":""},{"line_number":745,"context_line":""},{"line_number":746,"context_line":"@main_context_manager.reader"}],"source_content_type":"text/x-python","patch_set":4,"id":"9aed3d3a_4c45a36e","line":743,"in_reply_to":"9aed3d3a_7bb664dd","updated":"2016-02-26 16:19:16.000000000","message":"Understood, but it wasn\u0027t a gratuitous moving. The moved methods now depend on the new methods for select and exec, so they should be placed below for clarity.","commit_id":"4d44e2fddb0461dc418f3a066605fc487cc376ce"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"d9932eeddf301b323dff00b6d2964e81e8be32e0","unresolved":false,"context_lines":[{"line_number":768,"context_line":"    cols_in_output.extend(inv_cols)"},{"line_number":769,"context_line":""},{"line_number":770,"context_line":"    select \u003d sa.select(cols_in_output).select_from(disk_join)"},{"line_number":771,"context_line":"    select \u003d select.where(cn_tbl.c.deleted \u003d\u003d 0)"},{"line_number":772,"context_line":"    engine \u003d get_engine(context)"},{"line_number":773,"context_line":"    conn \u003d engine.connect()"},{"line_number":774,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"9aed3d3a_99a142fb","side":"PARENT","line":771,"updated":"2016-02-29 18:35:15.000000000","message":"not sure why you dropped this bit in the general query here.\n\nnormally we would use read_deleted in the context to control if this stays here or not, I think?\n\nhttps://github.com/openstack/nova/blob/master/nova/db/sqlalchemy/api.py#L306","commit_id":"bbf879878fd4eed23cfb75f88205cdd8b3fb1ff0"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"edb7b9762608e3e8f8011f4d1695c619fa67ee85","unresolved":false,"context_lines":[{"line_number":768,"context_line":"    cols_in_output.extend(inv_cols)"},{"line_number":769,"context_line":""},{"line_number":770,"context_line":"    select \u003d sa.select(cols_in_output).select_from(disk_join)"},{"line_number":771,"context_line":"    select \u003d select.where(cn_tbl.c.deleted \u003d\u003d 0)"},{"line_number":772,"context_line":"    engine \u003d get_engine(context)"},{"line_number":773,"context_line":"    conn \u003d engine.connect()"},{"line_number":774,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"9aed3d3a_c353d837","side":"PARENT","line":771,"in_reply_to":"9aed3d3a_99a142fb","updated":"2016-02-29 19:31:50.000000000","message":"Because the old method was for compute_node_get_all, which does not read deleted. The new generic method doesn\u0027t assume that *all* calls will be like that; instead, each method must specify whether deleted records should be ignored. Your comment on L740 is correct; I forgot to add it there. But see L763, L775 for where it is added.","commit_id":"bbf879878fd4eed23cfb75f88205cdd8b3fb1ff0"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"73980cc7b3198963a65d711fcfc5dadb81abad2a","unresolved":false,"context_lines":[{"line_number":768,"context_line":"    cols_in_output.extend(inv_cols)"},{"line_number":769,"context_line":""},{"line_number":770,"context_line":"    select \u003d sa.select(cols_in_output).select_from(disk_join)"},{"line_number":771,"context_line":"    select \u003d select.where(cn_tbl.c.deleted \u003d\u003d 0)"},{"line_number":772,"context_line":"    engine \u003d get_engine(context)"},{"line_number":773,"context_line":"    conn \u003d engine.connect()"},{"line_number":774,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"7af24918_13f3fe0b","side":"PARENT","line":771,"in_reply_to":"9aed3d3a_c353d837","updated":"2016-03-01 12:29:28.000000000","message":"please see def model_query() that implements all of the options where the context is modified to change this query.","commit_id":"bbf879878fd4eed23cfb75f88205cdd8b3fb1ff0"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"73980cc7b3198963a65d711fcfc5dadb81abad2a","unresolved":false,"context_lines":[{"line_number":306,"context_line":"    \"\"\""},{"line_number":307,"context_line":""},{"line_number":308,"context_line":"    if read_deleted is None:"},{"line_number":309,"context_line":"        read_deleted \u003d context.read_deleted"},{"line_number":310,"context_line":""},{"line_number":311,"context_line":"    query_kwargs \u003d {}"},{"line_number":312,"context_line":"    if \u0027no\u0027 \u003d\u003d read_deleted:"}],"source_content_type":"text/x-python","patch_set":5,"id":"7af24918_7348825c","line":309,"updated":"2016-03-01 12:29:28.000000000","message":"I think we default to the context, which defaults to read_deleted \u003d no\nhttps://github.com/openstack/nova/blob/master/nova/context.py#L73","commit_id":"bd728ce46a452cf585fad810e37bc1b9cb561f0a"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"d9932eeddf301b323dff00b6d2964e81e8be32e0","unresolved":false,"context_lines":[{"line_number":737,"context_line":"@main_context_manager.reader"},{"line_number":738,"context_line":"def compute_node_get(context, compute_id):"},{"line_number":739,"context_line":"    select \u003d _compute_node_select(context)"},{"line_number":740,"context_line":"    select \u003d select.where(_CN_TABLE.c.id \u003d\u003d compute_id)"},{"line_number":741,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":742,"context_line":"    if not results:"},{"line_number":743,"context_line":"        raise exception.ComputeHostNotFound(host\u003dcompute_id)"}],"source_content_type":"text/x-python","patch_set":5,"id":"9aed3d3a_b94ec66c","line":740,"updated":"2016-02-29 18:35:15.000000000","message":"Why are you not filtering out deleted nodes here?\n\nDo we not want a read_deleted kind of thing instead?","commit_id":"bd728ce46a452cf585fad810e37bc1b9cb561f0a"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"bd27fd735e3ea6dc3680cb7fb2db0ccf4d33bc4d","unresolved":false,"context_lines":[{"line_number":737,"context_line":"@main_context_manager.reader"},{"line_number":738,"context_line":"def compute_node_get(context, compute_id):"},{"line_number":739,"context_line":"    select \u003d _compute_node_select(context)"},{"line_number":740,"context_line":"    select \u003d select.where(_CN_TABLE.c.id \u003d\u003d compute_id)"},{"line_number":741,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":742,"context_line":"    if not results:"},{"line_number":743,"context_line":"        raise exception.ComputeHostNotFound(host\u003dcompute_id)"}],"source_content_type":"text/x-python","patch_set":5,"id":"7af24918_cfbe02d4","line":740,"in_reply_to":"7af24918_5368e6ba","updated":"2016-03-01 14:13:31.000000000","message":"My point is that I was refactoring the methods to use this temporary sqla approach. Some of the methods explicitly added a parameter for deleted, and others didn\u0027t. I kept the logic the same. And for this case, aren\u0027t there valid use cases for getting information about a node that may have been deleted?\n\nLook at the Base code for this method, L578 - L623. Note that all explicitly add read_deleted\u003d\u0027no\u0027, except for compute_node_get. I\u0027m not changing that logic here.","commit_id":"bd728ce46a452cf585fad810e37bc1b9cb561f0a"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"73980cc7b3198963a65d711fcfc5dadb81abad2a","unresolved":false,"context_lines":[{"line_number":737,"context_line":"@main_context_manager.reader"},{"line_number":738,"context_line":"def compute_node_get(context, compute_id):"},{"line_number":739,"context_line":"    select \u003d _compute_node_select(context)"},{"line_number":740,"context_line":"    select \u003d select.where(_CN_TABLE.c.id \u003d\u003d compute_id)"},{"line_number":741,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":742,"context_line":"    if not results:"},{"line_number":743,"context_line":"        raise exception.ComputeHostNotFound(host\u003dcompute_id)"}],"source_content_type":"text/x-python","patch_set":5,"id":"7af24918_5368e6ba","line":740,"in_reply_to":"9aed3d3a_462356a7","updated":"2016-03-01 12:29:28.000000000","message":"I think it did filter out deleted records, see above comment.\n\nThe harder bit is checking if the context was ever changed to different value of read deleted.","commit_id":"bd728ce46a452cf585fad810e37bc1b9cb561f0a"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"edb7b9762608e3e8f8011f4d1695c619fa67ee85","unresolved":false,"context_lines":[{"line_number":737,"context_line":"@main_context_manager.reader"},{"line_number":738,"context_line":"def compute_node_get(context, compute_id):"},{"line_number":739,"context_line":"    select \u003d _compute_node_select(context)"},{"line_number":740,"context_line":"    select \u003d select.where(_CN_TABLE.c.id \u003d\u003d compute_id)"},{"line_number":741,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":742,"context_line":"    if not results:"},{"line_number":743,"context_line":"        raise exception.ComputeHostNotFound(host\u003dcompute_id)"}],"source_content_type":"text/x-python","patch_set":5,"id":"9aed3d3a_462356a7","line":740,"in_reply_to":"9aed3d3a_b94ec66c","updated":"2016-02-29 19:31:50.000000000","message":"Because the original compute_node_get method did not filter out deleted records.","commit_id":"bd728ce46a452cf585fad810e37bc1b9cb561f0a"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"d9932eeddf301b323dff00b6d2964e81e8be32e0","unresolved":false,"context_lines":[{"line_number":739,"context_line":"    select \u003d _compute_node_select(context)"},{"line_number":740,"context_line":"    select \u003d select.where(_CN_TABLE.c.id \u003d\u003d compute_id)"},{"line_number":741,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":742,"context_line":"    if not results:"},{"line_number":743,"context_line":"        raise exception.ComputeHostNotFound(host\u003dcompute_id)"},{"line_number":744,"context_line":"    return results[0]"},{"line_number":745,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"9aed3d3a_7949de5f","line":742,"updated":"2016-02-29 18:35:15.000000000","message":"maybe len(results) !\u003d 1 also?","commit_id":"bd728ce46a452cf585fad810e37bc1b9cb561f0a"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"73980cc7b3198963a65d711fcfc5dadb81abad2a","unresolved":false,"context_lines":[{"line_number":739,"context_line":"    select \u003d _compute_node_select(context)"},{"line_number":740,"context_line":"    select \u003d select.where(_CN_TABLE.c.id \u003d\u003d compute_id)"},{"line_number":741,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":742,"context_line":"    if not results:"},{"line_number":743,"context_line":"        raise exception.ComputeHostNotFound(host\u003dcompute_id)"},{"line_number":744,"context_line":"    return results[0]"},{"line_number":745,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"7af24918_13413e0c","line":742,"in_reply_to":"9aed3d3a_26a3b2b3","updated":"2016-03-01 12:29:28.000000000","message":"yeah, I hate that, but you are right, we should keep that behaviour here.\n\nIt just feels like the new DB structure has more opportunity of multiples of things, but the unique constraints we have added now should help with that.","commit_id":"bd728ce46a452cf585fad810e37bc1b9cb561f0a"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"edb7b9762608e3e8f8011f4d1695c619fa67ee85","unresolved":false,"context_lines":[{"line_number":739,"context_line":"    select \u003d _compute_node_select(context)"},{"line_number":740,"context_line":"    select \u003d select.where(_CN_TABLE.c.id \u003d\u003d compute_id)"},{"line_number":741,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":742,"context_line":"    if not results:"},{"line_number":743,"context_line":"        raise exception.ComputeHostNotFound(host\u003dcompute_id)"},{"line_number":744,"context_line":"    return results[0]"},{"line_number":745,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"9aed3d3a_26a3b2b3","line":742,"in_reply_to":"9aed3d3a_7949de5f","updated":"2016-02-29 19:31:50.000000000","message":"Again, the original method called .first(), which does not complain if there is more than one record returned. I am simply keeping the same behavior.","commit_id":"bd728ce46a452cf585fad810e37bc1b9cb561f0a"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"d9932eeddf301b323dff00b6d2964e81e8be32e0","unresolved":false,"context_lines":[{"line_number":759,"context_line":"@main_context_manager.reader"},{"line_number":760,"context_line":"def compute_nodes_get_by_service_id(context, service_id):"},{"line_number":761,"context_line":"    select \u003d _compute_node_select(context)"},{"line_number":762,"context_line":"    select \u003d select.where(_CN_TABLE.c.service_id \u003d\u003d service_id)"},{"line_number":763,"context_line":"    select \u003d select.where(_CN_TABLE.c.deleted \u003d\u003d 0)"},{"line_number":764,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":765,"context_line":"    if not results:"}],"source_content_type":"text/x-python","patch_set":5,"id":"9aed3d3a_397e3619","line":762,"updated":"2016-02-29 18:35:15.000000000","message":"why not pass in filters \u003d {\"service_id\" \u003d service_id} into _compute_node_select rather than having _CN_TABLE leak out of that above method? or is that going to be messy?","commit_id":"bd728ce46a452cf585fad810e37bc1b9cb561f0a"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"bd27fd735e3ea6dc3680cb7fb2db0ccf4d33bc4d","unresolved":false,"context_lines":[{"line_number":759,"context_line":"@main_context_manager.reader"},{"line_number":760,"context_line":"def compute_nodes_get_by_service_id(context, service_id):"},{"line_number":761,"context_line":"    select \u003d _compute_node_select(context)"},{"line_number":762,"context_line":"    select \u003d select.where(_CN_TABLE.c.service_id \u003d\u003d service_id)"},{"line_number":763,"context_line":"    select \u003d select.where(_CN_TABLE.c.deleted \u003d\u003d 0)"},{"line_number":764,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":765,"context_line":"    if not results:"}],"source_content_type":"text/x-python","patch_set":5,"id":"7af24918_4fa03291","line":762,"in_reply_to":"7af24918_f848f189","updated":"2016-03-01 14:13:31.000000000","message":"OK, I\u0027ll switch it.","commit_id":"bd728ce46a452cf585fad810e37bc1b9cb561f0a"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"edb7b9762608e3e8f8011f4d1695c619fa67ee85","unresolved":false,"context_lines":[{"line_number":759,"context_line":"@main_context_manager.reader"},{"line_number":760,"context_line":"def compute_nodes_get_by_service_id(context, service_id):"},{"line_number":761,"context_line":"    select \u003d _compute_node_select(context)"},{"line_number":762,"context_line":"    select \u003d select.where(_CN_TABLE.c.service_id \u003d\u003d service_id)"},{"line_number":763,"context_line":"    select \u003d select.where(_CN_TABLE.c.deleted \u003d\u003d 0)"},{"line_number":764,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":765,"context_line":"    if not results:"}],"source_content_type":"text/x-python","patch_set":5,"id":"9aed3d3a_86cd5e87","line":762,"in_reply_to":"9aed3d3a_397e3619","updated":"2016-02-29 19:31:50.000000000","message":"I don\u0027t see one or the other as being any more or less leaky. You still have to know the table structure in either case, and at least pattern follows the pattern that Jay created in his earlier patch.","commit_id":"bd728ce46a452cf585fad810e37bc1b9cb561f0a"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"73980cc7b3198963a65d711fcfc5dadb81abad2a","unresolved":false,"context_lines":[{"line_number":759,"context_line":"@main_context_manager.reader"},{"line_number":760,"context_line":"def compute_nodes_get_by_service_id(context, service_id):"},{"line_number":761,"context_line":"    select \u003d _compute_node_select(context)"},{"line_number":762,"context_line":"    select \u003d select.where(_CN_TABLE.c.service_id \u003d\u003d service_id)"},{"line_number":763,"context_line":"    select \u003d select.where(_CN_TABLE.c.deleted \u003d\u003d 0)"},{"line_number":764,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":765,"context_line":"    if not results:"}],"source_content_type":"text/x-python","patch_set":5,"id":"7af24918_f848f189","line":762,"in_reply_to":"9aed3d3a_86cd5e87","updated":"2016-03-01 12:29:28.000000000","message":"If you do the above, you don\u0027t need the separate _compute_node_exec, and you don\u0027t need to have _CN_TABLE used here, you would just have:\n\n results \u003d _compute_node_select(context, filters\u003d{\"service_id\": service_id, \"deleted\": 0})\n if not results ...","commit_id":"bd728ce46a452cf585fad810e37bc1b9cb561f0a"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"a5af81d2ad2775e2ad5b22cb96d07c9c7ef45486","unresolved":false,"context_lines":[{"line_number":804,"context_line":"@main_context_manager.writer"},{"line_number":805,"context_line":"def compute_node_update(context, compute_id, values):"},{"line_number":806,"context_line":"    \"\"\"Updates the ComputeNode record with the most recent data.\"\"\""},{"line_number":807,"context_line":""},{"line_number":808,"context_line":"    compute_ref \u003d compute_node_get(context, compute_id)"},{"line_number":809,"context_line":"    # Always update this, even if there\u0027s going to be no other"},{"line_number":810,"context_line":"    # changes in data.  This ensures that we invalidate the"}],"source_content_type":"text/x-python","patch_set":6,"id":"9aed3d3a_f2c220e8","side":"PARENT","line":807,"updated":"2016-02-29 21:00:39.000000000","message":"unrelated whitespace damage","commit_id":"c61c526664954351656bcfe46ee89f524bee22b5"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"a5af81d2ad2775e2ad5b22cb96d07c9c7ef45486","unresolved":false,"context_lines":[{"line_number":812,"context_line":"    values[\u0027updated_at\u0027] \u003d timeutils.utcnow()"},{"line_number":813,"context_line":"    convert_objects_related_datetimes(values)"},{"line_number":814,"context_line":"    compute_ref.update(values)"},{"line_number":815,"context_line":""},{"line_number":816,"context_line":"    return compute_ref"},{"line_number":817,"context_line":""},{"line_number":818,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"9aed3d3a_d291dcf2","side":"PARENT","line":815,"updated":"2016-02-29 21:00:39.000000000","message":"unrelated whitespace damage","commit_id":"c61c526664954351656bcfe46ee89f524bee22b5"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"cc21ca095c539725ef37c796fe3be1616f75b7b3","unresolved":false,"context_lines":[{"line_number":740,"context_line":"    results \u003d _compute_node_exec(context, select)"},{"line_number":741,"context_line":"    if not results:"},{"line_number":742,"context_line":"        raise exception.ComputeHostNotFound(host\u003dcompute_id)"},{"line_number":743,"context_line":"    return results[0]"},{"line_number":744,"context_line":""},{"line_number":745,"context_line":""},{"line_number":746,"context_line":"@main_context_manager.reader"}],"source_content_type":"text/x-python","patch_set":8,"id":"7af24918_d32b5632","line":743,"updated":"2016-03-01 12:30:18.000000000","message":"I still think most of my comments on the previous patch set are still valid here, please see my replies on the previous patchset.","commit_id":"d3198af3388752753b1425fdcbde0200db3c4159"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"8fa8c9bfc7cfb01c05d96eaedc4b875ef120cfbf","unresolved":false,"context_lines":[{"line_number":726,"context_line":"    if context.read_deleted \u003d\u003d \"no\":"},{"line_number":727,"context_line":"        select \u003d select.where(cn_tbl.c.deleted \u003d\u003d 0)"},{"line_number":728,"context_line":"    if \"compute_id\" in filters:"},{"line_number":729,"context_line":"        select \u003d select.where(_CN_TABLE.c.id \u003d\u003d filters[\"compute_id\"])"},{"line_number":730,"context_line":"    if \"service_id\" in filters:"},{"line_number":731,"context_line":"        select \u003d select.where(_CN_TABLE.c.service_id \u003d\u003d filters[\"service_id\"])"},{"line_number":732,"context_line":"    if \"host\" in filters:"}],"source_content_type":"text/x-python","patch_set":10,"id":"7af24918_491144ac","line":729,"range":{"start_line":729,"start_character":30,"end_line":729,"end_character":39},"updated":"2016-03-01 16:44:27.000000000","message":"These references should be changed to \u0027cn_tbl\u0027. I\u0027ll fix that in a new patchset that includes unit tests.","commit_id":"b77dbfa51e03b04d1bcc215e68895aa6dd1708c1"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"8d184ffed6dcdbe4d17fe196b66d1ad72d1a30f2","unresolved":false,"context_lines":[{"line_number":575,"context_line":"###################"},{"line_number":576,"context_line":""},{"line_number":577,"context_line":"@main_context_manager.reader"},{"line_number":578,"context_line":"def compute_node_get(context, compute_id):"},{"line_number":579,"context_line":"    result \u003d model_query(context, models.ComputeNode).\\"},{"line_number":580,"context_line":"            filter_by(id\u003dcompute_id).\\"},{"line_number":581,"context_line":"            first()"}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_4bc0dc7c","side":"PARENT","line":578,"updated":"2016-03-02 13:10:23.000000000","message":"nit: it wasn\u0027t necessary to move those methods down after declaring _compute_node_select since Python imports this module once and already knows the references. It just makes harder to review that.","commit_id":"f115ce5d747a8a9373c86257f413a261c3aeb39a"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"8d184ffed6dcdbe4d17fe196b66d1ad72d1a30f2","unresolved":false,"context_lines":[{"line_number":646,"context_line":"    #     ON disk_inv.resource_provider_id \u003d disk_usage.resource_provider_id"},{"line_number":647,"context_line":"    # WHERE cn.deleted \u003d 0;"},{"line_number":648,"context_line":"    if filters is None:"},{"line_number":649,"context_line":"        filters \u003d {}"},{"line_number":650,"context_line":""},{"line_number":651,"context_line":"    RAM_MB \u003d fields.ResourceClass.index(fields.ResourceClass.MEMORY_MB)"},{"line_number":652,"context_line":"    VCPU \u003d fields.ResourceClass.index(fields.ResourceClass.VCPU)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_0b5c14ec","line":649,"updated":"2016-03-02 13:10:23.000000000","message":"thanks for having thought about how Python works with signatures.","commit_id":"1f840f7583ffdbb141d288cd2279cc42e02e9b0c"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"2f0b89173c96fe0f5776dd7da7dff1d912fe314d","unresolved":false,"context_lines":[{"line_number":740,"context_line":"    conn \u003d engine.connect()"},{"line_number":741,"context_line":""},{"line_number":742,"context_line":"    results \u003d conn.execute(select).fetchall()"},{"line_number":743,"context_line":""},{"line_number":744,"context_line":"    # Callers expect dict-like objects, not SQLAlchemy RowProxy objects..."},{"line_number":745,"context_line":"    results \u003d [dict(r) for r in results]"},{"line_number":746,"context_line":"    conn.close()"}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_07cb6ea6","line":743,"updated":"2016-03-02 11:08:05.000000000","message":"Nit: we should drop that if we have to respin, I guess.","commit_id":"1f840f7583ffdbb141d288cd2279cc42e02e9b0c"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"8d184ffed6dcdbe4d17fe196b66d1ad72d1a30f2","unresolved":false,"context_lines":[{"line_number":758,"context_line":"@main_context_manager.reader"},{"line_number":759,"context_line":"def compute_node_get_model(context, compute_id):"},{"line_number":760,"context_line":"    # TODO(edleafe): remove once the compute node resource provider migration"},{"line_number":761,"context_line":"    # is complete, and this distinction is no longer necessary."},{"line_number":762,"context_line":"    result \u003d model_query(context, models.ComputeNode).\\"},{"line_number":763,"context_line":"            filter_by(id\u003dcompute_id).\\"},{"line_number":764,"context_line":"            first()"}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_ebd3a836","line":761,"updated":"2016-03-02 13:10:23.000000000","message":"nit: Honestly, call that method \"Deprecated\" and put a big note saying \"You shouldn\u0027t use it unless you\u0027re 100% sure about what you want to do with it\"","commit_id":"1f840f7583ffdbb141d288cd2279cc42e02e9b0c"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"8d184ffed6dcdbe4d17fe196b66d1ad72d1a30f2","unresolved":false,"context_lines":[{"line_number":823,"context_line":"def compute_node_update(context, compute_id, values):"},{"line_number":824,"context_line":"    \"\"\"Updates the ComputeNode record with the most recent data.\"\"\""},{"line_number":825,"context_line":""},{"line_number":826,"context_line":"    compute_ref \u003d compute_node_get_model(context, compute_id)"},{"line_number":827,"context_line":"    # Always update this, even if there\u0027s going to be no other"},{"line_number":828,"context_line":"    # changes in data.  This ensures that we invalidate the"},{"line_number":829,"context_line":"    # scheduler cache of compute node data in case of races."}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_2bff5068","line":826,"updated":"2016-03-02 13:10:23.000000000","message":"since this is the only caller to compute_node_get_model and given how much you would like to remove that model() method, why not just not proposing the model() method in the DB API, and directly use that as a private method ? (like _compute_node_get_model())","commit_id":"1f840f7583ffdbb141d288cd2279cc42e02e9b0c"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"a5c4553beaf62fcb002d083b20c67654b3693642","unresolved":false,"context_lines":[{"line_number":823,"context_line":"def compute_node_update(context, compute_id, values):"},{"line_number":824,"context_line":"    \"\"\"Updates the ComputeNode record with the most recent data.\"\"\""},{"line_number":825,"context_line":""},{"line_number":826,"context_line":"    compute_ref \u003d compute_node_get_model(context, compute_id)"},{"line_number":827,"context_line":"    # Always update this, even if there\u0027s going to be no other"},{"line_number":828,"context_line":"    # changes in data.  This ensures that we invalidate the"},{"line_number":829,"context_line":"    # scheduler cache of compute node data in case of races."}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_75ff71aa","line":826,"in_reply_to":"7af24918_2bff5068","updated":"2016-03-02 14:20:45.000000000","message":"The only reason for surfacing it is if it is needed for the compute_node object work. If not, the model stuff can all be done inline in this method.","commit_id":"1f840f7583ffdbb141d288cd2279cc42e02e9b0c"},{"author":{"_account_id":7166,"name":"Sylvain Bauza","email":"sbauza@redhat.com","username":"sbauza"},"change_message_id":"836058843706dc0cd59169a5c46a68cf5d63d8c9","unresolved":false,"context_lines":[{"line_number":823,"context_line":"def compute_node_update(context, compute_id, values):"},{"line_number":824,"context_line":"    \"\"\"Updates the ComputeNode record with the most recent data.\"\"\""},{"line_number":825,"context_line":""},{"line_number":826,"context_line":"    compute_ref \u003d compute_node_get_model(context, compute_id)"},{"line_number":827,"context_line":"    # Always update this, even if there\u0027s going to be no other"},{"line_number":828,"context_line":"    # changes in data.  This ensures that we invalidate the"},{"line_number":829,"context_line":"    # scheduler cache of compute node data in case of races."}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_bdeb9faf","line":826,"in_reply_to":"7af24918_5a79c1f5","updated":"2016-03-02 14:57:31.000000000","message":"Okay, we can unexpose the public method from the DB API in a later patch. I\u0027m fine with that, was just asking the question hence my original +1.","commit_id":"1f840f7583ffdbb141d288cd2279cc42e02e9b0c"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"d1043e6478c92002b9d44f4a4b1a91a3c7545497","unresolved":false,"context_lines":[{"line_number":823,"context_line":"def compute_node_update(context, compute_id, values):"},{"line_number":824,"context_line":"    \"\"\"Updates the ComputeNode record with the most recent data.\"\"\""},{"line_number":825,"context_line":""},{"line_number":826,"context_line":"    compute_ref \u003d compute_node_get_model(context, compute_id)"},{"line_number":827,"context_line":"    # Always update this, even if there\u0027s going to be no other"},{"line_number":828,"context_line":"    # changes in data.  This ensures that we invalidate the"},{"line_number":829,"context_line":"    # scheduler cache of compute node data in case of races."}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_5a79c1f5","line":826,"in_reply_to":"7af24918_75ff71aa","updated":"2016-03-02 14:46:39.000000000","message":"Sylvain, I was initially in favor of removing the _model method from the public api, but since it\u0027s already done, I figured that it was easier to just leave it in place in case we need to use it urgently to patch up an issue with the inventories.\n\nAs for the name, _model makes sense to me.\n\nIf we respin, strengthening the comment language around not using this for new stuff would be fine.","commit_id":"1f840f7583ffdbb141d288cd2279cc42e02e9b0c"}],"nova/tests/unit/db/test_db_api.py":[{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"8fa8c9bfc7cfb01c05d96eaedc4b875ef120cfbf","unresolved":false,"context_lines":[{"line_number":7412,"context_line":"        # values for the inv_* fields in the returned list of dicts from"},{"line_number":7413,"context_line":"        # _compute_node_select()."},{"line_number":7414,"context_line":"        select \u003d sqlalchemy_api._compute_node_select(self.ctxt)"},{"line_number":7415,"context_line":"        nodes \u003d sqlalchemy_api._compute_node_exec(self.ctxt, select)"},{"line_number":7416,"context_line":"        self.assertEqual(1, len(nodes))"},{"line_number":7417,"context_line":"        node \u003d nodes[0]"},{"line_number":7418,"context_line":"        self.assertIsNone(node[\u0027inv_memory_mb\u0027])"}],"source_content_type":"text/x-python","patch_set":10,"id":"7af24918_698360cd","line":7415,"range":{"start_line":7415,"start_character":31,"end_line":7415,"end_character":49},"updated":"2016-03-01 16:44:27.000000000","message":"This also needs to be removed.","commit_id":"b77dbfa51e03b04d1bcc215e68895aa6dd1708c1"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"8fa8c9bfc7cfb01c05d96eaedc4b875ef120cfbf","unresolved":false,"context_lines":[{"line_number":7504,"context_line":""},{"line_number":7505,"context_line":"    def test_compute_node_exec(self):"},{"line_number":7506,"context_line":"        select \u003d sqlalchemy_api._compute_node_select(self.ctxt)"},{"line_number":7507,"context_line":"        results \u003d sqlalchemy_api._compute_node_exec(self.ctxt, select)"},{"line_number":7508,"context_line":"        self.assertIsInstance(results, list)"},{"line_number":7509,"context_line":"        self.assertEqual(1, len(results))"},{"line_number":7510,"context_line":"        self.assertIsInstance(results[0], dict)"}],"source_content_type":"text/x-python","patch_set":10,"id":"7af24918_2963181c","line":7507,"range":{"start_line":7507,"start_character":33,"end_line":7507,"end_character":51},"updated":"2016-03-01 16:44:27.000000000","message":"Ditto.","commit_id":"b77dbfa51e03b04d1bcc215e68895aa6dd1708c1"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"2f0b89173c96fe0f5776dd7da7dff1d912fe314d","unresolved":false,"context_lines":[{"line_number":7828,"context_line":"            def filter_by(self, id):"},{"line_number":7829,"context_line":"                return fake_filtered_cn"},{"line_number":7830,"context_line":""},{"line_number":7831,"context_line":"        mock_model_query.return_value \u003d FakeModelQuery()"},{"line_number":7832,"context_line":"        result \u003d sqlalchemy_api.compute_node_get_model(self.ctxt,"},{"line_number":7833,"context_line":"                                                       self.item[\"id\"])"},{"line_number":7834,"context_line":"        self.assertEqual(result, mock.sentinel.first)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_47fa96be","line":7831,"updated":"2016-03-02 11:08:05.000000000","message":"I think we are mocking was too much here.\n\nWe could just assert we get back the self.item correctly.\n\nBut lets do this as a follow up fix, as we need to get this chain moving, quickly.","commit_id":"1f840f7583ffdbb141d288cd2279cc42e02e9b0c"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"a5c4553beaf62fcb002d083b20c67654b3693642","unresolved":false,"context_lines":[{"line_number":7828,"context_line":"            def filter_by(self, id):"},{"line_number":7829,"context_line":"                return fake_filtered_cn"},{"line_number":7830,"context_line":""},{"line_number":7831,"context_line":"        mock_model_query.return_value \u003d FakeModelQuery()"},{"line_number":7832,"context_line":"        result \u003d sqlalchemy_api.compute_node_get_model(self.ctxt,"},{"line_number":7833,"context_line":"                                                       self.item[\"id\"])"},{"line_number":7834,"context_line":"        self.assertEqual(result, mock.sentinel.first)"}],"source_content_type":"text/x-python","patch_set":11,"id":"7af24918_55cb5553","line":7831,"in_reply_to":"7af24918_47fa96be","updated":"2016-03-02 14:20:45.000000000","message":"I still have a purist view of what \"unit\" means in unit tests. This just checks that the method passes the correct items to the correct places, and handles the return correctly. It isn\u0027t designed to test how well sqlalchemy works.","commit_id":"1f840f7583ffdbb141d288cd2279cc42e02e9b0c"}]}
