Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate name arg in Distribution.from_name #391

Merged
merged 4 commits into from Jun 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions 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
=======

Expand Down
4 changes: 4 additions & 0 deletions docs/conf.py
Expand Up @@ -20,6 +20,10 @@
pattern=r'PEP[- ](?P<pep_number>\d+)',
url='https://peps.python.org/pep-{pep_number:0>4}/',
),
dict(
pattern=r'(Python #|py-)(?P<python>\d+)',
url='https://github.com/python/cpython/issues/{python}',
),
],
)
}
Expand Down
5 changes: 4 additions & 1 deletion importlib_metadata/__init__.py
Expand Up @@ -548,15 +548,18 @@ 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.
:return: The Distribution instance (or subclass thereof) for the named
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:
Expand Down
16 changes: 16 additions & 0 deletions tests/fixtures.py
Expand Up @@ -5,6 +5,7 @@
import pathlib
import tempfile
import textwrap
import functools
import contextlib

from .py39compat import FS_NONASCII
Expand Down Expand Up @@ -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
8 changes: 8 additions & 0 deletions tests/test_main.py
Expand Up @@ -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):
Expand Down