From ed3ec04a085593dd0d07820f9bce836d2c46d01e Mon Sep 17 00:00:00 2001 From: Jon Dufresne Date: Tue, 24 Mar 2020 06:41:21 -0700 Subject: [PATCH] Fix resource leak in WheelFile.open() (#338) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In WheelFile.open(), if the hash does not exist, avoid opening the file before raising the exception. Previously would leak the open file resource which could result in a ResourceWarning when Python warnings are enabled: ResourceWarning: unclosed file <_io.FileIO name='…/test_testzip_missing_hash0/test-1.0-py2.py3-none-any.whl' mode='rb' closefd=True> Python warnings are now enabled during tests to help catch these earlier. --- .github/workflows/codeqa-test.yml | 2 +- src/wheel/wheelfile.py | 8 ++++---- tox.ini | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codeqa-test.yml b/.github/workflows/codeqa-test.yml index 7d638cb5..a84594b6 100644 --- a/.github/workflows/codeqa-test.yml +++ b/.github/workflows/codeqa-test.yml @@ -50,4 +50,4 @@ jobs: - name: Install test dependencies run: pip install .[test] - name: Test with pytest - run: pytest + run: python -b -m pytest -W always diff --git a/src/wheel/wheelfile.py b/src/wheel/wheelfile.py index acc5dab5..3ee97ddd 100644 --- a/src/wheel/wheelfile.py +++ b/src/wheel/wheelfile.py @@ -90,13 +90,13 @@ def _update_crc(newdata, eof=None): if eof and running_hash.digest() != expected_hash: raise WheelError("Hash mismatch for file '{}'".format(native(ef_name))) - ef = ZipFile.open(self, name_or_info, mode, pwd) ef_name = as_unicode(name_or_info.filename if isinstance(name_or_info, ZipInfo) else name_or_info) - if mode == 'r' and not ef_name.endswith('/'): - if ef_name not in self._file_hashes: - raise WheelError("No hash found for file '{}'".format(native(ef_name))) + if mode == 'r' and not ef_name.endswith('/') and ef_name not in self._file_hashes: + raise WheelError("No hash found for file '{}'".format(native(ef_name))) + ef = ZipFile.open(self, name_or_info, mode, pwd) + if mode == 'r' and not ef_name.endswith('/'): algorithm, expected_hash = self._file_hashes[ef_name] if expected_hash is not None: # Monkey patch the _update_crc method to also check for the hash from RECORD diff --git a/tox.ini b/tox.ini index e0dd820f..4a289ad8 100644 --- a/tox.ini +++ b/tox.ini @@ -9,7 +9,7 @@ minversion = 3.3.0 skip_missing_interpreters = true [testenv] -commands = pytest {posargs} +commands = {envpython} -b -m pytest -W always {posargs} extras = test [testenv:flake8]