Skip to content

Commit

Permalink
Clean up repaired wheels during test teardown
Browse files Browse the repository at this point in the history
This is cleaner than what we were doing before, which was to sometimes
clean up the wheel at the end of a test method and to sometimes not
clean it up.
  • Loading branch information
adang1345 committed Nov 12, 2024
1 parent dcb1179 commit 09f5a18
Showing 1 changed file with 54 additions and 110 deletions.
164 changes: 54 additions & 110 deletions tests/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,6 @@ def is_mangled(filename: str) -> bool:
return re.fullmatch(r'[^-]+-[0-9a-f]{32}\.dll', filename.lower()) is not None


def remove(path: str) -> None:
"""Version of os.remove() that ignores FileNotFoundError"""
try:
os.remove(path)
except FileNotFoundError:
pass


def import_iknowpy_successful(build_tag: str = '', modules: typing.Optional[list] = None) -> bool:
"""Return True iff wheelhouse/iknowpy-1.5.3-cp312-cp312-win_amd64.whl
can be installed successfully, imported, uninstalled, and deleted.
Expand Down Expand Up @@ -65,7 +57,6 @@ def import_iknowpy_successful(build_tag: str = '', modules: typing.Optional[list
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'iknowpy'])
except subprocess.CalledProcessError:
pass
remove(whl_path)


def import_simpleext_successful(build_tag: str = '', modules: typing.Optional[list] = None) -> bool:
Expand Down Expand Up @@ -95,7 +86,6 @@ def import_simpleext_successful(build_tag: str = '', modules: typing.Optional[li
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'simpleext'])
except subprocess.CalledProcessError:
pass
remove(whl_path)


class TestCase(unittest.TestCase):
Expand Down Expand Up @@ -123,7 +113,6 @@ def namespace_helper(self, whl: str, namespace_pkg: str, *,
importable: (optional) list of names that should be importable after
the repaired wheel is installed, must be None if testing on non-
Windows platform"""
repaired_whl = None
try:
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', *(() if mangle else ('--no-mangle-all',)), '--namespace-pkg', namespace_pkg, whl])
repaired_whl = os.path.join('wheelhouse', os.path.basename(whl))
Expand Down Expand Up @@ -163,11 +152,17 @@ def namespace_helper(self, whl: str, namespace_pkg: str, *,
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'simpleext'])
except subprocess.CalledProcessError:
pass
if repaired_whl:
remove(repaired_whl)

@classmethod
def tearDownClass(cls):
if DEBUG:
return
for item in os.listdir('.'):
if os.path.isdir(item) and item.startswith('wheelhouse'):
shutil.rmtree(item)


class ShowTestCase(unittest.TestCase):
class ShowTestCase(TestCase):
"""Tests for delvewheel show"""
def test_v(self):
"""-v"""
Expand All @@ -179,12 +174,9 @@ def test_vv(self):

def test_already_repaired(self):
"""Show is canceled if wheel is already repaired."""
try:
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', 'simpleext/simpleext-0.0.1-cp312-cp312-win_amd64.whl'])
output = subprocess.check_output(['delvewheel', 'show', 'wheelhouse/simpleext-0.0.1-cp312-cp312-win_amd64.whl'], text=True)
self.assertIn('has already repaired', output)
finally:
remove('wheelhouse/simpleext-0.0.1-cp312-cp312-win_amd64.whl')
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', 'simpleext/simpleext-0.0.1-cp312-cp312-win_amd64.whl'])
output = subprocess.check_output(['delvewheel', 'show', 'wheelhouse/simpleext-0.0.1-cp312-cp312-win_amd64.whl'], text=True)
self.assertIn('has already repaired', output)

def test_pure_python(self):
"""No dependencies needed if wheel is pure Python."""
Expand Down Expand Up @@ -436,7 +428,6 @@ def test_no_dll_iknowengine(self):
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'iknowpy'])
except subprocess.CalledProcessError:
pass
remove('wheelhouse/iknowpy-1.5.3-cp312-cp312-win_amd64.whl')

def test_exclude_iknowengine(self):
"""--exclude for iKnowEngine.dll, which should eliminate all iKnow*.dll
Expand All @@ -455,23 +446,16 @@ def test_exclude_iknowengine(self):
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'iknowpy'])
except subprocess.CalledProcessError:
pass
remove('wheelhouse/iknowpy-1.5.3-cp312-cp312-win_amd64.whl')

def test_exclude_all(self):
"""--exclude that removes all DLLs"""
try:
output = subprocess.check_output(['delvewheel', 'repair', '--add-path', 'iknowpy', '--exclude', 'iKnowEngine.dll;msvcp140.dll', '--no-mangle-all', 'iknowpy/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'], text=True)
self.assertIn('no external dependencies are needed', output)
finally:
remove('wheelhouse/iknowpy-1.5.3-cp312-cp312-win_amd64.whl')
output = subprocess.check_output(['delvewheel', 'repair', '--add-path', 'iknowpy', '--exclude', 'iKnowEngine.dll;msvcp140.dll', '--no-mangle-all', 'iknowpy/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'], text=True)
self.assertIn('no external dependencies are needed', output)

def test_exclude_all_2(self):
"""--exclude that removes all DLLs, flag specified twice"""
try:
output = subprocess.check_output(['delvewheel', 'repair', '--add-path', 'iknowpy', '--exclude', 'iKnowEngine.dll', '--exclude', 'msvcp140.dll', '--no-mangle-all', 'iknowpy/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'], text=True)
self.assertIn('no external dependencies are needed', output)
finally:
remove('wheelhouse/iknowpy-1.5.3-cp312-cp312-win_amd64.whl')
output = subprocess.check_output(['delvewheel', 'repair', '--add-path', 'iknowpy', '--exclude', 'iKnowEngine.dll', '--exclude', 'msvcp140.dll', '--no-mangle-all', 'iknowpy/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'], text=True)
self.assertIn('no external dependencies are needed', output)

def test_ignore_existing_irrelevant(self):
"""--ignore-existing when no DLLs are in the wheel"""
Expand Down Expand Up @@ -551,27 +535,17 @@ def test_extract_dir(self):
check_call(['delvewheel', 'repair', '--add-path', 'iknowpy', '--exclude', 'iKnowEngine.dll;msvcp140.dll', '--no-mangle-all', '--extract-dir', 'temp', 'iknowpy/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'])
self.assertTrue(os.path.exists('temp/iknowpy'))
finally:
if os.path.exists('temp'):
shutil.rmtree('temp')
remove('wheelhouse/iknowpy-1.5.3-cp312-cp312-win_amd64.whl')
shutil.rmtree('temp', True)

def test_wheel_dir_short(self):
"""-w"""
try:
check_call(['delvewheel', 'repair', '--add-path', 'iknowpy', '--exclude', 'iKnowEngine.dll', '-w', 'wheelhouse2', 'iknowpy/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'])
self.assertTrue(os.path.exists('wheelhouse2/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'))
finally:
if os.path.exists('wheelhouse2'):
shutil.rmtree('wheelhouse2')
check_call(['delvewheel', 'repair', '--add-path', 'iknowpy', '--exclude', 'iKnowEngine.dll', '-w', 'wheelhouse2', 'iknowpy/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'])
self.assertTrue(os.path.exists('wheelhouse2/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'))

def test_wheel_dir_long(self):
"""--wheel-dir"""
try:
check_call(['delvewheel', 'repair', '--add-path', 'iknowpy', '--exclude', 'iKnowEngine.dll', '-w', 'wheelhouse2', 'iknowpy/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'])
self.assertTrue(os.path.exists('wheelhouse2/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'))
finally:
if os.path.exists('wheelhouse2'):
shutil.rmtree('wheelhouse2')
check_call(['delvewheel', 'repair', '--add-path', 'iknowpy', '--exclude', 'iKnowEngine.dll', '-w', 'wheelhouse2', 'iknowpy/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'])
self.assertTrue(os.path.exists('wheelhouse2/iknowpy-1.5.3-cp312-cp312-win_amd64.whl'))

def test_lib_sdir_short(self):
"""-L"""
Expand Down Expand Up @@ -712,7 +686,6 @@ def test_multiple_versions(self):
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'simpleext'])
except subprocess.CalledProcessError:
pass
remove('wheelhouse/simpleext-0.0.1-cp36.cp312-cp36m.cp312-win_amd64.whl')

def test_multiple_wheels(self):
"""Repair multiple wheels in a single command"""
Expand All @@ -727,8 +700,6 @@ def test_multiple_wheels(self):
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'simpleext'])
except subprocess.CalledProcessError:
pass
remove('wheelhouse/simpleext-0.0.1-cp312-cp312-win_amd64.whl')
remove('wheelhouse/simpleext-0.0.1-cp36.cp312-cp36m.cp312-win_amd64.whl')

def test_v(self):
"""-v"""
Expand Down Expand Up @@ -759,7 +730,6 @@ def test_abi3_cp36(self):
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'simpleext'])
except subprocess.CalledProcessError:
pass
remove('wheelhouse/simpleext-0.0.1-cp36-abi3-win_amd64.whl')

def test_abi3_cp312(self):
"""Repair an abi3 wheel for CPython 3.12+."""
Expand All @@ -782,46 +752,33 @@ def test_abi3_cp312(self):
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'simpleext'])
except subprocess.CalledProcessError:
pass
remove('wheelhouse/simpleext-0.0.1-cp312-abi3-win_amd64.whl')

def test_already_repaired(self):
"""Repair is canceled if wheel is already repaired."""
try:
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', 'simpleext/simpleext-0.0.1-cp312-cp312-win_amd64.whl'])
output = subprocess.check_output(['delvewheel', 'repair', 'wheelhouse/simpleext-0.0.1-cp312-cp312-win_amd64.whl'], text=True)
self.assertIn('has already repaired', output)
finally:
remove('wheelhouse/simpleext-0.0.1-cp312-cp312-win_amd64.whl')
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', 'simpleext/simpleext-0.0.1-cp312-cp312-win_amd64.whl'])
output = subprocess.check_output(['delvewheel', 'repair', 'wheelhouse/simpleext-0.0.1-cp312-cp312-win_amd64.whl'], text=True)
self.assertIn('has already repaired', output)

def test_pure_python(self):
"""If wheel is pure Python, no repair happens, and the wheel is copied
as-is."""
try:
output = subprocess.check_output(['delvewheel', 'repair', 'no_dependencies/more_itertools-9.0.0-py3-none-any.whl'], text=True)
self.assertIn('no external dependencies are needed', output)
self.assertTrue(os.path.isfile('wheelhouse/more_itertools-9.0.0-py3-none-any.whl'))
finally:
remove('wheelhouse/more_itertools-9.0.0-py3-none-any.whl')
output = subprocess.check_output(['delvewheel', 'repair', 'no_dependencies/more_itertools-9.0.0-py3-none-any.whl'], text=True)
self.assertIn('no external dependencies are needed', output)
self.assertTrue(os.path.isfile('wheelhouse/more_itertools-9.0.0-py3-none-any.whl'))

def test_no_external(self):
"""If wheel has an extension module that has no external dependencies,
no repair happens, and the wheel is copied as-is."""
try:
output = subprocess.check_output(['delvewheel', 'repair', 'no_dependencies/h3ronpy-0.16.0-cp38-abi3-win_amd64.whl'], text=True)
self.assertIn('no external dependencies are needed', output)
self.assertTrue(os.path.isfile('wheelhouse/h3ronpy-0.16.0-cp38-abi3-win_amd64.whl'))
finally:
remove('wheelhouse/h3ronpy-0.16.0-cp38-abi3-win_amd64.whl')
output = subprocess.check_output(['delvewheel', 'repair', 'no_dependencies/h3ronpy-0.16.0-cp38-abi3-win_amd64.whl'], text=True)
self.assertIn('no external dependencies are needed', output)
self.assertTrue(os.path.isfile('wheelhouse/h3ronpy-0.16.0-cp38-abi3-win_amd64.whl'))

def test_wrong_platform(self):
"""If wheel has an extension module that is not for Windows, no repair
happens, and the wheel is copied as-is."""
try:
output = subprocess.check_output(['delvewheel', 'repair', 'no_dependencies/h3ronpy-0.16.0-cp38-abi3-macosx_10_7_x86_64.whl'], text=True)
self.assertIn('no external dependencies are needed', output)
self.assertTrue(os.path.isfile('wheelhouse/h3ronpy-0.16.0-cp38-abi3-macosx_10_7_x86_64.whl'))
finally:
remove('wheelhouse/h3ronpy-0.16.0-cp38-abi3-macosx_10_7_x86_64.whl')
output = subprocess.check_output(['delvewheel', 'repair', 'no_dependencies/h3ronpy-0.16.0-cp38-abi3-macosx_10_7_x86_64.whl'], text=True)
self.assertIn('no external dependencies are needed', output)
self.assertTrue(os.path.isfile('wheelhouse/h3ronpy-0.16.0-cp38-abi3-macosx_10_7_x86_64.whl'))

def test_header_space(self):
"""PE header space is added correctly in name-mangling step."""
Expand Down Expand Up @@ -1162,11 +1119,8 @@ def test_namespace10(self):

def test_ignore_data(self):
"""Ignore .pyd file in .data/data directory."""
try:
output = subprocess.check_output(['delvewheel', 'repair', 'simpleext/simpleext-0.0.1-0ignore-cp312-cp312-win_amd64.whl'], text=True)
self.assertIn('no external dependencies are needed', output)
finally:
remove('wheelhouse/simpleext-0.0.1-0ignore-cp312-cp312-win_amd64.whl')
output = subprocess.check_output(['delvewheel', 'repair', 'simpleext/simpleext-0.0.1-0ignore-cp312-cp312-win_amd64.whl'], text=True)
self.assertIn('no external dependencies are needed', output)

def test_include_symbols0(self):
"""Simple test of the --include-symbols flag."""
Expand Down Expand Up @@ -1230,28 +1184,22 @@ def test_filename_special_character(self):
def test_source_date_epoch(self):
"""The SOURCE_DATE_EPOCH environment variable can be used to have
reproducible builds."""
try:
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', '-w', 'wheelhouse1', 'simpleext/simpleext-0.0.1-cp312-cp312-win_amd64.whl'], {'SOURCE_DATE_EPOCH': None})
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', '-w', 'wheelhouse2', 'simpleext/simpleext-0.0.1-cp312-cp312-win_amd64.whl'], {'SOURCE_DATE_EPOCH': '650203200'})
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', '-w', 'wheelhouse3', 'simpleext/simpleext-0.0.1-cp312-cp312-win_amd64.whl'], {'SOURCE_DATE_EPOCH': '650203200'})
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', '-w', 'wheelhouse4', 'simpleext/simpleext-0.0.1-cp312-cp312-win_amd64.whl'], {'SOURCE_DATE_EPOCH': '650203202'})
with open('wheelhouse1/simpleext-0.0.1-cp312-cp312-win_amd64.whl', 'rb') as wheel1, \
open('wheelhouse2/simpleext-0.0.1-cp312-cp312-win_amd64.whl', 'rb') as wheel2, \
open('wheelhouse3/simpleext-0.0.1-cp312-cp312-win_amd64.whl', 'rb') as wheel3, \
open('wheelhouse4/simpleext-0.0.1-cp312-cp312-win_amd64.whl', 'rb') as wheel4:
contents1 = wheel1.read()
contents2 = wheel2.read()
contents3 = wheel3.read()
contents4 = wheel4.read()
self.assertNotEqual(contents1, contents2)
self.assertNotEqual(contents1, contents4)
self.assertEqual(contents2, contents3)
self.assertNotEqual(contents2, contents4)
finally:
remove('wheelhouse1/simpleext-0.0.1-cp312-cp312-win_amd64.whl')
remove('wheelhouse2/simpleext-0.0.1-cp312-cp312-win_amd64.whl')
remove('wheelhouse3/simpleext-0.0.1-cp312-cp312-win_amd64.whl')
remove('wheelhouse4/simpleext-0.0.1-cp312-cp312-win_amd64.whl')
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', '-w', 'wheelhouse1', 'simpleext/simpleext-0.0.1-cp312-cp312-win_amd64.whl'], {'SOURCE_DATE_EPOCH': None})
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', '-w', 'wheelhouse2', 'simpleext/simpleext-0.0.1-cp312-cp312-win_amd64.whl'], {'SOURCE_DATE_EPOCH': '650203200'})
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', '-w', 'wheelhouse3', 'simpleext/simpleext-0.0.1-cp312-cp312-win_amd64.whl'], {'SOURCE_DATE_EPOCH': '650203200'})
check_call(['delvewheel', 'repair', '--add-path', 'simpleext/x64', '-w', 'wheelhouse4', 'simpleext/simpleext-0.0.1-cp312-cp312-win_amd64.whl'], {'SOURCE_DATE_EPOCH': '650203202'})
with open('wheelhouse1/simpleext-0.0.1-cp312-cp312-win_amd64.whl', 'rb') as wheel1, \
open('wheelhouse2/simpleext-0.0.1-cp312-cp312-win_amd64.whl', 'rb') as wheel2, \
open('wheelhouse3/simpleext-0.0.1-cp312-cp312-win_amd64.whl', 'rb') as wheel3, \
open('wheelhouse4/simpleext-0.0.1-cp312-cp312-win_amd64.whl', 'rb') as wheel4:
contents1 = wheel1.read()
contents2 = wheel2.read()
contents3 = wheel3.read()
contents4 = wheel4.read()
self.assertNotEqual(contents1, contents2)
self.assertNotEqual(contents1, contents4)
self.assertEqual(contents2, contents3)
self.assertNotEqual(contents2, contents4)

def test_dependent_load_flags(self):
"""/DEPENDENTLOADFLAG:0x800 is cleared in vendored DLL when name-
Expand Down Expand Up @@ -1319,7 +1267,7 @@ def test_custom(self):
self.assertEqual(1, p.stdout.count(' (count 2)'))


class NeededTestCase(unittest.TestCase):
class NeededTestCase(TestCase):
"""Tests for delvewheel needed"""
def test_iknowengine(self):
p = subprocess.run(['delvewheel', 'needed', 'iknowpy/iKnowEngine.dll'], capture_output=True, text=True, check=True)
Expand Down Expand Up @@ -1355,7 +1303,7 @@ def test_msvcp140(self):


@unittest.skipUnless(sys.version_info[:2] == (3, 8), 'Python version is not 3.8')
class Python38TestCase(unittest.TestCase):
class Python38TestCase(TestCase):
"""delvewheel can be run on Python 3.8, the oldest supported version"""

# mock the Conda-Forge distribution of Python 3.8 to test loading with
Expand All @@ -1376,7 +1324,6 @@ def test_repair_simpleext(self):
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'simpleext'])
except subprocess.CalledProcessError:
pass
remove('wheelhouse/simpleext-0.0.1-cp38-cp38-win_amd64.whl')

def test_repair_iknowpy(self):
try:
Expand All @@ -1388,7 +1335,6 @@ def test_repair_iknowpy(self):
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'iknowpy'])
except subprocess.CalledProcessError:
pass
remove('wheelhouse/iknowpy-1.5.3-cp38-cp38-win_amd64.whl')

def test_needed(self):
check_call(['delvewheel', 'needed', 'simpleext/x64/simpledll.dll'])
Expand All @@ -1405,11 +1351,10 @@ def test_fixed_address(self):
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'simpleext'])
except subprocess.CalledProcessError:
pass
remove('wheelhouse/simpleext-0.0.1-0fixed-cp38-cp38-win_amd64.whl')


@unittest.skipUnless(sys.implementation.name == 'pypy', 'Python implementation is not PyPy')
class PyPyTestCase(unittest.TestCase):
class PyPyTestCase(TestCase):
"""delvewheel can be run on PyPy"""
def test_show(self):
check_call(['delvewheel', 'show', '--add-path', 'simpleext/x64', 'simpleext/simpleext-0.0.1-pp310-pypy310_pp73-win_amd64.whl'])
Expand All @@ -1425,7 +1370,6 @@ def test_repair(self):
check_call([sys.executable, '-m', 'pip', 'uninstall', '-y', 'simpleext'])
except subprocess.CalledProcessError:
pass
remove('wheelhouse/simpleext-0.0.1-pp310-pypy310_pp73-win_amd64.whl')

def test_needed(self):
check_call(['delvewheel', 'needed', 'simpleext/x64/simpledll.dll'])
Expand Down

0 comments on commit 09f5a18

Please sign in to comment.