Skip to content

Commit

Permalink
RF: Split requirement check into function, prefer importlib.metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
effigies committed Aug 17, 2023
1 parent 5bd725d commit 5373f1e
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 24 deletions.
49 changes: 34 additions & 15 deletions lazy_loader/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,27 +194,15 @@ def myfunc():
if not have_module:
not_found_message = f"No module named '{fullname}'"
elif require is not None:
import packaging.requirements

try:
import importlib_metadata
except ImportError:
import importlib.metadata as importlib_metadata

req = packaging.requirements.Requirement(require)
try:
have_module = req.specifier.contains(
importlib_metadata.version(req.name),
prereleases=True,
)
except importlib_metadata.PackageNotFoundError as e:
have_module = _check_requirement(require)
except ModuleNotFoundError as e:
raise ValueError(
f"Found module '{fullname}' but cannot test requirement '{require}'. "
"Requirements must match distribution name, not module name."
) from e

if not have_module:
not_found_message = f"No distribution can be found matching '{require}'"
not_found_message = f"No distribution can be found matching '{require}'"

if not have_module:
if error_on_import:
Expand Down Expand Up @@ -247,6 +235,37 @@ def myfunc():
return module


def _check_requirement(require: str) -> bool:
"""Verify that a package requirement is satisfied
If the package is required, a ``ModuleNotFoundError`` is raised
by ``importlib.metadata``.
Parameters
----------
require : str
A dependency requirement as defined in PEP-508
Returns
-------
satisfied : bool
True if the installed version of the dependency matches
the specified version, False otherwise.
"""
import packaging.requirements

try:
import importlib.metadata as importlib_metadata
except ImportError: # PY37
import importlib_metadata

req = packaging.requirements.Requirement(require)
return req.specifier.contains(
importlib_metadata.version(req.name),
prereleases=True,
)


def have_module(module_like: types.ModuleType) -> bool:
return not isinstance(module_like, DelayedImportErrorModule)

Expand Down
10 changes: 2 additions & 8 deletions lazy_loader/tests/test_lazy_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@

import lazy_loader as lazy

try:
import importlib_metadata # noqa

have_importlib_metadata = True
except ImportError:
have_importlib_metadata = False


def test_lazy_import_basics():
math = lazy.load("math")
Expand Down Expand Up @@ -160,7 +153,8 @@ def test_stub_loading_errors(tmp_path):


def test_require_kwarg():
dot = "_" if have_importlib_metadata else "."
have_importlib_metadata = importlib.util.find_spec("importlib.metadata") is not None
dot = "." if have_importlib_metadata else "_"
# Test with a module that definitely exists, behavior hinges on requirement
with mock.patch(f"importlib{dot}metadata.version") as version:
version.return_value = "1.0.0"
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ classifiers = [
description = "Makes it easy to load subpackages and functions on demand."
dependencies = [
"packaging",
"importlib_metadata; python_version < '3.9'",
"importlib_metadata; python_version < '3.8'",
]

[project.optional-dependencies]
Expand Down

0 comments on commit 5373f1e

Please sign in to comment.