Restore support for packages being installed from urls with fragments (#109267)
parent
5d3364521f
commit
8afcd53af6
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue