Restore support for packages being installed from urls with fragments (#109267)

pull/109294/head
J. Nick Koston 2024-01-31 21:56:57 -10:00 committed by GitHub
parent 5d3364521f
commit 8afcd53af6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 33 additions and 5 deletions

View File

@ -9,6 +9,7 @@ import os
from pathlib import Path
from subprocess import PIPE, Popen
import sys
from urllib.parse import urlparse
from packaging.requirements import InvalidRequirement, Requirement
@ -40,14 +41,32 @@ def is_installed(requirement_str: str) -> bool:
expected input is a pip compatible package specifier (requirement string)
e.g. "package==1.0.0" or "package>=1.0.0,<2.0.0"
For backward compatibility, it also accepts a URL with a fragment
e.g. "git+https://github.com/pypa/pip#pip>=1"
Returns True when the requirement is met.
Returns False when the package is not installed or doesn't meet req.
"""
try:
req = Requirement(requirement_str)
except InvalidRequirement:
_LOGGER.error("Invalid requirement '%s'", requirement_str)
return False
if "#" not in requirement_str:
_LOGGER.error("Invalid requirement '%s'", requirement_str)
return False
# This is likely a URL with a fragment
# example: git+https://github.com/pypa/pip#pip>=1
# fragment support was originally used to install zip files, and
# we no longer do this in Home Assistant. However, custom
# components started using it to install packages from git
# urls which would make it would be a breaking change to
# remove it.
try:
req = Requirement(urlparse(requirement_str).fragment)
except InvalidRequirement:
_LOGGER.error("Invalid requirement '%s'", requirement_str)
return False
try:
if (installed_version := version(req.name)) is None:

View File

@ -217,7 +217,7 @@ async def test_async_get_user_site(mock_env_copy) -> None:
assert ret == os.path.join(deps_dir, "lib_dir")
def test_check_package_global() -> None:
def test_check_package_global(caplog: pytest.LogCaptureFixture) -> None:
"""Test for an installed package."""
pkg = metadata("homeassistant")
installed_package = pkg["name"]
@ -229,10 +229,19 @@ def test_check_package_global() -> None:
assert package.is_installed(f"{installed_package}<={installed_version}")
assert not package.is_installed(f"{installed_package}<{installed_version}")
assert package.is_installed("-1 invalid_package") is False
assert "Invalid requirement '-1 invalid_package'" in caplog.text
def test_check_package_zip() -> None:
"""Test for an installed zip package."""
def test_check_package_fragment(caplog: pytest.LogCaptureFixture) -> None:
"""Test for an installed package with a fragment."""
assert not package.is_installed(TEST_ZIP_REQ)
assert package.is_installed("git+https://github.com/pypa/pip#pip>=1")
assert not package.is_installed("git+https://github.com/pypa/pip#-1 invalid")
assert (
"Invalid requirement 'git+https://github.com/pypa/pip#-1 invalid'"
in caplog.text
)
def test_get_is_installed() -> None: