Skip to content

Commit e461e21

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

File tree

3 files changed

+114
-3
lines changed

3 files changed

+114
-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: 78 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 DistInfoDistribution, Distribution, EggInfoDistribution
2021
from pkg_resources.extern.six.moves import map
2122
from pkg_resources.extern.six import text_type, string_types
2223

@@ -190,6 +191,83 @@ 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+
def check_version_missing(dist, metadata_path, expected_text,
221+
expected_dist_type):
222+
"""
223+
Check accessing dist.version when the "Version" header is missing.
224+
"""
225+
with pytest.raises(ValueError) as excinfo:
226+
dist.version
227+
228+
err = str(excinfo)
229+
# Include a string expression after the assert so the full strings
230+
# will be visible for inspection on failure.
231+
assert expected_text in err, str((expected_text, err))
232+
233+
# Also check the args passed to the ValueError.
234+
msg, dist = excinfo.value.args
235+
assert expected_text in msg
236+
# Check that the message portion contains the path.
237+
assert metadata_path in msg, str((metadata_path, msg))
238+
assert type(dist) == expected_dist_type
239+
240+
241+
class TestDistribution:
242+
243+
def test_version_missing(self, tmpdir):
244+
"""
245+
Test when the "Version" header is missing from the metadata file.
246+
"""
247+
dist, dist_dir = make_distribution_no_version(tmpdir, 'foo.egg-info')
248+
249+
expected_text = "Missing 'Version:' header and/or PKG-INFO file at path: "
250+
metadata_path = os.path.join(dist_dir, 'PKG-INFO')
251+
check_version_missing(dist, metadata_path=metadata_path,
252+
expected_text=expected_text,
253+
expected_dist_type=EggInfoDistribution)
254+
255+
256+
class TestDistInfoDistribution:
257+
258+
def test_version_missing(self, tmpdir):
259+
"""
260+
Test when the "Version" header is missing from the metadata file.
261+
"""
262+
dist, dist_dir = make_distribution_no_version(tmpdir, 'foo.dist-info')
263+
264+
expected_text = "Missing 'Version:' header and/or METADATA file at path: "
265+
metadata_path = os.path.join(dist_dir, 'METADATA')
266+
check_version_missing(dist, metadata_path=metadata_path,
267+
expected_text=expected_text,
268+
expected_dist_type=DistInfoDistribution)
269+
270+
193271
class TestDeepVersionLookupDistutils:
194272
@pytest.fixture
195273
def env(self, tmpdir):

0 commit comments

Comments
 (0)