1# Test packages (dotted-name import)
2
3import sys
4import os
5import tempfile
6import textwrap
7import unittest
8from test import support
9
10
11# Helpers to create and destroy hierarchies.
12
13def cleanout(root):
14    names = os.listdir(root)
15    for name in names:
16        fullname = os.path.join(root, name)
17        if os.path.isdir(fullname) and not os.path.islink(fullname):
18            cleanout(fullname)
19        else:
20            os.remove(fullname)
21    os.rmdir(root)
22
23def fixdir(lst):
24    if "__builtins__" in lst:
25        lst.remove("__builtins__")
26    if "__initializing__" in lst:
27        lst.remove("__initializing__")
28    return lst
29
30
31# XXX Things to test
32#
33# import package without __init__
34# import package with __init__
35# __init__ importing submodule
36# __init__ importing global module
37# __init__ defining variables
38# submodule importing other submodule
39# submodule importing global module
40# submodule import submodule via global name
41# from package import submodule
42# from package import subpackage
43# from package import variable (defined in __init__)
44# from package import * (defined in __init__)
45
46
47class TestPkg(unittest.TestCase):
48
49    def setUp(self):
50        self.root = None
51        self.pkgname = None
52        self.syspath = list(sys.path)
53        self.modules_before = support.modules_setup()
54
55    def tearDown(self):
56        sys.path[:] = self.syspath
57        support.modules_cleanup(*self.modules_before)
58        if self.root: # Only clean if the test was actually run
59            cleanout(self.root)
60
61        # delete all modules concerning the tested hierarchy
62        if self.pkgname:
63            modules = [name for name in sys.modules
64                       if self.pkgname in name.split('.')]
65            for name in modules:
66                del sys.modules[name]
67
68    def run_code(self, code):
69        exec(textwrap.dedent(code), globals(), {"self": self})
70
71    def mkhier(self, descr):
72        root = tempfile.mkdtemp()
73        sys.path.insert(0, root)
74        if not os.path.isdir(root):
75            os.mkdir(root)
76        for name, contents in descr:
77            comps = name.split()
78            fullname = root
79            for c in comps:
80                fullname = os.path.join(fullname, c)
81            if contents is None:
82                os.mkdir(fullname)
83            else:
84                f = open(fullname, "w")
85                f.write(contents)
86                if contents and contents[-1] != '\n':
87                    f.write('\n')
88                f.close()
89        self.root = root
90        # package name is the name of the first item
91        self.pkgname = descr[0][0]
92
93    def test_1(self):
94        hier = [("t1", None), ("t1 __init__.py", "")]
95        self.mkhier(hier)
96        import t1
97
98    def test_2(self):
99        hier = [
100         ("t2", None),
101         ("t2 __init__.py", "'doc for t2'"),
102         ("t2 sub", None),
103         ("t2 sub __init__.py", ""),
104         ("t2 sub subsub", None),
105         ("t2 sub subsub __init__.py", "spam = 1"),
106        ]
107        self.mkhier(hier)
108
109        import t2.sub
110        import t2.sub.subsub
111        self.assertEqual(t2.__name__, "t2")
112        self.assertEqual(t2.sub.__name__, "t2.sub")
113        self.assertEqual(t2.sub.subsub.__name__, "t2.sub.subsub")
114
115        # This exec crap is needed because Py3k forbids 'import *' outside
116        # of module-scope and __import__() is insufficient for what we need.
117        s = """
118            import t2
119            from t2 import *
120            self.assertEqual(dir(), ['self', 'sub', 't2'])
121            """
122        self.run_code(s)
123
124        from t2 import sub
125        from t2.sub import subsub
126        from t2.sub.subsub import spam
127        self.assertEqual(sub.__name__, "t2.sub")
128        self.assertEqual(subsub.__name__, "t2.sub.subsub")
129        self.assertEqual(sub.subsub.__name__, "t2.sub.subsub")
130        for name in ['spam', 'sub', 'subsub', 't2']:
131            self.assertTrue(locals()["name"], "Failed to import %s" % name)
132
133        import t2.sub
134        import t2.sub.subsub
135        self.assertEqual(t2.__name__, "t2")
136        self.assertEqual(t2.sub.__name__, "t2.sub")
137        self.assertEqual(t2.sub.subsub.__name__, "t2.sub.subsub")
138
139        s = """
140            from t2 import *
141            self.assertTrue(dir(), ['self', 'sub'])
142            """
143        self.run_code(s)
144
145    def test_3(self):
146        hier = [
147                ("t3", None),
148                ("t3 __init__.py", ""),
149                ("t3 sub", None),
150                ("t3 sub __init__.py", ""),
151                ("t3 sub subsub", None),
152                ("t3 sub subsub __init__.py", "spam = 1"),
153               ]
154        self.mkhier(hier)
155
156        import t3.sub.subsub
157        self.assertEqual(t3.__name__, "t3")
158        self.assertEqual(t3.sub.__name__, "t3.sub")
159        self.assertEqual(t3.sub.subsub.__name__, "t3.sub.subsub")
160
161    def test_4(self):
162        hier = [
163        ("t4.py", "raise RuntimeError('Shouldnt load t4.py')"),
164        ("t4", None),
165        ("t4 __init__.py", ""),
166        ("t4 sub.py", "raise RuntimeError('Shouldnt load sub.py')"),
167        ("t4 sub", None),
168        ("t4 sub __init__.py", ""),
169        ("t4 sub subsub.py",
170         "raise RuntimeError('Shouldnt load subsub.py')"),
171        ("t4 sub subsub", None),
172        ("t4 sub subsub __init__.py", "spam = 1"),
173               ]
174        self.mkhier(hier)
175
176        s = """
177            from t4.sub.subsub import *
178            self.assertEqual(spam, 1)
179            """
180        self.run_code(s)
181
182    def test_5(self):
183        hier = [
184        ("t5", None),
185        ("t5 __init__.py", "import t5.foo"),
186        ("t5 string.py", "spam = 1"),
187        ("t5 foo.py",
188         "from . import string; assert string.spam == 1"),
189         ]
190        self.mkhier(hier)
191
192        import t5
193        s = """
194            from t5 import *
195            self.assertEqual(dir(), ['foo', 'self', 'string', 't5'])
196            """
197        self.run_code(s)
198
199        import t5
200        self.assertEqual(fixdir(dir(t5)),
201                         ['__cached__', '__doc__', '__file__', '__loader__',
202                          '__name__', '__package__', '__path__', '__spec__',
203                          'foo', 'string', 't5'])
204        self.assertEqual(fixdir(dir(t5.foo)),
205                         ['__cached__', '__doc__', '__file__', '__loader__',
206                          '__name__', '__package__', '__spec__', 'string'])
207        self.assertEqual(fixdir(dir(t5.string)),
208                         ['__cached__', '__doc__', '__file__', '__loader__',
209                          '__name__', '__package__', '__spec__', 'spam'])
210
211    def test_6(self):
212        hier = [
213                ("t6", None),
214                ("t6 __init__.py",
215                 "__all__ = ['spam', 'ham', 'eggs']"),
216                ("t6 spam.py", ""),
217                ("t6 ham.py", ""),
218                ("t6 eggs.py", ""),
219               ]
220        self.mkhier(hier)
221
222        import t6
223        self.assertEqual(fixdir(dir(t6)),
224                         ['__all__', '__cached__', '__doc__', '__file__',
225                          '__loader__', '__name__', '__package__', '__path__',
226                          '__spec__'])
227        s = """
228            import t6
229            from t6 import *
230            self.assertEqual(fixdir(dir(t6)),
231                             ['__all__', '__cached__', '__doc__', '__file__',
232                              '__loader__', '__name__', '__package__',
233                              '__path__', '__spec__', 'eggs', 'ham', 'spam'])
234            self.assertEqual(dir(), ['eggs', 'ham', 'self', 'spam', 't6'])
235            """
236        self.run_code(s)
237
238    def test_7(self):
239        hier = [
240                ("t7.py", ""),
241                ("t7", None),
242                ("t7 __init__.py", ""),
243                ("t7 sub.py",
244                 "raise RuntimeError('Shouldnt load sub.py')"),
245                ("t7 sub", None),
246                ("t7 sub __init__.py", ""),
247                ("t7 sub .py",
248                 "raise RuntimeError('Shouldnt load subsub.py')"),
249                ("t7 sub subsub", None),
250                ("t7 sub subsub __init__.py",
251                 "spam = 1"),
252               ]
253        self.mkhier(hier)
254
255
256        t7, sub, subsub = None, None, None
257        import t7 as tas
258        self.assertEqual(fixdir(dir(tas)),
259                         ['__cached__', '__doc__', '__file__', '__loader__',
260                          '__name__', '__package__', '__path__', '__spec__'])
261        self.assertFalse(t7)
262        from t7 import sub as subpar
263        self.assertEqual(fixdir(dir(subpar)),
264                         ['__cached__', '__doc__', '__file__', '__loader__',
265                          '__name__', '__package__', '__path__', '__spec__'])
266        self.assertFalse(t7)
267        self.assertFalse(sub)
268        from t7.sub import subsub as subsubsub
269        self.assertEqual(fixdir(dir(subsubsub)),
270                         ['__cached__', '__doc__', '__file__', '__loader__',
271                          '__name__', '__package__', '__path__', '__spec__',
272                          'spam'])
273        self.assertFalse(t7)
274        self.assertFalse(sub)
275        self.assertFalse(subsub)
276        from t7.sub.subsub import spam as ham
277        self.assertEqual(ham, 1)
278        self.assertFalse(t7)
279        self.assertFalse(sub)
280        self.assertFalse(subsub)
281
282    @unittest.skipIf(sys.flags.optimize >= 2,
283                     "Docstrings are omitted with -O2 and above")
284    def test_8(self):
285        hier = [
286                ("t8", None),
287                ("t8 __init__"+os.extsep+"py", "'doc for t8'"),
288               ]
289        self.mkhier(hier)
290
291        import t8
292        self.assertEqual(t8.__doc__, "doc for t8")
293
294if __name__ == "__main__":
295    unittest.main()
296