)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"3d21c9ce201563a9e3debeaec2b7247cb53816fa","unresolved":false,"context_lines":[{"line_number":10,"context_line":"resource dictionaries by comparing ids. This was to take into"},{"line_number":11,"context_line":"account projects containing a list of tags, which cannot be"},{"line_number":12,"context_line":"hashed using the current implementation in order to determine"},{"line_number":13,"context_line":"duplicates."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"Change-Id: Ia23b8846fc2f272cc5ac11cf3ab54c98647220a1"},{"line_number":16,"context_line":"Partially-Implements: bp project-tags"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":13,"id":"7f515b1d_e3bf93a7","line":13,"range":{"start_line":13,"start_character":0,"end_line":13,"end_character":10},"updated":"2017-09-28 19:58:03.000000000","message":"Adding why this patch is needed for the project tag work would be useful, but documenting it in a comment would be good too.","commit_id":"3ef8214e5965d56bfc173c511f6bcbbabd61d3f4"}],"keystone/common/utils.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"b5fcd086dfc384121eef5ea8c36f803d8c35fa73","unresolved":false,"context_lines":[{"line_number":125,"context_line":""},{"line_number":126,"context_line":"    This compares duplicates based on resource id. This is to account"},{"line_number":127,"context_line":"    for resources that can contain values, such as a list of tags that"},{"line_number":128,"context_line":"    will not be guaranteed to be in order."},{"line_number":129,"context_line":"    \"\"\""},{"line_number":130,"context_line":"    resources \u003d []"},{"line_number":131,"context_line":"    ids \u003d set()"}],"source_content_type":"text/x-python","patch_set":2,"id":"9f436f4f_285f560f","line":128,"updated":"2017-08-18 16:04:16.000000000","message":"We should document the list and what type the \u0027resource\u0027 is. Here we\u0027re talking about a list of dictionaries, right?\n\nFWIW - I tested a few different implementations of this and timed them locally [0] [1]. Filtering duplicates based on containment seemed to be the fastest for me [2].\n\n[0] https://gist.github.com/lbragstad/a81776e2c679f728c19cad7f3a35703f\n[1] http://paste.openstack.org/show/618785/\n[2] https://gist.github.com/lbragstad/a81776e2c679f728c19cad7f3a35703f#file-attempt-py-L26-L34","commit_id":"ff7c81fb3e843b177482bce78e21f26f71f029f5"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"b5fcd086dfc384121eef5ea8c36f803d8c35fa73","unresolved":false,"context_lines":[{"line_number":130,"context_line":"    resources \u003d []"},{"line_number":131,"context_line":"    ids \u003d set()"},{"line_number":132,"context_line":"    for r in resource_list:"},{"line_number":133,"context_line":"        if r.get(\u0027id\u0027) not in ids:"},{"line_number":134,"context_line":"            ids.add(r[\u0027id\u0027])"},{"line_number":135,"context_line":"            resources.append(r)"},{"line_number":136,"context_line":"    return resources"}],"source_content_type":"text/x-python","patch_set":2,"id":"9f436f4f_486cda9b","line":133,"updated":"2017-08-18 16:04:16.000000000","message":"This actually does a deep copy comparison - which means you don\u0027t even have to deal with a set of id separately:\n\n  unique_resources \u003d []\n  for resource in resource_list:\n      if resource not in unique_resources:\n          unique_resources.append(resource)\n  return unique_resources\n\nAnd while this probably isn\u0027t likely in our specific case - it works with the following data set:\n\n  d1 \u003d {\u0027id\u0027: 1, \u0027foo\u0027: \u0027bar\u0027}\n  d2 \u003d {\u0027id\u0027: 1, \u0027foo\u0027: \u0027baz\u0027}\n\nWhere-as only comparing ID and assuming both dictionaries are equal based on the id only means ^ those are equal.","commit_id":"ff7c81fb3e843b177482bce78e21f26f71f029f5"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"54665f6425f01554b3c9491224653aa947838779","unresolved":false,"context_lines":[{"line_number":120,"context_line":"    return strutils.bool_from_string(val_attr, default\u003dTrue)"},{"line_number":121,"context_line":""},{"line_number":122,"context_line":""},{"line_number":123,"context_line":"def remove_duplicate_resources(resource_list):"},{"line_number":124,"context_line":"    \"\"\"Return a list with duplicate resources removed."},{"line_number":125,"context_line":""},{"line_number":126,"context_line":"    This compares duplicates based on resource id. This is to account"}],"source_content_type":"text/x-python","patch_set":6,"id":"7f287b81_bd71a878","line":123,"updated":"2017-08-29 21:27:20.000000000","message":"nit: the naming here doesn\u0027t have to imply resources, we could also include list in the method name so it\u0027s more descriptive of what we\u0027re operating on.\n\n  def remove_duplicate_dicts_from_list(l):\n\nor \n\n  def remove_duplicate_dictionaries_from_list(l):","commit_id":"b2ffac4d766773ebdc8fa173184c115faff53c23"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"6a8eb61129e8130eb371c36071d759ff8fa4fbe8","unresolved":false,"context_lines":[{"line_number":120,"context_line":"    return strutils.bool_from_string(val_attr, default\u003dTrue)"},{"line_number":121,"context_line":""},{"line_number":122,"context_line":""},{"line_number":123,"context_line":"def remove_duplicate_resources(resource_list):"},{"line_number":124,"context_line":"    \"\"\"Return a list with duplicate resources removed."},{"line_number":125,"context_line":""},{"line_number":126,"context_line":"    This compares duplicates based on resource id. This is to account"}],"source_content_type":"text/x-python","patch_set":6,"id":"7f287b81_a01a9b13","line":123,"in_reply_to":"7f287b81_bd71a878","updated":"2017-08-29 22:03:46.000000000","message":"Done","commit_id":"b2ffac4d766773ebdc8fa173184c115faff53c23"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"54665f6425f01554b3c9491224653aa947838779","unresolved":false,"context_lines":[{"line_number":125,"context_line":""},{"line_number":126,"context_line":"    This compares duplicates based on resource id. This is to account"},{"line_number":127,"context_line":"    for resources that can contain values, such as a list of tags that"},{"line_number":128,"context_line":"    will not be guaranteed to be in order."},{"line_number":129,"context_line":"    \"\"\""},{"line_number":130,"context_line":"    unique \u003d {}"},{"line_number":131,"context_line":"    for r in resource_list:"}],"source_content_type":"text/x-python","patch_set":6,"id":"7f287b81_9dbeecfc","line":128,"updated":"2017-08-29 21:27:20.000000000","message":"I think we should add the type of parameter and what we expect it to be here.\n\n  :param resource_list: a list of dictionaries\n  :returns: a list of unique dictionaries\n\nThat way people using it will know what it\u0027s supposed to be used for.","commit_id":"b2ffac4d766773ebdc8fa173184c115faff53c23"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"6a8eb61129e8130eb371c36071d759ff8fa4fbe8","unresolved":false,"context_lines":[{"line_number":125,"context_line":""},{"line_number":126,"context_line":"    This compares duplicates based on resource id. This is to account"},{"line_number":127,"context_line":"    for resources that can contain values, such as a list of tags that"},{"line_number":128,"context_line":"    will not be guaranteed to be in order."},{"line_number":129,"context_line":"    \"\"\""},{"line_number":130,"context_line":"    unique \u003d {}"},{"line_number":131,"context_line":"    for r in resource_list:"}],"source_content_type":"text/x-python","patch_set":6,"id":"7f287b81_80155fe7","line":128,"in_reply_to":"7f287b81_9dbeecfc","updated":"2017-08-29 22:03:46.000000000","message":"Done","commit_id":"b2ffac4d766773ebdc8fa173184c115faff53c23"}],"keystone/federation/controllers.py":[{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"5f7930844945dd2b57d72e11feaabfc8f61d8568","unresolved":false,"context_lines":[{"line_number":452,"context_line":"        domains \u003d domains + self.assignment_api.list_domains_for_user("},{"line_number":453,"context_line":"            request.auth_context[\u0027user_id\u0027])"},{"line_number":454,"context_line":"        # remove duplicates"},{"line_number":455,"context_line":"        domains \u003d k_utils.remove_duplicate_resources(domains)"},{"line_number":456,"context_line":"        return DomainV3.wrap_collection(request.context_dict, domains)"},{"line_number":457,"context_line":""},{"line_number":458,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"7f287b81_8c8b5866","line":455,"updated":"2017-08-30 00:45:58.000000000","message":"remove_duplicate_dicts_from_list","commit_id":"16b07de32bf13ac2e3df463c459302e4f832ee50"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"eddd4dc03814e4f1e543672aba59925593eebfbf","unresolved":false,"context_lines":[{"line_number":452,"context_line":"        domains \u003d domains + self.assignment_api.list_domains_for_user("},{"line_number":453,"context_line":"            request.auth_context[\u0027user_id\u0027])"},{"line_number":454,"context_line":"        # remove duplicates"},{"line_number":455,"context_line":"        domains \u003d k_utils.remove_duplicate_resources(domains)"},{"line_number":456,"context_line":"        return DomainV3.wrap_collection(request.context_dict, domains)"},{"line_number":457,"context_line":""},{"line_number":458,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"7f287b81_fac27d52","line":455,"in_reply_to":"7f287b81_04029c0a","updated":"2017-08-30 15:49:32.000000000","message":"Done","commit_id":"16b07de32bf13ac2e3df463c459302e4f832ee50"},{"author":{"_account_id":5707,"name":"Henry Nash","email":"henryn@linux.vnet.ibm.com","username":"henry-nash"},"change_message_id":"f9aa5f93236cce5e89ce8a2bdd4fc92cff088908","unresolved":false,"context_lines":[{"line_number":452,"context_line":"        domains \u003d domains + self.assignment_api.list_domains_for_user("},{"line_number":453,"context_line":"            request.auth_context[\u0027user_id\u0027])"},{"line_number":454,"context_line":"        # remove duplicates"},{"line_number":455,"context_line":"        domains \u003d k_utils.remove_duplicate_resources(domains)"},{"line_number":456,"context_line":"        return DomainV3.wrap_collection(request.context_dict, domains)"},{"line_number":457,"context_line":""},{"line_number":458,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"7f287b81_04029c0a","line":455,"in_reply_to":"7f287b81_8c8b5866","updated":"2017-08-30 03:39:53.000000000","message":"++","commit_id":"16b07de32bf13ac2e3df463c459302e4f832ee50"},{"author":{"_account_id":5046,"name":"Lance Bragstad","email":"lbragstad@redhat.com","username":"ldbragst"},"change_message_id":"5f7930844945dd2b57d72e11feaabfc8f61d8568","unresolved":false,"context_lines":[{"line_number":478,"context_line":"        projects \u003d projects + self.assignment_api.list_projects_for_user("},{"line_number":479,"context_line":"            request.auth_context[\u0027user_id\u0027])"},{"line_number":480,"context_line":"        # remove duplicates"},{"line_number":481,"context_line":"        projects \u003d k_utils.remove_duplicate_resources(projects)"},{"line_number":482,"context_line":"        return ProjectAssignmentV3.wrap_collection(request.context_dict,"},{"line_number":483,"context_line":"                                                   projects)"},{"line_number":484,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"7f287b81_6cecac29","line":481,"updated":"2017-08-30 00:45:58.000000000","message":"remove_duplicate_dicts_from_list","commit_id":"16b07de32bf13ac2e3df463c459302e4f832ee50"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"eddd4dc03814e4f1e543672aba59925593eebfbf","unresolved":false,"context_lines":[{"line_number":478,"context_line":"        projects \u003d projects + self.assignment_api.list_projects_for_user("},{"line_number":479,"context_line":"            request.auth_context[\u0027user_id\u0027])"},{"line_number":480,"context_line":"        # remove duplicates"},{"line_number":481,"context_line":"        projects \u003d k_utils.remove_duplicate_resources(projects)"},{"line_number":482,"context_line":"        return ProjectAssignmentV3.wrap_collection(request.context_dict,"},{"line_number":483,"context_line":"                                                   projects)"},{"line_number":484,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"7f287b81_daa341b1","line":481,"in_reply_to":"7f287b81_6cecac29","updated":"2017-08-30 15:49:32.000000000","message":"Done","commit_id":"16b07de32bf13ac2e3df463c459302e4f832ee50"},{"author":{"_account_id":17860,"name":"Samuel de Medeiros Queiroz","email":"samueldmq@gmail.com","username":"samueldmq"},"change_message_id":"33d5f5826d6bcee3a1e656023d78f3829160d1bc","unresolved":false,"context_lines":[{"line_number":452,"context_line":"        domains \u003d domains + self.assignment_api.list_domains_for_user("},{"line_number":453,"context_line":"            request.auth_context[\u0027user_id\u0027])"},{"line_number":454,"context_line":"        # remove duplicates"},{"line_number":455,"context_line":"        domains \u003d k_utils.remove_duplicate_dicts_from_list(domains)"},{"line_number":456,"context_line":"        return DomainV3.wrap_collection(request.context_dict, domains)"},{"line_number":457,"context_line":""},{"line_number":458,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"7f287b81_069d9256","line":455,"range":{"start_line":455,"start_character":26,"end_line":455,"end_character":58},"updated":"2017-09-04 13:26:15.000000000","message":"remove_duplicate_dicts_by_id could be a good name too","commit_id":"dd499f72e181457e15dd0b2e599569f860a0b0dc"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"87bad74f71befc406490e2cc0a658f34badc7e2b","unresolved":false,"context_lines":[{"line_number":452,"context_line":"        domains \u003d domains + self.assignment_api.list_domains_for_user("},{"line_number":453,"context_line":"            request.auth_context[\u0027user_id\u0027])"},{"line_number":454,"context_line":"        # remove duplicates"},{"line_number":455,"context_line":"        domains \u003d k_utils.remove_duplicate_dicts_from_list(domains)"},{"line_number":456,"context_line":"        return DomainV3.wrap_collection(request.context_dict, domains)"},{"line_number":457,"context_line":""},{"line_number":458,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"7f287b81_15ac9633","line":455,"range":{"start_line":455,"start_character":26,"end_line":455,"end_character":58},"in_reply_to":"7f287b81_069d9256","updated":"2017-09-04 17:47:31.000000000","message":"Yeah I think I like that name more, it describes what it does more accurately.","commit_id":"dd499f72e181457e15dd0b2e599569f860a0b0dc"}],"keystone/tests/unit/common/test_utils.py":[{"author":{"_account_id":17860,"name":"Samuel de Medeiros Queiroz","email":"samueldmq@gmail.com","username":"samueldmq"},"change_message_id":"33d5f5826d6bcee3a1e656023d78f3829160d1bc","unresolved":false,"context_lines":[{"line_number":87,"context_line":"            }"},{"line_number":88,"context_line":"            dict_list.append(new_dict)"},{"line_number":89,"context_line":"        dict_list.append(dup_value)"},{"line_number":90,"context_line":"        # Should be 12 values in the list, remove the duplicate"},{"line_number":91,"context_line":"        result \u003d common_utils.remove_duplicate_dicts_from_list(dict_list)"},{"line_number":92,"context_line":"        self.assertNotEqual(len(result), len(dict_list))"},{"line_number":93,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"7f287b81_26d08ef7","line":90,"range":{"start_line":90,"start_character":20,"end_line":90,"end_character":22},"updated":"2017-09-04 13:26:15.000000000","message":"11 values as range(1,10) gives 9","commit_id":"dd499f72e181457e15dd0b2e599569f860a0b0dc"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"87bad74f71befc406490e2cc0a658f34badc7e2b","unresolved":false,"context_lines":[{"line_number":87,"context_line":"            }"},{"line_number":88,"context_line":"            dict_list.append(new_dict)"},{"line_number":89,"context_line":"        dict_list.append(dup_value)"},{"line_number":90,"context_line":"        # Should be 12 values in the list, remove the duplicate"},{"line_number":91,"context_line":"        result \u003d common_utils.remove_duplicate_dicts_from_list(dict_list)"},{"line_number":92,"context_line":"        self.assertNotEqual(len(result), len(dict_list))"},{"line_number":93,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"7f287b81_556fbefb","line":90,"range":{"start_line":90,"start_character":20,"end_line":90,"end_character":22},"in_reply_to":"7f287b81_26d08ef7","updated":"2017-09-04 17:47:31.000000000","message":"Done","commit_id":"dd499f72e181457e15dd0b2e599569f860a0b0dc"},{"author":{"_account_id":17860,"name":"Samuel de Medeiros Queiroz","email":"samueldmq@gmail.com","username":"samueldmq"},"change_message_id":"33d5f5826d6bcee3a1e656023d78f3829160d1bc","unresolved":false,"context_lines":[{"line_number":89,"context_line":"        dict_list.append(dup_value)"},{"line_number":90,"context_line":"        # Should be 12 values in the list, remove the duplicate"},{"line_number":91,"context_line":"        result \u003d common_utils.remove_duplicate_dicts_from_list(dict_list)"},{"line_number":92,"context_line":"        self.assertNotEqual(len(result), len(dict_list))"},{"line_number":93,"context_line":""},{"line_number":94,"context_line":"    def test_hash(self):"},{"line_number":95,"context_line":"        password \u003d \u0027right\u0027"}],"source_content_type":"text/x-python","patch_set":9,"id":"7f287b81_6634564b","line":92,"range":{"start_line":92,"start_character":8,"end_line":92,"end_character":56},"updated":"2017-09-04 13:26:15.000000000","message":"self.assertEqual(len(result), len(dict_list)-1)\n\nwould be nice too, as we assert exactly one element was removed","commit_id":"dd499f72e181457e15dd0b2e599569f860a0b0dc"},{"author":{"_account_id":21420,"name":"Gage Hugo","email":"gagehugo@gmail.com","username":"ghugo"},"change_message_id":"87bad74f71befc406490e2cc0a658f34badc7e2b","unresolved":false,"context_lines":[{"line_number":89,"context_line":"        dict_list.append(dup_value)"},{"line_number":90,"context_line":"        # Should be 12 values in the list, remove the duplicate"},{"line_number":91,"context_line":"        result \u003d common_utils.remove_duplicate_dicts_from_list(dict_list)"},{"line_number":92,"context_line":"        self.assertNotEqual(len(result), len(dict_list))"},{"line_number":93,"context_line":""},{"line_number":94,"context_line":"    def test_hash(self):"},{"line_number":95,"context_line":"        password \u003d \u0027right\u0027"}],"source_content_type":"text/x-python","patch_set":9,"id":"7f287b81_357672da","line":92,"range":{"start_line":92,"start_character":8,"end_line":92,"end_character":56},"in_reply_to":"7f287b81_4f728daf","updated":"2017-09-04 17:47:31.000000000","message":"Done","commit_id":"dd499f72e181457e15dd0b2e599569f860a0b0dc"},{"author":{"_account_id":5707,"name":"Henry Nash","email":"henryn@linux.vnet.ibm.com","username":"henry-nash"},"change_message_id":"b1a9d93dda6e1163b63f24fc62a9afc9bca3064d","unresolved":false,"context_lines":[{"line_number":89,"context_line":"        dict_list.append(dup_value)"},{"line_number":90,"context_line":"        # Should be 12 values in the list, remove the duplicate"},{"line_number":91,"context_line":"        result \u003d common_utils.remove_duplicate_dicts_from_list(dict_list)"},{"line_number":92,"context_line":"        self.assertNotEqual(len(result), len(dict_list))"},{"line_number":93,"context_line":""},{"line_number":94,"context_line":"    def test_hash(self):"},{"line_number":95,"context_line":"        password \u003d \u0027right\u0027"}],"source_content_type":"text/x-python","patch_set":9,"id":"7f287b81_4f728daf","line":92,"range":{"start_line":92,"start_character":8,"end_line":92,"end_character":56},"in_reply_to":"7f287b81_6634564b","updated":"2017-09-04 15:07:10.000000000","message":"++ much better - otherwise you could easily write a de-dupe method which would pass by throwing out all indexes that were even, say. I would further test. that the correct item has been removed.","commit_id":"dd499f72e181457e15dd0b2e599569f860a0b0dc"}]}
