Skip to content

Commit 2333a67

Browse files
committed
Include the path in the error message if the version header can't be found.
1 parent f6b5f7f commit 2333a67

File tree

3 files changed

+107
-3
lines changed

3 files changed

+107
-3
lines changed

changelog.d/1664.change.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Include the path to the ``PKG-INFO`` or ``METADATA`` file in the exception
2+
text when the ``Version:`` header can't be found.

pkg_resources/__init__.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,8 +1403,15 @@ def get_resource_string(self, manager, resource_name):
14031403
def has_resource(self, resource_name):
14041404
return self._has(self._fn(self.module_path, resource_name))
14051405

1406+
def get_metadata_path(self, name):
1407+
return self._fn(self.egg_info, name)
1408+
14061409
def has_metadata(self, name):
1407-
return self.egg_info and self._has(self._fn(self.egg_info, name))
1410+
if not self.egg_info:
1411+
return self.egg_info
1412+
1413+
path = self.get_metadata_path(name)
1414+
return self._has(path)
14081415

14091416
def get_metadata(self, name):
14101417
if not self.egg_info:
@@ -1868,6 +1875,9 @@ class FileMetadata(EmptyProvider):
18681875
def __init__(self, path):
18691876
self.path = path
18701877

1878+
def get_metadata_path(self, name):
1879+
return self.path
1880+
18711881
def has_metadata(self, name):
18721882
return name == 'PKG-INFO' and os.path.isfile(self.path)
18731883

@@ -2656,15 +2666,23 @@ def _warn_legacy_version(self):
26562666

26572667
warnings.warn(tmpl.format(**vars(self)), PEP440Warning)
26582668

2669+
def _make_missing_version_message(self):
2670+
path = self._get_metadata_path_for_display(self.PKG_INFO)
2671+
tmpl = "Missing 'Version:' header and/or {} file at path: {}"
2672+
msg = tmpl.format(self.PKG_INFO, path)
2673+
2674+
return msg
2675+
26592676
@property
26602677
def version(self):
26612678
try:
26622679
return self._version
26632680
except AttributeError:
26642681
version = self._get_version()
26652682
if version is None:
2666-
tmpl = "Missing 'Version:' header and/or %s file"
2667-
raise ValueError(tmpl % self.PKG_INFO, self)
2683+
msg = self._make_missing_version_message()
2684+
raise ValueError(msg, self)
2685+
26682686
return version
26692687

26702688
@property
@@ -2722,6 +2740,19 @@ def requires(self, extras=()):
27222740
)
27232741
return deps
27242742

2743+
def _get_metadata_path_for_display(self, name):
2744+
"""
2745+
Return the path to the given metadata file, if available.
2746+
"""
2747+
try:
2748+
path = self.get_metadata_path(name)
2749+
# Handle exceptions e.g. in case the distribution's metadata
2750+
# provider doesn't support get_metadata_path().
2751+
except Exception:
2752+
return '[could not detect]'
2753+
2754+
return path
2755+
27252756
def _get_metadata(self, name):
27262757
if self.has_metadata(name):
27272758
for line in self.get_metadata_lines(name):

pkg_resources/tests/test_pkg_resources.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
except ImportError:
1818
import mock
1919

20+
from pkg_resources import Distribution
2021
from pkg_resources.extern.six.moves import map
2122
from pkg_resources.extern.six import text_type, string_types
2223

@@ -190,6 +191,76 @@ def test_setuptools_not_imported(self):
190191
subprocess.check_call(cmd)
191192

192193

194+
def touch_file(path):
195+
"""
196+
Create an empty file.
197+
"""
198+
with open(path, 'w') as f:
199+
f.write('')
200+
201+
202+
def make_distribution_no_version(tmpdir, basename):
203+
"""
204+
Create a distribution directory with no file containing the version.
205+
"""
206+
# Convert the LocalPath object to a string before joining.
207+
dist_dir = os.path.join(str(tmpdir), basename)
208+
os.mkdir(dist_dir)
209+
# Make the directory non-empty so distributions_from_metadata()
210+
# will detect it and yield it.
211+
touch_file(os.path.join(dist_dir, 'temp.txt'))
212+
213+
dists = list(pkg_resources.distributions_from_metadata(dist_dir))
214+
assert len(dists) == 1
215+
dist, = dists
216+
217+
return dist, dist_dir
218+
219+
220+
class TestDistribution:
221+
222+
def test_version_missing(self, tmpdir):
223+
"""
224+
Check that the error message contains the path to the metadata file.
225+
"""
226+
dist, dist_dir = make_distribution_no_version(tmpdir, 'foo.egg-info')
227+
228+
with pytest.raises(ValueError) as excinfo:
229+
dist.version
230+
231+
err = str(excinfo)
232+
assert (
233+
"Missing 'Version:' header and/or PKG-INFO file at path" in err
234+
)
235+
# Check that the error message contains the path.
236+
metadata_path = os.path.join(dist_dir, 'PKG-INFO')
237+
# Include a string expression after the assert so that the full
238+
# strings will be visible for inspection on failure.
239+
assert metadata_path in err, str((metadata_path, err))
240+
241+
242+
class TestDistInfoDistribution:
243+
244+
def test_version_missing(self, tmpdir):
245+
"""
246+
Check that the error message contains the path to the metadata file.
247+
"""
248+
dist, dist_dir = make_distribution_no_version(tmpdir, 'foo.dist-info')
249+
250+
with pytest.raises(ValueError) as excinfo:
251+
dist.version
252+
253+
err = str(excinfo)
254+
assert (
255+
"Missing 'Version:' header and/or METADATA file at path" in err
256+
)
257+
# Check that the error message contains the path.
258+
metadata_path = os.path.join(dist_dir, 'METADATA')
259+
# Include a string expression after the assert so that the full
260+
# strings will be visible for inspection on failure.
261+
assert metadata_path in err, str((metadata_path, err))
262+
263+
193264
class TestDeepVersionLookupDistutils:
194265
@pytest.fixture
195266
def env(self, tmpdir):

0 commit comments

Comments
 (0)