Browse Source

ref: close files preventing ResourceWarnings for project_release_file_details (#35429)

anthony sottile 2 years ago
parent
commit
fb6dfa52af

+ 23 - 3
src/sentry/api/endpoints/project_release_file_details.py

@@ -41,6 +41,26 @@ def _get_from_index(release: Release, dist: Optional[Distribution], url: str) ->
     return pseudo_releasefile(url, entry, dist)
 
 
+class ClosesDependentFiles:
+    def __init__(self, f, *closables) -> None:
+        self._f = f
+        self._closables = closables
+
+    def close(self):
+        self._f.close()
+        for closable in self._closables:
+            closable.close()
+
+    def __getattr__(self, attr):
+        return getattr(self._f, attr)
+
+    def __dir__(self):
+        ret = list(super().__dir__())
+        ret.extend(dir(self._f))
+        ret.sort()
+        return ret
+
+
 class ReleaseFileDetailsMixin:
     """Shared functionality of ProjectReleaseFileDetails and OrganizationReleaseFileDetails
 
@@ -67,12 +87,12 @@ class ReleaseFileDetailsMixin:
 
         # Do not use ReleaseFileCache here, we view download as a singular event
         archive_file = ReleaseFile.objects.get(release_id=release.id, ident=archive_ident)
-        archive = ZipFile(archive_file.file.getfile())
-        fp = archive.open(entry["filename"])
+        archive_file_fp = archive_file.file.getfile()
+        fp = ZipFile(archive_file_fp).open(entry["filename"])
         headers = entry.get("headers", {})
 
         response = FileResponse(
-            fp,
+            ClosesDependentFiles(fp, archive_file_fp),
             content_type=headers.get("content-type", "application/octet-stream"),
         )
         response["Content-Length"] = entry["size"]

+ 1 - 0
tests/sentry/api/endpoints/test_project_release_file_details.py

@@ -88,6 +88,7 @@ class ReleaseFileDetailsTest(APITestCase):
         self.login_as(user=self.user)
         response = self.client.get(url + "?download=1")
         assert response.get("Content-Type") == "application/octet-stream"
+        assert b"File contents here" == b"".join(response.streaming_content)
 
         # # Download as a user without sufficient role
         self.organization.update_option("sentry:debug_files_role", "owner")