Skip to content

Commit

Permalink
mkvenv: assume presence of importlib.metadata
Browse files Browse the repository at this point in the history
importlib.metadata is included in Python 3.8, so there is no
need to fallback to either importlib-metadata or pkgresources
when generating console script shims.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
  • Loading branch information
bonzini committed Sep 7, 2023
1 parent ca056f4 commit 3e4b6b0
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 178 deletions.
197 changes: 28 additions & 169 deletions python/scripts/mkvenv.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
"""

# The duplication between importlib and pkg_resources does not help
# pylint: disable=too-many-lines

# Copyright (C) 2022-2023 Red Hat, Inc.
Expand All @@ -74,6 +73,13 @@
# later. See the COPYING file in the top-level directory.

import argparse
from importlib.metadata import (
Distribution,
EntryPoint,
PackageNotFoundError,
distribution,
version,
)
from importlib.util import find_spec
import logging
import os
Expand Down Expand Up @@ -428,25 +434,7 @@ def _stringify(data: Union[str, bytes]) -> str:
print(builder.get_value("env_exe"))


def _gen_importlib(packages: Sequence[str]) -> Iterator[str]:
# pylint: disable=import-outside-toplevel
# pylint: disable=no-name-in-module
# pylint: disable=import-error
try:
# First preference: Python 3.8+ stdlib
from importlib.metadata import ( # type: ignore
EntryPoint,
PackageNotFoundError,
distribution,
)
except ImportError as exc:
logger.debug("%s", str(exc))
# Second preference: Commonly available PyPI backport
from importlib_metadata import ( # type: ignore
EntryPoint,
PackageNotFoundError,
distribution,
)
def _get_entry_points(packages: Sequence[str]) -> Iterator[str]:

def _generator() -> Iterator[str]:
for package in packages:
Expand All @@ -468,24 +456,6 @@ def _generator() -> Iterator[str]:
return _generator()


def _gen_pkg_resources(packages: Sequence[str]) -> Iterator[str]:
# pylint: disable=import-outside-toplevel
# Bundled with setuptools; has a good chance of being available.
import pkg_resources

def _generator() -> Iterator[str]:
for package in packages:
try:
eps = pkg_resources.get_entry_map(package, "console_scripts")
except pkg_resources.DistributionNotFound:
continue

for entry_point in eps.values():
yield str(entry_point)

return _generator()


def generate_console_scripts(
packages: Sequence[str],
python_path: Optional[str] = None,
Expand All @@ -510,30 +480,11 @@ def generate_console_scripts(
if not packages:
return

def _get_entry_points() -> Iterator[str]:
"""Python 3.7 compatibility shim for iterating entry points."""
# Python 3.8+, or Python 3.7 with importlib_metadata installed.
try:
return _gen_importlib(packages)
except ImportError as exc:
logger.debug("%s", str(exc))

# Python 3.7 with setuptools installed.
try:
return _gen_pkg_resources(packages)
except ImportError as exc:
logger.debug("%s", str(exc))
raise Ouch(
"Neither importlib.metadata nor pkg_resources found, "
"can't generate console script shims.\n"
"Use Python 3.8+, or install importlib-metadata or setuptools."
) from exc

maker = distlib.scripts.ScriptMaker(None, bin_path)
maker.variants = {""}
maker.clobber = False

for entry_point in _get_entry_points():
for entry_point in _get_entry_points(packages):
for filename in maker.make(entry_point):
logger.debug("wrote console_script '%s'", filename)

Expand Down Expand Up @@ -587,57 +538,6 @@ def pkgname_from_depspec(dep_spec: str) -> str:
return match.group(0)


def _get_path_importlib(package: str) -> Optional[str]:
# pylint: disable=import-outside-toplevel
# pylint: disable=no-name-in-module
# pylint: disable=import-error
try:
# First preference: Python 3.8+ stdlib
from importlib.metadata import ( # type: ignore
PackageNotFoundError,
distribution,
)
except ImportError as exc:
logger.debug("%s", str(exc))
# Second preference: Commonly available PyPI backport
from importlib_metadata import ( # type: ignore
PackageNotFoundError,
distribution,
)

try:
return str(distribution(package).locate_file("."))
except PackageNotFoundError:
return None


def _get_path_pkg_resources(package: str) -> Optional[str]:
# pylint: disable=import-outside-toplevel
# Bundled with setuptools; has a good chance of being available.
import pkg_resources

try:
return str(pkg_resources.get_distribution(package).location)
except pkg_resources.DistributionNotFound:
return None


def _get_path(package: str) -> Optional[str]:
try:
return _get_path_importlib(package)
except ImportError as exc:
logger.debug("%s", str(exc))

try:
return _get_path_pkg_resources(package)
except ImportError as exc:
logger.debug("%s", str(exc))
raise Ouch(
"Neither importlib.metadata nor pkg_resources found. "
"Use Python 3.8+, or install importlib-metadata or setuptools."
) from exc


def _path_is_prefix(prefix: Optional[str], path: str) -> bool:
try:
return (
Expand All @@ -647,65 +547,14 @@ def _path_is_prefix(prefix: Optional[str], path: str) -> bool:
return False


def _is_system_package(package: str) -> bool:
path = _get_path(package)
return path is not None and not (
def _is_system_package(dist: Distribution) -> bool:
path = str(dist.locate_file("."))
return not (
_path_is_prefix(sysconfig.get_path("purelib"), path)
or _path_is_prefix(sysconfig.get_path("platlib"), path)
)


def _get_version_importlib(package: str) -> Optional[str]:
# pylint: disable=import-outside-toplevel
# pylint: disable=no-name-in-module
# pylint: disable=import-error
try:
# First preference: Python 3.8+ stdlib
from importlib.metadata import ( # type: ignore
PackageNotFoundError,
distribution,
)
except ImportError as exc:
logger.debug("%s", str(exc))
# Second preference: Commonly available PyPI backport
from importlib_metadata import ( # type: ignore
PackageNotFoundError,
distribution,
)

try:
return str(distribution(package).version)
except PackageNotFoundError:
return None


def _get_version_pkg_resources(package: str) -> Optional[str]:
# pylint: disable=import-outside-toplevel
# Bundled with setuptools; has a good chance of being available.
import pkg_resources

try:
return str(pkg_resources.get_distribution(package).version)
except pkg_resources.DistributionNotFound:
return None


def _get_version(package: str) -> Optional[str]:
try:
return _get_version_importlib(package)
except ImportError as exc:
logger.debug("%s", str(exc))

try:
return _get_version_pkg_resources(package)
except ImportError as exc:
logger.debug("%s", str(exc))
raise Ouch(
"Neither importlib.metadata nor pkg_resources found. "
"Use Python 3.8+, or install importlib-metadata or setuptools."
) from exc


def diagnose(
dep_spec: str,
online: bool,
Expand All @@ -731,7 +580,11 @@ def diagnose(
bad = False

pkg_name = pkgname_from_depspec(dep_spec)
pkg_version = _get_version(pkg_name)
pkg_version: Optional[str] = None
try:
pkg_version = version(pkg_name)
except PackageNotFoundError:
pass

lines = []

Expand Down Expand Up @@ -868,19 +721,25 @@ def _do_ensure(
constraint = _make_version_constraint(info, False)
matcher = distlib.version.LegacyMatcher(name + constraint)
print(f"mkvenv: checking for {matcher}", file=sys.stderr)
ver = _get_version(name)

dist: Optional[Distribution] = None
try:
dist = distribution(matcher.name)
except PackageNotFoundError:
pass

if (
ver is None
dist is None
# Always pass installed package to pip, so that they can be
# updated if the requested version changes
or not _is_system_package(name)
or not matcher.match(distlib.version.LegacyVersion(ver))
or not _is_system_package(dist)
or not matcher.match(distlib.version.LegacyVersion(dist.version))
):
absent.append(name + _make_version_constraint(info, True))
if len(absent) == 1:
canary = info.get("canary", None)
else:
logger.info("found %s %s", name, ver)
logger.info("found %s %s", name, dist.version)
present.append(name)

if present:
Expand Down
9 changes: 0 additions & 9 deletions python/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -108,15 +108,6 @@ ignore_missing_imports = True
[mypy-pygments]
ignore_missing_imports = True

[mypy-importlib.metadata]
ignore_missing_imports = True

[mypy-importlib_metadata]
ignore_missing_imports = True

[mypy-pkg_resources]
ignore_missing_imports = True

[mypy-distlib]
ignore_missing_imports = True

Expand Down

0 comments on commit 3e4b6b0

Please sign in to comment.