qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] mkvenv: always pass locally-installed packages to pip


From: John Snow
Subject: Re: [PATCH] mkvenv: always pass locally-installed packages to pip
Date: Tue, 6 Jun 2023 15:52:31 -0400

On Tue, Jun 6, 2023 at 4:23 AM Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> Let pip decide whether a new version should be installed or the current
> one is okay.  This ensures that the virtual environment is updated
> (either upgraded or downgraded) whenever a new version of a package is
> requested.
>
> The hardest part here is figuring out if a package is installed in
> the venv (which also has to be done twice to account for the presence
> of either setuptools in Python <3.8, or importlib in Python >=3.8).
>
> Suggested-by: Peter Maydell <peter.maydell@linaro.org>
> Cc: John Snow <jsnow@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  python/scripts/mkvenv.py | 76 ++++++++++++++++++++++++++++++++++++++--

:(

The best laid plans of mice and men,

--js

>  1 file changed, 74 insertions(+), 2 deletions(-)
>
> diff --git a/python/scripts/mkvenv.py b/python/scripts/mkvenv.py
> index 3a9aef46a51..3957e7d6e08 100644
> --- a/python/scripts/mkvenv.py
> +++ b/python/scripts/mkvenv.py
> @@ -553,6 +553,74 @@ 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: Union[str, Path], path: Union[str, Path]) -> 
> bool:
> +    prefix = str(prefix)
> +    path = str(path)
> +    try:
> +        return os.path.commonpath([prefix, path]) == prefix
> +    except ValueError:
> +        return False
> +
> +
> +def _is_system_package(package: str) -> bool:
> +    path = _get_path(package)
> +    return path is not None and 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
> @@ -741,8 +809,12 @@ def _do_ensure(
>      for spec in dep_specs:
>          matcher = distlib.version.LegacyMatcher(spec)
>          ver = _get_version(matcher.name)
> -        if ver is None or not matcher.match(
> -            distlib.version.LegacyVersion(ver)
> +        if (
> +            ver is None
> +            # Always pass installed package to pip, so that they can be
> +            # updated if the requested version changes
> +            or not _is_system_package(matcher.name)
> +            or not matcher.match(distlib.version.LegacyVersion(ver))

Wait, so what exactly does this change? In what cases will we
downgrade and in what cases will we be fine with what we already have?

I'm a little fuzzy on what precisely this fixes, though I gather it's
to do with Avocado-Framework.

>          ):
>              absent.append(spec)
>          else:
> --
> 2.40.1
>




reply via email to

[Prev in Thread] Current Thread [Next in Thread]