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