)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":841,"name":"Akihiro Motoki","email":"amotoki@gmail.com","username":"amotoki"},"change_message_id":"245f75c6e2fc79c9be14230df73d54d57c2f113c","unresolved":false,"context_lines":[{"line_number":22,"context_line":"[3] https://review.opendev.org/351362/"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"Change-Id: Iebb1e78c718b931d632445e4de6d7a29ccb92be2"},{"line_number":25,"context_line":"Closes-Bug: #1849351"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"3fa7e38b_4272737e","line":25,"range":{"start_line":25,"start_character":0,"end_line":25,"end_character":20},"updated":"2019-10-23 06:13:42.000000000","message":"Could you refer bug 1847959?","commit_id":"b4f934bfbb4bdf581e0c2a3ea69edd9e692ca129"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"8296ca5f1153c7565628c5261b027a14e988db78","unresolved":false,"context_lines":[{"line_number":22,"context_line":"[3] https://review.opendev.org/351362/"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"Change-Id: Iebb1e78c718b931d632445e4de6d7a29ccb92be2"},{"line_number":25,"context_line":"Closes-Bug: #1849351"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"3fa7e38b_b8beefab","line":25,"range":{"start_line":25,"start_character":0,"end_line":25,"end_character":20},"in_reply_to":"3fa7e38b_4272737e","updated":"2019-10-23 16:02:20.000000000","message":"Sure.","commit_id":"b4f934bfbb4bdf581e0c2a3ea69edd9e692ca129"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"6a5ddb5a3518fff57e4a09f722ab302b2a93ceb4","unresolved":false,"context_lines":[{"line_number":22,"context_line":"[3] https://review.opendev.org/351362/"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"Change-Id: Iebb1e78c718b931d632445e4de6d7a29ccb92be2"},{"line_number":25,"context_line":"Closes-Bug: #1849351"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"3fa7e38b_d8f72b8c","line":25,"range":{"start_line":25,"start_character":0,"end_line":25,"end_character":20},"in_reply_to":"3fa7e38b_b8beefab","updated":"2019-10-23 16:04:04.000000000","message":"Done","commit_id":"b4f934bfbb4bdf581e0c2a3ea69edd9e692ca129"}],"openstack_dashboard/api/nova.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"af1e505a3871a92c228a1c4f73f051256afda36b","unresolved":false,"context_lines":[{"line_number":1131,"context_line":"    Example values for the extension_name include AdminActions, ConsoleOutput,"},{"line_number":1132,"context_line":"    etc."},{"line_number":1133,"context_line":"    \"\"\""},{"line_number":1134,"context_line":"    for ext in list_extensions(request):"},{"line_number":1135,"context_line":"        if ext \u003d\u003d extension_name:"},{"line_number":1136,"context_line":"            return True"},{"line_number":1137,"context_line":"    return False"}],"source_content_type":"text/x-python","patch_set":4,"id":"3fa7e38b_284ff56a","line":1134,"updated":"2019-10-24 19:19:55.000000000","message":"This should just use an \u0027in\u0027 statement.","commit_id":"6273231c009e987ecc0dd3cf300d895ae2d3fbb6"}],"openstack_dashboard/api/rest/nova.py":[{"author":{"_account_id":841,"name":"Akihiro Motoki","email":"amotoki@gmail.com","username":"amotoki"},"change_message_id":"0f79ffe2e63eb0d215fe6d9136a337559ee9ddfb","unresolved":false,"context_lines":[{"line_number":518,"context_line":"        http://localhost/api/nova/extensions"},{"line_number":519,"context_line":"        \"\"\""},{"line_number":520,"context_line":"        result \u003d api.nova.list_extensions(request)"},{"line_number":521,"context_line":"        return {\u0027items\u0027: [e.to_dict() for e in result]}"},{"line_number":522,"context_line":""},{"line_number":523,"context_line":""},{"line_number":524,"context_line":"@urls.register"}],"source_content_type":"text/x-python","patch_set":2,"id":"3fa7e38b_1844e373","side":"PARENT","line":521,"updated":"2019-10-23 16:14:33.000000000","message":"After digging into the code more, I noticed that /api/nova/extensions REST API provided by openstack_dashboard/api/rest/nova.py is used by the JS side [1], so we cannot simply drop it.\nThe response is used by [2] and [3]. Looking at [3], it accepts a list of nova extension names and [2] provides a cache of the nova extension list.\n\nIt looks like we need to provide some list of extension names here.\n\nOne idea in my mind is to provide a list of nova extension names used by the horizon code currently.\n\nDo you think it works as a workaround?\n\nIf it works, I can try this route, though I am not so familiar with this area (as we lost all JS developers who wrote these codes.....).\n\n[1] https://github.com/openstack/horizon/blob/master/openstack_dashboard/static/app/core/openstack-service-api/nova.service.js#L562-L566\n[2] https://github.com/openstack/horizon/blob/master/openstack_dashboard/static/app/core/openstack-service-api/extensions.service.js\n[3] https://github.com/openstack/horizon/blob/master/openstack_dashboard/static/app/core/cloud-services/hz-if-nova-extensions.directive.js","commit_id":"85a1dddf126691921924edcecaee5c054c7df6c2"},{"author":{"_account_id":841,"name":"Akihiro Motoki","email":"amotoki@gmail.com","username":"amotoki"},"change_message_id":"933690dd936fc93a05ae65682828a09311d8474d","unresolved":false,"context_lines":[{"line_number":518,"context_line":"        http://localhost/api/nova/extensions"},{"line_number":519,"context_line":"        \"\"\""},{"line_number":520,"context_line":"        result \u003d api.nova.list_extensions(request)"},{"line_number":521,"context_line":"        return {\u0027items\u0027: [e.to_dict() for e in result]}"},{"line_number":522,"context_line":""},{"line_number":523,"context_line":""},{"line_number":524,"context_line":"@urls.register"}],"source_content_type":"text/x-python","patch_set":2,"id":"3fa7e38b_ad21befe","side":"PARENT","line":521,"in_reply_to":"3fa7e38b_13a9248f","updated":"2019-10-24 13:31:00.000000000","message":"\u003e Do we know what those js files are used for? I mean, can they also be removed and if not, why not? What are they doing?\n\nAs far as I checked, they are used mainly in the \"Launch Server\" form.\nhttp://paste.openstack.org/show/785541/\n\nThe following are referred.\n\n- DiskConfig\n- ConfigDrive\n- BlockDeviceMappingV2Boot\n- Keypairs\n- ServerGroups\n- SchedulerHints\n\n\u003e Otherwise yeah I think one option would be just hard-coding a list from the current list of exension names in the API today, otherwise we have to think about doing something in horizon to get the extensions without using novaclient, e.g. does horizon have anything using openstacksdk yet?\n\nConsidering the above, your option to hard-code the current list sounds reasonable as a temporary workaround.\nAnother option is that horizon calls the nova API directly temporarily, but it seems the hard-coded list is easier to unblock python-novaclient 16.0.0.\n\n\u003e In general horizon should be moving away from anything related to feature toggling the compute API extensions since that is deprecated in the compute API. The reason I wanted to preserve support for the blacklist config though was the comment about it potentially being a performance boost (though I doubt that is very true after we [nova] have mainlined all of that extension code in the API).\n\nI totally agree. I have a doubt on why the blacklist config mentions a performance impact too.\nI am thinking to deprecate the blacklist config and drop it soon.\nI also plan to b bump the minimum version of nova API which horizon uses and assume all features in Nova are available.","commit_id":"85a1dddf126691921924edcecaee5c054c7df6c2"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"29ee5b8c361677eba59683436e643bf5d0512284","unresolved":false,"context_lines":[{"line_number":518,"context_line":"        http://localhost/api/nova/extensions"},{"line_number":519,"context_line":"        \"\"\""},{"line_number":520,"context_line":"        result \u003d api.nova.list_extensions(request)"},{"line_number":521,"context_line":"        return {\u0027items\u0027: [e.to_dict() for e in result]}"},{"line_number":522,"context_line":""},{"line_number":523,"context_line":""},{"line_number":524,"context_line":"@urls.register"}],"source_content_type":"text/x-python","patch_set":2,"id":"3fa7e38b_13a9248f","side":"PARENT","line":521,"in_reply_to":"3fa7e38b_1844e373","updated":"2019-10-23 16:37:36.000000000","message":"Ugh, OK I didn\u0027t search for hits in js code.\n\nDo we know what those js files are used for? I mean, can they also be removed and if not, why not? What are they doing?\n\nOtherwise yeah I think one option would be just hard-coding a list from the current list of exension names in the API today, otherwise we have to think about doing something in horizon to get the extensions without using novaclient, e.g. does horizon have anything using openstacksdk yet?\n\nIn general horizon should be moving away from anything related to feature toggling the compute API extensions since that is deprecated in the compute API. The reason I wanted to preserve support for the blacklist config though was the comment about it potentially being a performance boost (though I doubt that is very true after we [nova] have mainlined all of that extension code in the API).","commit_id":"85a1dddf126691921924edcecaee5c054c7df6c2"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"5e51af20fbdef5a74dc750208603ab92bd81928d","unresolved":false,"context_lines":[{"line_number":518,"context_line":"        http://localhost/api/nova/extensions"},{"line_number":519,"context_line":"        \"\"\""},{"line_number":520,"context_line":"        result \u003d api.nova.list_extensions(request)"},{"line_number":521,"context_line":"        return {\u0027items\u0027: [e.to_dict() for e in result]}"},{"line_number":522,"context_line":""},{"line_number":523,"context_line":""},{"line_number":524,"context_line":"@urls.register"}],"source_content_type":"text/x-python","patch_set":2,"id":"3fa7e38b_e1a33dff","side":"PARENT","line":521,"in_reply_to":"3fa7e38b_ad21befe","updated":"2019-10-24 15:33:59.000000000","message":"\u003e I totally agree. I have a doubt on why the blacklist config\n \u003e mentions a performance impact too.\n \u003e I am thinking to deprecate the blacklist config and drop it soon.\n \u003e I also plan to b bump the minimum version of nova API which horizon\n \u003e uses and assume all features in Nova are available.\n\nOK, cool. So it sounds like the plan is:\n\n1. I\u0027ll update this to hard-code the extensions from the nova API (using what I get from current devstack master). That will unblock python-novaclient 16.0.0 from getting into upper-constraints.\n\n2. Horizon will deprecate the blacklist setting so eventually the hard-coded extension list can be removed as well.","commit_id":"85a1dddf126691921924edcecaee5c054c7df6c2"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"8f49bf4591410395e587c0ea7fa1ba8d9a0d7d77","unresolved":false,"context_lines":[{"line_number":518,"context_line":"        http://localhost/api/nova/extensions"},{"line_number":519,"context_line":"        \"\"\""},{"line_number":520,"context_line":"        result \u003d api.nova.list_extensions(request)"},{"line_number":521,"context_line":"        return {\u0027items\u0027: [e.to_dict() for e in result]}"},{"line_number":522,"context_line":""},{"line_number":523,"context_line":""},{"line_number":524,"context_line":"@urls.register"}],"source_content_type":"text/x-python","patch_set":2,"id":"3fa7e38b_5c2d56a6","side":"PARENT","line":521,"in_reply_to":"3fa7e38b_e1a33dff","updated":"2019-10-24 17:17:17.000000000","message":"Here are the extensions from a master devstack created today:\n\n$ openstack extension list --compute -f value -c Name --sort-column Name\nAccessIPs\nAdminActions\nAdminPassword\nAgents\nAggregates\nAssistedVolumeSnapshots\nAttachInterfaces\nAvailabilityZone\nBareMetalExtStatus\nBareMetalNodes\nBlockDeviceMapping\nBlockDeviceMappingV2Boot\nCellCapacities\nCells\nCertificates\nCloudpipe\nCloudpipeUpdate\nConfigDrive\nConsoleAuthTokens\nConsoleOutput\nConsoles\nCreateBackup\nCreateserverext\nDeferredDelete\nDiskConfig\nEvacuate\nExtendedAvailabilityZone\nExtendedEvacuateFindHost\nExtendedFloatingIps\nExtendedHypervisors\nExtendedIps\nExtendedIpsMac\nExtendedNetworks\nExtendedQuotas\nExtendedRescueWithImage\nExtendedServerAttributes\nExtendedServices\nExtendedServicesDelete\nExtendedStatus\nExtendedStatus\nExtendedVolumes\nFixedIPs\nFlavorAccess\nFlavorDisabled\nFlavorExtraData\nFlavorExtraSpecs\nFlavorManage\nFlavorRxtx\nFlavorSwap\nFloatingIpDns\nFloatingIpPools\nFloatingIps\nFloatingIpsBulk\nFping\nHideServerAddresses\nHosts\nHypervisorStatus\nHypervisors\nImageSize\nInstanceActions\nKeypairs\nLockServer\nMigrateServer\nMigrations\nMultinic\nMultipleCreate\nNetworkAssociationSupport\nNetworks\nOSInstanceUsageAuditLog\nOSTenantNetworks\nPauseServer\nPersonality\nPreserveEphemeralOnRebuild\nQuotaClasses\nQuotas\nRescue\nSchedulerHints\nSecurityGroupDefaultRules\nSecurityGroups\nServerDiagnostics\nServerExternalEvents\nServerGroupQuotas\nServerGroups\nServerListMultiStatus\nServerPassword\nServerSortKeys\nServerStartStop\nServerUsage\nServices\nShelve\nSimpleTenantUsage\nSuspendServer\nUsedLimits\nUsedLimitsForAdmin\nUserData\nUserQuotas\nVirtualInterfaces\nVolumeAttachmentUpdate\nVolumes","commit_id":"85a1dddf126691921924edcecaee5c054c7df6c2"},{"author":{"_account_id":841,"name":"Akihiro Motoki","email":"amotoki@gmail.com","username":"amotoki"},"change_message_id":"806b971596adb98c51101f6b645498367d6633a9","unresolved":false,"context_lines":[{"line_number":518,"context_line":"        http://localhost/api/nova/extensions"},{"line_number":519,"context_line":"        \"\"\""},{"line_number":520,"context_line":"        result \u003d api.nova.list_extensions(request)"},{"line_number":521,"context_line":"        return {\u0027items\u0027: [e.to_dict() for e in result]}"},{"line_number":522,"context_line":""},{"line_number":523,"context_line":""},{"line_number":524,"context_line":"@urls.register"}],"source_content_type":"text/x-python","patch_set":2,"id":"3fa7e38b_dc3f0685","side":"PARENT","line":521,"in_reply_to":"3fa7e38b_e1a33dff","updated":"2019-10-24 16:28:59.000000000","message":"That\u0027s fine. Thanks.","commit_id":"85a1dddf126691921924edcecaee5c054c7df6c2"}],"openstack_dashboard/test/unit/api/rest/test_nova.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"af1e505a3871a92c228a1c4f73f051256afda36b","unresolved":false,"context_lines":[{"line_number":489,"context_line":"    @test.create_mocks({api.nova: [\u0027list_extensions\u0027]})"},{"line_number":490,"context_line":"    @mock.patch.object(settings,"},{"line_number":491,"context_line":"                       \u0027OPENSTACK_NOVA_EXTENSIONS_BLACKLIST\u0027, [\u0027baz\u0027])"},{"line_number":492,"context_line":"    def _test_extension_list(self):"},{"line_number":493,"context_line":"        request \u003d self.mock_rest_request()"},{"line_number":494,"context_line":"        self.mock_list_extensions.return_value \u003d ["},{"line_number":495,"context_line":"            mock.Mock(**{\u0027to_dict.return_value\u0027: {\u0027name\u0027: \u0027foo\u0027}}),"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_8554d255","side":"PARENT","line":492,"updated":"2019-10-24 19:19:55.000000000","message":"This test wasn\u0027t even getting run since it\u0027s prefixed with _ and nothing is using it. It was wrong anyway because if list_extensions is mocked to return foo/bar/baz but the blacklist includes baz, then list_extensions, which filters based on the blacklist, should be filtering out baz and that\u0027s what is being asserted below but I don\u0027t think it works and since the test isn\u0027t run it doesn\u0027t fail.","commit_id":"85a1dddf126691921924edcecaee5c054c7df6c2"}],"openstack_dashboard/test/unit/api/test_nova.py":[{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"44418edc2dbf294f7076b001fa982b6c63516923","unresolved":false,"context_lines":[{"line_number":75,"context_line":"    @mock.patch.object(settings, \u0027OPENSTACK_NOVA_EXTENSIONS_BLACKLIST\u0027,"},{"line_number":76,"context_line":"                       [\u0027baz\u0027])"},{"line_number":77,"context_line":"    def test_extension_supported(self):"},{"line_number":78,"context_line":"        self.assertTrue(api.nova.extension_supported(\u0027foo\u0027))"},{"line_number":79,"context_line":"        self.assertFalse(api.nova.extension_supported(\u0027baz\u0027))"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    @mock.patch.object(api._nova, \u0027novaclient\u0027)"}],"source_content_type":"text/x-python","patch_set":1,"id":"3fa7e38b_c10668ce","line":78,"updated":"2019-10-22 20:26:34.000000000","message":"Something failing here:\n\n2019-10-22 17:31:14.679264 | ubuntu-bionic | test_cold_migrate_host_succeed (openstack_dashboard.test.unit.api.test_nova.ComputeApiTests) ... ok\n\n2019-10-22 17:31:14.688877 | ubuntu-bionic | test_extension_supported (openstack_dashboard.test.unit.api.test_nova.ComputeApiTests) ... /home/zuul/src/opendev.org/openstack/horizon/openstack_dashboard/test/unit/api/test_nova.py:78: UnhashableKeyWarning: The key of openstack_dashboard.api.nova extension_supported is not hashable and cannot be memoized: ((\u0027foo\u0027,), ())\n\n2019-10-22 17:31:14.688922 | ubuntu-bionic |\n\n2019-10-22 17:31:14.689029 | ubuntu-bionic |   self.assertTrue(api.nova.extension_supported(\u0027foo\u0027))\n\n2019-10-22 17:31:14.689065 | ubuntu-bionic | ERROR","commit_id":"82e17675d984df5e4b001ce572ff5ef5417747dd"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"3736520ea3b050a2be35b020c3457f1b9fcf3b8a","unresolved":false,"context_lines":[{"line_number":75,"context_line":"    @mock.patch.object(settings, \u0027OPENSTACK_NOVA_EXTENSIONS_BLACKLIST\u0027,"},{"line_number":76,"context_line":"                       [\u0027baz\u0027])"},{"line_number":77,"context_line":"    def test_extension_supported(self):"},{"line_number":78,"context_line":"        self.assertTrue(api.nova.extension_supported(\u0027foo\u0027))"},{"line_number":79,"context_line":"        self.assertFalse(api.nova.extension_supported(\u0027baz\u0027))"},{"line_number":80,"context_line":""},{"line_number":81,"context_line":"    @mock.patch.object(api._nova, \u0027novaclient\u0027)"}],"source_content_type":"text/x-python","patch_set":1,"id":"3fa7e38b_33230fc1","line":78,"in_reply_to":"3fa7e38b_c10668ce","updated":"2019-10-22 21:32:49.000000000","message":"Need to pass a mock for the request arg.","commit_id":"82e17675d984df5e4b001ce572ff5ef5417747dd"},{"author":{"_account_id":841,"name":"Akihiro Motoki","email":"amotoki@gmail.com","username":"amotoki"},"change_message_id":"245f75c6e2fc79c9be14230df73d54d57c2f113c","unresolved":false,"context_lines":[{"line_number":72,"context_line":"        # To handle upgrade_api"},{"line_number":73,"context_line":"        mock_novaclient.api_version \u003d api_versions.APIVersion(version)"},{"line_number":74,"context_line":""},{"line_number":75,"context_line":"    @mock.patch.object(settings, \u0027OPENSTACK_NOVA_EXTENSIONS_BLACKLIST\u0027,"},{"line_number":76,"context_line":"                       [\u0027baz\u0027])"},{"line_number":77,"context_line":"    def test_extension_supported(self):"},{"line_number":78,"context_line":"        self.assertTrue(api.nova.extension_supported("},{"line_number":79,"context_line":"            \u0027foo\u0027, mock.sentinel.request))"}],"source_content_type":"text/x-python","patch_set":2,"id":"3fa7e38b_69e8ba7b","line":76,"range":{"start_line":75,"start_character":3,"end_line":76,"end_character":31},"updated":"2019-10-23 06:13:42.000000000","message":"This works, but the django way is:\n\n from django.test.utils import override_settings\n\n ...\n\n @override_settings(OPENSTACK_NOVA_EXTENSION_BLACKLIST\u003d[\u0027baz\u0027])","commit_id":"b4f934bfbb4bdf581e0c2a3ea69edd9e692ca129"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"8296ca5f1153c7565628c5261b027a14e988db78","unresolved":false,"context_lines":[{"line_number":72,"context_line":"        # To handle upgrade_api"},{"line_number":73,"context_line":"        mock_novaclient.api_version \u003d api_versions.APIVersion(version)"},{"line_number":74,"context_line":""},{"line_number":75,"context_line":"    @mock.patch.object(settings, \u0027OPENSTACK_NOVA_EXTENSIONS_BLACKLIST\u0027,"},{"line_number":76,"context_line":"                       [\u0027baz\u0027])"},{"line_number":77,"context_line":"    def test_extension_supported(self):"},{"line_number":78,"context_line":"        self.assertTrue(api.nova.extension_supported("},{"line_number":79,"context_line":"            \u0027foo\u0027, mock.sentinel.request))"}],"source_content_type":"text/x-python","patch_set":2,"id":"3fa7e38b_98c3f338","line":76,"range":{"start_line":75,"start_character":3,"end_line":76,"end_character":31},"in_reply_to":"3fa7e38b_69e8ba7b","updated":"2019-10-23 16:02:20.000000000","message":"I just copied what was done in the test I removed:\n\nhttps://review.opendev.org/#/c/690134/2/openstack_dashboard/test/unit/api/rest/test_nova.py","commit_id":"b4f934bfbb4bdf581e0c2a3ea69edd9e692ca129"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"6a5ddb5a3518fff57e4a09f722ab302b2a93ceb4","unresolved":false,"context_lines":[{"line_number":72,"context_line":"        # To handle upgrade_api"},{"line_number":73,"context_line":"        mock_novaclient.api_version \u003d api_versions.APIVersion(version)"},{"line_number":74,"context_line":""},{"line_number":75,"context_line":"    @mock.patch.object(settings, \u0027OPENSTACK_NOVA_EXTENSIONS_BLACKLIST\u0027,"},{"line_number":76,"context_line":"                       [\u0027baz\u0027])"},{"line_number":77,"context_line":"    def test_extension_supported(self):"},{"line_number":78,"context_line":"        self.assertTrue(api.nova.extension_supported("},{"line_number":79,"context_line":"            \u0027foo\u0027, mock.sentinel.request))"}],"source_content_type":"text/x-python","patch_set":2,"id":"3fa7e38b_38019f6b","line":76,"range":{"start_line":75,"start_character":3,"end_line":76,"end_character":31},"in_reply_to":"3fa7e38b_98c3f338","updated":"2019-10-23 16:04:04.000000000","message":"Done","commit_id":"b4f934bfbb4bdf581e0c2a3ea69edd9e692ca129"}]}
