From d3de33538948081d9ef39168fde870c977e30115 Mon Sep 17 00:00:00 2001 From: Erik Bray Date: Thu, 31 Dec 2015 14:17:41 -0500 Subject: Fixes the original root cause of #231, and re-enables the test when the tempdir is a symlink (this does not explicitly test that /tmp itself is a symlink, but the effect is the same--only one of the path levels needs to be a symlink to reproduce this isssue) --- pkg_resources/__init__.py | 9 +++++++-- pkg_resources/tests/test_resources.py | 26 ++++++++++++++++++++------ 2 files changed, 27 insertions(+), 8 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 7becc951..7d2fa7e9 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -2182,9 +2182,14 @@ def _handle_ns(packageName, path_item): path = module.__path__ path.append(subpath) loader.load_module(packageName) + + # Ensure that all paths on __path__ have been run through + # normalize_path + normalized_paths = set(_normalize_cached(p) for p in module.__path__) for path_item in path: - if path_item not in module.__path__: - module.__path__.append(path_item) + normalized = _normalize_cached(path_item) + if normalized not in normalized_paths: + module.__path__.append(normalized) return subpath def declare_namespace(packageName): diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index 4241765a..ba12d857 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -610,18 +610,32 @@ class TestNamespaces: def setup_method(self, method): self._ns_pkgs = pkg_resources._namespace_packages.copy() - self._tmpdir = tempfile.mkdtemp(prefix="tests-setuptools-") + + # Further, test case where the temp dir is a symlink, where applicable + # See #231 + if hasattr(os, 'symlink'): + real_tmpdir = tempfile.mkdtemp(prefix="real-tests-setuptools-") + tmpdir_base, tmpdir_name = os.path.split(real_tmpdir) + tmpdir = os.path.join(tmpdir_base, tmpdir_name[5:]) + os.symlink(real_tmpdir, tmpdir) + self._real_tmpdir = real_tmpdir + self._tmpdir = tmpdir + else: + tmpdir = tempfile.mkdtemp(prefix="tests-setuptools-") + self._real_tmpdir = self._tmpdir = tmpdir + os.makedirs(os.path.join(self._tmpdir, "site-pkgs")) self._prev_sys_path = sys.path[:] sys.path.append(os.path.join(self._tmpdir, "site-pkgs")) def teardown_method(self, method): - shutil.rmtree(self._tmpdir) + shutil.rmtree(self._real_tmpdir) + if os.path.islink(self._tmpdir): + os.unlink(self._tmpdir) + pkg_resources._namespace_packages = self._ns_pkgs.copy() sys.path = self._prev_sys_path[:] - @pytest.mark.skipif(os.path.islink(tempfile.gettempdir()), - reason="Test fails when /tmp is a symlink. See #231") def test_two_levels_deep(self): """ Test nested namespace packages @@ -653,7 +667,7 @@ class TestNamespaces: assert pkg_resources._namespace_packages["pkg1"] == ["pkg1.pkg2"] # check the __path__ attribute contains both paths expected = [ - os.path.join(self._tmpdir, "site-pkgs", "pkg1", "pkg2"), - os.path.join(self._tmpdir, "site-pkgs2", "pkg1", "pkg2"), + os.path.join(self._real_tmpdir, "site-pkgs", "pkg1", "pkg2"), + os.path.join(self._real_tmpdir, "site-pkgs2", "pkg1", "pkg2"), ] assert pkg1.pkg2.__path__ == expected -- cgit v1.2.3 From ebc54982b1085b05054a75dbcdd16008ac20a60e Mon Sep 17 00:00:00 2001 From: Erik Bray Date: Wed, 6 Jan 2016 17:08:56 -0500 Subject: Sort __path__ entries for namespace packages according to their order in sys.path. This ensures that lookups in __path__ will be the same as sys.path resolution. This also adds a replace argument to Distribution.insert_on meant to be used with the replace argumen to WorkingSet.add. This ensures that new sys.path entries added via WorkingSet.add are inserted at the beginning, rather than appended to the end. This is necessary for consistency with the above change, and kind of makes more sense anyways. This means that if a Distribution is added to a WorkingSet, that replaces a different version of that Distribution, the new version of that Distribution will have its location first on sys.path. --- pkg_resources/__init__.py | 28 +++++++++++++++++----------- pkg_resources/tests/test_resources.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 11 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 7d2fa7e9..46db5cc7 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -755,7 +755,7 @@ class WorkingSet(object): will be called. """ if insert: - dist.insert_on(self.entries, entry) + dist.insert_on(self.entries, entry, replace=replace) if entry is None: entry = dist.location @@ -2183,13 +2183,16 @@ def _handle_ns(packageName, path_item): path.append(subpath) loader.load_module(packageName) - # Ensure that all paths on __path__ have been run through - # normalize_path - normalized_paths = set(_normalize_cached(p) for p in module.__path__) - for path_item in path: - normalized = _normalize_cached(path_item) - if normalized not in normalized_paths: - module.__path__.append(normalized) + # Rebuild mod.__path__ ensuring that all entries are ordered + # corresponding to their sys.path order + sys_path= [(p and _normalize_cached(p) or p) for p in sys.path] + def sort_key(p): + parts = p.split(os.sep) + parts = parts[:-(packageName.count('.') + 1)] + return sys_path.index(_normalize_cached(os.sep.join(parts))) + + path.sort(key=sort_key) + module.__path__[:] = [_normalize_cached(p) for p in path] return subpath def declare_namespace(packageName): @@ -2644,7 +2647,7 @@ class Distribution(object): """Ensure distribution is importable on `path` (default=sys.path)""" if path is None: path = sys.path - self.insert_on(path) + self.insert_on(path, replace=True) if path is sys.path: fixup_namespace_packages(self.location) for pkg in self._get_metadata('namespace_packages.txt'): @@ -2721,7 +2724,7 @@ class Distribution(object): """Return the EntryPoint object for `group`+`name`, or ``None``""" return self.get_entry_map(group).get(name) - def insert_on(self, path, loc = None): + def insert_on(self, path, loc=None, replace=False): """Insert self.location in path before its nearest parent directory""" loc = loc or self.location @@ -2745,7 +2748,10 @@ class Distribution(object): else: if path is sys.path: self.check_version_conflict() - path.append(loc) + if replace: + path.insert(0, loc) + else: + path.append(loc) return # p is the spot where we found or inserted loc; now remove duplicates diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index ba12d857..7176cc70 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -671,3 +671,37 @@ class TestNamespaces: os.path.join(self._real_tmpdir, "site-pkgs2", "pkg1", "pkg2"), ] assert pkg1.pkg2.__path__ == expected + + def test_path_order(self): + """ + Test that if multiple versions of the same namespace package subpackage + are on different sys.path entries, that only the one earliest on + sys.path is imported, and that the namespace package's __path__ is in + the correct order. + + Regression test for https://bitbucket.org/pypa/setuptools/issues/207 + """ + + site_pkgs = ["site-pkgs", "site-pkgs2", "site-pkgs3"] + + ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n" + vers_str = "__version__ = %r" + + for idx, site in enumerate(site_pkgs): + if idx > 0: + sys.path.append(os.path.join(self._tmpdir, site)) + os.makedirs(os.path.join(self._tmpdir, site, "nspkg", "subpkg")) + with open(os.path.join(self._tmpdir, site, "nspkg", + "__init__.py"), "w") as f: + f.write(ns_str) + + with open(os.path.join(self._tmpdir, site, "nspkg", "subpkg", + "__init__.py"), "w") as f: + f.write(vers_str % (idx + 1)) + + import nspkg.subpkg + import nspkg + assert nspkg.__path__ == [os.path.join(self._real_tmpdir, site, + "nspkg") + for site in site_pkgs] + assert nspkg.subpkg.__version__ == 1 -- cgit v1.2.3 From 8af3b6ef5b4173a0d0d6735147c98c882ae98344 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 16 Jan 2016 06:54:00 -0500 Subject: Always use Python 3 version of map --- pkg_resources/__init__.py | 2 +- pkg_resources/tests/test_pkg_resources.py | 2 ++ pkg_resources/tests/test_resources.py | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 7becc951..8382571e 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -46,7 +46,7 @@ except ImportError: import imp as _imp from pkg_resources.extern import six -from pkg_resources.extern.six.moves import urllib +from pkg_resources.extern.six.moves import urllib, map # capture these to bypass sandboxing from os import utime diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index 31eee635..8b276ffc 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -12,6 +12,8 @@ import stat import distutils.dist import distutils.command.install_egg_info +from pkg_resources.extern.six.moves import map + import pytest import pkg_resources diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index 4241765a..84133a32 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -4,6 +4,8 @@ import tempfile import shutil import string +from pkg_resources.extern.six.moves import map + import pytest from pkg_resources.extern import packaging @@ -158,7 +160,7 @@ class TestDistro: for i in range(3): targets = list(ws.resolve(parse_requirements("Foo"), ad)) assert targets == [Foo] - list(map(ws.add,targets)) + list(map(ws.add, targets)) with pytest.raises(VersionConflict): ws.resolve(parse_requirements("Foo==0.9"), ad) ws = WorkingSet([]) # reset -- cgit v1.2.3 From e2f1814e0d3d8963cf3a1eb4dff6d400b58b4a52 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 23 Jan 2016 18:13:32 -0500 Subject: Invoke import on importlib.machinery directly. Access an attribute to force import in delayed-import environments. Fixes #487. --- pkg_resources/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 50b86cdb..3ecf4c64 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -60,10 +60,11 @@ except ImportError: from os import open as os_open from os.path import isdir, split -# Avoid try/except due to potential problems with delayed import mechanisms. -if sys.version_info >= (3, 3) and sys.implementation.name == "cpython": +try: import importlib.machinery as importlib_machinery -else: + # access attribute to force import under delayed import mechanisms. + importlib_machinery.__name__ +except ImportError: importlib_machinery = None try: -- cgit v1.2.3 From e01792ec62653b00b6d1c25e1ca0d10d22c1b6b9 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 26 Jan 2016 14:30:34 -0500 Subject: Combine redundant imports of future functionality --- pkg_resources/__init__.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 3ecf4c64..2ba5ca42 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -46,7 +46,7 @@ except ImportError: import imp as _imp from pkg_resources.extern import six -from pkg_resources.extern.six.moves import urllib, map +from pkg_resources.extern.six.moves import urllib, map, filter # capture these to bypass sandboxing from os import utime @@ -77,9 +77,6 @@ __import__('pkg_resources.extern.packaging.version') __import__('pkg_resources.extern.packaging.specifiers') -filter = six.moves.filter -map = six.moves.map - if (3, 0) < sys.version_info < (3, 3): msg = ( "Support for Python 3.0-3.2 has been dropped. Future versions " -- cgit v1.2.3 From 397d759e48bc93597c535c2335c9da37178721a5 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 26 Jan 2016 14:34:31 -0500 Subject: Pull up DefaultProvider registration into a classmethod. --- pkg_resources/__init__.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 2ba5ca42..b4f910c6 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -1725,10 +1725,14 @@ class DefaultProvider(EggProvider): with open(path, 'rb') as stream: return stream.read() -register_loader_type(type(None), DefaultProvider) + @classmethod + def _register(cls): + register_loader_type(type(None), cls) -if importlib_machinery is not None: - register_loader_type(importlib_machinery.SourceFileLoader, DefaultProvider) + if importlib_machinery is not None: + register_loader_type(importlib_machinery.SourceFileLoader, cls) + +DefaultProvider._register() class EmptyProvider(NullProvider): -- cgit v1.2.3 From 66b3a623dd256def923ddde303b8c95592d0223b Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 26 Jan 2016 14:42:03 -0500 Subject: Adapt resolution of classes from importlib.machinery. Restores compatibility for PyPy3 where importlib.machinery exists but FileFinder and SourceFileLoader aren't implemented. --- pkg_resources/__init__.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index b4f910c6..f15becbb 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -1727,10 +1727,9 @@ class DefaultProvider(EggProvider): @classmethod def _register(cls): - register_loader_type(type(None), cls) - - if importlib_machinery is not None: - register_loader_type(importlib_machinery.SourceFileLoader, cls) + loader_cls = getattr(importlib_machinery, 'SourceFileLoader', + type(None)) + register_loader_type(loader_cls, cls) DefaultProvider._register() @@ -2138,7 +2137,7 @@ def find_on_path(importer, path_item, only=False): break register_finder(pkgutil.ImpImporter, find_on_path) -if importlib_machinery is not None: +if hasattr(importlib_machinery, 'FileFinder'): register_finder(importlib_machinery.FileFinder, find_on_path) _declare_state('dict', _namespace_handlers={}) @@ -2255,7 +2254,7 @@ def file_ns_handler(importer, path_item, packageName, module): register_namespace_handler(pkgutil.ImpImporter, file_ns_handler) register_namespace_handler(zipimport.zipimporter, file_ns_handler) -if importlib_machinery is not None: +if hasattr(importlib_machinery, 'FileFinder'): register_namespace_handler(importlib_machinery.FileFinder, file_ns_handler) -- cgit v1.2.3 From d16b24ef68298295224f078c96fcbf732aa0dacc Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 31 Jan 2016 04:24:04 -0500 Subject: Extract function _rebuild_mod_path --- pkg_resources/__init__.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index f15becbb..3398a56b 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -2183,18 +2183,24 @@ def _handle_ns(packageName, path_item): path = module.__path__ path.append(subpath) loader.load_module(packageName) + _rebuild_mod_path(path, packageName, module) + return subpath - # Rebuild mod.__path__ ensuring that all entries are ordered - # corresponding to their sys.path order - sys_path= [(p and _normalize_cached(p) or p) for p in sys.path] - def sort_key(p): - parts = p.split(os.sep) - parts = parts[:-(packageName.count('.') + 1)] - return sys_path.index(_normalize_cached(os.sep.join(parts))) - path.sort(key=sort_key) - module.__path__[:] = [_normalize_cached(p) for p in path] - return subpath +def _rebuild_mod_path(orig_path, package_name, module): + """ + Rebuild module.__path__ ensuring that all entries are ordered + corresponding to their sys.path order + """ + sys_path= [(p and _normalize_cached(p) or p) for p in sys.path] + def sort_key(p): + parts = p.split(os.sep) + parts = parts[:-(package_name.count('.') + 1)] + return sys_path.index(_normalize_cached(os.sep.join(parts))) + + orig_path.sort(key=sort_key) + module.__path__[:] = [_normalize_cached(p) for p in orig_path] + def declare_namespace(packageName): """Declare that package 'packageName' is a namespace package""" -- cgit v1.2.3 From c8a0d2d70aedf13382c6e0a506c04d449851ec45 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 31 Jan 2016 04:28:06 -0500 Subject: Rename inner function and add docstring --- pkg_resources/__init__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 3398a56b..70658062 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -2192,13 +2192,16 @@ def _rebuild_mod_path(orig_path, package_name, module): Rebuild module.__path__ ensuring that all entries are ordered corresponding to their sys.path order """ - sys_path= [(p and _normalize_cached(p) or p) for p in sys.path] - def sort_key(p): + sys_path = [(p and _normalize_cached(p) or p) for p in sys.path] + def position_in_sys_path(p): + """ + Return the ordinal of the path based on its position in sys.path + """ parts = p.split(os.sep) parts = parts[:-(package_name.count('.') + 1)] return sys_path.index(_normalize_cached(os.sep.join(parts))) - orig_path.sort(key=sort_key) + orig_path.sort(key=position_in_sys_path) module.__path__[:] = [_normalize_cached(p) for p in orig_path] -- cgit v1.2.3 From 94e1f4c266b7fdde993c5fde05f87dcc0afd186e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 31 Jan 2016 04:46:53 -0500 Subject: Normalize all paths, not excluding ''. Fixes #491. --- pkg_resources/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'pkg_resources') diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 70658062..7ba23bf5 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -2192,7 +2192,7 @@ def _rebuild_mod_path(orig_path, package_name, module): Rebuild module.__path__ ensuring that all entries are ordered corresponding to their sys.path order """ - sys_path = [(p and _normalize_cached(p) or p) for p in sys.path] + sys_path = [_normalize_cached(p) for p in sys.path] def position_in_sys_path(p): """ Return the ordinal of the path based on its position in sys.path -- cgit v1.2.3 From 0dcee791dfdcfacddaaec79b29f30a347a147413 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 31 Jan 2016 21:35:13 -0500 Subject: Extract variable for template string --- pkg_resources/__init__.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 7ba23bf5..4fdc5f91 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -1174,22 +1174,23 @@ class ResourceManager: old_exc = sys.exc_info()[1] cache_path = self.extraction_path or get_default_cache() - err = ExtractionError("""Can't extract file(s) to egg cache + tmpl = textwrap.dedent(""" + Can't extract file(s) to egg cache -The following error occurred while trying to extract file(s) to the Python egg -cache: + The following error occurred while trying to extract file(s) to the Python egg + cache: - %s + %s -The Python egg cache directory is currently set to: + The Python egg cache directory is currently set to: - %s + %s -Perhaps your account does not have write access to this directory? You can -change the cache directory by setting the PYTHON_EGG_CACHE environment -variable to point to an accessible directory. -""" % (old_exc, cache_path) - ) + Perhaps your account does not have write access to this directory? You can + change the cache directory by setting the PYTHON_EGG_CACHE environment + variable to point to an accessible directory. + """).lstrip() + err = ExtractionError(tmpl % (old_exc, cache_path)) err.manager = self err.cache_path = cache_path err.original_error = old_exc -- cgit v1.2.3 From f9bd9b9f5df54ef5a0bf8d16c3a889ab8c640580 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 31 Jan 2016 21:36:23 -0500 Subject: Use new style string formatting --- pkg_resources/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 4fdc5f91..d04cd347 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -1180,17 +1180,17 @@ class ResourceManager: The following error occurred while trying to extract file(s) to the Python egg cache: - %s + {old_exc} The Python egg cache directory is currently set to: - %s + {cache_path} Perhaps your account does not have write access to this directory? You can change the cache directory by setting the PYTHON_EGG_CACHE environment variable to point to an accessible directory. """).lstrip() - err = ExtractionError(tmpl % (old_exc, cache_path)) + err = ExtractionError(tmpl.format(**locals())) err.manager = self err.cache_path = cache_path err.original_error = old_exc -- cgit v1.2.3 From e3d7334022838f8153a06b0105c6b8f4a32762a2 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 3 Feb 2016 09:02:34 -0500 Subject: Rewrite setup/teardown methods as pytest fixtures, encapsulating concepts for clarity. Incidentally, this also fixes #231. --- pkg_resources/tests/test_resources.py | 94 +++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 42 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index 6f68bf77..49acd036 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -610,35 +610,41 @@ class TestParsing: class TestNamespaces: - def setup_method(self, method): - self._ns_pkgs = pkg_resources._namespace_packages.copy() - - # Further, test case where the temp dir is a symlink, where applicable - # See #231 - if hasattr(os, 'symlink'): - real_tmpdir = tempfile.mkdtemp(prefix="real-tests-setuptools-") - tmpdir_base, tmpdir_name = os.path.split(real_tmpdir) - tmpdir = os.path.join(tmpdir_base, tmpdir_name[5:]) - os.symlink(real_tmpdir, tmpdir) - self._real_tmpdir = real_tmpdir - self._tmpdir = tmpdir - else: - tmpdir = tempfile.mkdtemp(prefix="tests-setuptools-") - self._real_tmpdir = self._tmpdir = tmpdir - - os.makedirs(os.path.join(self._tmpdir, "site-pkgs")) - self._prev_sys_path = sys.path[:] - sys.path.append(os.path.join(self._tmpdir, "site-pkgs")) - - def teardown_method(self, method): - shutil.rmtree(self._real_tmpdir) - if os.path.islink(self._tmpdir): - os.unlink(self._tmpdir) - - pkg_resources._namespace_packages = self._ns_pkgs.copy() - sys.path = self._prev_sys_path[:] - - def test_two_levels_deep(self): + @pytest.yield_fixture + def symlinked_tmpdir(self, tmpdir): + """ + Where available, return the tempdir as a symlink, + which as revealed in #231 is more fragile than + a natural tempdir. + """ + if not hasattr(os, 'symlink'): + return str(tmpdir) + + link_name = str(tmpdir) + '-linked' + os.symlink(str(tmpdir), link_name) + try: + yield type(tmpdir)(link_name) + finally: + os.unlink(link_name) + + @pytest.yield_fixture(autouse=True) + def patched_path(self, tmpdir): + """ + Patch sys.path to include the 'site-pkgs' dir. Also + restore pkg_resources._namespace_packages to its + former state. + """ + saved_ns_pkgs = pkg_resources._namespace_packages.copy() + saved_sys_path = sys.path[:] + site_pkgs = tmpdir.mkdir('site-pkgs') + sys.path.append(str(site_pkgs)) + try: + yield + finally: + pkg_resources._namespace_packages = saved_ns_pkgs + sys.path = saved_sys_path + + def test_two_levels_deep(self, symlinked_tmpdir): """ Test nested namespace packages Create namespace packages in the following tree : @@ -647,16 +653,18 @@ class TestNamespaces: Check both are in the _namespace_packages dict and that their __path__ is correct """ - sys.path.append(os.path.join(self._tmpdir, "site-pkgs2")) - os.makedirs(os.path.join(self._tmpdir, "site-pkgs", "pkg1", "pkg2")) - os.makedirs(os.path.join(self._tmpdir, "site-pkgs2", "pkg1", "pkg2")) + real_tmpdir = str(symlinked_tmpdir.realpath()) + tmpdir = str(symlinked_tmpdir) + sys.path.append(os.path.join(tmpdir, "site-pkgs2")) + os.makedirs(os.path.join(tmpdir, "site-pkgs", "pkg1", "pkg2")) + os.makedirs(os.path.join(tmpdir, "site-pkgs2", "pkg1", "pkg2")) ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n" for site in ["site-pkgs", "site-pkgs2"]: - pkg1_init = open(os.path.join(self._tmpdir, site, + pkg1_init = open(os.path.join(tmpdir, site, "pkg1", "__init__.py"), "w") pkg1_init.write(ns_str) pkg1_init.close() - pkg2_init = open(os.path.join(self._tmpdir, site, + pkg2_init = open(os.path.join(tmpdir, site, "pkg1", "pkg2", "__init__.py"), "w") pkg2_init.write(ns_str) pkg2_init.close() @@ -669,12 +677,12 @@ class TestNamespaces: assert pkg_resources._namespace_packages["pkg1"] == ["pkg1.pkg2"] # check the __path__ attribute contains both paths expected = [ - os.path.join(self._real_tmpdir, "site-pkgs", "pkg1", "pkg2"), - os.path.join(self._real_tmpdir, "site-pkgs2", "pkg1", "pkg2"), + os.path.join(real_tmpdir, "site-pkgs", "pkg1", "pkg2"), + os.path.join(real_tmpdir, "site-pkgs2", "pkg1", "pkg2"), ] assert pkg1.pkg2.__path__ == expected - def test_path_order(self): + def test_path_order(self, symlinked_tmpdir): """ Test that if multiple versions of the same namespace package subpackage are on different sys.path entries, that only the one earliest on @@ -684,6 +692,8 @@ class TestNamespaces: Regression test for https://bitbucket.org/pypa/setuptools/issues/207 """ + real_tmpdir = str(symlinked_tmpdir.realpath()) + tmpdir = str(symlinked_tmpdir) site_pkgs = ["site-pkgs", "site-pkgs2", "site-pkgs3"] ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n" @@ -691,19 +701,19 @@ class TestNamespaces: for idx, site in enumerate(site_pkgs): if idx > 0: - sys.path.append(os.path.join(self._tmpdir, site)) - os.makedirs(os.path.join(self._tmpdir, site, "nspkg", "subpkg")) - with open(os.path.join(self._tmpdir, site, "nspkg", + sys.path.append(os.path.join(tmpdir, site)) + os.makedirs(os.path.join(tmpdir, site, "nspkg", "subpkg")) + with open(os.path.join(tmpdir, site, "nspkg", "__init__.py"), "w") as f: f.write(ns_str) - with open(os.path.join(self._tmpdir, site, "nspkg", "subpkg", + with open(os.path.join(tmpdir, site, "nspkg", "subpkg", "__init__.py"), "w") as f: f.write(vers_str % (idx + 1)) import nspkg.subpkg import nspkg - assert nspkg.__path__ == [os.path.join(self._real_tmpdir, site, + assert nspkg.__path__ == [os.path.join(real_tmpdir, site, "nspkg") for site in site_pkgs] assert nspkg.subpkg.__version__ == 1 -- cgit v1.2.3 From 397879392e928a873953bddd978dd87292211e62 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 3 Feb 2016 10:06:00 -0500 Subject: Use py.path objects for cleaner setup --- pkg_resources/tests/test_resources.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index 49acd036..00f0307d 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -653,21 +653,17 @@ class TestNamespaces: Check both are in the _namespace_packages dict and that their __path__ is correct """ - real_tmpdir = str(symlinked_tmpdir.realpath()) - tmpdir = str(symlinked_tmpdir) - sys.path.append(os.path.join(tmpdir, "site-pkgs2")) - os.makedirs(os.path.join(tmpdir, "site-pkgs", "pkg1", "pkg2")) - os.makedirs(os.path.join(tmpdir, "site-pkgs2", "pkg1", "pkg2")) + real_tmpdir = symlinked_tmpdir.realpath() + tmpdir = symlinked_tmpdir + sys.path.append(str(tmpdir / 'site-pkgs2')) + site_dirs = tmpdir / 'site-pkgs', tmpdir / 'site-pkgs2' ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n" - for site in ["site-pkgs", "site-pkgs2"]: - pkg1_init = open(os.path.join(tmpdir, site, - "pkg1", "__init__.py"), "w") - pkg1_init.write(ns_str) - pkg1_init.close() - pkg2_init = open(os.path.join(tmpdir, site, - "pkg1", "pkg2", "__init__.py"), "w") - pkg2_init.write(ns_str) - pkg2_init.close() + for site in site_dirs: + pkg1 = site / 'pkg1' + pkg2 = pkg1 / 'pkg2' + pkg2.ensure_dir() + (pkg1 / '__init__.py').write_text(ns_str, encoding='utf-8') + (pkg2 / '__init__.py').write_text(ns_str, encoding='utf-8') import pkg1 assert "pkg1" in pkg_resources._namespace_packages # attempt to import pkg2 from site-pkgs2 @@ -677,8 +673,8 @@ class TestNamespaces: assert pkg_resources._namespace_packages["pkg1"] == ["pkg1.pkg2"] # check the __path__ attribute contains both paths expected = [ - os.path.join(real_tmpdir, "site-pkgs", "pkg1", "pkg2"), - os.path.join(real_tmpdir, "site-pkgs2", "pkg1", "pkg2"), + str(real_tmpdir / "site-pkgs" / "pkg1" / "pkg2"), + str(real_tmpdir / "site-pkgs2" / "pkg1" / "pkg2"), ] assert pkg1.pkg2.__path__ == expected -- cgit v1.2.3 From 656a5f3b9c4f289c28e2810ce10ca71b571d6a2c Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 3 Feb 2016 10:13:36 -0500 Subject: Extract variable for readability --- pkg_resources/tests/test_resources.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index 00f0307d..c6ab6d0e 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -709,7 +709,9 @@ class TestNamespaces: import nspkg.subpkg import nspkg - assert nspkg.__path__ == [os.path.join(real_tmpdir, site, - "nspkg") - for site in site_pkgs] + expected = [ + os.path.join(real_tmpdir, site, "nspkg") + for site in site_pkgs + ] + assert nspkg.__path__ == expected assert nspkg.subpkg.__version__ == 1 -- cgit v1.2.3 From 3ff6789b02e2543cb352c8c9f89ceda5c61ca74e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 3 Feb 2016 10:16:32 -0500 Subject: Use py.path objects for cleaner setup --- pkg_resources/tests/test_resources.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index c6ab6d0e..553eecb4 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -688,30 +688,30 @@ class TestNamespaces: Regression test for https://bitbucket.org/pypa/setuptools/issues/207 """ - real_tmpdir = str(symlinked_tmpdir.realpath()) - tmpdir = str(symlinked_tmpdir) - site_pkgs = ["site-pkgs", "site-pkgs2", "site-pkgs3"] + tmpdir = symlinked_tmpdir + site_dirs = ( + tmpdir / "site-pkgs", + tmpdir / "site-pkgs2", + tmpdir / "site-pkgs3", + ) ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n" vers_str = "__version__ = %r" - for idx, site in enumerate(site_pkgs): + for idx, site in enumerate(site_dirs): if idx > 0: - sys.path.append(os.path.join(tmpdir, site)) - os.makedirs(os.path.join(tmpdir, site, "nspkg", "subpkg")) - with open(os.path.join(tmpdir, site, "nspkg", - "__init__.py"), "w") as f: - f.write(ns_str) - - with open(os.path.join(tmpdir, site, "nspkg", "subpkg", - "__init__.py"), "w") as f: - f.write(vers_str % (idx + 1)) + sys.path.append(str(site)) + nspkg = site / 'nspkg' + subpkg = nspkg / 'subpkg' + subpkg.ensure_dir() + (nspkg / '__init__.py').write_text(ns_str, encoding='utf-8') + (subpkg / '__init__.py').write_text(vers_str % (idx + 1), encoding='utf-8') import nspkg.subpkg import nspkg expected = [ - os.path.join(real_tmpdir, site, "nspkg") - for site in site_pkgs + str(site.realpath() / 'nspkg') + for site in site_dirs ] assert nspkg.__path__ == expected assert nspkg.subpkg.__version__ == 1 -- cgit v1.2.3 From a9a38182f64da197bd52efdf3c63d68448c80942 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 3 Feb 2016 10:17:48 -0500 Subject: Use consistent numbering for clarity. --- pkg_resources/tests/test_resources.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index 553eecb4..5b3ba546 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -698,14 +698,14 @@ class TestNamespaces: ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n" vers_str = "__version__ = %r" - for idx, site in enumerate(site_dirs): - if idx > 0: + for number, site in enumerate(site_dirs, 1): + if number > 1: sys.path.append(str(site)) nspkg = site / 'nspkg' subpkg = nspkg / 'subpkg' subpkg.ensure_dir() (nspkg / '__init__.py').write_text(ns_str, encoding='utf-8') - (subpkg / '__init__.py').write_text(vers_str % (idx + 1), encoding='utf-8') + (subpkg / '__init__.py').write_text(vers_str % number, encoding='utf-8') import nspkg.subpkg import nspkg -- cgit v1.2.3 From 20413e816e9c0809c97598b0a758120be6460f90 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 3 Feb 2016 10:20:29 -0500 Subject: Extract ns_str as class attribute --- pkg_resources/tests/test_resources.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index 5b3ba546..e25fbc78 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -610,6 +610,8 @@ class TestParsing: class TestNamespaces: + ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n" + @pytest.yield_fixture def symlinked_tmpdir(self, tmpdir): """ @@ -657,13 +659,12 @@ class TestNamespaces: tmpdir = symlinked_tmpdir sys.path.append(str(tmpdir / 'site-pkgs2')) site_dirs = tmpdir / 'site-pkgs', tmpdir / 'site-pkgs2' - ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n" for site in site_dirs: pkg1 = site / 'pkg1' pkg2 = pkg1 / 'pkg2' pkg2.ensure_dir() - (pkg1 / '__init__.py').write_text(ns_str, encoding='utf-8') - (pkg2 / '__init__.py').write_text(ns_str, encoding='utf-8') + (pkg1 / '__init__.py').write_text(self.ns_str, encoding='utf-8') + (pkg2 / '__init__.py').write_text(self.ns_str, encoding='utf-8') import pkg1 assert "pkg1" in pkg_resources._namespace_packages # attempt to import pkg2 from site-pkgs2 @@ -695,7 +696,6 @@ class TestNamespaces: tmpdir / "site-pkgs3", ) - ns_str = "__import__('pkg_resources').declare_namespace(__name__)\n" vers_str = "__version__ = %r" for number, site in enumerate(site_dirs, 1): @@ -704,7 +704,7 @@ class TestNamespaces: nspkg = site / 'nspkg' subpkg = nspkg / 'subpkg' subpkg.ensure_dir() - (nspkg / '__init__.py').write_text(ns_str, encoding='utf-8') + (nspkg / '__init__.py').write_text(self.ns_str, encoding='utf-8') (subpkg / '__init__.py').write_text(vers_str % number, encoding='utf-8') import nspkg.subpkg -- cgit v1.2.3 From 8954900a7c88831cf96679f404c2e02e16cefda0 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 3 Feb 2016 10:22:24 -0500 Subject: Remove unused imports --- pkg_resources/tests/test_resources.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'pkg_resources') diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index e25fbc78..542795cf 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -1,7 +1,5 @@ import os import sys -import tempfile -import shutil import string from pkg_resources.extern.six.moves import map -- cgit v1.2.3 From bc9ec216eb133fd0b593dfd2661878f9c020bc7a Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 7 Feb 2016 09:38:18 -0500 Subject: Fix syntax errors on Python 2 --- pkg_resources/tests/test_resources.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'pkg_resources') diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index 542795cf..efaf8db4 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -618,7 +618,8 @@ class TestNamespaces: a natural tempdir. """ if not hasattr(os, 'symlink'): - return str(tmpdir) + yield str(tmpdir) + return link_name = str(tmpdir) + '-linked' os.symlink(str(tmpdir), link_name) -- cgit v1.2.3 From b8d92af19e26efa9bf50c2d3e63618b0a6f09fa5 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 7 Feb 2016 09:38:50 -0500 Subject: Fix failing tests on Python 2 --- pkg_resources/tests/test_resources.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'pkg_resources') diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index efaf8db4..f2afdf95 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals + import os import sys import string -- cgit v1.2.3