mirror of
https://github.com/home-assistant/core.git
synced 2025-08-06 20:18:21 +00:00
Add hassfest check to help with future dependency updates (#149624)
This commit is contained in:
parent
fe2bd8d09e
commit
f350a1a1fa
@ -43,6 +43,13 @@ PACKAGE_CHECK_VERSION_RANGE = {
|
||||
"urllib3": "SemVer",
|
||||
"yarl": "SemVer",
|
||||
}
|
||||
PACKAGE_CHECK_PREPARE_UPDATE: dict[str, int] = {
|
||||
# In the form dict("dependencyX": n+1)
|
||||
# - dependencyX should be the name of the referenced dependency
|
||||
# - current major version +1
|
||||
# Pandas will only fully support Python 3.14 in v3.
|
||||
"pandas": 3,
|
||||
}
|
||||
PACKAGE_CHECK_VERSION_RANGE_EXCEPTIONS: dict[str, dict[str, set[str]]] = {
|
||||
# In the form dict("domain": {"package": {"dependency1", "dependency2"}})
|
||||
# - domain is the integration domain
|
||||
@ -53,6 +60,10 @@ PACKAGE_CHECK_VERSION_RANGE_EXCEPTIONS: dict[str, dict[str, set[str]]] = {
|
||||
# geocachingapi > reverse_geocode > scipy > numpy
|
||||
"scipy": {"numpy"}
|
||||
},
|
||||
"noaa_tides": {
|
||||
# https://github.com/GClunies/noaa_coops/pull/69
|
||||
"noaa-coops": {"pandas"}
|
||||
},
|
||||
}
|
||||
|
||||
PACKAGE_REGEX = re.compile(
|
||||
@ -568,7 +579,7 @@ def check_dependency_version_range(
|
||||
version == "Any"
|
||||
or (convention := PACKAGE_CHECK_VERSION_RANGE.get(pkg)) is None
|
||||
or all(
|
||||
_is_dependency_version_range_valid(version_part, convention)
|
||||
_is_dependency_version_range_valid(version_part, convention, pkg)
|
||||
for version_part in version.split(";", 1)[0].split(",")
|
||||
)
|
||||
):
|
||||
@ -582,22 +593,35 @@ def check_dependency_version_range(
|
||||
return False
|
||||
|
||||
|
||||
def _is_dependency_version_range_valid(version_part: str, convention: str) -> bool:
|
||||
def _is_dependency_version_range_valid(
|
||||
version_part: str, convention: str, pkg: str | None = None
|
||||
) -> bool:
|
||||
prepare_update = PACKAGE_CHECK_PREPARE_UPDATE.get(pkg) if pkg else None
|
||||
version_match = PIP_VERSION_RANGE_SEPARATOR.match(version_part.strip())
|
||||
operator = version_match.group(1)
|
||||
version = version_match.group(2)
|
||||
awesome = AwesomeVersion(version)
|
||||
|
||||
if operator in (">", ">=", "!="):
|
||||
# Lower version binding and version exclusion are fine
|
||||
return True
|
||||
|
||||
if prepare_update is not None:
|
||||
if operator in ("==", "~="):
|
||||
# Only current major version allowed which prevents updates to the next one
|
||||
return False
|
||||
# Allow upper constraints for major version + 1
|
||||
if operator == "<" and awesome.section(0) < prepare_update + 1:
|
||||
return False
|
||||
if operator == "<=" and awesome.section(0) < prepare_update:
|
||||
return False
|
||||
|
||||
if convention == "SemVer":
|
||||
if operator == "==":
|
||||
# Explicit version with wildcard is allowed only on major version
|
||||
# e.g. ==1.* is allowed, but ==1.2.* is not
|
||||
return version.endswith(".*") and version.count(".") == 1
|
||||
|
||||
awesome = AwesomeVersion(version)
|
||||
if operator in ("<", "<="):
|
||||
# Upper version binding only allowed on major version
|
||||
# e.g. <=3 is allowed, but <=3.1 is not
|
||||
|
@ -1,11 +1,17 @@
|
||||
"""Tests for hassfest requirements."""
|
||||
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from script.hassfest.model import Config, Integration
|
||||
from script.hassfest.requirements import validate_requirements_format
|
||||
from script.hassfest.requirements import (
|
||||
PACKAGE_CHECK_PREPARE_UPDATE,
|
||||
PACKAGE_CHECK_VERSION_RANGE,
|
||||
check_dependency_version_range,
|
||||
validate_requirements_format,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@ -105,3 +111,41 @@ def test_validate_requirements_format_github_custom(integration: Integration) ->
|
||||
integration.path = Path("")
|
||||
assert validate_requirements_format(integration)
|
||||
assert len(integration.errors) == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("version", "result"),
|
||||
[
|
||||
(">2", True),
|
||||
(">=2.0", True),
|
||||
(">=2.0,<4", True),
|
||||
("<4", True),
|
||||
("<=3.0", True),
|
||||
(">=2.0,<4;python_version<'3.14'", True),
|
||||
("<3", False),
|
||||
("==2.*", False),
|
||||
("~=2.0", False),
|
||||
("<=2.100", False),
|
||||
(">2,<3", False),
|
||||
(">=2.0,<3", False),
|
||||
(">=2.0,<3;python_version<'3.14'", False),
|
||||
],
|
||||
)
|
||||
def test_dependency_version_range_prepare_update(
|
||||
version: str, result: bool, integration: Integration
|
||||
) -> None:
|
||||
"""Test dependency version range check for prepare update is working correctly."""
|
||||
with (
|
||||
patch.dict(PACKAGE_CHECK_VERSION_RANGE, {"numpy-test": "SemVer"}, clear=True),
|
||||
patch.dict(PACKAGE_CHECK_PREPARE_UPDATE, {"numpy-test": 3}, clear=True),
|
||||
):
|
||||
assert (
|
||||
check_dependency_version_range(
|
||||
integration,
|
||||
"test",
|
||||
pkg="numpy-test",
|
||||
version=version,
|
||||
package_exceptions=set(),
|
||||
)
|
||||
== result
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user