diff --git a/homeassistant/util/yaml/loader.py b/homeassistant/util/yaml/loader.py index 275a51cd760..4a14afb53b2 100644 --- a/homeassistant/util/yaml/loader.py +++ b/homeassistant/util/yaml/loader.py @@ -1,7 +1,7 @@ """Custom loader.""" from __future__ import annotations -from collections.abc import Iterator +from collections.abc import Callable, Iterator from contextlib import suppress import fnmatch from io import StringIO, TextIOWrapper @@ -23,7 +23,7 @@ except ImportError: ) from homeassistant.exceptions import HomeAssistantError -from homeassistant.helpers.deprecation import deprecated_class +from homeassistant.helpers.frame import report from .const import SECRET_YAML from .objects import Input, NodeDictClass, NodeListClass, NodeStrClass @@ -137,10 +137,36 @@ class FastSafeLoader(FastestAvailableSafeLoader, _LoaderMixin): self.secrets = secrets -@deprecated_class("FastSafeLoader") class SafeLoader(FastSafeLoader): """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): """Python safe loader.""" @@ -151,10 +177,36 @@ class PythonSafeLoader(yaml.SafeLoader, _LoaderMixin): self.secrets = secrets -@deprecated_class("PythonSafeLoader") class SafeLineLoader(PythonSafeLoader): """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 diff --git a/tests/util/yaml/test_init.py b/tests/util/yaml/test_init.py index 6f6f48813ce..c4e5c58e235 100644 --- a/tests/util/yaml/test_init.py +++ b/tests/util/yaml/test_init.py @@ -590,7 +590,7 @@ async def test_loading_actual_file_with_syntax_error( def mock_integration_frame() -> Generator[Mock, None, None]: """Mock as if we're calling code from inside an integration.""" correct_frame = Mock( - filename="/home/paulus/.homeassistant/custom_components/hue/light.py", + filename="/home/paulus/homeassistant/components/hue/light.py", lineno="23", line="self.light.is_on", ) @@ -614,12 +614,12 @@ def mock_integration_frame() -> Generator[Mock, None, None]: @pytest.mark.parametrize( - ("loader_class", "new_class"), + ("loader_class", "message"), [ - (yaml.loader.SafeLoader, "FastSafeLoader"), + (yaml.loader.SafeLoader, "'SafeLoader' instead of 'FastSafeLoader'"), ( yaml.loader.SafeLineLoader, - "PythonSafeLoader", + "'SafeLineLoader' instead of 'PythonSafeLoader'", ), ], ) @@ -628,17 +628,14 @@ async def test_deprecated_loaders( mock_integration_frame: Mock, caplog: pytest.LogCaptureFixture, loader_class, - new_class: str, + message: str, ) -> None: """Test instantiating the deprecated yaml loaders logs a warning.""" with pytest.raises(TypeError), patch( "homeassistant.helpers.frame._REPORTED_INTEGRATIONS", set() ): loader_class() - assert ( - f"{loader_class.__name__} was instantiated from hue, this is a deprecated " - f"class. Use {new_class} instead" - ) in caplog.text + assert (f"Detected that integration 'hue' uses deprecated {message}") in caplog.text def test_string_annotated(try_both_loaders) -> None: