)]}'
{"microversion_parse/__init__.py":[{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"585d2b3d1d88ee4275bf17e95af73e3e640b75b5","unresolved":false,"context_lines":[{"line_number":162,"context_line":"    min_version_string \u003d versions_list[0]"},{"line_number":163,"context_line":"    max_version_string \u003d versions_list[-1]"},{"line_number":164,"context_line":""},{"line_number":165,"context_line":"    version_string \u003d found_version or min_version_string"},{"line_number":166,"context_line":"    if version_string \u003d\u003d \u0027latest\u0027:"},{"line_number":167,"context_line":"        version_string \u003d max_version_string"},{"line_number":168,"context_line":"    request_version \u003d parse_version_string(version_string)"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_9578c3f8","line":165,"range":{"start_line":165,"start_character":21,"end_line":165,"end_character":56},"updated":"2017-08-22 13:36:55.000000000","message":"This could use a comment, as I always have to think a bit as to why this should be the case. Just something like \"the microversion for the specified service was not passed, so default to the min_version\".","commit_id":"b8a485ed348466eb65c577d0108f349b35ab4c0f"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"82e92ad703fa5ee430b33a091f6c387364ebf71e","unresolved":false,"context_lines":[{"line_number":162,"context_line":"    min_version_string \u003d versions_list[0]"},{"line_number":163,"context_line":"    max_version_string \u003d versions_list[-1]"},{"line_number":164,"context_line":""},{"line_number":165,"context_line":"    version_string \u003d found_version or min_version_string"},{"line_number":166,"context_line":"    if version_string \u003d\u003d \u0027latest\u0027:"},{"line_number":167,"context_line":"        version_string \u003d max_version_string"},{"line_number":168,"context_line":"    request_version \u003d parse_version_string(version_string)"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_df31c1ee","line":165,"in_reply_to":"7f287b81_9578c3f8","updated":"2017-08-22 18:00:16.000000000","message":"good idea","commit_id":"b8a485ed348466eb65c577d0108f349b35ab4c0f"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"d9ec820042cb5a6581c05dccbb98e05373b45bd7","unresolved":false,"context_lines":[{"line_number":162,"context_line":"    min_version_string \u003d versions_list[0]"},{"line_number":163,"context_line":"    max_version_string \u003d versions_list[-1]"},{"line_number":164,"context_line":""},{"line_number":165,"context_line":"    version_string \u003d found_version or min_version_string"},{"line_number":166,"context_line":"    if version_string \u003d\u003d \u0027latest\u0027:"},{"line_number":167,"context_line":"        version_string \u003d max_version_string"},{"line_number":168,"context_line":"    request_version \u003d parse_version_string(version_string)"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_cbc57f5d","line":165,"in_reply_to":"7f287b81_df31c1ee","updated":"2017-08-22 20:54:01.000000000","message":"Done","commit_id":"b8a485ed348466eb65c577d0108f349b35ab4c0f"},{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"585d2b3d1d88ee4275bf17e95af73e3e640b75b5","unresolved":false,"context_lines":[{"line_number":177,"context_line":"    raise ValueError(\u0027Unacceptable version header: %s\u0027 % version_string)"},{"line_number":178,"context_line":""},{"line_number":179,"context_line":""},{"line_number":180,"context_line":"class Version(collections.namedtuple(\u0027Version\u0027, \u0027major minor\u0027)):"},{"line_number":181,"context_line":"    \"\"\"A namedtuple containing major and minor values."},{"line_number":182,"context_line":""},{"line_number":183,"context_line":"    Since it is a tuple is automatically comparable."}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_75931751","line":180,"range":{"start_line":180,"start_character":0,"end_line":180,"end_character":13},"updated":"2017-08-22 13:36:55.000000000","message":"Nit: I know it makes no semantic difference, but I think it\u0027s clearer if a class is defined in code above the code that references it.","commit_id":"b8a485ed348466eb65c577d0108f349b35ab4c0f"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"82e92ad703fa5ee430b33a091f6c387364ebf71e","unresolved":false,"context_lines":[{"line_number":177,"context_line":"    raise ValueError(\u0027Unacceptable version header: %s\u0027 % version_string)"},{"line_number":178,"context_line":""},{"line_number":179,"context_line":""},{"line_number":180,"context_line":"class Version(collections.namedtuple(\u0027Version\u0027, \u0027major minor\u0027)):"},{"line_number":181,"context_line":"    \"\"\"A namedtuple containing major and minor values."},{"line_number":182,"context_line":""},{"line_number":183,"context_line":"    Since it is a tuple is automatically comparable."}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_bf75d59a","line":180,"in_reply_to":"7f287b81_75931751","updated":"2017-08-22 18:00:16.000000000","message":"yeah, normally I would do that too. In this case I didn\u0027t bother because after surgery, this class became very small (relative to its original in placement). I\u0027ll move things around in a next version.","commit_id":"b8a485ed348466eb65c577d0108f349b35ab4c0f"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"d9ec820042cb5a6581c05dccbb98e05373b45bd7","unresolved":false,"context_lines":[{"line_number":177,"context_line":"    raise ValueError(\u0027Unacceptable version header: %s\u0027 % version_string)"},{"line_number":178,"context_line":""},{"line_number":179,"context_line":""},{"line_number":180,"context_line":"class Version(collections.namedtuple(\u0027Version\u0027, \u0027major minor\u0027)):"},{"line_number":181,"context_line":"    \"\"\"A namedtuple containing major and minor values."},{"line_number":182,"context_line":""},{"line_number":183,"context_line":"    Since it is a tuple is automatically comparable."}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_eb9ddb66","line":180,"in_reply_to":"7f287b81_bf75d59a","updated":"2017-08-22 20:54:01.000000000","message":"Done","commit_id":"b8a485ed348466eb65c577d0108f349b35ab4c0f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"aeb1ffb3bc941237fdb342278f9466d1301da80c","unresolved":false,"context_lines":[{"line_number":23,"context_line":"class Version(collections.namedtuple(\u0027Version\u0027, \u0027major minor\u0027)):"},{"line_number":24,"context_line":"    \"\"\"A namedtuple containing major and minor values."},{"line_number":25,"context_line":""},{"line_number":26,"context_line":"    Since it is a tuple is automatically comparable."},{"line_number":27,"context_line":"    \"\"\""},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"    def __str__(self):"}],"source_content_type":"text/x-python","patch_set":2,"id":"3f4b6375_56ad4e86","line":26,"range":{"start_line":26,"start_character":18,"end_line":26,"end_character":26},"updated":"2017-10-23 12:32:10.000000000","message":"tuple, it is","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"8e0e87a7d0d431226903366d56f937961e6408e3","unresolved":false,"context_lines":[{"line_number":23,"context_line":"class Version(collections.namedtuple(\u0027Version\u0027, \u0027major minor\u0027)):"},{"line_number":24,"context_line":"    \"\"\"A namedtuple containing major and minor values."},{"line_number":25,"context_line":""},{"line_number":26,"context_line":"    Since it is a tuple is automatically comparable."},{"line_number":27,"context_line":"    \"\"\""},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"    def __str__(self):"}],"source_content_type":"text/x-python","patch_set":2,"id":"ff6b8bd7_3c6d3d98","line":26,"range":{"start_line":26,"start_character":18,"end_line":26,"end_character":26},"in_reply_to":"3f4b6375_56ad4e86","updated":"2018-03-07 10:30:49.000000000","message":"Done","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"aeb1ffb3bc941237fdb342278f9466d1301da80c","unresolved":false,"context_lines":[{"line_number":170,"context_line":""},{"line_number":171,"context_line":"    :param headers: Request headers as dict list or WSGI environ"},{"line_number":172,"context_line":"    :param service_type: The service_type as a string"},{"line_number":173,"context_line":"    :param versions_list: List of all possible microversions as strings."},{"line_number":174,"context_line":"    \"\"\""},{"line_number":175,"context_line":"    found_version \u003d get_version(headers, service_type\u003dservice_type)"},{"line_number":176,"context_line":"    min_version_string \u003d versions_list[0]"}],"source_content_type":"text/x-python","patch_set":2,"id":"3f4b6375_963f4624","line":173,"range":{"start_line":173,"start_character":26,"end_line":173,"end_character":72},"updated":"2017-10-23 12:32:10.000000000","message":"Either document that this must be sorted from least to greatest...","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"8e0e87a7d0d431226903366d56f937961e6408e3","unresolved":false,"context_lines":[{"line_number":170,"context_line":""},{"line_number":171,"context_line":"    :param headers: Request headers as dict list or WSGI environ"},{"line_number":172,"context_line":"    :param service_type: The service_type as a string"},{"line_number":173,"context_line":"    :param versions_list: List of all possible microversions as strings."},{"line_number":174,"context_line":"    \"\"\""},{"line_number":175,"context_line":"    found_version \u003d get_version(headers, service_type\u003dservice_type)"},{"line_number":176,"context_line":"    min_version_string \u003d versions_list[0]"}],"source_content_type":"text/x-python","patch_set":2,"id":"ff6b8bd7_5cffd1a9","line":173,"range":{"start_line":173,"start_character":26,"end_line":173,"end_character":72},"in_reply_to":"3f4b6375_713cd4be","updated":"2018-03-07 10:30:49.000000000","message":"Done","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"b5ed0e117f4b1796afe1bc81b51aa08bf48d97e2","unresolved":false,"context_lines":[{"line_number":170,"context_line":""},{"line_number":171,"context_line":"    :param headers: Request headers as dict list or WSGI environ"},{"line_number":172,"context_line":"    :param service_type: The service_type as a string"},{"line_number":173,"context_line":"    :param versions_list: List of all possible microversions as strings."},{"line_number":174,"context_line":"    \"\"\""},{"line_number":175,"context_line":"    found_version \u003d get_version(headers, service_type\u003dservice_type)"},{"line_number":176,"context_line":"    min_version_string \u003d versions_list[0]"}],"source_content_type":"text/x-python","patch_set":2,"id":"3f4b6375_713cd4be","line":173,"range":{"start_line":173,"start_character":26,"end_line":173,"end_character":72},"in_reply_to":"3f4b6375_963f4624","updated":"2017-10-23 12:47:56.000000000","message":"will document, don\u0027t want to impose a sort here","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"aeb1ffb3bc941237fdb342278f9466d1301da80c","unresolved":false,"context_lines":[{"line_number":173,"context_line":"    :param versions_list: List of all possible microversions as strings."},{"line_number":174,"context_line":"    \"\"\""},{"line_number":175,"context_line":"    found_version \u003d get_version(headers, service_type\u003dservice_type)"},{"line_number":176,"context_line":"    min_version_string \u003d versions_list[0]"},{"line_number":177,"context_line":"    max_version_string \u003d versions_list[-1]"},{"line_number":178,"context_line":""},{"line_number":179,"context_line":"    # If there was no version found in the headers, choose the minimum"},{"line_number":180,"context_line":"    # available version."}],"source_content_type":"text/x-python","patch_set":2,"id":"3f4b6375_364412b7","line":177,"range":{"start_line":176,"start_character":0,"end_line":177,"end_character":42},"updated":"2017-10-23 12:32:10.000000000","message":"...or sort it before you do this.","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"aeb1ffb3bc941237fdb342278f9466d1301da80c","unresolved":false,"context_lines":[{"line_number":176,"context_line":"    min_version_string \u003d versions_list[0]"},{"line_number":177,"context_line":"    max_version_string \u003d versions_list[-1]"},{"line_number":178,"context_line":""},{"line_number":179,"context_line":"    # If there was no version found in the headers, choose the minimum"},{"line_number":180,"context_line":"    # available version."},{"line_number":181,"context_line":"    version_string \u003d found_version or min_version_string"},{"line_number":182,"context_line":"    if version_string \u003d\u003d \u0027latest\u0027:"},{"line_number":183,"context_line":"        version_string \u003d max_version_string"},{"line_number":184,"context_line":"    request_version \u003d parse_version_string(version_string)"}],"source_content_type":"text/x-python","patch_set":2,"id":"3f4b6375_1607d684","line":181,"range":{"start_line":179,"start_character":0,"end_line":181,"end_character":56},"updated":"2017-10-23 12:32:10.000000000","message":"This quirk should be documented.","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"b5ed0e117f4b1796afe1bc81b51aa08bf48d97e2","unresolved":false,"context_lines":[{"line_number":176,"context_line":"    min_version_string \u003d versions_list[0]"},{"line_number":177,"context_line":"    max_version_string \u003d versions_list[-1]"},{"line_number":178,"context_line":""},{"line_number":179,"context_line":"    # If there was no version found in the headers, choose the minimum"},{"line_number":180,"context_line":"    # available version."},{"line_number":181,"context_line":"    version_string \u003d found_version or min_version_string"},{"line_number":182,"context_line":"    if version_string \u003d\u003d \u0027latest\u0027:"},{"line_number":183,"context_line":"        version_string \u003d max_version_string"},{"line_number":184,"context_line":"    request_version \u003d parse_version_string(version_string)"}],"source_content_type":"text/x-python","patch_set":2,"id":"3f4b6375_516438e4","line":181,"range":{"start_line":179,"start_character":0,"end_line":181,"end_character":56},"in_reply_to":"3f4b6375_1607d684","updated":"2017-10-23 12:47:56.000000000","message":"This is microversions by definition: http://specs.openstack.org/openstack/api-wg/guidelines/microversion_specification.html\n\nI\u0027m not sure how much of that should be recapitulated here","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b42ea62e45a386f2c5d4512b51f44478d9bf6102","unresolved":false,"context_lines":[{"line_number":176,"context_line":"    min_version_string \u003d versions_list[0]"},{"line_number":177,"context_line":"    max_version_string \u003d versions_list[-1]"},{"line_number":178,"context_line":""},{"line_number":179,"context_line":"    # If there was no version found in the headers, choose the minimum"},{"line_number":180,"context_line":"    # available version."},{"line_number":181,"context_line":"    version_string \u003d found_version or min_version_string"},{"line_number":182,"context_line":"    if version_string \u003d\u003d \u0027latest\u0027:"},{"line_number":183,"context_line":"        version_string \u003d max_version_string"},{"line_number":184,"context_line":"    request_version \u003d parse_version_string(version_string)"}],"source_content_type":"text/x-python","patch_set":2,"id":"3f4b6375_b1700cde","line":181,"range":{"start_line":179,"start_character":0,"end_line":181,"end_character":56},"in_reply_to":"3f4b6375_516438e4","updated":"2017-10-23 13:22:10.000000000","message":"Agree it\u0027s microversions by definition by the time it reaches the API consumer, but at that level there\u0027s no telling where in the code it would actually be implemented.  Here is that place (or one of those places).  So I think it\u0027s worth mentioning in this docstring and the README.","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"8e0e87a7d0d431226903366d56f937961e6408e3","unresolved":false,"context_lines":[{"line_number":176,"context_line":"    min_version_string \u003d versions_list[0]"},{"line_number":177,"context_line":"    max_version_string \u003d versions_list[-1]"},{"line_number":178,"context_line":""},{"line_number":179,"context_line":"    # If there was no version found in the headers, choose the minimum"},{"line_number":180,"context_line":"    # available version."},{"line_number":181,"context_line":"    version_string \u003d found_version or min_version_string"},{"line_number":182,"context_line":"    if version_string \u003d\u003d \u0027latest\u0027:"},{"line_number":183,"context_line":"        version_string \u003d max_version_string"},{"line_number":184,"context_line":"    request_version \u003d parse_version_string(version_string)"}],"source_content_type":"text/x-python","patch_set":2,"id":"ff6b8bd7_3cac5d8b","line":181,"range":{"start_line":179,"start_character":0,"end_line":181,"end_character":56},"in_reply_to":"3f4b6375_b1700cde","updated":"2018-03-07 10:30:49.000000000","message":"Done","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"aeb1ffb3bc941237fdb342278f9466d1301da80c","unresolved":false,"context_lines":[{"line_number":179,"context_line":"    # If there was no version found in the headers, choose the minimum"},{"line_number":180,"context_line":"    # available version."},{"line_number":181,"context_line":"    version_string \u003d found_version or min_version_string"},{"line_number":182,"context_line":"    if version_string \u003d\u003d \u0027latest\u0027:"},{"line_number":183,"context_line":"        version_string \u003d max_version_string"},{"line_number":184,"context_line":"    request_version \u003d parse_version_string(version_string)"},{"line_number":185,"context_line":"    # We need a version that is in versions_list and within the min and"}],"source_content_type":"text/x-python","patch_set":2,"id":"3f4b6375_f62e7af8","line":182,"range":{"start_line":182,"start_character":7,"end_line":182,"end_character":21},"updated":"2017-10-23 12:32:10.000000000","message":"care to be case-insensitive?","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"8e0e87a7d0d431226903366d56f937961e6408e3","unresolved":false,"context_lines":[{"line_number":179,"context_line":"    # If there was no version found in the headers, choose the minimum"},{"line_number":180,"context_line":"    # available version."},{"line_number":181,"context_line":"    version_string \u003d found_version or min_version_string"},{"line_number":182,"context_line":"    if version_string \u003d\u003d \u0027latest\u0027:"},{"line_number":183,"context_line":"        version_string \u003d max_version_string"},{"line_number":184,"context_line":"    request_version \u003d parse_version_string(version_string)"},{"line_number":185,"context_line":"    # We need a version that is in versions_list and within the min and"}],"source_content_type":"text/x-python","patch_set":2,"id":"ff6b8bd7_bc838d04","line":182,"range":{"start_line":182,"start_character":7,"end_line":182,"end_character":21},"in_reply_to":"3f4b6375_1cd4971f","updated":"2018-03-07 10:30:49.000000000","message":"I\u0027ve gone with being liberal in what we accept","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"b42ea62e45a386f2c5d4512b51f44478d9bf6102","unresolved":false,"context_lines":[{"line_number":179,"context_line":"    # If there was no version found in the headers, choose the minimum"},{"line_number":180,"context_line":"    # available version."},{"line_number":181,"context_line":"    version_string \u003d found_version or min_version_string"},{"line_number":182,"context_line":"    if version_string \u003d\u003d \u0027latest\u0027:"},{"line_number":183,"context_line":"        version_string \u003d max_version_string"},{"line_number":184,"context_line":"    request_version \u003d parse_version_string(version_string)"},{"line_number":185,"context_line":"    # We need a version that is in versions_list and within the min and"}],"source_content_type":"text/x-python","patch_set":2,"id":"3f4b6375_1cd4971f","line":182,"range":{"start_line":182,"start_character":7,"end_line":182,"end_character":21},"in_reply_to":"3f4b6375_919870c0","updated":"2017-10-23 13:22:10.000000000","message":"The header *keys* are always case-insensitive.  That doesn\u0027t mean the *values* should be, but a consumer could be forgiven for thinking so.  Particularly since there\u0027s spillover e.g. where we respond with a key as a value (e.g. OpenStack-API-Version in the Vary header).\n\nAre we case-insensitive on the service type (e.g. \u0027compute\u0027, \u0027placement\u0027, etc.)?  The spec is also not specific on that point.\n\nProbably worth nailing that down across the board.","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"b5ed0e117f4b1796afe1bc81b51aa08bf48d97e2","unresolved":false,"context_lines":[{"line_number":179,"context_line":"    # If there was no version found in the headers, choose the minimum"},{"line_number":180,"context_line":"    # available version."},{"line_number":181,"context_line":"    version_string \u003d found_version or min_version_string"},{"line_number":182,"context_line":"    if version_string \u003d\u003d \u0027latest\u0027:"},{"line_number":183,"context_line":"        version_string \u003d max_version_string"},{"line_number":184,"context_line":"    request_version \u003d parse_version_string(version_string)"},{"line_number":185,"context_line":"    # We need a version that is in versions_list and within the min and"}],"source_content_type":"text/x-python","patch_set":2,"id":"3f4b6375_919870c0","line":182,"range":{"start_line":182,"start_character":7,"end_line":182,"end_character":21},"in_reply_to":"3f4b6375_f62e7af8","updated":"2017-10-23 12:47:56.000000000","message":"Not sure, the spec is ambiguous: http://specs.openstack.org/openstack/api-wg/guidelines/microversion_specification.html\n\nThe original intent was that using latest would be rare, and thus \"special\", in which case I would think that lower-only is the way to go.\n\nIn the sense that it is supposed to be a symbol, in and of itself, I would think it should be case sensitive, but that may be a bit harsh.","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"aeb1ffb3bc941237fdb342278f9466d1301da80c","unresolved":false,"context_lines":[{"line_number":188,"context_line":"    min_version \u003d parse_version_string(min_version_string)"},{"line_number":189,"context_line":"    max_version \u003d parse_version_string(max_version_string)"},{"line_number":190,"context_line":"    if (str(request_version) in versions_list"},{"line_number":191,"context_line":"            and request_version.matches(min_version, max_version)):"},{"line_number":192,"context_line":"        return request_version"},{"line_number":193,"context_line":"    raise ValueError(\u0027Unacceptable version header: %s\u0027 % version_string)"}],"source_content_type":"text/x-python","patch_set":2,"id":"3f4b6375_167a36f0","line":191,"range":{"start_line":191,"start_character":12,"end_line":191,"end_character":66},"updated":"2017-10-23 12:32:10.000000000","message":"This should be redundant, nah?  Under what circumstances would a value be in the versions_list, but not between its min and max bounds?","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"b5ed0e117f4b1796afe1bc81b51aa08bf48d97e2","unresolved":false,"context_lines":[{"line_number":188,"context_line":"    min_version \u003d parse_version_string(min_version_string)"},{"line_number":189,"context_line":"    max_version \u003d parse_version_string(max_version_string)"},{"line_number":190,"context_line":"    if (str(request_version) in versions_list"},{"line_number":191,"context_line":"            and request_version.matches(min_version, max_version)):"},{"line_number":192,"context_line":"        return request_version"},{"line_number":193,"context_line":"    raise ValueError(\u0027Unacceptable version header: %s\u0027 % version_string)"}],"source_content_type":"text/x-python","patch_set":2,"id":"3f4b6375_b1f6ccf8","line":191,"range":{"start_line":191,"start_character":12,"end_line":191,"end_character":66},"in_reply_to":"3f4b6375_167a36f0","updated":"2017-10-23 12:47:56.000000000","message":"Good point, where were you when I wrote this code the first time? Only the first half of the condition is needed (the idea being that it should be possible to administratively remove a microversion within the list)","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"8e0e87a7d0d431226903366d56f937961e6408e3","unresolved":false,"context_lines":[{"line_number":188,"context_line":"    min_version \u003d parse_version_string(min_version_string)"},{"line_number":189,"context_line":"    max_version \u003d parse_version_string(max_version_string)"},{"line_number":190,"context_line":"    if (str(request_version) in versions_list"},{"line_number":191,"context_line":"            and request_version.matches(min_version, max_version)):"},{"line_number":192,"context_line":"        return request_version"},{"line_number":193,"context_line":"    raise ValueError(\u0027Unacceptable version header: %s\u0027 % version_string)"}],"source_content_type":"text/x-python","patch_set":2,"id":"ff6b8bd7_7ccbb552","line":191,"range":{"start_line":191,"start_character":12,"end_line":191,"end_character":66},"in_reply_to":"3f4b6375_b1f6ccf8","updated":"2018-03-07 10:30:49.000000000","message":"Done","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"6f8f1a9fbdcb9ad4e7f9accf651f6a234a32f6a2","unresolved":false,"context_lines":[{"line_number":142,"context_line":"    return value"},{"line_number":143,"context_line":""},{"line_number":144,"context_line":""},{"line_number":145,"context_line":"def parse_version_string(version_string):"},{"line_number":146,"context_line":"    \"\"\"Turn a version string into a Version"},{"line_number":147,"context_line":""},{"line_number":148,"context_line":"    :param version_string: A string of two numerals, X.Y."}],"source_content_type":"text/x-python","patch_set":3,"id":"df7087c5_9f349be0","line":145,"updated":"2018-03-07 00:59:34.000000000","message":"To throw out another option -- you could roll this into Version with something along the lines of\n\n diff --git a/microversion_parse/__init__.py b/microversion_parse/__init__.py\n index 0559380..7456262 100644\n --- a/microversion_parse/__init__.py\n +++ b/microversion_parse/__init__.py\n @@ -26,6 +26,29 @@ class Version(collections.namedtuple(\u0027Version\u0027, \u0027major minor\u0027)):\n      Since it is a tuple, it is automatically comparable.\n      \"\"\"\n  \n +    def __new__(cls, *args):\n +        \"\"\"Turn a version string into a Version\n +\n +        :param version_string: A string of two numerals, X.Y.\n +        :returns: a Version\n +        :raises: TypeError\n +        \"\"\"\n +        if len(args) \u003d\u003d 2:\n +            return super(Version, cls).__new__(cls, *args)\n +        if len(args) \u003d\u003d 1 and isinstance(args[0], str):\n +            try:\n +                # The combination of int and a limited split with the\n +                # named tuple means that this incantation will raise\n +                # ValueError, TypeError or AttributeError when the incoming\n +                # data is poorly formed but will, however, naturally adapt to\n +                # extraneous whitespace.\n +                return super(Version, cls).__new__(cls, *(\n +                    int(value) for value in args[0].split(\u0027.\u0027, 1)))\n +            except (ValueError, TypeError, AttributeError) as exc:\n +                raise TypeError(\u0027invalid version string: %s; %s\u0027 % (\n +                    args[0], exc))\n +        raise TypeError\n +\n      def __str__(self):\n          return \u0027%s.%s\u0027 % (self.major, self.minor)\n  \n @@ -142,26 +165,6 @@ def _extract_header_value(headers, header_name):\n      return value\n  \n  \n -def parse_version_string(version_string):\n -    \"\"\"Turn a version string into a Version\n -\n -    :param version_string: A string of two numerals, X.Y.\n -    :returns: a Version\n -    :raises: TypeError\n -    \"\"\"\n -    try:\n -        # The combination of int and a limited split with the\n -        # named tuple means that this incantation will raise\n -        # ValueError, TypeError or AttributeError when the incoming\n -        # data is poorly formed but will, however, naturally adapt to\n -        # extraneous whitespace.\n -        return Version(*(int(value) for value\n -                         in version_string.split(\u0027.\u0027, 1)))\n -    except (ValueError, TypeError, AttributeError) as exc:\n -        raise TypeError(\u0027invalid version string: %s; %s\u0027 % (\n -            version_string, exc))\n -\n -\n  def extract_version(headers, service_type, versions_list):\n      \"\"\"Extract the microversion from the headers.\n  \n @@ -187,7 +190,7 @@ def extract_version(headers, service_type, versions_list):\n      version_string \u003d found_version or min_version_string\n      if version_string \u003d\u003d \u0027latest\u0027:\n          version_string \u003d max_version_string\n -    request_version \u003d parse_version_string(version_string)\n +    request_version \u003d Version(version_string)\n      # We need a version that is in versions_list. This gives us the option\n      # to administratively disable a version if we really need to.\n      if str(request_version) in versions_list:","commit_id":"ed426421200de823c3486c26852de9e4e206fe5c"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"8e0e87a7d0d431226903366d56f937961e6408e3","unresolved":false,"context_lines":[{"line_number":142,"context_line":"    return value"},{"line_number":143,"context_line":""},{"line_number":144,"context_line":""},{"line_number":145,"context_line":"def parse_version_string(version_string):"},{"line_number":146,"context_line":"    \"\"\"Turn a version string into a Version"},{"line_number":147,"context_line":""},{"line_number":148,"context_line":"    :param version_string: A string of two numerals, X.Y."}],"source_content_type":"text/x-python","patch_set":3,"id":"df7087c5_5b128eb3","line":145,"in_reply_to":"df7087c5_9f349be0","updated":"2018-03-07 10:30:49.000000000","message":"Yeah, I considered something like this way back in the earliest versions of this code (back in enamel[1]) and chose to avoid it to keep the Version object as simple as possible and use module-level functions as much as possible (mostly an aesthetic choice, but I tend to think of minimizing OO as a good thing™). Now, parse_version_string is effectively a public interface and nicely explicit, so...\n\n\n[1] https://github.com/jaypipes/enamel","commit_id":"ed426421200de823c3486c26852de9e4e206fe5c"}],"microversion_parse/tests/test_extract_version.py":[{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"585d2b3d1d88ee4275bf17e95af73e3e640b75b5","unresolved":false,"context_lines":[{"line_number":21,"context_line":""},{"line_number":22,"context_line":"    def setUp(self):"},{"line_number":23,"context_line":"        super(TestVersion, self).setUp()"},{"line_number":24,"context_line":"        self.version \u003d microversion_parse.Version(1, 5)"},{"line_number":25,"context_line":""},{"line_number":26,"context_line":"    def test_version_is_tuple(self):"},{"line_number":27,"context_line":"        self.assertEqual((1, 5), self.version)"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_35afcf95","line":24,"range":{"start_line":24,"start_character":50,"end_line":24,"end_character":54},"updated":"2017-08-22 13:36:55.000000000","message":"I know it\u0027s the Nova Way of Testing, but I really dislike magic numbers like this.","commit_id":"b8a485ed348466eb65c577d0108f349b35ab4c0f"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"82e92ad703fa5ee430b33a091f6c387364ebf71e","unresolved":false,"context_lines":[{"line_number":21,"context_line":""},{"line_number":22,"context_line":"    def setUp(self):"},{"line_number":23,"context_line":"        super(TestVersion, self).setUp()"},{"line_number":24,"context_line":"        self.version \u003d microversion_parse.Version(1, 5)"},{"line_number":25,"context_line":""},{"line_number":26,"context_line":"    def test_version_is_tuple(self):"},{"line_number":27,"context_line":"        self.assertEqual((1, 5), self.version)"}],"source_content_type":"text/x-python","patch_set":1,"id":"7f287b81_9fed7927","line":24,"in_reply_to":"7f287b81_35afcf95","updated":"2017-08-22 18:00:16.000000000","message":"You mean I should assign (1, 5) to an object field and use it here and in there tests where it is used?\n\nWhat about \u00271.5\u0027, (1, 20), (1, 3) and the various things only used once?\n\nOr do you mean I shouldn\u0027t set self.version at all since it makes the real value invisible in the test?\n\nAt a certain point these tests are mostly just a way of repeating \"python works\".","commit_id":"b8a485ed348466eb65c577d0108f349b35ab4c0f"}],"tox.ini":[{"author":{"_account_id":1063,"name":"Ed Leafe","email":"ed@leafe.com","username":"ed-leafe"},"change_message_id":"585d2b3d1d88ee4275bf17e95af73e3e640b75b5","unresolved":false,"context_lines":[{"line_number":13,"context_line":"usedevelop \u003d True"},{"line_number":14,"context_line":"whitelist_externals \u003d rm"},{"line_number":15,"context_line":"commands \u003d"},{"line_number":16,"context_line":"    rm -Rf .testrepository/times.dbm"},{"line_number":17,"context_line":"    python setup.py testr --testr-args\u003d\"{posargs}\""},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"[testenv:venv]"}],"source_content_type":"text/x-properties","patch_set":1,"id":"7f287b81_d5fc0b40","line":16,"range":{"start_line":16,"start_character":4,"end_line":16,"end_character":36},"updated":"2017-08-22 13:36:55.000000000","message":"Just curious: why is this needed?","commit_id":"b8a485ed348466eb65c577d0108f349b35ab4c0f"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"d9ec820042cb5a6581c05dccbb98e05373b45bd7","unresolved":false,"context_lines":[{"line_number":13,"context_line":"usedevelop \u003d True"},{"line_number":14,"context_line":"whitelist_externals \u003d rm"},{"line_number":15,"context_line":"commands \u003d"},{"line_number":16,"context_line":"    rm -Rf .testrepository/times.dbm"},{"line_number":17,"context_line":"    python setup.py testr --testr-args\u003d\"{posargs}\""},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"[testenv:venv]"}],"source_content_type":"text/x-properties","patch_set":1,"id":"7f287b81_4b606f33","line":16,"in_reply_to":"7f287b81_d5fc0b40","updated":"2017-08-22 20:54:01.000000000","message":"will add a comment","commit_id":"b8a485ed348466eb65c577d0108f349b35ab4c0f"},{"author":{"_account_id":14070,"name":"Eric Fried","email":"openstack@fried.cc","username":"efried"},"change_message_id":"aeb1ffb3bc941237fdb342278f9466d1301da80c","unresolved":false,"context_lines":[{"line_number":11,"context_line":"install_command \u003d pip install -U {opts} {packages}"},{"line_number":12,"context_line":"setenv \u003d OS_TEST_PATH\u003dmicroversion_parse/tests/"},{"line_number":13,"context_line":"usedevelop \u003d True"},{"line_number":14,"context_line":"whitelist_externals \u003d rm"},{"line_number":15,"context_line":"# Delete times.dbm before running tests because testr uses a different"},{"line_number":16,"context_line":"# dbm format in python2 and python3 and will sometimes die trying to"},{"line_number":17,"context_line":"# read its own file."},{"line_number":18,"context_line":"commands \u003d"},{"line_number":19,"context_line":"    rm -Rf .testrepository/times.dbm"},{"line_number":20,"context_line":"    python setup.py testr --testr-args\u003d\"{posargs}\""},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"[testenv:venv]"}],"source_content_type":"text/x-properties","patch_set":2,"id":"3f4b6375_b6d482be","line":19,"range":{"start_line":14,"start_character":0,"end_line":19,"end_character":36},"updated":"2017-10-23 12:32:10.000000000","message":"Unrelated change.  But if you want to fix this, you can less intrusively change L6 to do py3 before py2.","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"},{"author":{"_account_id":11564,"name":"Chris Dent","email":"cdent@anticdent.org","username":"chdent"},"change_message_id":"b5ed0e117f4b1796afe1bc81b51aa08bf48d97e2","unresolved":false,"context_lines":[{"line_number":11,"context_line":"install_command \u003d pip install -U {opts} {packages}"},{"line_number":12,"context_line":"setenv \u003d OS_TEST_PATH\u003dmicroversion_parse/tests/"},{"line_number":13,"context_line":"usedevelop \u003d True"},{"line_number":14,"context_line":"whitelist_externals \u003d rm"},{"line_number":15,"context_line":"# Delete times.dbm before running tests because testr uses a different"},{"line_number":16,"context_line":"# dbm format in python2 and python3 and will sometimes die trying to"},{"line_number":17,"context_line":"# read its own file."},{"line_number":18,"context_line":"commands \u003d"},{"line_number":19,"context_line":"    rm -Rf .testrepository/times.dbm"},{"line_number":20,"context_line":"    python setup.py testr --testr-args\u003d\"{posargs}\""},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"[testenv:venv]"}],"source_content_type":"text/x-properties","patch_set":2,"id":"3f4b6375_b1cfecae","line":19,"range":{"start_line":14,"start_character":0,"end_line":19,"end_character":36},"in_reply_to":"3f4b6375_b6d482be","updated":"2017-10-23 12:47:56.000000000","message":"I probably didn\u0027t mean to commit this, was just having the problem while fiddling with it (however long ago that was). I\u0027ll make a separate change.","commit_id":"e750b83f5d6a0b3eceeab7492e545ce452bf7012"}]}
