Brett Cannon | 0dbb4c7 | 2013-05-31 18:56:47 -0400 | [diff] [blame] | 1 | import contextlib |
Brett Cannon | 64ef00f | 2009-07-20 03:19:18 +0000 | [diff] [blame] | 2 | import inspect |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 3 | import io |
| 4 | import marshal |
| 5 | import os |
| 6 | import sys |
Brett Cannon | 0dbb4c7 | 2013-05-31 18:56:47 -0400 | [diff] [blame] | 7 | from test import support |
Brett Cannon | ef88802 | 2013-06-15 18:39:21 -0400 | [diff] [blame] | 8 | import types |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 9 | import unittest |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 10 | from unittest import mock |
Eric Snow | 1500d49 | 2014-01-06 20:49:04 -0700 | [diff] [blame] | 11 | import warnings |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 12 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 13 | from . import util as test_util |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 14 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 15 | init = test_util.import_importlib('importlib') |
| 16 | abc = test_util.import_importlib('importlib.abc') |
| 17 | machinery = test_util.import_importlib('importlib.machinery') |
| 18 | util = test_util.import_importlib('importlib.util') |
| 19 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 20 | |
Brett Cannon | 9ffe85e | 2013-05-26 16:45:10 -0400 | [diff] [blame] | 21 | ##### Inheritance ############################################################## |
Brett Cannon | 64ef00f | 2009-07-20 03:19:18 +0000 | [diff] [blame] | 22 | class InheritanceTests: |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 23 | |
Brett Cannon | 64ef00f | 2009-07-20 03:19:18 +0000 | [diff] [blame] | 24 | """Test that the specified class is a subclass/superclass of the expected |
| 25 | classes.""" |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 26 | |
Brett Cannon | 64ef00f | 2009-07-20 03:19:18 +0000 | [diff] [blame] | 27 | subclasses = [] |
| 28 | superclasses = [] |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 29 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 30 | def setUp(self): |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 31 | self.superclasses = [getattr(self.abc, class_name) |
| 32 | for class_name in self.superclass_names] |
| 33 | if hasattr(self, 'subclass_names'): |
| 34 | # Because test.support.import_fresh_module() creates a new |
| 35 | # importlib._bootstrap per module, inheritance checks fail when |
| 36 | # checking across module boundaries (i.e. the _bootstrap in abc is |
| 37 | # not the same as the one in machinery). That means stealing one of |
| 38 | # the modules from the other to make sure the same instance is used. |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 39 | machinery = self.abc.machinery |
| 40 | self.subclasses = [getattr(machinery, class_name) |
| 41 | for class_name in self.subclass_names] |
Brett Cannon | 64ef00f | 2009-07-20 03:19:18 +0000 | [diff] [blame] | 42 | assert self.subclasses or self.superclasses, self.__class__ |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 43 | self.__test = getattr(self.abc, self._NAME) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 44 | |
Brett Cannon | 64ef00f | 2009-07-20 03:19:18 +0000 | [diff] [blame] | 45 | def test_subclasses(self): |
| 46 | # Test that the expected subclasses inherit. |
| 47 | for subclass in self.subclasses: |
| 48 | self.assertTrue(issubclass(subclass, self.__test), |
| 49 | "{0} is not a subclass of {1}".format(subclass, self.__test)) |
| 50 | |
| 51 | def test_superclasses(self): |
| 52 | # Test that the class inherits from the expected superclasses. |
| 53 | for superclass in self.superclasses: |
| 54 | self.assertTrue(issubclass(self.__test, superclass), |
| 55 | "{0} is not a superclass of {1}".format(superclass, self.__test)) |
| 56 | |
Brett Cannon | f4dc920 | 2012-08-10 12:21:12 -0400 | [diff] [blame] | 57 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 58 | class MetaPathFinder(InheritanceTests): |
| 59 | superclass_names = ['Finder'] |
| 60 | subclass_names = ['BuiltinImporter', 'FrozenImporter', 'PathFinder', |
| 61 | 'WindowsRegistryFinder'] |
Nick Coghlan | 8a9080f | 2012-08-02 21:26:03 +1000 | [diff] [blame] | 62 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 63 | |
| 64 | (Frozen_MetaPathFinderInheritanceTests, |
| 65 | Source_MetaPathFinderInheritanceTests |
| 66 | ) = test_util.test_both(MetaPathFinder, abc=abc) |
Brett Cannon | 64ef00f | 2009-07-20 03:19:18 +0000 | [diff] [blame] | 67 | |
Brett Cannon | f4dc920 | 2012-08-10 12:21:12 -0400 | [diff] [blame] | 68 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 69 | class PathEntryFinder(InheritanceTests): |
| 70 | superclass_names = ['Finder'] |
| 71 | subclass_names = ['FileFinder'] |
Brett Cannon | 64ef00f | 2009-07-20 03:19:18 +0000 | [diff] [blame] | 72 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 73 | |
| 74 | (Frozen_PathEntryFinderInheritanceTests, |
| 75 | Source_PathEntryFinderInheritanceTests |
| 76 | ) = test_util.test_both(PathEntryFinder, abc=abc) |
Brett Cannon | 64ef00f | 2009-07-20 03:19:18 +0000 | [diff] [blame] | 77 | |
| 78 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 79 | class ResourceLoader(InheritanceTests): |
| 80 | superclass_names = ['Loader'] |
Brett Cannon | 64ef00f | 2009-07-20 03:19:18 +0000 | [diff] [blame] | 81 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 82 | |
| 83 | (Frozen_ResourceLoaderInheritanceTests, |
| 84 | Source_ResourceLoaderInheritanceTests |
| 85 | ) = test_util.test_both(ResourceLoader, abc=abc) |
Brett Cannon | 64ef00f | 2009-07-20 03:19:18 +0000 | [diff] [blame] | 86 | |
| 87 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 88 | class InspectLoader(InheritanceTests): |
| 89 | superclass_names = ['Loader'] |
| 90 | subclass_names = ['BuiltinImporter', 'FrozenImporter', 'ExtensionFileLoader'] |
Brett Cannon | 6919427 | 2009-07-20 04:23:48 +0000 | [diff] [blame] | 91 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 92 | |
| 93 | (Frozen_InspectLoaderInheritanceTests, |
| 94 | Source_InspectLoaderInheritanceTests |
| 95 | ) = test_util.test_both(InspectLoader, abc=abc) |
Brett Cannon | 6919427 | 2009-07-20 04:23:48 +0000 | [diff] [blame] | 96 | |
| 97 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 98 | class ExecutionLoader(InheritanceTests): |
| 99 | superclass_names = ['InspectLoader'] |
Eric Snow | 7e70fa5 | 2013-10-04 20:28:52 -0600 | [diff] [blame] | 100 | subclass_names = ['ExtensionFileLoader'] |
Brett Cannon | 938d44d | 2012-04-22 19:58:33 -0400 | [diff] [blame] | 101 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 102 | |
| 103 | (Frozen_ExecutionLoaderInheritanceTests, |
| 104 | Source_ExecutionLoaderInheritanceTests |
| 105 | ) = test_util.test_both(ExecutionLoader, abc=abc) |
Brett Cannon | 938d44d | 2012-04-22 19:58:33 -0400 | [diff] [blame] | 106 | |
| 107 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 108 | class FileLoader(InheritanceTests): |
| 109 | superclass_names = ['ResourceLoader', 'ExecutionLoader'] |
| 110 | subclass_names = ['SourceFileLoader', 'SourcelessFileLoader'] |
Brett Cannon | b7183d8 | 2010-06-28 05:46:25 +0000 | [diff] [blame] | 111 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 112 | |
| 113 | (Frozen_FileLoaderInheritanceTests, |
| 114 | Source_FileLoaderInheritanceTests |
| 115 | ) = test_util.test_both(FileLoader, abc=abc) |
Brett Cannon | b7183d8 | 2010-06-28 05:46:25 +0000 | [diff] [blame] | 116 | |
| 117 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 118 | class SourceLoader(InheritanceTests): |
| 119 | superclass_names = ['ResourceLoader', 'ExecutionLoader'] |
| 120 | subclass_names = ['SourceFileLoader'] |
| 121 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 122 | |
| 123 | (Frozen_SourceLoaderInheritanceTests, |
| 124 | Source_SourceLoaderInheritanceTests |
| 125 | ) = test_util.test_both(SourceLoader, abc=abc) |
| 126 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 127 | |
Brett Cannon | 9ffe85e | 2013-05-26 16:45:10 -0400 | [diff] [blame] | 128 | ##### Default return values #################################################### |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 129 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 130 | def make_abc_subclasses(base_class, name=None, inst=False, **kwargs): |
| 131 | if name is None: |
| 132 | name = base_class.__name__ |
| 133 | base = {kind: getattr(splitabc, name) |
| 134 | for kind, splitabc in abc.items()} |
| 135 | return {cls._KIND: cls() if inst else cls |
| 136 | for cls in test_util.split_frozen(base_class, base, **kwargs)} |
| 137 | |
| 138 | |
| 139 | class ABCTestHarness: |
| 140 | |
| 141 | @property |
| 142 | def ins(self): |
| 143 | # Lazily set ins on the class. |
| 144 | cls = self.SPLIT[self._KIND] |
| 145 | ins = cls() |
| 146 | self.__class__.ins = ins |
| 147 | return ins |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 148 | |
| 149 | |
| 150 | class MetaPathFinder: |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 151 | |
| 152 | def find_module(self, fullname, path): |
| 153 | return super().find_module(fullname, path) |
| 154 | |
| 155 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 156 | class MetaPathFinderDefaultsTests(ABCTestHarness): |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 157 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 158 | SPLIT = make_abc_subclasses(MetaPathFinder) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 159 | |
| 160 | def test_find_module(self): |
| 161 | # Default should return None. |
| 162 | self.assertIsNone(self.ins.find_module('something', None)) |
| 163 | |
| 164 | def test_invalidate_caches(self): |
| 165 | # Calling the method is a no-op. |
| 166 | self.ins.invalidate_caches() |
| 167 | |
| 168 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 169 | (Frozen_MPFDefaultTests, |
| 170 | Source_MPFDefaultTests |
| 171 | ) = test_util.test_both(MetaPathFinderDefaultsTests) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 172 | |
| 173 | |
| 174 | class PathEntryFinder: |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 175 | |
| 176 | def find_loader(self, fullname): |
| 177 | return super().find_loader(fullname) |
| 178 | |
| 179 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 180 | class PathEntryFinderDefaultsTests(ABCTestHarness): |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 181 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 182 | SPLIT = make_abc_subclasses(PathEntryFinder) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 183 | |
| 184 | def test_find_loader(self): |
| 185 | self.assertEqual((None, []), self.ins.find_loader('something')) |
| 186 | |
| 187 | def find_module(self): |
| 188 | self.assertEqual(None, self.ins.find_module('something')) |
| 189 | |
| 190 | def test_invalidate_caches(self): |
| 191 | # Should be a no-op. |
| 192 | self.ins.invalidate_caches() |
| 193 | |
| 194 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 195 | (Frozen_PEFDefaultTests, |
| 196 | Source_PEFDefaultTests |
| 197 | ) = test_util.test_both(PathEntryFinderDefaultsTests) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 198 | |
| 199 | |
| 200 | class Loader: |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 201 | |
| 202 | def load_module(self, fullname): |
| 203 | return super().load_module(fullname) |
| 204 | |
| 205 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 206 | class LoaderDefaultsTests(ABCTestHarness): |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 207 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 208 | SPLIT = make_abc_subclasses(Loader) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 209 | |
| 210 | def test_load_module(self): |
| 211 | with self.assertRaises(ImportError): |
| 212 | self.ins.load_module('something') |
| 213 | |
| 214 | def test_module_repr(self): |
Brett Cannon | ef88802 | 2013-06-15 18:39:21 -0400 | [diff] [blame] | 215 | mod = types.ModuleType('blah') |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 216 | with self.assertRaises(NotImplementedError): |
| 217 | self.ins.module_repr(mod) |
| 218 | original_repr = repr(mod) |
| 219 | mod.__loader__ = self.ins |
| 220 | # Should still return a proper repr. |
| 221 | self.assertTrue(repr(mod)) |
| 222 | |
| 223 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 224 | (Frozen_LDefaultTests, |
| 225 | SourceLDefaultTests |
| 226 | ) = test_util.test_both(LoaderDefaultsTests) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 227 | |
| 228 | |
| 229 | class ResourceLoader(Loader): |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 230 | |
| 231 | def get_data(self, path): |
| 232 | return super().get_data(path) |
| 233 | |
| 234 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 235 | class ResourceLoaderDefaultsTests(ABCTestHarness): |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 236 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 237 | SPLIT = make_abc_subclasses(ResourceLoader) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 238 | |
| 239 | def test_get_data(self): |
| 240 | with self.assertRaises(IOError): |
| 241 | self.ins.get_data('/some/path') |
| 242 | |
| 243 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 244 | (Frozen_RLDefaultTests, |
| 245 | Source_RLDefaultTests |
| 246 | ) = test_util.test_both(ResourceLoaderDefaultsTests) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 247 | |
| 248 | |
| 249 | class InspectLoader(Loader): |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 250 | |
| 251 | def is_package(self, fullname): |
| 252 | return super().is_package(fullname) |
| 253 | |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 254 | def get_source(self, fullname): |
| 255 | return super().get_source(fullname) |
| 256 | |
| 257 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 258 | SPLIT_IL = make_abc_subclasses(InspectLoader) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 259 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 260 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 261 | class InspectLoaderDefaultsTests(ABCTestHarness): |
| 262 | |
| 263 | SPLIT = SPLIT_IL |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 264 | |
| 265 | def test_is_package(self): |
| 266 | with self.assertRaises(ImportError): |
| 267 | self.ins.is_package('blah') |
| 268 | |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 269 | def test_get_source(self): |
| 270 | with self.assertRaises(ImportError): |
| 271 | self.ins.get_source('blah') |
| 272 | |
| 273 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 274 | (Frozen_ILDefaultTests, |
| 275 | Source_ILDefaultTests |
| 276 | ) = test_util.test_both(InspectLoaderDefaultsTests) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 277 | |
| 278 | |
| 279 | class ExecutionLoader(InspectLoader): |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 280 | |
| 281 | def get_filename(self, fullname): |
| 282 | return super().get_filename(fullname) |
| 283 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 284 | |
| 285 | SPLIT_EL = make_abc_subclasses(ExecutionLoader) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 286 | |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 287 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 288 | class ExecutionLoaderDefaultsTests(ABCTestHarness): |
| 289 | |
| 290 | SPLIT = SPLIT_EL |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 291 | |
| 292 | def test_get_filename(self): |
| 293 | with self.assertRaises(ImportError): |
| 294 | self.ins.get_filename('blah') |
| 295 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 296 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 297 | (Frozen_ELDefaultTests, |
| 298 | Source_ELDefaultsTests |
| 299 | ) = test_util.test_both(InspectLoaderDefaultsTests) |
| 300 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 301 | |
Brett Cannon | 8d94229 | 2014-01-07 15:52:42 -0500 | [diff] [blame] | 302 | ##### MetaPathFinder concrete methods ########################################## |
Brett Cannon | 8d94229 | 2014-01-07 15:52:42 -0500 | [diff] [blame] | 303 | class MetaPathFinderFindModuleTests: |
| 304 | |
| 305 | @classmethod |
| 306 | def finder(cls, spec): |
| 307 | class MetaPathSpecFinder(cls.abc.MetaPathFinder): |
| 308 | |
| 309 | def find_spec(self, fullname, path, target=None): |
| 310 | self.called_for = fullname, path |
| 311 | return spec |
| 312 | |
| 313 | return MetaPathSpecFinder() |
| 314 | |
| 315 | def test_no_spec(self): |
| 316 | finder = self.finder(None) |
| 317 | path = ['a', 'b', 'c'] |
| 318 | name = 'blah' |
| 319 | found = finder.find_module(name, path) |
| 320 | self.assertIsNone(found) |
| 321 | self.assertEqual(name, finder.called_for[0]) |
| 322 | self.assertEqual(path, finder.called_for[1]) |
| 323 | |
| 324 | def test_spec(self): |
| 325 | loader = object() |
| 326 | spec = self.util.spec_from_loader('blah', loader) |
| 327 | finder = self.finder(spec) |
| 328 | found = finder.find_module('blah', None) |
| 329 | self.assertIs(found, spec.loader) |
| 330 | |
| 331 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 332 | (Frozen_MPFFindModuleTests, |
| 333 | Source_MPFFindModuleTests |
| 334 | ) = test_util.test_both(MetaPathFinderFindModuleTests, abc=abc, util=util) |
| 335 | |
Brett Cannon | 8d94229 | 2014-01-07 15:52:42 -0500 | [diff] [blame] | 336 | |
| 337 | ##### PathEntryFinder concrete methods ######################################### |
Brett Cannon | 8d94229 | 2014-01-07 15:52:42 -0500 | [diff] [blame] | 338 | class PathEntryFinderFindLoaderTests: |
| 339 | |
| 340 | @classmethod |
| 341 | def finder(cls, spec): |
| 342 | class PathEntrySpecFinder(cls.abc.PathEntryFinder): |
| 343 | |
| 344 | def find_spec(self, fullname, target=None): |
| 345 | self.called_for = fullname |
| 346 | return spec |
| 347 | |
| 348 | return PathEntrySpecFinder() |
| 349 | |
| 350 | def test_no_spec(self): |
| 351 | finder = self.finder(None) |
| 352 | name = 'blah' |
| 353 | found = finder.find_loader(name) |
| 354 | self.assertIsNone(found[0]) |
| 355 | self.assertEqual([], found[1]) |
| 356 | self.assertEqual(name, finder.called_for) |
| 357 | |
| 358 | def test_spec_with_loader(self): |
| 359 | loader = object() |
| 360 | spec = self.util.spec_from_loader('blah', loader) |
| 361 | finder = self.finder(spec) |
| 362 | found = finder.find_loader('blah') |
| 363 | self.assertIs(found[0], spec.loader) |
| 364 | |
| 365 | def test_spec_with_portions(self): |
| 366 | spec = self.machinery.ModuleSpec('blah', None) |
| 367 | paths = ['a', 'b', 'c'] |
| 368 | spec.submodule_search_locations = paths |
| 369 | finder = self.finder(spec) |
| 370 | found = finder.find_loader('blah') |
| 371 | self.assertIsNone(found[0]) |
| 372 | self.assertEqual(paths, found[1]) |
| 373 | |
| 374 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 375 | (Frozen_PEFFindLoaderTests, |
| 376 | Source_PEFFindLoaderTests |
| 377 | ) = test_util.test_both(PathEntryFinderFindLoaderTests, abc=abc, util=util, |
| 378 | machinery=machinery) |
Brett Cannon | 8d94229 | 2014-01-07 15:52:42 -0500 | [diff] [blame] | 379 | |
| 380 | |
| 381 | ##### Loader concrete methods ################################################## |
| 382 | class LoaderLoadModuleTests: |
| 383 | |
| 384 | def loader(self): |
| 385 | class SpecLoader(self.abc.Loader): |
| 386 | found = None |
| 387 | def exec_module(self, module): |
| 388 | self.found = module |
| 389 | |
| 390 | def is_package(self, fullname): |
| 391 | """Force some non-default module state to be set.""" |
| 392 | return True |
| 393 | |
| 394 | return SpecLoader() |
| 395 | |
| 396 | def test_fresh(self): |
| 397 | loader = self.loader() |
| 398 | name = 'blah' |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 399 | with test_util.uncache(name): |
Brett Cannon | 8d94229 | 2014-01-07 15:52:42 -0500 | [diff] [blame] | 400 | loader.load_module(name) |
| 401 | module = loader.found |
| 402 | self.assertIs(sys.modules[name], module) |
| 403 | self.assertEqual(loader, module.__loader__) |
| 404 | self.assertEqual(loader, module.__spec__.loader) |
| 405 | self.assertEqual(name, module.__name__) |
| 406 | self.assertEqual(name, module.__spec__.name) |
| 407 | self.assertIsNotNone(module.__path__) |
| 408 | self.assertIsNotNone(module.__path__, |
| 409 | module.__spec__.submodule_search_locations) |
| 410 | |
| 411 | def test_reload(self): |
| 412 | name = 'blah' |
| 413 | loader = self.loader() |
| 414 | module = types.ModuleType(name) |
| 415 | module.__spec__ = self.util.spec_from_loader(name, loader) |
| 416 | module.__loader__ = loader |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 417 | with test_util.uncache(name): |
Brett Cannon | 8d94229 | 2014-01-07 15:52:42 -0500 | [diff] [blame] | 418 | sys.modules[name] = module |
| 419 | loader.load_module(name) |
| 420 | found = loader.found |
| 421 | self.assertIs(found, sys.modules[name]) |
| 422 | self.assertIs(module, sys.modules[name]) |
| 423 | |
| 424 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 425 | (Frozen_LoaderLoadModuleTests, |
| 426 | Source_LoaderLoadModuleTests |
| 427 | ) = test_util.test_both(LoaderLoadModuleTests, abc=abc, util=util) |
Brett Cannon | 8d94229 | 2014-01-07 15:52:42 -0500 | [diff] [blame] | 428 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 429 | |
Brett Cannon | 9ffe85e | 2013-05-26 16:45:10 -0400 | [diff] [blame] | 430 | ##### InspectLoader concrete methods ########################################### |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 431 | class InspectLoaderSourceToCodeTests: |
Brett Cannon | 9ffe85e | 2013-05-26 16:45:10 -0400 | [diff] [blame] | 432 | |
| 433 | def source_to_module(self, data, path=None): |
| 434 | """Help with source_to_code() tests.""" |
Brett Cannon | ef88802 | 2013-06-15 18:39:21 -0400 | [diff] [blame] | 435 | module = types.ModuleType('blah') |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 436 | loader = self.InspectLoaderSubclass() |
Brett Cannon | 9ffe85e | 2013-05-26 16:45:10 -0400 | [diff] [blame] | 437 | if path is None: |
| 438 | code = loader.source_to_code(data) |
| 439 | else: |
| 440 | code = loader.source_to_code(data, path) |
| 441 | exec(code, module.__dict__) |
| 442 | return module |
| 443 | |
| 444 | def test_source_to_code_source(self): |
| 445 | # Since compile() can handle strings, so should source_to_code(). |
| 446 | source = 'attr = 42' |
| 447 | module = self.source_to_module(source) |
| 448 | self.assertTrue(hasattr(module, 'attr')) |
| 449 | self.assertEqual(module.attr, 42) |
| 450 | |
| 451 | def test_source_to_code_bytes(self): |
| 452 | # Since compile() can handle bytes, so should source_to_code(). |
| 453 | source = b'attr = 42' |
| 454 | module = self.source_to_module(source) |
| 455 | self.assertTrue(hasattr(module, 'attr')) |
| 456 | self.assertEqual(module.attr, 42) |
| 457 | |
| 458 | def test_source_to_code_path(self): |
| 459 | # Specifying a path should set it for the code object. |
| 460 | path = 'path/to/somewhere' |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 461 | loader = self.InspectLoaderSubclass() |
Brett Cannon | 9ffe85e | 2013-05-26 16:45:10 -0400 | [diff] [blame] | 462 | code = loader.source_to_code('', path) |
| 463 | self.assertEqual(code.co_filename, path) |
| 464 | |
| 465 | def test_source_to_code_no_path(self): |
| 466 | # Not setting a path should still work and be set to <string> since that |
| 467 | # is a pre-existing practice as a default to compile(). |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 468 | loader = self.InspectLoaderSubclass() |
Brett Cannon | 9ffe85e | 2013-05-26 16:45:10 -0400 | [diff] [blame] | 469 | code = loader.source_to_code('') |
| 470 | self.assertEqual(code.co_filename, '<string>') |
| 471 | |
| 472 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 473 | (Frozen_ILSourceToCodeTests, |
| 474 | Source_ILSourceToCodeTests |
| 475 | ) = test_util.test_both(InspectLoaderSourceToCodeTests, |
| 476 | InspectLoaderSubclass=SPLIT_IL) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 477 | |
| 478 | |
| 479 | class InspectLoaderGetCodeTests: |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 480 | |
| 481 | def test_get_code(self): |
| 482 | # Test success. |
Brett Cannon | ef88802 | 2013-06-15 18:39:21 -0400 | [diff] [blame] | 483 | module = types.ModuleType('blah') |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 484 | with mock.patch.object(self.InspectLoaderSubclass, 'get_source') as mocked: |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 485 | mocked.return_value = 'attr = 42' |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 486 | loader = self.InspectLoaderSubclass() |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 487 | code = loader.get_code('blah') |
| 488 | exec(code, module.__dict__) |
| 489 | self.assertEqual(module.attr, 42) |
| 490 | |
| 491 | def test_get_code_source_is_None(self): |
| 492 | # If get_source() is None then this should be None. |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 493 | with mock.patch.object(self.InspectLoaderSubclass, 'get_source') as mocked: |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 494 | mocked.return_value = None |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 495 | loader = self.InspectLoaderSubclass() |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 496 | code = loader.get_code('blah') |
| 497 | self.assertIsNone(code) |
| 498 | |
| 499 | def test_get_code_source_not_found(self): |
| 500 | # If there is no source then there is no code object. |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 501 | loader = self.InspectLoaderSubclass() |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 502 | with self.assertRaises(ImportError): |
| 503 | loader.get_code('blah') |
| 504 | |
| 505 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 506 | (Frozen_ILGetCodeTests, |
| 507 | Source_ILGetCodeTests |
| 508 | ) = test_util.test_both(InspectLoaderGetCodeTests, |
| 509 | InspectLoaderSubclass=SPLIT_IL) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 510 | |
| 511 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 512 | class InspectLoaderLoadModuleTests: |
Brett Cannon | 0dbb4c7 | 2013-05-31 18:56:47 -0400 | [diff] [blame] | 513 | |
| 514 | """Test InspectLoader.load_module().""" |
| 515 | |
| 516 | module_name = 'blah' |
| 517 | |
| 518 | def setUp(self): |
| 519 | support.unload(self.module_name) |
| 520 | self.addCleanup(support.unload, self.module_name) |
| 521 | |
| 522 | def mock_get_code(self): |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 523 | return mock.patch.object(self.InspectLoaderSubclass, 'get_code') |
Brett Cannon | 0dbb4c7 | 2013-05-31 18:56:47 -0400 | [diff] [blame] | 524 | |
| 525 | def test_get_code_ImportError(self): |
| 526 | # If get_code() raises ImportError, it should propagate. |
| 527 | with self.mock_get_code() as mocked_get_code: |
| 528 | mocked_get_code.side_effect = ImportError |
| 529 | with self.assertRaises(ImportError): |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 530 | loader = self.InspectLoaderSubclass() |
Eric Snow | 1500d49 | 2014-01-06 20:49:04 -0700 | [diff] [blame] | 531 | with warnings.catch_warnings(): |
| 532 | warnings.simplefilter('ignore', DeprecationWarning) |
| 533 | loader.load_module(self.module_name) |
Brett Cannon | 0dbb4c7 | 2013-05-31 18:56:47 -0400 | [diff] [blame] | 534 | |
| 535 | def test_get_code_None(self): |
| 536 | # If get_code() returns None, raise ImportError. |
| 537 | with self.mock_get_code() as mocked_get_code: |
| 538 | mocked_get_code.return_value = None |
| 539 | with self.assertRaises(ImportError): |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 540 | loader = self.InspectLoaderSubclass() |
Brett Cannon | 0dbb4c7 | 2013-05-31 18:56:47 -0400 | [diff] [blame] | 541 | loader.load_module(self.module_name) |
| 542 | |
| 543 | def test_module_returned(self): |
| 544 | # The loaded module should be returned. |
| 545 | code = compile('attr = 42', '<string>', 'exec') |
| 546 | with self.mock_get_code() as mocked_get_code: |
| 547 | mocked_get_code.return_value = code |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 548 | loader = self.InspectLoaderSubclass() |
Brett Cannon | 0dbb4c7 | 2013-05-31 18:56:47 -0400 | [diff] [blame] | 549 | module = loader.load_module(self.module_name) |
| 550 | self.assertEqual(module, sys.modules[self.module_name]) |
| 551 | |
| 552 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 553 | (Frozen_ILLoadModuleTests, |
| 554 | Source_ILLoadModuleTests |
| 555 | ) = test_util.test_both(InspectLoaderLoadModuleTests, |
| 556 | InspectLoaderSubclass=SPLIT_IL) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 557 | |
| 558 | |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 559 | ##### ExecutionLoader concrete methods ######################################### |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 560 | class ExecutionLoaderGetCodeTests: |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 561 | |
| 562 | def mock_methods(self, *, get_source=False, get_filename=False): |
| 563 | source_mock_context, filename_mock_context = None, None |
| 564 | if get_source: |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 565 | source_mock_context = mock.patch.object(self.ExecutionLoaderSubclass, |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 566 | 'get_source') |
| 567 | if get_filename: |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 568 | filename_mock_context = mock.patch.object(self.ExecutionLoaderSubclass, |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 569 | 'get_filename') |
| 570 | return source_mock_context, filename_mock_context |
| 571 | |
| 572 | def test_get_code(self): |
| 573 | path = 'blah.py' |
| 574 | source_mock_context, filename_mock_context = self.mock_methods( |
| 575 | get_source=True, get_filename=True) |
| 576 | with source_mock_context as source_mock, filename_mock_context as name_mock: |
| 577 | source_mock.return_value = 'attr = 42' |
| 578 | name_mock.return_value = path |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 579 | loader = self.ExecutionLoaderSubclass() |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 580 | code = loader.get_code('blah') |
| 581 | self.assertEqual(code.co_filename, path) |
Brett Cannon | ef88802 | 2013-06-15 18:39:21 -0400 | [diff] [blame] | 582 | module = types.ModuleType('blah') |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 583 | exec(code, module.__dict__) |
| 584 | self.assertEqual(module.attr, 42) |
| 585 | |
| 586 | def test_get_code_source_is_None(self): |
| 587 | # If get_source() is None then this should be None. |
| 588 | source_mock_context, _ = self.mock_methods(get_source=True) |
| 589 | with source_mock_context as mocked: |
| 590 | mocked.return_value = None |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 591 | loader = self.ExecutionLoaderSubclass() |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 592 | code = loader.get_code('blah') |
| 593 | self.assertIsNone(code) |
| 594 | |
| 595 | def test_get_code_source_not_found(self): |
| 596 | # If there is no source then there is no code object. |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 597 | loader = self.ExecutionLoaderSubclass() |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 598 | with self.assertRaises(ImportError): |
| 599 | loader.get_code('blah') |
| 600 | |
| 601 | def test_get_code_no_path(self): |
| 602 | # If get_filename() raises ImportError then simply skip setting the path |
| 603 | # on the code object. |
| 604 | source_mock_context, filename_mock_context = self.mock_methods( |
| 605 | get_source=True, get_filename=True) |
| 606 | with source_mock_context as source_mock, filename_mock_context as name_mock: |
| 607 | source_mock.return_value = 'attr = 42' |
| 608 | name_mock.side_effect = ImportError |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 609 | loader = self.ExecutionLoaderSubclass() |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 610 | code = loader.get_code('blah') |
| 611 | self.assertEqual(code.co_filename, '<string>') |
Brett Cannon | ef88802 | 2013-06-15 18:39:21 -0400 | [diff] [blame] | 612 | module = types.ModuleType('blah') |
Brett Cannon | 3b62ca8 | 2013-05-27 21:11:04 -0400 | [diff] [blame] | 613 | exec(code, module.__dict__) |
| 614 | self.assertEqual(module.attr, 42) |
| 615 | |
| 616 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 617 | (Frozen_ELGetCodeTests, |
| 618 | Source_ELGetCodeTests |
| 619 | ) = test_util.test_both(ExecutionLoaderGetCodeTests, |
| 620 | ExecutionLoaderSubclass=SPLIT_EL) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 621 | |
| 622 | |
Brett Cannon | 9ffe85e | 2013-05-26 16:45:10 -0400 | [diff] [blame] | 623 | ##### SourceLoader concrete methods ############################################ |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 624 | class SourceOnlyLoader: |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 625 | |
| 626 | # Globals that should be defined for all modules. |
| 627 | source = (b"_ = '::'.join([__name__, __file__, __cached__, __package__, " |
| 628 | b"repr(__loader__)])") |
| 629 | |
| 630 | def __init__(self, path): |
| 631 | self.path = path |
| 632 | |
| 633 | def get_data(self, path): |
| 634 | if path != self.path: |
| 635 | raise IOError |
| 636 | return self.source |
| 637 | |
| 638 | def get_filename(self, fullname): |
| 639 | return self.path |
| 640 | |
| 641 | def module_repr(self, module): |
| 642 | return '<module>' |
| 643 | |
| 644 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 645 | SPLIT_SOL = make_abc_subclasses(SourceOnlyLoader, 'SourceLoader') |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 646 | |
| 647 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 648 | class SourceLoader(SourceOnlyLoader): |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 649 | |
| 650 | source_mtime = 1 |
| 651 | |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 652 | def __init__(self, path, magic=None): |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 653 | super().__init__(path) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 654 | self.bytecode_path = self.util.cache_from_source(self.path) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 655 | self.source_size = len(self.source) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 656 | if magic is None: |
| 657 | magic = self.util.MAGIC_NUMBER |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 658 | data = bytearray(magic) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 659 | data.extend(self.init._w_long(self.source_mtime)) |
| 660 | data.extend(self.init._w_long(self.source_size)) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 661 | code_object = compile(self.source, self.path, 'exec', |
| 662 | dont_inherit=True) |
| 663 | data.extend(marshal.dumps(code_object)) |
| 664 | self.bytecode = bytes(data) |
| 665 | self.written = {} |
| 666 | |
| 667 | def get_data(self, path): |
| 668 | if path == self.path: |
| 669 | return super().get_data(path) |
| 670 | elif path == self.bytecode_path: |
| 671 | return self.bytecode |
| 672 | else: |
| 673 | raise OSError |
| 674 | |
| 675 | def path_stats(self, path): |
| 676 | if path != self.path: |
| 677 | raise IOError |
| 678 | return {'mtime': self.source_mtime, 'size': self.source_size} |
| 679 | |
| 680 | def set_data(self, path, data): |
| 681 | self.written[path] = bytes(data) |
| 682 | return path == self.bytecode_path |
| 683 | |
| 684 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 685 | SPLIT_SL = make_abc_subclasses(SourceLoader, util=util, init=init) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 686 | |
| 687 | |
| 688 | class SourceLoaderTestHarness: |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 689 | |
| 690 | def setUp(self, *, is_package=True, **kwargs): |
| 691 | self.package = 'pkg' |
| 692 | if is_package: |
| 693 | self.path = os.path.join(self.package, '__init__.py') |
| 694 | self.name = self.package |
| 695 | else: |
| 696 | module_name = 'mod' |
| 697 | self.path = os.path.join(self.package, '.'.join(['mod', 'py'])) |
| 698 | self.name = '.'.join([self.package, module_name]) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 699 | self.cached = self.util.cache_from_source(self.path) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 700 | self.loader = self.loader_mock(self.path, **kwargs) |
| 701 | |
| 702 | def verify_module(self, module): |
| 703 | self.assertEqual(module.__name__, self.name) |
| 704 | self.assertEqual(module.__file__, self.path) |
| 705 | self.assertEqual(module.__cached__, self.cached) |
| 706 | self.assertEqual(module.__package__, self.package) |
| 707 | self.assertEqual(module.__loader__, self.loader) |
| 708 | values = module._.split('::') |
| 709 | self.assertEqual(values[0], self.name) |
| 710 | self.assertEqual(values[1], self.path) |
| 711 | self.assertEqual(values[2], self.cached) |
| 712 | self.assertEqual(values[3], self.package) |
| 713 | self.assertEqual(values[4], repr(self.loader)) |
| 714 | |
| 715 | def verify_code(self, code_object): |
Brett Cannon | ef88802 | 2013-06-15 18:39:21 -0400 | [diff] [blame] | 716 | module = types.ModuleType(self.name) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 717 | module.__file__ = self.path |
| 718 | module.__cached__ = self.cached |
| 719 | module.__package__ = self.package |
| 720 | module.__loader__ = self.loader |
| 721 | module.__path__ = [] |
| 722 | exec(code_object, module.__dict__) |
| 723 | self.verify_module(module) |
| 724 | |
| 725 | |
| 726 | class SourceOnlyLoaderTests(SourceLoaderTestHarness): |
| 727 | |
| 728 | """Test importlib.abc.SourceLoader for source-only loading. |
| 729 | |
| 730 | Reload testing is subsumed by the tests for |
| 731 | importlib.util.module_for_loader. |
| 732 | |
| 733 | """ |
| 734 | |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 735 | def test_get_source(self): |
| 736 | # Verify the source code is returned as a string. |
| 737 | # If an OSError is raised by get_data then raise ImportError. |
| 738 | expected_source = self.loader.source.decode('utf-8') |
| 739 | self.assertEqual(self.loader.get_source(self.name), expected_source) |
| 740 | def raise_OSError(path): |
| 741 | raise OSError |
| 742 | self.loader.get_data = raise_OSError |
| 743 | with self.assertRaises(ImportError) as cm: |
| 744 | self.loader.get_source(self.name) |
| 745 | self.assertEqual(cm.exception.name, self.name) |
| 746 | |
| 747 | def test_is_package(self): |
| 748 | # Properly detect when loading a package. |
| 749 | self.setUp(is_package=False) |
| 750 | self.assertFalse(self.loader.is_package(self.name)) |
| 751 | self.setUp(is_package=True) |
| 752 | self.assertTrue(self.loader.is_package(self.name)) |
| 753 | self.assertFalse(self.loader.is_package(self.name + '.__init__')) |
| 754 | |
| 755 | def test_get_code(self): |
| 756 | # Verify the code object is created. |
| 757 | code_object = self.loader.get_code(self.name) |
| 758 | self.verify_code(code_object) |
| 759 | |
| 760 | def test_source_to_code(self): |
| 761 | # Verify the compiled code object. |
| 762 | code = self.loader.source_to_code(self.loader.source, self.path) |
| 763 | self.verify_code(code) |
| 764 | |
| 765 | def test_load_module(self): |
| 766 | # Loading a module should set __name__, __loader__, __package__, |
| 767 | # __path__ (for packages), __file__, and __cached__. |
| 768 | # The module should also be put into sys.modules. |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 769 | with test_util.uncache(self.name): |
Eric Snow | 1500d49 | 2014-01-06 20:49:04 -0700 | [diff] [blame] | 770 | with warnings.catch_warnings(): |
| 771 | warnings.simplefilter('ignore', DeprecationWarning) |
| 772 | module = self.loader.load_module(self.name) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 773 | self.verify_module(module) |
| 774 | self.assertEqual(module.__path__, [os.path.dirname(self.path)]) |
| 775 | self.assertIn(self.name, sys.modules) |
| 776 | |
| 777 | def test_package_settings(self): |
| 778 | # __package__ needs to be set, while __path__ is set on if the module |
| 779 | # is a package. |
| 780 | # Testing the values for a package are covered by test_load_module. |
| 781 | self.setUp(is_package=False) |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 782 | with test_util.uncache(self.name): |
Eric Snow | 1500d49 | 2014-01-06 20:49:04 -0700 | [diff] [blame] | 783 | with warnings.catch_warnings(): |
| 784 | warnings.simplefilter('ignore', DeprecationWarning) |
| 785 | module = self.loader.load_module(self.name) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 786 | self.verify_module(module) |
Serhiy Storchaka | 344f831 | 2014-07-07 14:08:19 +0300 | [diff] [blame] | 787 | self.assertFalse(hasattr(module, '__path__')) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 788 | |
| 789 | def test_get_source_encoding(self): |
| 790 | # Source is considered encoded in UTF-8 by default unless otherwise |
| 791 | # specified by an encoding line. |
| 792 | source = "_ = 'ü'" |
| 793 | self.loader.source = source.encode('utf-8') |
| 794 | returned_source = self.loader.get_source(self.name) |
| 795 | self.assertEqual(returned_source, source) |
| 796 | source = "# coding: latin-1\n_ = ü" |
| 797 | self.loader.source = source.encode('latin-1') |
| 798 | returned_source = self.loader.get_source(self.name) |
| 799 | self.assertEqual(returned_source, source) |
| 800 | |
| 801 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 802 | (Frozen_SourceOnlyLoaderTests, |
| 803 | Source_SourceOnlyLoaderTests |
| 804 | ) = test_util.test_both(SourceOnlyLoaderTests, util=util, |
| 805 | loader_mock=SPLIT_SOL) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 806 | |
| 807 | |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 808 | @unittest.skipIf(sys.dont_write_bytecode, "sys.dont_write_bytecode is true") |
| 809 | class SourceLoaderBytecodeTests(SourceLoaderTestHarness): |
| 810 | |
| 811 | """Test importlib.abc.SourceLoader's use of bytecode. |
| 812 | |
| 813 | Source-only testing handled by SourceOnlyLoaderTests. |
| 814 | |
| 815 | """ |
| 816 | |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 817 | def verify_code(self, code_object, *, bytecode_written=False): |
| 818 | super().verify_code(code_object) |
| 819 | if bytecode_written: |
| 820 | self.assertIn(self.cached, self.loader.written) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 821 | data = bytearray(self.util.MAGIC_NUMBER) |
| 822 | data.extend(self.init._w_long(self.loader.source_mtime)) |
| 823 | data.extend(self.init._w_long(self.loader.source_size)) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 824 | data.extend(marshal.dumps(code_object)) |
| 825 | self.assertEqual(self.loader.written[self.cached], bytes(data)) |
| 826 | |
| 827 | def test_code_with_everything(self): |
| 828 | # When everything should work. |
| 829 | code_object = self.loader.get_code(self.name) |
| 830 | self.verify_code(code_object) |
| 831 | |
| 832 | def test_no_bytecode(self): |
| 833 | # If no bytecode exists then move on to the source. |
| 834 | self.loader.bytecode_path = "<does not exist>" |
| 835 | # Sanity check |
| 836 | with self.assertRaises(OSError): |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 837 | bytecode_path = self.util.cache_from_source(self.path) |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 838 | self.loader.get_data(bytecode_path) |
| 839 | code_object = self.loader.get_code(self.name) |
| 840 | self.verify_code(code_object, bytecode_written=True) |
| 841 | |
| 842 | def test_code_bad_timestamp(self): |
| 843 | # Bytecode is only used when the timestamp matches the source EXACTLY. |
| 844 | for source_mtime in (0, 2): |
| 845 | assert source_mtime != self.loader.source_mtime |
| 846 | original = self.loader.source_mtime |
| 847 | self.loader.source_mtime = source_mtime |
| 848 | # If bytecode is used then EOFError would be raised by marshal. |
| 849 | self.loader.bytecode = self.loader.bytecode[8:] |
| 850 | code_object = self.loader.get_code(self.name) |
| 851 | self.verify_code(code_object, bytecode_written=True) |
| 852 | self.loader.source_mtime = original |
| 853 | |
| 854 | def test_code_bad_magic(self): |
| 855 | # Skip over bytecode with a bad magic number. |
| 856 | self.setUp(magic=b'0000') |
| 857 | # If bytecode is used then EOFError would be raised by marshal. |
| 858 | self.loader.bytecode = self.loader.bytecode[8:] |
| 859 | code_object = self.loader.get_code(self.name) |
| 860 | self.verify_code(code_object, bytecode_written=True) |
| 861 | |
| 862 | def test_dont_write_bytecode(self): |
| 863 | # Bytecode is not written if sys.dont_write_bytecode is true. |
| 864 | # Can assume it is false already thanks to the skipIf class decorator. |
| 865 | try: |
| 866 | sys.dont_write_bytecode = True |
| 867 | self.loader.bytecode_path = "<does not exist>" |
| 868 | code_object = self.loader.get_code(self.name) |
| 869 | self.assertNotIn(self.cached, self.loader.written) |
| 870 | finally: |
| 871 | sys.dont_write_bytecode = False |
| 872 | |
| 873 | def test_no_set_data(self): |
| 874 | # If set_data is not defined, one can still read bytecode. |
| 875 | self.setUp(magic=b'0000') |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 876 | original_set_data = self.loader.__class__.mro()[1].set_data |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 877 | try: |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 878 | del self.loader.__class__.mro()[1].set_data |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 879 | code_object = self.loader.get_code(self.name) |
| 880 | self.verify_code(code_object) |
| 881 | finally: |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 882 | self.loader.__class__.mro()[1].set_data = original_set_data |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 883 | |
| 884 | def test_set_data_raises_exceptions(self): |
| 885 | # Raising NotImplementedError or OSError is okay for set_data. |
| 886 | def raise_exception(exc): |
| 887 | def closure(*args, **kwargs): |
| 888 | raise exc |
| 889 | return closure |
| 890 | |
| 891 | self.setUp(magic=b'0000') |
| 892 | self.loader.set_data = raise_exception(NotImplementedError) |
| 893 | code_object = self.loader.get_code(self.name) |
| 894 | self.verify_code(code_object) |
| 895 | |
| 896 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 897 | (Frozen_SLBytecodeTests, |
| 898 | SourceSLBytecodeTests |
| 899 | ) = test_util.test_both(SourceLoaderBytecodeTests, init=init, util=util, |
| 900 | loader_mock=SPLIT_SL) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 901 | |
| 902 | |
| 903 | class SourceLoaderGetSourceTests: |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 904 | |
| 905 | """Tests for importlib.abc.SourceLoader.get_source().""" |
| 906 | |
| 907 | def test_default_encoding(self): |
| 908 | # Should have no problems with UTF-8 text. |
| 909 | name = 'mod' |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 910 | mock = self.SourceOnlyLoaderMock('mod.file') |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 911 | source = 'x = "ü"' |
| 912 | mock.source = source.encode('utf-8') |
| 913 | returned_source = mock.get_source(name) |
| 914 | self.assertEqual(returned_source, source) |
| 915 | |
| 916 | def test_decoded_source(self): |
| 917 | # Decoding should work. |
| 918 | name = 'mod' |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 919 | mock = self.SourceOnlyLoaderMock("mod.file") |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 920 | source = "# coding: Latin-1\nx='ü'" |
| 921 | assert source.encode('latin-1') != source.encode('utf-8') |
| 922 | mock.source = source.encode('latin-1') |
| 923 | returned_source = mock.get_source(name) |
| 924 | self.assertEqual(returned_source, source) |
| 925 | |
| 926 | def test_universal_newlines(self): |
| 927 | # PEP 302 says universal newlines should be used. |
| 928 | name = 'mod' |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 929 | mock = self.SourceOnlyLoaderMock('mod.file') |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 930 | source = "x = 42\r\ny = -13\r\n" |
| 931 | mock.source = source.encode('utf-8') |
| 932 | expect = io.IncrementalNewlineDecoder(None, True).decode(source) |
| 933 | self.assertEqual(mock.get_source(name), expect) |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 934 | |
| 935 | |
Eric Snow | 3497c0b | 2014-05-16 11:40:40 -0600 | [diff] [blame] | 936 | (Frozen_SourceOnlyLoaderGetSourceTests, |
| 937 | Source_SourceOnlyLoaderGetSourceTests |
| 938 | ) = test_util.test_both(SourceLoaderGetSourceTests, |
| 939 | SourceOnlyLoaderMock=SPLIT_SOL) |
Brett Cannon | 3ad327e | 2013-10-04 14:47:14 -0400 | [diff] [blame] | 940 | |
| 941 | |
Brett Cannon | 2a922ed | 2009-03-09 03:35:50 +0000 | [diff] [blame] | 942 | if __name__ == '__main__': |
Brett Cannon | 100883f | 2013-04-09 16:59:39 -0400 | [diff] [blame] | 943 | unittest.main() |