~ubuntu-branches/ubuntu/trusty/python3.4/trusty-proposed

« back to all changes in this revision

Viewing changes to Lib/test/test_namespace_pkgs.py

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-11-25 09:44:27 UTC
  • Revision ID: package-import@ubuntu.com-20131125094427-lzxj8ap5w01lmo7f
Tags: upstream-3.4~b1
ImportĀ upstreamĀ versionĀ 3.4~b1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import contextlib
 
2
import importlib.abc
 
3
import importlib.machinery
 
4
import os
 
5
import sys
 
6
import types
 
7
import unittest
 
8
 
 
9
from test.test_importlib import util
 
10
from test.support import run_unittest
 
11
 
 
12
# needed tests:
 
13
#
 
14
# need to test when nested, so that the top-level path isn't sys.path
 
15
# need to test dynamic path detection, both at top-level and nested
 
16
# with dynamic path, check when a loader is returned on path reload (that is,
 
17
#  trying to switch from a namespace package to a regular package)
 
18
 
 
19
 
 
20
@contextlib.contextmanager
 
21
def sys_modules_context():
 
22
    """
 
23
    Make sure sys.modules is the same object and has the same content
 
24
    when exiting the context as when entering.
 
25
 
 
26
    Similar to importlib.test.util.uncache, but doesn't require explicit
 
27
    names.
 
28
    """
 
29
    sys_modules_saved = sys.modules
 
30
    sys_modules_copy = sys.modules.copy()
 
31
    try:
 
32
        yield
 
33
    finally:
 
34
        sys.modules = sys_modules_saved
 
35
        sys.modules.clear()
 
36
        sys.modules.update(sys_modules_copy)
 
37
 
 
38
 
 
39
@contextlib.contextmanager
 
40
def namespace_tree_context(**kwargs):
 
41
    """
 
42
    Save import state and sys.modules cache and restore it on exit.
 
43
    Typical usage:
 
44
 
 
45
    >>> with namespace_tree_context(path=['/tmp/xxyy/portion1',
 
46
    ...         '/tmp/xxyy/portion2']):
 
47
    ...     pass
 
48
    """
 
49
    # use default meta_path and path_hooks unless specified otherwise
 
50
    kwargs.setdefault('meta_path', sys.meta_path)
 
51
    kwargs.setdefault('path_hooks', sys.path_hooks)
 
52
    import_context = util.import_state(**kwargs)
 
53
    with import_context, sys_modules_context():
 
54
        yield
 
55
 
 
56
class NamespacePackageTest(unittest.TestCase):
 
57
    """
 
58
    Subclasses should define self.root and self.paths (under that root)
 
59
    to be added to sys.path.
 
60
    """
 
61
    root = os.path.join(os.path.dirname(__file__), 'namespace_pkgs')
 
62
 
 
63
    def setUp(self):
 
64
        self.resolved_paths = [
 
65
            os.path.join(self.root, path) for path in self.paths
 
66
        ]
 
67
        self.ctx = namespace_tree_context(path=self.resolved_paths)
 
68
        self.ctx.__enter__()
 
69
 
 
70
    def tearDown(self):
 
71
        # TODO: will we ever want to pass exc_info to __exit__?
 
72
        self.ctx.__exit__(None, None, None)
 
73
 
 
74
class SingleNamespacePackage(NamespacePackageTest):
 
75
    paths = ['portion1']
 
76
 
 
77
    def test_simple_package(self):
 
78
        import foo.one
 
79
        self.assertEqual(foo.one.attr, 'portion1 foo one')
 
80
 
 
81
    def test_cant_import_other(self):
 
82
        with self.assertRaises(ImportError):
 
83
            import foo.two
 
84
 
 
85
    def test_module_repr(self):
 
86
        import foo.one
 
87
        self.assertEqual(repr(foo), "<module 'foo' (namespace)>")
 
88
 
 
89
 
 
90
class DynamicPatheNamespacePackage(NamespacePackageTest):
 
91
    paths = ['portion1']
 
92
 
 
93
    def test_dynamic_path(self):
 
94
        # Make sure only 'foo.one' can be imported
 
95
        import foo.one
 
96
        self.assertEqual(foo.one.attr, 'portion1 foo one')
 
97
 
 
98
        with self.assertRaises(ImportError):
 
99
            import foo.two
 
100
 
 
101
        # Now modify sys.path
 
102
        sys.path.append(os.path.join(self.root, 'portion2'))
 
103
 
 
104
        # And make sure foo.two is now importable
 
105
        import foo.two
 
106
        self.assertEqual(foo.two.attr, 'portion2 foo two')
 
107
 
 
108
 
 
109
class CombinedNamespacePackages(NamespacePackageTest):
 
110
    paths = ['both_portions']
 
111
 
 
112
    def test_imports(self):
 
113
        import foo.one
 
114
        import foo.two
 
115
        self.assertEqual(foo.one.attr, 'both_portions foo one')
 
116
        self.assertEqual(foo.two.attr, 'both_portions foo two')
 
117
 
 
118
 
 
119
class SeparatedNamespacePackages(NamespacePackageTest):
 
120
    paths = ['portion1', 'portion2']
 
121
 
 
122
    def test_imports(self):
 
123
        import foo.one
 
124
        import foo.two
 
125
        self.assertEqual(foo.one.attr, 'portion1 foo one')
 
126
        self.assertEqual(foo.two.attr, 'portion2 foo two')
 
127
 
 
128
 
 
129
class SeparatedOverlappingNamespacePackages(NamespacePackageTest):
 
130
    paths = ['portion1', 'both_portions']
 
131
 
 
132
    def test_first_path_wins(self):
 
133
        import foo.one
 
134
        import foo.two
 
135
        self.assertEqual(foo.one.attr, 'portion1 foo one')
 
136
        self.assertEqual(foo.two.attr, 'both_portions foo two')
 
137
 
 
138
    def test_first_path_wins_again(self):
 
139
        sys.path.reverse()
 
140
        import foo.one
 
141
        import foo.two
 
142
        self.assertEqual(foo.one.attr, 'both_portions foo one')
 
143
        self.assertEqual(foo.two.attr, 'both_portions foo two')
 
144
 
 
145
    def test_first_path_wins_importing_second_first(self):
 
146
        import foo.two
 
147
        import foo.one
 
148
        self.assertEqual(foo.one.attr, 'portion1 foo one')
 
149
        self.assertEqual(foo.two.attr, 'both_portions foo two')
 
150
 
 
151
 
 
152
class SingleZipNamespacePackage(NamespacePackageTest):
 
153
    paths = ['top_level_portion1.zip']
 
154
 
 
155
    def test_simple_package(self):
 
156
        import foo.one
 
157
        self.assertEqual(foo.one.attr, 'portion1 foo one')
 
158
 
 
159
    def test_cant_import_other(self):
 
160
        with self.assertRaises(ImportError):
 
161
            import foo.two
 
162
 
 
163
 
 
164
class SeparatedZipNamespacePackages(NamespacePackageTest):
 
165
    paths = ['top_level_portion1.zip', 'portion2']
 
166
 
 
167
    def test_imports(self):
 
168
        import foo.one
 
169
        import foo.two
 
170
        self.assertEqual(foo.one.attr, 'portion1 foo one')
 
171
        self.assertEqual(foo.two.attr, 'portion2 foo two')
 
172
        self.assertIn('top_level_portion1.zip', foo.one.__file__)
 
173
        self.assertNotIn('.zip', foo.two.__file__)
 
174
 
 
175
 
 
176
class SingleNestedZipNamespacePackage(NamespacePackageTest):
 
177
    paths = ['nested_portion1.zip/nested_portion1']
 
178
 
 
179
    def test_simple_package(self):
 
180
        import foo.one
 
181
        self.assertEqual(foo.one.attr, 'portion1 foo one')
 
182
 
 
183
    def test_cant_import_other(self):
 
184
        with self.assertRaises(ImportError):
 
185
            import foo.two
 
186
 
 
187
 
 
188
class SeparatedNestedZipNamespacePackages(NamespacePackageTest):
 
189
    paths = ['nested_portion1.zip/nested_portion1', 'portion2']
 
190
 
 
191
    def test_imports(self):
 
192
        import foo.one
 
193
        import foo.two
 
194
        self.assertEqual(foo.one.attr, 'portion1 foo one')
 
195
        self.assertEqual(foo.two.attr, 'portion2 foo two')
 
196
        fn = os.path.join('nested_portion1.zip', 'nested_portion1')
 
197
        self.assertIn(fn, foo.one.__file__)
 
198
        self.assertNotIn('.zip', foo.two.__file__)
 
199
 
 
200
 
 
201
class LegacySupport(NamespacePackageTest):
 
202
    paths = ['not_a_namespace_pkg', 'portion1', 'portion2', 'both_portions']
 
203
 
 
204
    def test_non_namespace_package_takes_precedence(self):
 
205
        import foo.one
 
206
        with self.assertRaises(ImportError):
 
207
            import foo.two
 
208
        self.assertIn('__init__', foo.__file__)
 
209
        self.assertNotIn('namespace', str(foo.__loader__).lower())
 
210
 
 
211
 
 
212
class DynamicPathCalculation(NamespacePackageTest):
 
213
    paths = ['project1', 'project2']
 
214
 
 
215
    def test_project3_fails(self):
 
216
        import parent.child.one
 
217
        self.assertEqual(len(parent.__path__), 2)
 
218
        self.assertEqual(len(parent.child.__path__), 2)
 
219
        import parent.child.two
 
220
        self.assertEqual(len(parent.__path__), 2)
 
221
        self.assertEqual(len(parent.child.__path__), 2)
 
222
 
 
223
        self.assertEqual(parent.child.one.attr, 'parent child one')
 
224
        self.assertEqual(parent.child.two.attr, 'parent child two')
 
225
 
 
226
        with self.assertRaises(ImportError):
 
227
            import parent.child.three
 
228
 
 
229
        self.assertEqual(len(parent.__path__), 2)
 
230
        self.assertEqual(len(parent.child.__path__), 2)
 
231
 
 
232
    def test_project3_succeeds(self):
 
233
        import parent.child.one
 
234
        self.assertEqual(len(parent.__path__), 2)
 
235
        self.assertEqual(len(parent.child.__path__), 2)
 
236
        import parent.child.two
 
237
        self.assertEqual(len(parent.__path__), 2)
 
238
        self.assertEqual(len(parent.child.__path__), 2)
 
239
 
 
240
        self.assertEqual(parent.child.one.attr, 'parent child one')
 
241
        self.assertEqual(parent.child.two.attr, 'parent child two')
 
242
 
 
243
        with self.assertRaises(ImportError):
 
244
            import parent.child.three
 
245
 
 
246
        # now add project3
 
247
        sys.path.append(os.path.join(self.root, 'project3'))
 
248
        import parent.child.three
 
249
 
 
250
        # the paths dynamically get longer, to include the new directories
 
251
        self.assertEqual(len(parent.__path__), 3)
 
252
        self.assertEqual(len(parent.child.__path__), 3)
 
253
 
 
254
        self.assertEqual(parent.child.three.attr, 'parent child three')
 
255
 
 
256
 
 
257
class ZipWithMissingDirectory(NamespacePackageTest):
 
258
    paths = ['missing_directory.zip']
 
259
 
 
260
    @unittest.expectedFailure
 
261
    def test_missing_directory(self):
 
262
        # This will fail because missing_directory.zip contains:
 
263
        #   Length      Date    Time    Name
 
264
        # ---------  ---------- -----   ----
 
265
        #        29  2012-05-03 18:13   foo/one.py
 
266
        #         0  2012-05-03 20:57   bar/
 
267
        #        38  2012-05-03 20:57   bar/two.py
 
268
        # ---------                     -------
 
269
        #        67                     3 files
 
270
 
 
271
        # Because there is no 'foo/', the zipimporter currently doesn't
 
272
        #  know that foo is a namespace package
 
273
 
 
274
        import foo.one
 
275
 
 
276
    def test_present_directory(self):
 
277
        # This succeeds because there is a "bar/" in the zip file
 
278
        import bar.two
 
279
        self.assertEqual(bar.two.attr, 'missing_directory foo two')
 
280
 
 
281
 
 
282
class ModuleAndNamespacePackageInSameDir(NamespacePackageTest):
 
283
    paths = ['module_and_namespace_package']
 
284
 
 
285
    def test_module_before_namespace_package(self):
 
286
        # Make sure we find the module in preference to the
 
287
        #  namespace package.
 
288
        import a_test
 
289
        self.assertEqual(a_test.attr, 'in module')
 
290
 
 
291
 
 
292
if __name__ == "__main__":
 
293
    unittest.main()