diff --git a/CHANGES.rst b/CHANGES.rst index bf7098cc..84684eec 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,10 @@ +v4.12.0 +======= + +* py-93259: Now raise ``ValueError`` when ``None`` or an empty + string are passed to ``Distribution.from_name`` (and other + callers). + v4.11.4 ======= diff --git a/docs/conf.py b/docs/conf.py index 0192ca80..ec2bfe59 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,6 +20,10 @@ pattern=r'PEP[- ](?P\d+)', url='https://peps.python.org/pep-{pep_number:0>4}/', ), + dict( + pattern=r'(Python #|py-)(?P\d+)', + url='https://github.com/python/cpython/issues/{python}', + ), ], ) } diff --git a/importlib_metadata/__init__.py b/importlib_metadata/__init__.py index ac9bb0bc..8761307a 100644 --- a/importlib_metadata/__init__.py +++ b/importlib_metadata/__init__.py @@ -548,7 +548,7 @@ def locate_file(self, path): """ @classmethod - def from_name(cls, name): + def from_name(cls, name: str): """Return the Distribution for the given package name. :param name: The name of the distribution package to search for. @@ -556,7 +556,10 @@ def from_name(cls, name): package, if found. :raises PackageNotFoundError: When the named package's distribution metadata cannot be found. + :raises ValueError: When an invalid value is supplied for name. """ + if not name: + raise ValueError("A distribution name is required.") try: return next(cls.discover(name=name)) except StopIteration: diff --git a/tests/fixtures.py b/tests/fixtures.py index 08a478ac..6d9a9d2b 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -5,6 +5,7 @@ import pathlib import tempfile import textwrap +import functools import contextlib from .py39compat import FS_NONASCII @@ -294,3 +295,18 @@ def setUp(self): # Add self.zip_name to the front of sys.path. self.resources = contextlib.ExitStack() self.addCleanup(self.resources.close) + + +def parameterize(*args_set): + """Run test method with a series of parameters.""" + + def wrapper(func): + @functools.wraps(func) + def _inner(self): + for args in args_set: + with self.subTest(**args): + func(self, **args) + + return _inner + + return wrapper diff --git a/tests/test_main.py b/tests/test_main.py index 215662dd..921f5d9c 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -50,6 +50,14 @@ def test_new_style_classes(self): self.assertIsInstance(Distribution, type) self.assertIsInstance(MetadataPathFinder, type) + @fixtures.parameterize( + dict(name=None), + dict(name=''), + ) + def test_invalid_inputs_to_from_name(self, name): + with self.assertRaises(Exception): + Distribution.from_name(name) + class ImportTests(fixtures.DistInfoPkg, unittest.TestCase): def test_import_nonexistent_module(self):