From f269cc6b145b94436fd34deb3550c36dfb3f11b0 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Sat, 29 Mar 2014 15:57:44 -0600 Subject: Issue #21097: Move test_namespace_pkgs into test_importlib. --- Lib/test/namespace_pkgs/both_portions/foo/one.py | 1 - Lib/test/namespace_pkgs/both_portions/foo/two.py | 1 - Lib/test/namespace_pkgs/missing_directory.zip | Bin 515 -> 0 bytes .../module_and_namespace_package/a_test.py | 1 - .../module_and_namespace_package/a_test/empty | 0 Lib/test/namespace_pkgs/nested_portion1.zip | Bin 556 -> 0 bytes .../not_a_namespace_pkg/foo/__init__.py | 0 .../namespace_pkgs/not_a_namespace_pkg/foo/one.py | 1 - Lib/test/namespace_pkgs/portion1/foo/one.py | 1 - Lib/test/namespace_pkgs/portion2/foo/two.py | 1 - .../namespace_pkgs/project1/parent/child/one.py | 1 - .../namespace_pkgs/project2/parent/child/two.py | 1 - .../namespace_pkgs/project3/parent/child/three.py | 1 - Lib/test/namespace_pkgs/top_level_portion1.zip | Bin 332 -> 0 bytes .../namespace_pkgs/both_portions/foo/one.py | 1 + .../namespace_pkgs/both_portions/foo/two.py | 1 + .../namespace_pkgs/missing_directory.zip | Bin 0 -> 515 bytes .../module_and_namespace_package/a_test.py | 1 + .../module_and_namespace_package/a_test/empty | 0 .../namespace_pkgs/nested_portion1.zip | Bin 0 -> 556 bytes .../not_a_namespace_pkg/foo/__init__.py | 0 .../namespace_pkgs/not_a_namespace_pkg/foo/one.py | 1 + .../namespace_pkgs/portion1/foo/one.py | 1 + .../namespace_pkgs/portion2/foo/two.py | 1 + .../namespace_pkgs/project1/parent/child/one.py | 1 + .../namespace_pkgs/project2/parent/child/two.py | 1 + .../namespace_pkgs/project3/parent/child/three.py | 1 + .../namespace_pkgs/top_level_portion1.zip | Bin 0 -> 332 bytes Lib/test/test_importlib/test_namespace_pkgs.py | 293 +++++++++++++++++++++ Lib/test/test_namespace_pkgs.py | 293 --------------------- Misc/NEWS | 2 + 31 files changed, 304 insertions(+), 302 deletions(-) delete mode 100644 Lib/test/namespace_pkgs/both_portions/foo/one.py delete mode 100644 Lib/test/namespace_pkgs/both_portions/foo/two.py delete mode 100644 Lib/test/namespace_pkgs/missing_directory.zip delete mode 100644 Lib/test/namespace_pkgs/module_and_namespace_package/a_test.py delete mode 100644 Lib/test/namespace_pkgs/module_and_namespace_package/a_test/empty delete mode 100644 Lib/test/namespace_pkgs/nested_portion1.zip delete mode 100644 Lib/test/namespace_pkgs/not_a_namespace_pkg/foo/__init__.py delete mode 100644 Lib/test/namespace_pkgs/not_a_namespace_pkg/foo/one.py delete mode 100644 Lib/test/namespace_pkgs/portion1/foo/one.py delete mode 100644 Lib/test/namespace_pkgs/portion2/foo/two.py delete mode 100644 Lib/test/namespace_pkgs/project1/parent/child/one.py delete mode 100644 Lib/test/namespace_pkgs/project2/parent/child/two.py delete mode 100644 Lib/test/namespace_pkgs/project3/parent/child/three.py delete mode 100644 Lib/test/namespace_pkgs/top_level_portion1.zip create mode 100644 Lib/test/test_importlib/namespace_pkgs/both_portions/foo/one.py create mode 100644 Lib/test/test_importlib/namespace_pkgs/both_portions/foo/two.py create mode 100644 Lib/test/test_importlib/namespace_pkgs/missing_directory.zip create mode 100644 Lib/test/test_importlib/namespace_pkgs/module_and_namespace_package/a_test.py create mode 100644 Lib/test/test_importlib/namespace_pkgs/module_and_namespace_package/a_test/empty create mode 100644 Lib/test/test_importlib/namespace_pkgs/nested_portion1.zip create mode 100644 Lib/test/test_importlib/namespace_pkgs/not_a_namespace_pkg/foo/__init__.py create mode 100644 Lib/test/test_importlib/namespace_pkgs/not_a_namespace_pkg/foo/one.py create mode 100644 Lib/test/test_importlib/namespace_pkgs/portion1/foo/one.py create mode 100644 Lib/test/test_importlib/namespace_pkgs/portion2/foo/two.py create mode 100644 Lib/test/test_importlib/namespace_pkgs/project1/parent/child/one.py create mode 100644 Lib/test/test_importlib/namespace_pkgs/project2/parent/child/two.py create mode 100644 Lib/test/test_importlib/namespace_pkgs/project3/parent/child/three.py create mode 100644 Lib/test/test_importlib/namespace_pkgs/top_level_portion1.zip create mode 100644 Lib/test/test_importlib/test_namespace_pkgs.py delete mode 100644 Lib/test/test_namespace_pkgs.py diff --git a/Lib/test/namespace_pkgs/both_portions/foo/one.py b/Lib/test/namespace_pkgs/both_portions/foo/one.py deleted file mode 100644 index 3080f6f..0000000 --- a/Lib/test/namespace_pkgs/both_portions/foo/one.py +++ /dev/null @@ -1 +0,0 @@ -attr = 'both_portions foo one' diff --git a/Lib/test/namespace_pkgs/both_portions/foo/two.py b/Lib/test/namespace_pkgs/both_portions/foo/two.py deleted file mode 100644 index 4131d3d..0000000 --- a/Lib/test/namespace_pkgs/both_portions/foo/two.py +++ /dev/null @@ -1 +0,0 @@ -attr = 'both_portions foo two' diff --git a/Lib/test/namespace_pkgs/missing_directory.zip b/Lib/test/namespace_pkgs/missing_directory.zip deleted file mode 100644 index 836a910..0000000 Binary files a/Lib/test/namespace_pkgs/missing_directory.zip and /dev/null differ diff --git a/Lib/test/namespace_pkgs/module_and_namespace_package/a_test.py b/Lib/test/namespace_pkgs/module_and_namespace_package/a_test.py deleted file mode 100644 index 43cbedb..0000000 --- a/Lib/test/namespace_pkgs/module_and_namespace_package/a_test.py +++ /dev/null @@ -1 +0,0 @@ -attr = 'in module' diff --git a/Lib/test/namespace_pkgs/module_and_namespace_package/a_test/empty b/Lib/test/namespace_pkgs/module_and_namespace_package/a_test/empty deleted file mode 100644 index e69de29..0000000 diff --git a/Lib/test/namespace_pkgs/nested_portion1.zip b/Lib/test/namespace_pkgs/nested_portion1.zip deleted file mode 100644 index 8d22406..0000000 Binary files a/Lib/test/namespace_pkgs/nested_portion1.zip and /dev/null differ diff --git a/Lib/test/namespace_pkgs/not_a_namespace_pkg/foo/__init__.py b/Lib/test/namespace_pkgs/not_a_namespace_pkg/foo/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/Lib/test/namespace_pkgs/not_a_namespace_pkg/foo/one.py b/Lib/test/namespace_pkgs/not_a_namespace_pkg/foo/one.py deleted file mode 100644 index d8f5c83..0000000 --- a/Lib/test/namespace_pkgs/not_a_namespace_pkg/foo/one.py +++ /dev/null @@ -1 +0,0 @@ -attr = 'portion1 foo one' diff --git a/Lib/test/namespace_pkgs/portion1/foo/one.py b/Lib/test/namespace_pkgs/portion1/foo/one.py deleted file mode 100644 index d8f5c83..0000000 --- a/Lib/test/namespace_pkgs/portion1/foo/one.py +++ /dev/null @@ -1 +0,0 @@ -attr = 'portion1 foo one' diff --git a/Lib/test/namespace_pkgs/portion2/foo/two.py b/Lib/test/namespace_pkgs/portion2/foo/two.py deleted file mode 100644 index d092e1e..0000000 --- a/Lib/test/namespace_pkgs/portion2/foo/two.py +++ /dev/null @@ -1 +0,0 @@ -attr = 'portion2 foo two' diff --git a/Lib/test/namespace_pkgs/project1/parent/child/one.py b/Lib/test/namespace_pkgs/project1/parent/child/one.py deleted file mode 100644 index 2776fcd..0000000 --- a/Lib/test/namespace_pkgs/project1/parent/child/one.py +++ /dev/null @@ -1 +0,0 @@ -attr = 'parent child one' diff --git a/Lib/test/namespace_pkgs/project2/parent/child/two.py b/Lib/test/namespace_pkgs/project2/parent/child/two.py deleted file mode 100644 index 8b037bc..0000000 --- a/Lib/test/namespace_pkgs/project2/parent/child/two.py +++ /dev/null @@ -1 +0,0 @@ -attr = 'parent child two' diff --git a/Lib/test/namespace_pkgs/project3/parent/child/three.py b/Lib/test/namespace_pkgs/project3/parent/child/three.py deleted file mode 100644 index f8abfe1..0000000 --- a/Lib/test/namespace_pkgs/project3/parent/child/three.py +++ /dev/null @@ -1 +0,0 @@ -attr = 'parent child three' diff --git a/Lib/test/namespace_pkgs/top_level_portion1.zip b/Lib/test/namespace_pkgs/top_level_portion1.zip deleted file mode 100644 index 3b866c9..0000000 Binary files a/Lib/test/namespace_pkgs/top_level_portion1.zip and /dev/null differ diff --git a/Lib/test/test_importlib/namespace_pkgs/both_portions/foo/one.py b/Lib/test/test_importlib/namespace_pkgs/both_portions/foo/one.py new file mode 100644 index 0000000..3080f6f --- /dev/null +++ b/Lib/test/test_importlib/namespace_pkgs/both_portions/foo/one.py @@ -0,0 +1 @@ +attr = 'both_portions foo one' diff --git a/Lib/test/test_importlib/namespace_pkgs/both_portions/foo/two.py b/Lib/test/test_importlib/namespace_pkgs/both_portions/foo/two.py new file mode 100644 index 0000000..4131d3d --- /dev/null +++ b/Lib/test/test_importlib/namespace_pkgs/both_portions/foo/two.py @@ -0,0 +1 @@ +attr = 'both_portions foo two' diff --git a/Lib/test/test_importlib/namespace_pkgs/missing_directory.zip b/Lib/test/test_importlib/namespace_pkgs/missing_directory.zip new file mode 100644 index 0000000..836a910 Binary files /dev/null and b/Lib/test/test_importlib/namespace_pkgs/missing_directory.zip differ diff --git a/Lib/test/test_importlib/namespace_pkgs/module_and_namespace_package/a_test.py b/Lib/test/test_importlib/namespace_pkgs/module_and_namespace_package/a_test.py new file mode 100644 index 0000000..43cbedb --- /dev/null +++ b/Lib/test/test_importlib/namespace_pkgs/module_and_namespace_package/a_test.py @@ -0,0 +1 @@ +attr = 'in module' diff --git a/Lib/test/test_importlib/namespace_pkgs/module_and_namespace_package/a_test/empty b/Lib/test/test_importlib/namespace_pkgs/module_and_namespace_package/a_test/empty new file mode 100644 index 0000000..e69de29 diff --git a/Lib/test/test_importlib/namespace_pkgs/nested_portion1.zip b/Lib/test/test_importlib/namespace_pkgs/nested_portion1.zip new file mode 100644 index 0000000..8d22406 Binary files /dev/null and b/Lib/test/test_importlib/namespace_pkgs/nested_portion1.zip differ diff --git a/Lib/test/test_importlib/namespace_pkgs/not_a_namespace_pkg/foo/__init__.py b/Lib/test/test_importlib/namespace_pkgs/not_a_namespace_pkg/foo/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Lib/test/test_importlib/namespace_pkgs/not_a_namespace_pkg/foo/one.py b/Lib/test/test_importlib/namespace_pkgs/not_a_namespace_pkg/foo/one.py new file mode 100644 index 0000000..d8f5c83 --- /dev/null +++ b/Lib/test/test_importlib/namespace_pkgs/not_a_namespace_pkg/foo/one.py @@ -0,0 +1 @@ +attr = 'portion1 foo one' diff --git a/Lib/test/test_importlib/namespace_pkgs/portion1/foo/one.py b/Lib/test/test_importlib/namespace_pkgs/portion1/foo/one.py new file mode 100644 index 0000000..d8f5c83 --- /dev/null +++ b/Lib/test/test_importlib/namespace_pkgs/portion1/foo/one.py @@ -0,0 +1 @@ +attr = 'portion1 foo one' diff --git a/Lib/test/test_importlib/namespace_pkgs/portion2/foo/two.py b/Lib/test/test_importlib/namespace_pkgs/portion2/foo/two.py new file mode 100644 index 0000000..d092e1e --- /dev/null +++ b/Lib/test/test_importlib/namespace_pkgs/portion2/foo/two.py @@ -0,0 +1 @@ +attr = 'portion2 foo two' diff --git a/Lib/test/test_importlib/namespace_pkgs/project1/parent/child/one.py b/Lib/test/test_importlib/namespace_pkgs/project1/parent/child/one.py new file mode 100644 index 0000000..2776fcd --- /dev/null +++ b/Lib/test/test_importlib/namespace_pkgs/project1/parent/child/one.py @@ -0,0 +1 @@ +attr = 'parent child one' diff --git a/Lib/test/test_importlib/namespace_pkgs/project2/parent/child/two.py b/Lib/test/test_importlib/namespace_pkgs/project2/parent/child/two.py new file mode 100644 index 0000000..8b037bc --- /dev/null +++ b/Lib/test/test_importlib/namespace_pkgs/project2/parent/child/two.py @@ -0,0 +1 @@ +attr = 'parent child two' diff --git a/Lib/test/test_importlib/namespace_pkgs/project3/parent/child/three.py b/Lib/test/test_importlib/namespace_pkgs/project3/parent/child/three.py new file mode 100644 index 0000000..f8abfe1 --- /dev/null +++ b/Lib/test/test_importlib/namespace_pkgs/project3/parent/child/three.py @@ -0,0 +1 @@ +attr = 'parent child three' diff --git a/Lib/test/test_importlib/namespace_pkgs/top_level_portion1.zip b/Lib/test/test_importlib/namespace_pkgs/top_level_portion1.zip new file mode 100644 index 0000000..3b866c9 Binary files /dev/null and b/Lib/test/test_importlib/namespace_pkgs/top_level_portion1.zip differ diff --git a/Lib/test/test_importlib/test_namespace_pkgs.py b/Lib/test/test_importlib/test_namespace_pkgs.py new file mode 100644 index 0000000..6639612 --- /dev/null +++ b/Lib/test/test_importlib/test_namespace_pkgs.py @@ -0,0 +1,293 @@ +import contextlib +import importlib.abc +import importlib.machinery +import os +import sys +import types +import unittest + +from test.test_importlib import util +from test.support import run_unittest + +# needed tests: +# +# need to test when nested, so that the top-level path isn't sys.path +# need to test dynamic path detection, both at top-level and nested +# with dynamic path, check when a loader is returned on path reload (that is, +# trying to switch from a namespace package to a regular package) + + +@contextlib.contextmanager +def sys_modules_context(): + """ + Make sure sys.modules is the same object and has the same content + when exiting the context as when entering. + + Similar to importlib.test.util.uncache, but doesn't require explicit + names. + """ + sys_modules_saved = sys.modules + sys_modules_copy = sys.modules.copy() + try: + yield + finally: + sys.modules = sys_modules_saved + sys.modules.clear() + sys.modules.update(sys_modules_copy) + + +@contextlib.contextmanager +def namespace_tree_context(**kwargs): + """ + Save import state and sys.modules cache and restore it on exit. + Typical usage: + + >>> with namespace_tree_context(path=['/tmp/xxyy/portion1', + ... '/tmp/xxyy/portion2']): + ... pass + """ + # use default meta_path and path_hooks unless specified otherwise + kwargs.setdefault('meta_path', sys.meta_path) + kwargs.setdefault('path_hooks', sys.path_hooks) + import_context = util.import_state(**kwargs) + with import_context, sys_modules_context(): + yield + +class NamespacePackageTest(unittest.TestCase): + """ + Subclasses should define self.root and self.paths (under that root) + to be added to sys.path. + """ + root = os.path.join(os.path.dirname(__file__), 'namespace_pkgs') + + def setUp(self): + self.resolved_paths = [ + os.path.join(self.root, path) for path in self.paths + ] + self.ctx = namespace_tree_context(path=self.resolved_paths) + self.ctx.__enter__() + + def tearDown(self): + # TODO: will we ever want to pass exc_info to __exit__? + self.ctx.__exit__(None, None, None) + +class SingleNamespacePackage(NamespacePackageTest): + paths = ['portion1'] + + def test_simple_package(self): + import foo.one + self.assertEqual(foo.one.attr, 'portion1 foo one') + + def test_cant_import_other(self): + with self.assertRaises(ImportError): + import foo.two + + def test_module_repr(self): + import foo.one + self.assertEqual(repr(foo), "") + + +class DynamicPatheNamespacePackage(NamespacePackageTest): + paths = ['portion1'] + + def test_dynamic_path(self): + # Make sure only 'foo.one' can be imported + import foo.one + self.assertEqual(foo.one.attr, 'portion1 foo one') + + with self.assertRaises(ImportError): + import foo.two + + # Now modify sys.path + sys.path.append(os.path.join(self.root, 'portion2')) + + # And make sure foo.two is now importable + import foo.two + self.assertEqual(foo.two.attr, 'portion2 foo two') + + +class CombinedNamespacePackages(NamespacePackageTest): + paths = ['both_portions'] + + def test_imports(self): + import foo.one + import foo.two + self.assertEqual(foo.one.attr, 'both_portions foo one') + self.assertEqual(foo.two.attr, 'both_portions foo two') + + +class SeparatedNamespacePackages(NamespacePackageTest): + paths = ['portion1', 'portion2'] + + def test_imports(self): + import foo.one + import foo.two + self.assertEqual(foo.one.attr, 'portion1 foo one') + self.assertEqual(foo.two.attr, 'portion2 foo two') + + +class SeparatedOverlappingNamespacePackages(NamespacePackageTest): + paths = ['portion1', 'both_portions'] + + def test_first_path_wins(self): + import foo.one + import foo.two + self.assertEqual(foo.one.attr, 'portion1 foo one') + self.assertEqual(foo.two.attr, 'both_portions foo two') + + def test_first_path_wins_again(self): + sys.path.reverse() + import foo.one + import foo.two + self.assertEqual(foo.one.attr, 'both_portions foo one') + self.assertEqual(foo.two.attr, 'both_portions foo two') + + def test_first_path_wins_importing_second_first(self): + import foo.two + import foo.one + self.assertEqual(foo.one.attr, 'portion1 foo one') + self.assertEqual(foo.two.attr, 'both_portions foo two') + + +class SingleZipNamespacePackage(NamespacePackageTest): + paths = ['top_level_portion1.zip'] + + def test_simple_package(self): + import foo.one + self.assertEqual(foo.one.attr, 'portion1 foo one') + + def test_cant_import_other(self): + with self.assertRaises(ImportError): + import foo.two + + +class SeparatedZipNamespacePackages(NamespacePackageTest): + paths = ['top_level_portion1.zip', 'portion2'] + + def test_imports(self): + import foo.one + import foo.two + self.assertEqual(foo.one.attr, 'portion1 foo one') + self.assertEqual(foo.two.attr, 'portion2 foo two') + self.assertIn('top_level_portion1.zip', foo.one.__file__) + self.assertNotIn('.zip', foo.two.__file__) + + +class SingleNestedZipNamespacePackage(NamespacePackageTest): + paths = ['nested_portion1.zip/nested_portion1'] + + def test_simple_package(self): + import foo.one + self.assertEqual(foo.one.attr, 'portion1 foo one') + + def test_cant_import_other(self): + with self.assertRaises(ImportError): + import foo.two + + +class SeparatedNestedZipNamespacePackages(NamespacePackageTest): + paths = ['nested_portion1.zip/nested_portion1', 'portion2'] + + def test_imports(self): + import foo.one + import foo.two + self.assertEqual(foo.one.attr, 'portion1 foo one') + self.assertEqual(foo.two.attr, 'portion2 foo two') + fn = os.path.join('nested_portion1.zip', 'nested_portion1') + self.assertIn(fn, foo.one.__file__) + self.assertNotIn('.zip', foo.two.__file__) + + +class LegacySupport(NamespacePackageTest): + paths = ['not_a_namespace_pkg', 'portion1', 'portion2', 'both_portions'] + + def test_non_namespace_package_takes_precedence(self): + import foo.one + with self.assertRaises(ImportError): + import foo.two + self.assertIn('__init__', foo.__file__) + self.assertNotIn('namespace', str(foo.__loader__).lower()) + + +class DynamicPathCalculation(NamespacePackageTest): + paths = ['project1', 'project2'] + + def test_project3_fails(self): + import parent.child.one + self.assertEqual(len(parent.__path__), 2) + self.assertEqual(len(parent.child.__path__), 2) + import parent.child.two + self.assertEqual(len(parent.__path__), 2) + self.assertEqual(len(parent.child.__path__), 2) + + self.assertEqual(parent.child.one.attr, 'parent child one') + self.assertEqual(parent.child.two.attr, 'parent child two') + + with self.assertRaises(ImportError): + import parent.child.three + + self.assertEqual(len(parent.__path__), 2) + self.assertEqual(len(parent.child.__path__), 2) + + def test_project3_succeeds(self): + import parent.child.one + self.assertEqual(len(parent.__path__), 2) + self.assertEqual(len(parent.child.__path__), 2) + import parent.child.two + self.assertEqual(len(parent.__path__), 2) + self.assertEqual(len(parent.child.__path__), 2) + + self.assertEqual(parent.child.one.attr, 'parent child one') + self.assertEqual(parent.child.two.attr, 'parent child two') + + with self.assertRaises(ImportError): + import parent.child.three + + # now add project3 + sys.path.append(os.path.join(self.root, 'project3')) + import parent.child.three + + # the paths dynamically get longer, to include the new directories + self.assertEqual(len(parent.__path__), 3) + self.assertEqual(len(parent.child.__path__), 3) + + self.assertEqual(parent.child.three.attr, 'parent child three') + + +class ZipWithMissingDirectory(NamespacePackageTest): + paths = ['missing_directory.zip'] + + @unittest.expectedFailure + def test_missing_directory(self): + # This will fail because missing_directory.zip contains: + # Length Date Time Name + # --------- ---------- ----- ---- + # 29 2012-05-03 18:13 foo/one.py + # 0 2012-05-03 20:57 bar/ + # 38 2012-05-03 20:57 bar/two.py + # --------- ------- + # 67 3 files + + # Because there is no 'foo/', the zipimporter currently doesn't + # know that foo is a namespace package + + import foo.one + + def test_present_directory(self): + # This succeeds because there is a "bar/" in the zip file + import bar.two + self.assertEqual(bar.two.attr, 'missing_directory foo two') + + +class ModuleAndNamespacePackageInSameDir(NamespacePackageTest): + paths = ['module_and_namespace_package'] + + def test_module_before_namespace_package(self): + # Make sure we find the module in preference to the + # namespace package. + import a_test + self.assertEqual(a_test.attr, 'in module') + + +if __name__ == "__main__": + unittest.main() diff --git a/Lib/test/test_namespace_pkgs.py b/Lib/test/test_namespace_pkgs.py deleted file mode 100644 index 6639612..0000000 --- a/Lib/test/test_namespace_pkgs.py +++ /dev/null @@ -1,293 +0,0 @@ -import contextlib -import importlib.abc -import importlib.machinery -import os -import sys -import types -import unittest - -from test.test_importlib import util -from test.support import run_unittest - -# needed tests: -# -# need to test when nested, so that the top-level path isn't sys.path -# need to test dynamic path detection, both at top-level and nested -# with dynamic path, check when a loader is returned on path reload (that is, -# trying to switch from a namespace package to a regular package) - - -@contextlib.contextmanager -def sys_modules_context(): - """ - Make sure sys.modules is the same object and has the same content - when exiting the context as when entering. - - Similar to importlib.test.util.uncache, but doesn't require explicit - names. - """ - sys_modules_saved = sys.modules - sys_modules_copy = sys.modules.copy() - try: - yield - finally: - sys.modules = sys_modules_saved - sys.modules.clear() - sys.modules.update(sys_modules_copy) - - -@contextlib.contextmanager -def namespace_tree_context(**kwargs): - """ - Save import state and sys.modules cache and restore it on exit. - Typical usage: - - >>> with namespace_tree_context(path=['/tmp/xxyy/portion1', - ... '/tmp/xxyy/portion2']): - ... pass - """ - # use default meta_path and path_hooks unless specified otherwise - kwargs.setdefault('meta_path', sys.meta_path) - kwargs.setdefault('path_hooks', sys.path_hooks) - import_context = util.import_state(**kwargs) - with import_context, sys_modules_context(): - yield - -class NamespacePackageTest(unittest.TestCase): - """ - Subclasses should define self.root and self.paths (under that root) - to be added to sys.path. - """ - root = os.path.join(os.path.dirname(__file__), 'namespace_pkgs') - - def setUp(self): - self.resolved_paths = [ - os.path.join(self.root, path) for path in self.paths - ] - self.ctx = namespace_tree_context(path=self.resolved_paths) - self.ctx.__enter__() - - def tearDown(self): - # TODO: will we ever want to pass exc_info to __exit__? - self.ctx.__exit__(None, None, None) - -class SingleNamespacePackage(NamespacePackageTest): - paths = ['portion1'] - - def test_simple_package(self): - import foo.one - self.assertEqual(foo.one.attr, 'portion1 foo one') - - def test_cant_import_other(self): - with self.assertRaises(ImportError): - import foo.two - - def test_module_repr(self): - import foo.one - self.assertEqual(repr(foo), "") - - -class DynamicPatheNamespacePackage(NamespacePackageTest): - paths = ['portion1'] - - def test_dynamic_path(self): - # Make sure only 'foo.one' can be imported - import foo.one - self.assertEqual(foo.one.attr, 'portion1 foo one') - - with self.assertRaises(ImportError): - import foo.two - - # Now modify sys.path - sys.path.append(os.path.join(self.root, 'portion2')) - - # And make sure foo.two is now importable - import foo.two - self.assertEqual(foo.two.attr, 'portion2 foo two') - - -class CombinedNamespacePackages(NamespacePackageTest): - paths = ['both_portions'] - - def test_imports(self): - import foo.one - import foo.two - self.assertEqual(foo.one.attr, 'both_portions foo one') - self.assertEqual(foo.two.attr, 'both_portions foo two') - - -class SeparatedNamespacePackages(NamespacePackageTest): - paths = ['portion1', 'portion2'] - - def test_imports(self): - import foo.one - import foo.two - self.assertEqual(foo.one.attr, 'portion1 foo one') - self.assertEqual(foo.two.attr, 'portion2 foo two') - - -class SeparatedOverlappingNamespacePackages(NamespacePackageTest): - paths = ['portion1', 'both_portions'] - - def test_first_path_wins(self): - import foo.one - import foo.two - self.assertEqual(foo.one.attr, 'portion1 foo one') - self.assertEqual(foo.two.attr, 'both_portions foo two') - - def test_first_path_wins_again(self): - sys.path.reverse() - import foo.one - import foo.two - self.assertEqual(foo.one.attr, 'both_portions foo one') - self.assertEqual(foo.two.attr, 'both_portions foo two') - - def test_first_path_wins_importing_second_first(self): - import foo.two - import foo.one - self.assertEqual(foo.one.attr, 'portion1 foo one') - self.assertEqual(foo.two.attr, 'both_portions foo two') - - -class SingleZipNamespacePackage(NamespacePackageTest): - paths = ['top_level_portion1.zip'] - - def test_simple_package(self): - import foo.one - self.assertEqual(foo.one.attr, 'portion1 foo one') - - def test_cant_import_other(self): - with self.assertRaises(ImportError): - import foo.two - - -class SeparatedZipNamespacePackages(NamespacePackageTest): - paths = ['top_level_portion1.zip', 'portion2'] - - def test_imports(self): - import foo.one - import foo.two - self.assertEqual(foo.one.attr, 'portion1 foo one') - self.assertEqual(foo.two.attr, 'portion2 foo two') - self.assertIn('top_level_portion1.zip', foo.one.__file__) - self.assertNotIn('.zip', foo.two.__file__) - - -class SingleNestedZipNamespacePackage(NamespacePackageTest): - paths = ['nested_portion1.zip/nested_portion1'] - - def test_simple_package(self): - import foo.one - self.assertEqual(foo.one.attr, 'portion1 foo one') - - def test_cant_import_other(self): - with self.assertRaises(ImportError): - import foo.two - - -class SeparatedNestedZipNamespacePackages(NamespacePackageTest): - paths = ['nested_portion1.zip/nested_portion1', 'portion2'] - - def test_imports(self): - import foo.one - import foo.two - self.assertEqual(foo.one.attr, 'portion1 foo one') - self.assertEqual(foo.two.attr, 'portion2 foo two') - fn = os.path.join('nested_portion1.zip', 'nested_portion1') - self.assertIn(fn, foo.one.__file__) - self.assertNotIn('.zip', foo.two.__file__) - - -class LegacySupport(NamespacePackageTest): - paths = ['not_a_namespace_pkg', 'portion1', 'portion2', 'both_portions'] - - def test_non_namespace_package_takes_precedence(self): - import foo.one - with self.assertRaises(ImportError): - import foo.two - self.assertIn('__init__', foo.__file__) - self.assertNotIn('namespace', str(foo.__loader__).lower()) - - -class DynamicPathCalculation(NamespacePackageTest): - paths = ['project1', 'project2'] - - def test_project3_fails(self): - import parent.child.one - self.assertEqual(len(parent.__path__), 2) - self.assertEqual(len(parent.child.__path__), 2) - import parent.child.two - self.assertEqual(len(parent.__path__), 2) - self.assertEqual(len(parent.child.__path__), 2) - - self.assertEqual(parent.child.one.attr, 'parent child one') - self.assertEqual(parent.child.two.attr, 'parent child two') - - with self.assertRaises(ImportError): - import parent.child.three - - self.assertEqual(len(parent.__path__), 2) - self.assertEqual(len(parent.child.__path__), 2) - - def test_project3_succeeds(self): - import parent.child.one - self.assertEqual(len(parent.__path__), 2) - self.assertEqual(len(parent.child.__path__), 2) - import parent.child.two - self.assertEqual(len(parent.__path__), 2) - self.assertEqual(len(parent.child.__path__), 2) - - self.assertEqual(parent.child.one.attr, 'parent child one') - self.assertEqual(parent.child.two.attr, 'parent child two') - - with self.assertRaises(ImportError): - import parent.child.three - - # now add project3 - sys.path.append(os.path.join(self.root, 'project3')) - import parent.child.three - - # the paths dynamically get longer, to include the new directories - self.assertEqual(len(parent.__path__), 3) - self.assertEqual(len(parent.child.__path__), 3) - - self.assertEqual(parent.child.three.attr, 'parent child three') - - -class ZipWithMissingDirectory(NamespacePackageTest): - paths = ['missing_directory.zip'] - - @unittest.expectedFailure - def test_missing_directory(self): - # This will fail because missing_directory.zip contains: - # Length Date Time Name - # --------- ---------- ----- ---- - # 29 2012-05-03 18:13 foo/one.py - # 0 2012-05-03 20:57 bar/ - # 38 2012-05-03 20:57 bar/two.py - # --------- ------- - # 67 3 files - - # Because there is no 'foo/', the zipimporter currently doesn't - # know that foo is a namespace package - - import foo.one - - def test_present_directory(self): - # This succeeds because there is a "bar/" in the zip file - import bar.two - self.assertEqual(bar.two.attr, 'missing_directory foo two') - - -class ModuleAndNamespacePackageInSameDir(NamespacePackageTest): - paths = ['module_and_namespace_package'] - - def test_module_before_namespace_package(self): - # Make sure we find the module in preference to the - # namespace package. - import a_test - self.assertEqual(a_test.attr, 'in module') - - -if __name__ == "__main__": - unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS index 38928f8..21bd779 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -122,6 +122,8 @@ Tests - Issue #20743: Fix a reference leak in test_tcl. +- Issue #21097: Move test_namespace_pkgs into test_importlib. + - Issue #20939: Avoid various network test failures due to new redirect of http://www.python.org/ to https://www.python.org: use http://www.example.com instead. -- cgit v0.12