Allow passing breaks_in_ha_version to deprecation helper decorators (#104985)
This commit is contained in:
parent
d8a6d864c0
commit
db51a8e1f7
4 changed files with 67 additions and 24 deletions
|
@ -97,7 +97,7 @@ def get_deprecated(
|
||||||
|
|
||||||
|
|
||||||
def deprecated_class(
|
def deprecated_class(
|
||||||
replacement: str,
|
replacement: str, *, breaks_in_ha_version: str | None = None
|
||||||
) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]:
|
) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]:
|
||||||
"""Mark class as deprecated and provide a replacement class to be used instead.
|
"""Mark class as deprecated and provide a replacement class to be used instead.
|
||||||
|
|
||||||
|
@ -111,7 +111,9 @@ def deprecated_class(
|
||||||
@functools.wraps(cls)
|
@functools.wraps(cls)
|
||||||
def deprecated_cls(*args: _P.args, **kwargs: _P.kwargs) -> _R:
|
def deprecated_cls(*args: _P.args, **kwargs: _P.kwargs) -> _R:
|
||||||
"""Wrap for the original class."""
|
"""Wrap for the original class."""
|
||||||
_print_deprecation_warning(cls, replacement, "class", "instantiated")
|
_print_deprecation_warning(
|
||||||
|
cls, replacement, "class", "instantiated", breaks_in_ha_version
|
||||||
|
)
|
||||||
return cls(*args, **kwargs)
|
return cls(*args, **kwargs)
|
||||||
|
|
||||||
return deprecated_cls
|
return deprecated_cls
|
||||||
|
@ -120,7 +122,7 @@ def deprecated_class(
|
||||||
|
|
||||||
|
|
||||||
def deprecated_function(
|
def deprecated_function(
|
||||||
replacement: str,
|
replacement: str, *, breaks_in_ha_version: str | None = None
|
||||||
) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]:
|
) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]:
|
||||||
"""Mark function as deprecated and provide a replacement to be used instead.
|
"""Mark function as deprecated and provide a replacement to be used instead.
|
||||||
|
|
||||||
|
@ -134,7 +136,9 @@ def deprecated_function(
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
def deprecated_func(*args: _P.args, **kwargs: _P.kwargs) -> _R:
|
def deprecated_func(*args: _P.args, **kwargs: _P.kwargs) -> _R:
|
||||||
"""Wrap for the original function."""
|
"""Wrap for the original function."""
|
||||||
_print_deprecation_warning(func, replacement, "function", "called")
|
_print_deprecation_warning(
|
||||||
|
func, replacement, "function", "called", breaks_in_ha_version
|
||||||
|
)
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
return deprecated_func
|
return deprecated_func
|
||||||
|
@ -147,15 +151,21 @@ def _print_deprecation_warning(
|
||||||
replacement: str,
|
replacement: str,
|
||||||
description: str,
|
description: str,
|
||||||
verb: str,
|
verb: str,
|
||||||
|
breaks_in_ha_version: str | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
logger = logging.getLogger(obj.__module__)
|
logger = logging.getLogger(obj.__module__)
|
||||||
|
if breaks_in_ha_version:
|
||||||
|
breaks_in = f" which will be removed in HA Core {breaks_in_ha_version}"
|
||||||
|
else:
|
||||||
|
breaks_in = ""
|
||||||
try:
|
try:
|
||||||
integration_frame = get_integration_frame()
|
integration_frame = get_integration_frame()
|
||||||
except MissingIntegrationFrame:
|
except MissingIntegrationFrame:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"%s is a deprecated %s. Use %s instead",
|
"%s is a deprecated %s%s. Use %s instead",
|
||||||
obj.__name__,
|
obj.__name__,
|
||||||
description,
|
description,
|
||||||
|
breaks_in,
|
||||||
replacement,
|
replacement,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
@ -170,22 +180,24 @@ def _print_deprecation_warning(
|
||||||
)
|
)
|
||||||
logger.warning(
|
logger.warning(
|
||||||
(
|
(
|
||||||
"%s was %s from %s, this is a deprecated %s. Use %s instead,"
|
"%s was %s from %s, this is a deprecated %s%s. Use %s instead,"
|
||||||
" please %s"
|
" please %s"
|
||||||
),
|
),
|
||||||
obj.__name__,
|
obj.__name__,
|
||||||
verb,
|
verb,
|
||||||
integration_frame.integration,
|
integration_frame.integration,
|
||||||
description,
|
description,
|
||||||
|
breaks_in,
|
||||||
replacement,
|
replacement,
|
||||||
report_issue,
|
report_issue,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"%s was %s from %s, this is a deprecated %s. Use %s instead",
|
"%s was %s from %s, this is a deprecated %s%s. Use %s instead",
|
||||||
obj.__name__,
|
obj.__name__,
|
||||||
verb,
|
verb,
|
||||||
integration_frame.integration,
|
integration_frame.integration,
|
||||||
description,
|
description,
|
||||||
|
breaks_in,
|
||||||
replacement,
|
replacement,
|
||||||
)
|
)
|
||||||
|
|
|
@ -137,7 +137,7 @@ class FastSafeLoader(FastestAvailableSafeLoader, _LoaderMixin):
|
||||||
self.secrets = secrets
|
self.secrets = secrets
|
||||||
|
|
||||||
|
|
||||||
@deprecated_class("FastSafeLoader")
|
@deprecated_class("FastSafeLoader", breaks_in_ha_version="2024.6")
|
||||||
class SafeLoader(FastSafeLoader):
|
class SafeLoader(FastSafeLoader):
|
||||||
"""Provided for backwards compatibility. Logs when instantiated."""
|
"""Provided for backwards compatibility. Logs when instantiated."""
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ class PythonSafeLoader(yaml.SafeLoader, _LoaderMixin):
|
||||||
self.secrets = secrets
|
self.secrets = secrets
|
||||||
|
|
||||||
|
|
||||||
@deprecated_class("PythonSafeLoader")
|
@deprecated_class("PythonSafeLoader", breaks_in_ha_version="2024.6")
|
||||||
class SafeLineLoader(PythonSafeLoader):
|
class SafeLineLoader(PythonSafeLoader):
|
||||||
"""Provided for backwards compatibility. Logs when instantiated."""
|
"""Provided for backwards compatibility. Logs when instantiated."""
|
||||||
|
|
||||||
|
|
|
@ -119,32 +119,52 @@ def test_deprecated_class(mock_get_logger) -> None:
|
||||||
assert len(mock_logger.warning.mock_calls) == 1
|
assert len(mock_logger.warning.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
def test_deprecated_function(caplog: pytest.LogCaptureFixture) -> None:
|
@pytest.mark.parametrize(
|
||||||
|
("breaks_in_ha_version", "extra_msg"),
|
||||||
|
[
|
||||||
|
(None, ""),
|
||||||
|
("2099.1", " which will be removed in HA Core 2099.1"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_deprecated_function(
|
||||||
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
breaks_in_ha_version: str | None,
|
||||||
|
extra_msg: str,
|
||||||
|
) -> None:
|
||||||
"""Test deprecated_function decorator.
|
"""Test deprecated_function decorator.
|
||||||
|
|
||||||
This tests the behavior when the calling integration is not known.
|
This tests the behavior when the calling integration is not known.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@deprecated_function("new_function")
|
@deprecated_function("new_function", breaks_in_ha_version=breaks_in_ha_version)
|
||||||
def mock_deprecated_function():
|
def mock_deprecated_function():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
mock_deprecated_function()
|
mock_deprecated_function()
|
||||||
assert (
|
assert (
|
||||||
"mock_deprecated_function is a deprecated function. Use new_function instead"
|
f"mock_deprecated_function is a deprecated function{extra_msg}. "
|
||||||
in caplog.text
|
"Use new_function instead"
|
||||||
)
|
) in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("breaks_in_ha_version", "extra_msg"),
|
||||||
|
[
|
||||||
|
(None, ""),
|
||||||
|
("2099.1", " which will be removed in HA Core 2099.1"),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_deprecated_function_called_from_built_in_integration(
|
def test_deprecated_function_called_from_built_in_integration(
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
breaks_in_ha_version: str | None,
|
||||||
|
extra_msg: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test deprecated_function decorator.
|
"""Test deprecated_function decorator.
|
||||||
|
|
||||||
This tests the behavior when the calling integration is built-in.
|
This tests the behavior when the calling integration is built-in.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@deprecated_function("new_function")
|
@deprecated_function("new_function", breaks_in_ha_version=breaks_in_ha_version)
|
||||||
def mock_deprecated_function():
|
def mock_deprecated_function():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -170,14 +190,24 @@ def test_deprecated_function_called_from_built_in_integration(
|
||||||
):
|
):
|
||||||
mock_deprecated_function()
|
mock_deprecated_function()
|
||||||
assert (
|
assert (
|
||||||
"mock_deprecated_function was called from hue, this is a deprecated function. "
|
"mock_deprecated_function was called from hue, "
|
||||||
"Use new_function instead" in caplog.text
|
f"this is a deprecated function{extra_msg}. "
|
||||||
)
|
"Use new_function instead"
|
||||||
|
) in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("breaks_in_ha_version", "extra_msg"),
|
||||||
|
[
|
||||||
|
(None, ""),
|
||||||
|
("2099.1", " which will be removed in HA Core 2099.1"),
|
||||||
|
],
|
||||||
|
)
|
||||||
def test_deprecated_function_called_from_custom_integration(
|
def test_deprecated_function_called_from_custom_integration(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
|
breaks_in_ha_version: str | None,
|
||||||
|
extra_msg: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test deprecated_function decorator.
|
"""Test deprecated_function decorator.
|
||||||
|
|
||||||
|
@ -186,7 +216,7 @@ def test_deprecated_function_called_from_custom_integration(
|
||||||
|
|
||||||
mock_integration(hass, MockModule("hue"), built_in=False)
|
mock_integration(hass, MockModule("hue"), built_in=False)
|
||||||
|
|
||||||
@deprecated_function("new_function")
|
@deprecated_function("new_function", breaks_in_ha_version=breaks_in_ha_version)
|
||||||
def mock_deprecated_function():
|
def mock_deprecated_function():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -212,7 +242,8 @@ def test_deprecated_function_called_from_custom_integration(
|
||||||
):
|
):
|
||||||
mock_deprecated_function()
|
mock_deprecated_function()
|
||||||
assert (
|
assert (
|
||||||
"mock_deprecated_function was called from hue, this is a deprecated function. "
|
"mock_deprecated_function was called from hue, "
|
||||||
"Use new_function instead, please report it to the author of the 'hue' custom "
|
f"this is a deprecated function{extra_msg}. "
|
||||||
"integration" in caplog.text
|
"Use new_function instead, please report it to the author of the "
|
||||||
)
|
"'hue' custom integration"
|
||||||
|
) in caplog.text
|
||||||
|
|
|
@ -637,7 +637,7 @@ async def test_deprecated_loaders(
|
||||||
loader_class()
|
loader_class()
|
||||||
assert (
|
assert (
|
||||||
f"{loader_class.__name__} was instantiated from hue, this is a deprecated "
|
f"{loader_class.__name__} was instantiated from hue, this is a deprecated "
|
||||||
f"class. Use {new_class} instead"
|
f"class which will be removed in HA Core 2024.6. Use {new_class} instead"
|
||||||
) in caplog.text
|
) in caplog.text
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue