Don't use deprecated_class decorator on deprecated YAML classes (#105063)

This commit is contained in:
Erik Montnemery 2023-12-05 11:36:26 +01:00 committed by GitHub
parent ae002e2f38
commit 5b59e043fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 13 deletions

View File

@ -1,7 +1,7 @@
"""Custom loader.""" """Custom loader."""
from __future__ import annotations from __future__ import annotations
from collections.abc import Iterator from collections.abc import Callable, Iterator
from contextlib import suppress from contextlib import suppress
import fnmatch import fnmatch
from io import StringIO, TextIOWrapper from io import StringIO, TextIOWrapper
@ -23,7 +23,7 @@ except ImportError:
) )
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.deprecation import deprecated_class from homeassistant.helpers.frame import report
from .const import SECRET_YAML from .const import SECRET_YAML
from .objects import Input, NodeDictClass, NodeListClass, NodeStrClass from .objects import Input, NodeDictClass, NodeListClass, NodeStrClass
@ -137,10 +137,36 @@ class FastSafeLoader(FastestAvailableSafeLoader, _LoaderMixin):
self.secrets = secrets self.secrets = secrets
@deprecated_class("FastSafeLoader")
class SafeLoader(FastSafeLoader): class SafeLoader(FastSafeLoader):
"""Provided for backwards compatibility. Logs when instantiated.""" """Provided for backwards compatibility. Logs when instantiated."""
def __init__(*args: Any, **kwargs: Any) -> None:
"""Log a warning and call super."""
SafeLoader.__report_deprecated()
FastSafeLoader.__init__(*args, **kwargs)
@classmethod
def add_constructor(cls, tag: str, constructor: Callable) -> None:
"""Log a warning and call super."""
SafeLoader.__report_deprecated()
FastSafeLoader.add_constructor(tag, constructor)
@classmethod
def add_multi_constructor(
cls, tag_prefix: str, multi_constructor: Callable
) -> None:
"""Log a warning and call super."""
SafeLoader.__report_deprecated()
FastSafeLoader.add_multi_constructor(tag_prefix, multi_constructor)
@staticmethod
def __report_deprecated() -> None:
"""Log deprecation warning."""
report(
"uses deprecated 'SafeLoader' instead of 'FastSafeLoader', "
"which will stop working in HA Core 2024.6,"
)
class PythonSafeLoader(yaml.SafeLoader, _LoaderMixin): class PythonSafeLoader(yaml.SafeLoader, _LoaderMixin):
"""Python safe loader.""" """Python safe loader."""
@ -151,10 +177,36 @@ class PythonSafeLoader(yaml.SafeLoader, _LoaderMixin):
self.secrets = secrets self.secrets = secrets
@deprecated_class("PythonSafeLoader")
class SafeLineLoader(PythonSafeLoader): class SafeLineLoader(PythonSafeLoader):
"""Provided for backwards compatibility. Logs when instantiated.""" """Provided for backwards compatibility. Logs when instantiated."""
def __init__(*args: Any, **kwargs: Any) -> None:
"""Log a warning and call super."""
SafeLineLoader.__report_deprecated()
PythonSafeLoader.__init__(*args, **kwargs)
@classmethod
def add_constructor(cls, tag: str, constructor: Callable) -> None:
"""Log a warning and call super."""
SafeLineLoader.__report_deprecated()
PythonSafeLoader.add_constructor(tag, constructor)
@classmethod
def add_multi_constructor(
cls, tag_prefix: str, multi_constructor: Callable
) -> None:
"""Log a warning and call super."""
SafeLineLoader.__report_deprecated()
PythonSafeLoader.add_multi_constructor(tag_prefix, multi_constructor)
@staticmethod
def __report_deprecated() -> None:
"""Log deprecation warning."""
report(
"uses deprecated 'SafeLineLoader' instead of 'PythonSafeLoader', "
"which will stop working in HA Core 2024.6,"
)
LoaderType = FastSafeLoader | PythonSafeLoader LoaderType = FastSafeLoader | PythonSafeLoader

View File

@ -590,7 +590,7 @@ async def test_loading_actual_file_with_syntax_error(
def mock_integration_frame() -> Generator[Mock, None, None]: def mock_integration_frame() -> Generator[Mock, None, None]:
"""Mock as if we're calling code from inside an integration.""" """Mock as if we're calling code from inside an integration."""
correct_frame = Mock( correct_frame = Mock(
filename="/home/paulus/.homeassistant/custom_components/hue/light.py", filename="/home/paulus/homeassistant/components/hue/light.py",
lineno="23", lineno="23",
line="self.light.is_on", line="self.light.is_on",
) )
@ -614,12 +614,12 @@ def mock_integration_frame() -> Generator[Mock, None, None]:
@pytest.mark.parametrize( @pytest.mark.parametrize(
("loader_class", "new_class"), ("loader_class", "message"),
[ [
(yaml.loader.SafeLoader, "FastSafeLoader"), (yaml.loader.SafeLoader, "'SafeLoader' instead of 'FastSafeLoader'"),
( (
yaml.loader.SafeLineLoader, yaml.loader.SafeLineLoader,
"PythonSafeLoader", "'SafeLineLoader' instead of 'PythonSafeLoader'",
), ),
], ],
) )
@ -628,17 +628,14 @@ async def test_deprecated_loaders(
mock_integration_frame: Mock, mock_integration_frame: Mock,
caplog: pytest.LogCaptureFixture, caplog: pytest.LogCaptureFixture,
loader_class, loader_class,
new_class: str, message: str,
) -> None: ) -> None:
"""Test instantiating the deprecated yaml loaders logs a warning.""" """Test instantiating the deprecated yaml loaders logs a warning."""
with pytest.raises(TypeError), patch( with pytest.raises(TypeError), patch(
"homeassistant.helpers.frame._REPORTED_INTEGRATIONS", set() "homeassistant.helpers.frame._REPORTED_INTEGRATIONS", set()
): ):
loader_class() loader_class()
assert ( assert (f"Detected that integration 'hue' uses deprecated {message}") in caplog.text
f"{loader_class.__name__} was instantiated from hue, this is a deprecated "
f"class. Use {new_class} instead"
) in caplog.text
def test_string_annotated(try_both_loaders) -> None: def test_string_annotated(try_both_loaders) -> None: