OLD | NEW |
(Empty) | |
| 1 """msvc9compiler monkey patch test |
| 2 |
| 3 This test ensures that importing setuptools is sufficient to replace |
| 4 the standard find_vcvarsall function with our patched version that |
| 5 finds the Visual C++ for Python package. |
| 6 """ |
| 7 |
| 8 import os |
| 9 import shutil |
| 10 import sys |
| 11 import tempfile |
| 12 import unittest |
| 13 import distutils.errors |
| 14 import contextlib |
| 15 |
| 16 # importing only setuptools should apply the patch |
| 17 __import__('setuptools') |
| 18 |
| 19 class MockReg: |
| 20 """Mock for distutils.msvc9compiler.Reg. We patch it |
| 21 with an instance of this class that mocks out the |
| 22 functions that access the registry. |
| 23 """ |
| 24 |
| 25 def __init__(self, hkey_local_machine={}, hkey_current_user={}): |
| 26 self.hklm = hkey_local_machine |
| 27 self.hkcu = hkey_current_user |
| 28 |
| 29 def __enter__(self): |
| 30 self.original_read_keys = distutils.msvc9compiler.Reg.read_keys |
| 31 self.original_read_values = distutils.msvc9compiler.Reg.read_values |
| 32 |
| 33 _winreg = getattr(distutils.msvc9compiler, '_winreg', None) |
| 34 winreg = getattr(distutils.msvc9compiler, 'winreg', _winreg) |
| 35 |
| 36 hives = { |
| 37 winreg.HKEY_CURRENT_USER: self.hkcu, |
| 38 winreg.HKEY_LOCAL_MACHINE: self.hklm, |
| 39 } |
| 40 |
| 41 def read_keys(cls, base, key): |
| 42 """Return list of registry keys.""" |
| 43 hive = hives.get(base, {}) |
| 44 return [k.rpartition('\\')[2] |
| 45 for k in hive if k.startswith(key.lower())] |
| 46 |
| 47 def read_values(cls, base, key): |
| 48 """Return dict of registry keys and values.""" |
| 49 hive = hives.get(base, {}) |
| 50 return dict((k.rpartition('\\')[2], hive[k]) |
| 51 for k in hive if k.startswith(key.lower())) |
| 52 |
| 53 distutils.msvc9compiler.Reg.read_keys = classmethod(read_keys) |
| 54 distutils.msvc9compiler.Reg.read_values = classmethod(read_values) |
| 55 |
| 56 return self |
| 57 |
| 58 def __exit__(self, exc_type, exc_value, exc_tb): |
| 59 distutils.msvc9compiler.Reg.read_keys = self.original_read_keys |
| 60 distutils.msvc9compiler.Reg.read_values = self.original_read_values |
| 61 |
| 62 @contextlib.contextmanager |
| 63 def patch_env(**replacements): |
| 64 """ |
| 65 In a context, patch the environment with replacements. Pass None values |
| 66 to clear the values. |
| 67 """ |
| 68 saved = dict( |
| 69 (key, os.environ['key']) |
| 70 for key in replacements |
| 71 if key in os.environ |
| 72 ) |
| 73 |
| 74 # remove values that are null |
| 75 remove = (key for (key, value) in replacements.items() if value is None) |
| 76 for key in list(remove): |
| 77 os.environ.pop(key, None) |
| 78 replacements.pop(key) |
| 79 |
| 80 os.environ.update(replacements) |
| 81 |
| 82 try: |
| 83 yield saved |
| 84 finally: |
| 85 for key in replacements: |
| 86 os.environ.pop(key, None) |
| 87 os.environ.update(saved) |
| 88 |
| 89 class TestMSVC9Compiler(unittest.TestCase): |
| 90 |
| 91 def test_find_vcvarsall_patch(self): |
| 92 if not hasattr(distutils, 'msvc9compiler'): |
| 93 # skip |
| 94 return |
| 95 |
| 96 self.assertEqual( |
| 97 "setuptools.msvc9_support", |
| 98 distutils.msvc9compiler.find_vcvarsall.__module__, |
| 99 "find_vcvarsall was not patched" |
| 100 ) |
| 101 |
| 102 find_vcvarsall = distutils.msvc9compiler.find_vcvarsall |
| 103 query_vcvarsall = distutils.msvc9compiler.query_vcvarsall |
| 104 |
| 105 # No registry entries or environment variable means we should |
| 106 # not find anything |
| 107 with patch_env(VS90COMNTOOLS=None): |
| 108 with MockReg(): |
| 109 self.assertIsNone(find_vcvarsall(9.0)) |
| 110 |
| 111 try: |
| 112 query_vcvarsall(9.0) |
| 113 self.fail('Expected DistutilsPlatformError from query_vcvars
all()') |
| 114 except distutils.errors.DistutilsPlatformError: |
| 115 exc_message = str(sys.exc_info()[1]) |
| 116 self.assertIn('aka.ms/vcpython27', exc_message) |
| 117 |
| 118 key_32 = r'software\microsoft\devdiv\vcforpython\9.0\installdir' |
| 119 key_64 = r'software\wow6432node\microsoft\devdiv\vcforpython\9.0\install
dir' |
| 120 |
| 121 # Make two mock files so we can tell whether HCKU entries are |
| 122 # preferred to HKLM entries. |
| 123 mock_installdir_1 = tempfile.mkdtemp() |
| 124 mock_vcvarsall_bat_1 = os.path.join(mock_installdir_1, 'vcvarsall.bat') |
| 125 open(mock_vcvarsall_bat_1, 'w').close() |
| 126 mock_installdir_2 = tempfile.mkdtemp() |
| 127 mock_vcvarsall_bat_2 = os.path.join(mock_installdir_2, 'vcvarsall.bat') |
| 128 open(mock_vcvarsall_bat_2, 'w').close() |
| 129 try: |
| 130 # Ensure we get the current user's setting first |
| 131 with MockReg( |
| 132 hkey_current_user={key_32: mock_installdir_1}, |
| 133 hkey_local_machine={ |
| 134 key_32: mock_installdir_2, |
| 135 key_64: mock_installdir_2, |
| 136 } |
| 137 ): |
| 138 self.assertEqual(mock_vcvarsall_bat_1, find_vcvarsall(9.0)) |
| 139 |
| 140 # Ensure we get the local machine value if it's there |
| 141 with MockReg(hkey_local_machine={key_32: mock_installdir_2}): |
| 142 self.assertEqual(mock_vcvarsall_bat_2, find_vcvarsall(9.0)) |
| 143 |
| 144 # Ensure we prefer the 64-bit local machine key |
| 145 # (*not* the Wow6432Node key) |
| 146 with MockReg( |
| 147 hkey_local_machine={ |
| 148 # This *should* only exist on 32-bit machines |
| 149 key_32: mock_installdir_1, |
| 150 # This *should* only exist on 64-bit machines |
| 151 key_64: mock_installdir_2, |
| 152 } |
| 153 ): |
| 154 self.assertEqual(mock_vcvarsall_bat_1, find_vcvarsall(9.0)) |
| 155 finally: |
| 156 shutil.rmtree(mock_installdir_1) |
| 157 shutil.rmtree(mock_installdir_2) |
OLD | NEW |