aboutsummaryrefslogtreecommitdiffstats
path: root/pkg_resources
diff options
context:
space:
mode:
Diffstat (limited to 'pkg_resources')
-rw-r--r--pkg_resources/__init__.py85
-rw-r--r--pkg_resources/api_tests.txt6
-rw-r--r--pkg_resources/extern/__init__.py7
-rw-r--r--pkg_resources/py2_warn.py21
-rw-r--r--pkg_resources/tests/data/my-test-package-source/setup.cfg0
-rw-r--r--pkg_resources/tests/data/my-test-package-source/setup.py6
-rw-r--r--pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/PKG-INFO10
-rw-r--r--pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/SOURCES.txt7
-rw-r--r--pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/dependency_links.txt1
-rw-r--r--pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/top_level.txt1
-rw-r--r--pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/zip-safe1
-rw-r--r--pkg_resources/tests/data/my-test-package_zipped-egg/my_test_package-1.0-py3.7.eggbin0 -> 843 bytes
-rw-r--r--pkg_resources/tests/test_find_distributions.py58
-rw-r--r--pkg_resources/tests/test_pkg_resources.py16
-rw-r--r--pkg_resources/tests/test_resources.py22
-rw-r--r--pkg_resources/tests/test_working_set.py4
16 files changed, 141 insertions, 104 deletions
diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py
index 1f170cfd..edd3d2e8 100644
--- a/pkg_resources/__init__.py
+++ b/pkg_resources/__init__.py
@@ -55,7 +55,7 @@ except NameError:
FileExistsError = OSError
from pkg_resources.extern import six
-from pkg_resources.extern.six.moves import urllib, map, filter
+from pkg_resources.extern.six.moves import map, filter
# capture these to bypass sandboxing
from os import utime
@@ -83,13 +83,14 @@ __import__('pkg_resources.extern.packaging.version')
__import__('pkg_resources.extern.packaging.specifiers')
__import__('pkg_resources.extern.packaging.requirements')
__import__('pkg_resources.extern.packaging.markers')
+__import__('pkg_resources.py2_warn')
__metaclass__ = type
-if (3, 0) < sys.version_info < (3, 4):
- raise RuntimeError("Python 3.4 or later is required")
+if (3, 0) < sys.version_info < (3, 5):
+ raise RuntimeError("Python 3.5 or later is required")
if six.PY2:
# Those builtin exceptions are only defined in Python 3
@@ -178,10 +179,10 @@ def get_supported_platform():
"""Return this platform's maximum compatible version.
distutils.util.get_platform() normally reports the minimum version
- of Mac OS X that would be required to *use* extensions produced by
+ of macOS that would be required to *use* extensions produced by
distutils. But what we want when checking compatibility is to know the
- version of Mac OS X that we are *running*. To allow usage of packages that
- explicitly require a newer version of Mac OS X, we must also know the
+ version of macOS that we are *running*. To allow usage of packages that
+ explicitly require a newer version of macOS, we must also know the
current version of the OS.
If this condition occurs for any other platform with a version in its
@@ -191,9 +192,9 @@ def get_supported_platform():
m = macosVersionString.match(plat)
if m is not None and sys.platform == "darwin":
try:
- plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3))
+ plat = 'macosx-%s-%s' % ('.'.join(_macos_vers()[:2]), m.group(3))
except ValueError:
- # not Mac OS X
+ # not macOS
pass
return plat
@@ -333,7 +334,7 @@ class UnknownExtra(ResolutionError):
_provider_factories = {}
-PY_MAJOR = sys.version[:3]
+PY_MAJOR = '{}.{}'.format(*sys.version_info)
EGG_DIST = 3
BINARY_DIST = 2
SOURCE_DIST = 1
@@ -364,7 +365,7 @@ def get_provider(moduleOrReq):
return _find_adapter(_provider_factories, loader)(module)
-def _macosx_vers(_cache=[]):
+def _macos_vers(_cache=[]):
if not _cache:
version = platform.mac_ver()[0]
# fallback for MacPorts
@@ -380,7 +381,7 @@ def _macosx_vers(_cache=[]):
return _cache[0]
-def _macosx_arch(machine):
+def _macos_arch(machine):
return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine)
@@ -388,18 +389,18 @@ def get_build_platform():
"""Return this platform's string for platform-specific distributions
XXX Currently this is the same as ``distutils.util.get_platform()``, but it
- needs some hacks for Linux and Mac OS X.
+ needs some hacks for Linux and macOS.
"""
from sysconfig import get_platform
plat = get_platform()
if sys.platform == "darwin" and not plat.startswith('macosx-'):
try:
- version = _macosx_vers()
+ version = _macos_vers()
machine = os.uname()[4].replace(" ", "_")
return "macosx-%d.%d-%s" % (
int(version[0]), int(version[1]),
- _macosx_arch(machine),
+ _macos_arch(machine),
)
except ValueError:
# if someone is running a non-Mac darwin system, this will fall
@@ -425,7 +426,7 @@ def compatible_platforms(provided, required):
# easy case
return True
- # Mac OS X special cases
+ # macOS special cases
reqMac = macosVersionString.match(required)
if reqMac:
provMac = macosVersionString.match(provided)
@@ -434,7 +435,7 @@ def compatible_platforms(provided, required):
if not provMac:
# this is backwards compatibility for packages built before
# setuptools 0.6. All packages built after this point will
- # use the new macosx designation.
+ # use the new macOS designation.
provDarwin = darwinVersionString.match(provided)
if provDarwin:
dversion = int(provDarwin.group(1))
@@ -442,7 +443,7 @@ def compatible_platforms(provided, required):
if dversion == 7 and macosversion >= "10.3" or \
dversion == 8 and macosversion >= "10.4":
return True
- # egg isn't macosx or legacy darwin
+ # egg isn't macOS or legacy darwin
return False
# are they the same major version and machine type?
@@ -1234,12 +1235,13 @@ class ResourceManager:
mode = os.stat(path).st_mode
if mode & stat.S_IWOTH or mode & stat.S_IWGRP:
msg = (
- "%s is writable by group/others and vulnerable to attack "
- "when "
- "used with get_resource_filename. Consider a more secure "
+ "Extraction path is writable by group/others "
+ "and vulnerable to attack when "
+ "used with get_resource_filename ({path}). "
+ "Consider a more secure "
"location (set with .set_extraction_path or the "
- "PYTHON_EGG_CACHE environment variable)." % path
- )
+ "PYTHON_EGG_CACHE environment variable)."
+ ).format(**locals())
warnings.warn(msg, UserWarning)
def postprocess(self, tempname, filename):
@@ -2067,11 +2069,14 @@ def find_on_path(importer, path_item, only=False):
def dist_factory(path_item, entry, only):
- """
- Return a dist_factory for a path_item and entry
- """
+ """Return a dist_factory for the given entry."""
lower = entry.lower()
- is_meta = any(map(lower.endswith, ('.egg-info', '.dist-info')))
+ is_egg_info = lower.endswith('.egg-info')
+ is_dist_info = (
+ lower.endswith('.dist-info') and
+ os.path.isdir(os.path.join(path_item, entry))
+ )
+ is_meta = is_egg_info or is_dist_info
return (
distributions_from_metadata
if is_meta else
@@ -2195,10 +2200,14 @@ def _handle_ns(packageName, path_item):
if importer is None:
return None
- # capture warnings due to #1111
- with warnings.catch_warnings():
- warnings.simplefilter("ignore")
- loader = importer.find_module(packageName)
+ # use find_spec (PEP 451) and fall-back to find_module (PEP 302)
+ try:
+ loader = importer.find_spec(packageName).loader
+ except AttributeError:
+ # capture warnings due to #1111
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ loader = importer.find_module(packageName)
if loader is None:
return None
@@ -2328,7 +2337,8 @@ register_namespace_handler(object, null_ns_handler)
def normalize_path(filename):
"""Normalize a file/dir name for comparison purposes"""
- return os.path.normcase(os.path.realpath(os.path.normpath(_cygwin_patch(filename))))
+ return os.path.normcase(os.path.realpath(os.path.normpath(
+ _cygwin_patch(filename))))
def _cygwin_patch(filename): # pragma: nocover
@@ -2536,15 +2546,6 @@ class EntryPoint:
return maps
-def _remove_md5_fragment(location):
- if not location:
- return ''
- parsed = urllib.parse.urlparse(location)
- if parsed[-1].startswith('md5='):
- return urllib.parse.urlunparse(parsed[:-1] + ('',))
- return location
-
-
def _version_from_file(lines):
"""
Given an iterable of lines from a Metadata file, return
@@ -2601,7 +2602,7 @@ class Distribution:
self.parsed_version,
self.precedence,
self.key,
- _remove_md5_fragment(self.location),
+ self.location,
self.py_version or '',
self.platform or '',
)
@@ -3109,6 +3110,7 @@ class Requirement(packaging.requirements.Requirement):
self.extras = tuple(map(safe_extra, self.extras))
self.hashCmp = (
self.key,
+ self.url,
self.specifier,
frozenset(self.extras),
str(self.marker) if self.marker else None,
@@ -3286,6 +3288,7 @@ def _initialize_master_working_set():
list(map(working_set.add_entry, sys.path))
globals().update(locals())
+
class PkgResourcesDeprecationWarning(Warning):
"""
Base class for warning about deprecations in ``pkg_resources``
diff --git a/pkg_resources/api_tests.txt b/pkg_resources/api_tests.txt
index 0a75170e..ded18800 100644
--- a/pkg_resources/api_tests.txt
+++ b/pkg_resources/api_tests.txt
@@ -36,7 +36,7 @@ Distributions have various introspectable attributes::
>>> dist.version
'0.9'
- >>> dist.py_version == sys.version[:3]
+ >>> dist.py_version == '{}.{}'.format(*sys.version_info)
True
>>> print(dist.platform)
@@ -290,8 +290,8 @@ Platform Compatibility Rules
----------------------------
On the Mac, there are potential compatibility issues for modules compiled
-on newer versions of Mac OS X than what the user is running. Additionally,
-Mac OS X will soon have two platforms to contend with: Intel and PowerPC.
+on newer versions of macOS than what the user is running. Additionally,
+macOS will soon have two platforms to contend with: Intel and PowerPC.
Basic equality works as on other platforms::
diff --git a/pkg_resources/extern/__init__.py b/pkg_resources/extern/__init__.py
index c1eb9e99..bf98d8f2 100644
--- a/pkg_resources/extern/__init__.py
+++ b/pkg_resources/extern/__init__.py
@@ -43,13 +43,6 @@ class VendorImporter:
__import__(extant)
mod = sys.modules[extant]
sys.modules[fullname] = mod
- # mysterious hack:
- # Remove the reference to the extant package/module
- # on later Python versions to cause relative imports
- # in the vendor package to resolve the same modules
- # as those going through this importer.
- if prefix and sys.version_info > (3, 3):
- del sys.modules[extant]
return mod
except ImportError:
pass
diff --git a/pkg_resources/py2_warn.py b/pkg_resources/py2_warn.py
new file mode 100644
index 00000000..bfc35234
--- /dev/null
+++ b/pkg_resources/py2_warn.py
@@ -0,0 +1,21 @@
+import sys
+import warnings
+import textwrap
+
+
+msg = textwrap.dedent("""
+ You are running Setuptools on Python 2, which is no longer
+ supported and
+ >>> SETUPTOOLS WILL STOP WORKING <<<
+ in a subsequent release (no sooner than 2020-04-20).
+ Please ensure you are installing
+ Setuptools using pip 9.x or later or pin to `setuptools<45`
+ in your environment.
+ If you have done those things and are still encountering
+ this message, please follow up at
+ https://bit.ly/setuptools-py2-warning.
+ """)
+
+pre = "Setuptools will stop working on Python 2\n"
+
+sys.version_info < (3,) and warnings.warn(pre + "*" * 60 + msg + "*" * 60)
diff --git a/pkg_resources/tests/data/my-test-package-source/setup.cfg b/pkg_resources/tests/data/my-test-package-source/setup.cfg
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/pkg_resources/tests/data/my-test-package-source/setup.cfg
diff --git a/pkg_resources/tests/data/my-test-package-source/setup.py b/pkg_resources/tests/data/my-test-package-source/setup.py
new file mode 100644
index 00000000..fe80d28f
--- /dev/null
+++ b/pkg_resources/tests/data/my-test-package-source/setup.py
@@ -0,0 +1,6 @@
+import setuptools
+setuptools.setup(
+ name="my-test-package",
+ version="1.0",
+ zip_safe=True,
+)
diff --git a/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/PKG-INFO b/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/PKG-INFO
new file mode 100644
index 00000000..7328e3f7
--- /dev/null
+++ b/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/PKG-INFO
@@ -0,0 +1,10 @@
+Metadata-Version: 1.0
+Name: my-test-package
+Version: 1.0
+Summary: UNKNOWN
+Home-page: UNKNOWN
+Author: UNKNOWN
+Author-email: UNKNOWN
+License: UNKNOWN
+Description: UNKNOWN
+Platform: UNKNOWN
diff --git a/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/SOURCES.txt b/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/SOURCES.txt
new file mode 100644
index 00000000..3c4ee167
--- /dev/null
+++ b/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/SOURCES.txt
@@ -0,0 +1,7 @@
+setup.cfg
+setup.py
+my_test_package.egg-info/PKG-INFO
+my_test_package.egg-info/SOURCES.txt
+my_test_package.egg-info/dependency_links.txt
+my_test_package.egg-info/top_level.txt
+my_test_package.egg-info/zip-safe \ No newline at end of file
diff --git a/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/dependency_links.txt b/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/dependency_links.txt
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/top_level.txt b/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/top_level.txt
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/top_level.txt
@@ -0,0 +1 @@
+
diff --git a/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/zip-safe b/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/zip-safe
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/pkg_resources/tests/data/my-test-package_unpacked-egg/my_test_package-1.0-py3.7.egg/EGG-INFO/zip-safe
@@ -0,0 +1 @@
+
diff --git a/pkg_resources/tests/data/my-test-package_zipped-egg/my_test_package-1.0-py3.7.egg b/pkg_resources/tests/data/my-test-package_zipped-egg/my_test_package-1.0-py3.7.egg
new file mode 100644
index 00000000..5115b895
--- /dev/null
+++ b/pkg_resources/tests/data/my-test-package_zipped-egg/my_test_package-1.0-py3.7.egg
Binary files differ
diff --git a/pkg_resources/tests/test_find_distributions.py b/pkg_resources/tests/test_find_distributions.py
index d735c590..f9594422 100644
--- a/pkg_resources/tests/test_find_distributions.py
+++ b/pkg_resources/tests/test_find_distributions.py
@@ -1,17 +1,9 @@
-import subprocess
-import sys
-
+import py
import pytest
import pkg_resources
-SETUP_TEMPLATE = """
-import setuptools
-setuptools.setup(
- name="my-test-package",
- version="1.0",
- zip_safe=True,
-)
-""".lstrip()
+
+TESTS_DATA_DIR = py.path.local(__file__).dirpath('data')
class TestFindDistributions:
@@ -21,46 +13,22 @@ class TestFindDistributions:
target_dir = tmpdir.mkdir('target')
# place a .egg named directory in the target that is not an egg:
target_dir.mkdir('not.an.egg')
- return str(target_dir)
-
- @pytest.fixture
- def project_dir(self, tmpdir):
- project_dir = tmpdir.mkdir('my-test-package')
- (project_dir / "setup.py").write(SETUP_TEMPLATE)
- return str(project_dir)
+ return target_dir
def test_non_egg_dir_named_egg(self, target_dir):
- dists = pkg_resources.find_distributions(target_dir)
+ dists = pkg_resources.find_distributions(str(target_dir))
assert not list(dists)
- def test_standalone_egg_directory(self, project_dir, target_dir):
- # install this distro as an unpacked egg:
- args = [
- sys.executable,
- '-c', 'from setuptools.command.easy_install import main; main()',
- '-mNx',
- '-d', target_dir,
- '--always-unzip',
- project_dir,
- ]
- subprocess.check_call(args)
- dists = pkg_resources.find_distributions(target_dir)
+ def test_standalone_egg_directory(self, target_dir):
+ (TESTS_DATA_DIR / 'my-test-package_unpacked-egg').copy(target_dir)
+ dists = pkg_resources.find_distributions(str(target_dir))
assert [dist.project_name for dist in dists] == ['my-test-package']
- dists = pkg_resources.find_distributions(target_dir, only=True)
+ dists = pkg_resources.find_distributions(str(target_dir), only=True)
assert not list(dists)
- def test_zipped_egg(self, project_dir, target_dir):
- # install this distro as an unpacked egg:
- args = [
- sys.executable,
- '-c', 'from setuptools.command.easy_install import main; main()',
- '-mNx',
- '-d', target_dir,
- '--zip-ok',
- project_dir,
- ]
- subprocess.check_call(args)
- dists = pkg_resources.find_distributions(target_dir)
+ def test_zipped_egg(self, target_dir):
+ (TESTS_DATA_DIR / 'my-test-package_zipped-egg').copy(target_dir)
+ dists = pkg_resources.find_distributions(str(target_dir))
assert [dist.project_name for dist in dists] == ['my-test-package']
- dists = pkg_resources.find_distributions(target_dir, only=True)
+ dists = pkg_resources.find_distributions(str(target_dir), only=True)
assert not list(dists)
diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py
index 5960868a..189a8668 100644
--- a/pkg_resources/tests/test_pkg_resources.py
+++ b/pkg_resources/tests/test_pkg_resources.py
@@ -17,7 +17,9 @@ try:
except ImportError:
import mock
-from pkg_resources import DistInfoDistribution, Distribution, EggInfoDistribution
+from pkg_resources import (
+ DistInfoDistribution, Distribution, EggInfoDistribution,
+)
from setuptools.extern import six
from pkg_resources.extern.six.moves import map
from pkg_resources.extern.six import text_type, string_types
@@ -279,8 +281,8 @@ def make_distribution_no_version(tmpdir, basename):
('dist-info', 'METADATA', DistInfoDistribution),
],
)
-def test_distribution_version_missing(tmpdir, suffix, expected_filename,
- expected_dist_type):
+def test_distribution_version_missing(
+ tmpdir, suffix, expected_filename, expected_dist_type):
"""
Test Distribution.version when the "Version" header is missing.
"""
@@ -328,6 +330,14 @@ def test_distribution_version_missing_undetected_path():
assert msg == expected
+@pytest.mark.parametrize('only', [False, True])
+def test_dist_info_is_not_dir(tmp_path, only):
+ """Test path containing a file with dist-info extension."""
+ dist_info = tmp_path / 'foobar.dist-info'
+ dist_info.touch()
+ assert not pkg_resources.dist_factory(str(tmp_path), str(dist_info), only)
+
+
class TestDeepVersionLookupDistutils:
@pytest.fixture
def env(self, tmpdir):
diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py
index 86afcf74..ed7cdfcc 100644
--- a/pkg_resources/tests/test_resources.py
+++ b/pkg_resources/tests/test_resources.py
@@ -15,7 +15,7 @@ import pkg_resources
from pkg_resources import (
parse_requirements, VersionConflict, parse_version,
Distribution, EntryPoint, Requirement, safe_version, safe_name,
- WorkingSet, PkgResourcesDeprecationWarning)
+ WorkingSet)
# from Python 3.6 docs.
@@ -116,7 +116,7 @@ class TestDistro:
self.checkFooPkg(d)
d = Distribution("/some/path")
- assert d.py_version == sys.version[:3]
+ assert d.py_version == '{}.{}'.format(*sys.version_info)
assert d.platform is None
def testDistroParse(self):
@@ -501,7 +501,6 @@ class TestEntryPoints:
ep.load(require=False)
-
class TestRequirements:
def testBasics(self):
r = Requirement.parse("Twisted>=1.2")
@@ -520,6 +519,11 @@ class TestRequirements:
assert r1 == r2
assert str(r1) == str(r2)
assert str(r2) == "Twisted==1.2c1,>=1.2"
+ assert (
+ Requirement("Twisted")
+ !=
+ Requirement("Twisted @ https://localhost/twisted.zip")
+ )
def testBasicContains(self):
r = Requirement("Twisted>=1.2")
@@ -546,11 +550,23 @@ class TestRequirements:
==
hash((
"twisted",
+ None,
packaging.specifiers.SpecifierSet(">=1.2"),
frozenset(["foo", "bar"]),
None
))
)
+ assert (
+ hash(Requirement.parse("Twisted @ https://localhost/twisted.zip"))
+ ==
+ hash((
+ "twisted",
+ "https://localhost/twisted.zip",
+ packaging.specifiers.SpecifierSet(),
+ frozenset(),
+ None
+ ))
+ )
def testVersionEquality(self):
r1 = Requirement.parse("foo==0.3a2")
diff --git a/pkg_resources/tests/test_working_set.py b/pkg_resources/tests/test_working_set.py
index b3ca4ea8..7a759bbb 100644
--- a/pkg_resources/tests/test_working_set.py
+++ b/pkg_resources/tests/test_working_set.py
@@ -14,8 +14,8 @@ __metaclass__ = type
def strip_comments(s):
return '\n'.join(
- l for l in s.split('\n')
- if l.strip() and not l.strip().startswith('#')
+ line for line in s.split('\n')
+ if line.strip() and not line.strip().startswith('#')
)