1"""PEP 366 ("Main module explicit relative imports") specifies the 2semantics for the __package__ attribute on modules. This attribute is 3used, when available, to detect which package a module belongs to (instead 4of using the typical __path__/__name__ test). 5 6""" 7import unittest 8import warnings 9from test.test_importlib import util 10 11 12class Using__package__: 13 14 """Use of __package__ supersedes the use of __name__/__path__ to calculate 15 what package a module belongs to. The basic algorithm is [__package__]:: 16 17 def resolve_name(name, package, level): 18 level -= 1 19 base = package.rsplit('.', level)[0] 20 return '{0}.{1}'.format(base, name) 21 22 But since there is no guarantee that __package__ has been set (or not been 23 set to None [None]), there has to be a way to calculate the attribute's value 24 [__name__]:: 25 26 def calc_package(caller_name, has___path__): 27 if has__path__: 28 return caller_name 29 else: 30 return caller_name.rsplit('.', 1)[0] 31 32 Then the normal algorithm for relative name imports can proceed as if 33 __package__ had been set. 34 35 """ 36 37 def import_module(self, globals_): 38 with self.mock_modules('pkg.__init__', 'pkg.fake') as importer: 39 with util.import_state(meta_path=[importer]): 40 self.__import__('pkg.fake') 41 module = self.__import__('', 42 globals=globals_, 43 fromlist=['attr'], level=2) 44 return module 45 46 def test_using___package__(self): 47 # [__package__] 48 module = self.import_module({'__package__': 'pkg.fake'}) 49 self.assertEqual(module.__name__, 'pkg') 50 51 def test_using___name__(self): 52 # [__name__] 53 with warnings.catch_warnings(): 54 warnings.simplefilter("ignore") 55 module = self.import_module({'__name__': 'pkg.fake', 56 '__path__': []}) 57 self.assertEqual(module.__name__, 'pkg') 58 59 def test_warn_when_using___name__(self): 60 with self.assertWarns(ImportWarning): 61 self.import_module({'__name__': 'pkg.fake', '__path__': []}) 62 63 def test_None_as___package__(self): 64 # [None] 65 with warnings.catch_warnings(): 66 warnings.simplefilter("ignore") 67 module = self.import_module({ 68 '__name__': 'pkg.fake', '__path__': [], '__package__': None }) 69 self.assertEqual(module.__name__, 'pkg') 70 71 def test_spec_fallback(self): 72 # If __package__ isn't defined, fall back on __spec__.parent. 73 module = self.import_module({'__spec__': FakeSpec('pkg.fake')}) 74 self.assertEqual(module.__name__, 'pkg') 75 76 def test_warn_when_package_and_spec_disagree(self): 77 # Raise an ImportWarning if __package__ != __spec__.parent. 78 with self.assertWarns(ImportWarning): 79 self.import_module({'__package__': 'pkg.fake', 80 '__spec__': FakeSpec('pkg.fakefake')}) 81 82 def test_bad__package__(self): 83 globals = {'__package__': '<not real>'} 84 with self.assertRaises(ModuleNotFoundError): 85 self.__import__('', globals, {}, ['relimport'], 1) 86 87 def test_bunk__package__(self): 88 globals = {'__package__': 42} 89 with self.assertRaises(TypeError): 90 self.__import__('', globals, {}, ['relimport'], 1) 91 92 93class FakeSpec: 94 def __init__(self, parent): 95 self.parent = parent 96 97 98class Using__package__PEP302(Using__package__): 99 mock_modules = util.mock_modules 100 101 def test_using___package__(self): 102 with warnings.catch_warnings(): 103 warnings.simplefilter("ignore", ImportWarning) 104 super().test_using___package__() 105 106 def test_spec_fallback(self): 107 with warnings.catch_warnings(): 108 warnings.simplefilter("ignore", ImportWarning) 109 super().test_spec_fallback() 110 111 112(Frozen_UsingPackagePEP302, 113 Source_UsingPackagePEP302 114 ) = util.test_both(Using__package__PEP302, __import__=util.__import__) 115 116 117class Using__package__PEP451(Using__package__): 118 mock_modules = util.mock_spec 119 120 121(Frozen_UsingPackagePEP451, 122 Source_UsingPackagePEP451 123 ) = util.test_both(Using__package__PEP451, __import__=util.__import__) 124 125 126class Setting__package__: 127 128 """Because __package__ is a new feature, it is not always set by a loader. 129 Import will set it as needed to help with the transition to relying on 130 __package__. 131 132 For a top-level module, __package__ is set to None [top-level]. For a 133 package __name__ is used for __package__ [package]. For submodules the 134 value is __name__.rsplit('.', 1)[0] [submodule]. 135 136 """ 137 138 __import__ = util.__import__['Source'] 139 140 # [top-level] 141 def test_top_level(self): 142 with self.mock_modules('top_level') as mock: 143 with util.import_state(meta_path=[mock]): 144 del mock['top_level'].__package__ 145 module = self.__import__('top_level') 146 self.assertEqual(module.__package__, '') 147 148 # [package] 149 def test_package(self): 150 with self.mock_modules('pkg.__init__') as mock: 151 with util.import_state(meta_path=[mock]): 152 del mock['pkg'].__package__ 153 module = self.__import__('pkg') 154 self.assertEqual(module.__package__, 'pkg') 155 156 # [submodule] 157 def test_submodule(self): 158 with self.mock_modules('pkg.__init__', 'pkg.mod') as mock: 159 with util.import_state(meta_path=[mock]): 160 del mock['pkg.mod'].__package__ 161 pkg = self.__import__('pkg.mod') 162 module = getattr(pkg, 'mod') 163 self.assertEqual(module.__package__, 'pkg') 164 165class Setting__package__PEP302(Setting__package__, unittest.TestCase): 166 mock_modules = util.mock_modules 167 168 def test_top_level(self): 169 with warnings.catch_warnings(): 170 warnings.simplefilter("ignore", ImportWarning) 171 super().test_top_level() 172 173 def test_package(self): 174 with warnings.catch_warnings(): 175 warnings.simplefilter("ignore", ImportWarning) 176 super().test_package() 177 178 def test_submodule(self): 179 with warnings.catch_warnings(): 180 warnings.simplefilter("ignore", ImportWarning) 181 super().test_submodule() 182 183class Setting__package__PEP451(Setting__package__, unittest.TestCase): 184 mock_modules = util.mock_spec 185 186 187if __name__ == '__main__': 188 unittest.main() 189