mirror of
https://github.com/esphome/esphome.git
synced 2025-07-31 15:37:49 +00:00
Add cv.deprecated and cv.removed to config validation
These are adapted from HA core Currently we remove keys from YAML which breaks user configurations without any notice. In HA we mark these as deprecated or removed which gives users time to adapt. Example https://github.com/esphome/esphome/pull/7770/files#diff-8d5bfacdc6c7d62624eeb1029bdcec74878e95cf16fc5e421c2fb2c87b879680L75
This commit is contained in:
parent
31e90e5544
commit
3b6eede039
@ -8,6 +8,7 @@ import logging
|
||||
import os
|
||||
import re
|
||||
from string import ascii_letters, digits
|
||||
from typing import Callable
|
||||
import uuid as uuid_
|
||||
|
||||
import voluptuous as vol
|
||||
@ -88,6 +89,8 @@ from esphome.util import parse_esphome_version
|
||||
from esphome.voluptuous_schema import _Schema
|
||||
from esphome.yaml_util import make_data_base
|
||||
|
||||
from .frame import get_component_logger
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# pylint: disable=consider-using-f-string
|
||||
@ -2259,3 +2262,120 @@ def rename_key(old_key, new_key):
|
||||
return config
|
||||
|
||||
return validator
|
||||
|
||||
|
||||
def _deprecated_or_removed(
|
||||
key: str,
|
||||
replacement_key: str | None,
|
||||
default: Any | None,
|
||||
raise_if_present: bool,
|
||||
option_removed: bool,
|
||||
) -> Callable[[dict], dict]:
|
||||
"""Log key as deprecated and provide a replacement (if exists) or fail.
|
||||
|
||||
Expected behavior:
|
||||
- Outputs or throws the appropriate deprecation warning if key is detected
|
||||
- Outputs or throws the appropriate error if key is detected
|
||||
and removed from support
|
||||
- Processes schema moving the value from key to replacement_key
|
||||
- Processes schema changing nothing if only replacement_key provided
|
||||
- No warning if only replacement_key provided
|
||||
- No warning if neither key nor replacement_key are provided
|
||||
- Adds replacement_key with default value in this case
|
||||
"""
|
||||
|
||||
def validator(config: dict) -> dict:
|
||||
"""Check if key is in config and log warning or error."""
|
||||
if key in config:
|
||||
if option_removed:
|
||||
level = logging.ERROR
|
||||
option_status = "has been removed"
|
||||
else:
|
||||
level = logging.WARNING
|
||||
option_status = "is deprecated"
|
||||
|
||||
try:
|
||||
# near = (
|
||||
# f"near {config.__config_file__}" # type: ignore[attr-defined]
|
||||
# f":{config.__line__} " # type: ignore[attr-defined]
|
||||
# )
|
||||
near = "" # TODO: fix this
|
||||
except AttributeError:
|
||||
near = ""
|
||||
arguments: tuple[str, ...]
|
||||
if replacement_key:
|
||||
warning = "The '%s' option %s%s, please replace it with '%s'"
|
||||
arguments = (key, near, option_status, replacement_key)
|
||||
else:
|
||||
warning = (
|
||||
"The '%s' option %s%s, please remove it from your configuration"
|
||||
)
|
||||
arguments = (key, near, option_status)
|
||||
|
||||
if raise_if_present:
|
||||
raise vol.Invalid(warning % arguments)
|
||||
|
||||
get_component_logger(__name__).log(level, warning, *arguments)
|
||||
value = config[key]
|
||||
if replacement_key or option_removed:
|
||||
config.pop(key)
|
||||
else:
|
||||
value = default
|
||||
|
||||
keys = [key]
|
||||
if replacement_key:
|
||||
keys.append(replacement_key)
|
||||
if value is not None and (
|
||||
replacement_key not in config or default == config.get(replacement_key)
|
||||
):
|
||||
config[replacement_key] = value
|
||||
|
||||
return has_at_most_one_key(*keys)(config)
|
||||
|
||||
return validator
|
||||
|
||||
|
||||
def deprecated(
|
||||
key: str,
|
||||
replacement_key: str | None = None,
|
||||
default: Any | None = None,
|
||||
raise_if_present: bool | None = False,
|
||||
) -> Callable[[dict], dict]:
|
||||
"""Log key as deprecated and provide a replacement (if exists).
|
||||
|
||||
Expected behavior:
|
||||
- Outputs the appropriate deprecation warning if key is detected
|
||||
or raises an exception
|
||||
- Processes schema moving the value from key to replacement_key
|
||||
- Processes schema changing nothing if only replacement_key provided
|
||||
- No warning if only replacement_key provided
|
||||
- No warning if neither key nor replacement_key are provided
|
||||
- Adds replacement_key with default value in this case
|
||||
"""
|
||||
return _deprecated_or_removed(
|
||||
key,
|
||||
replacement_key=replacement_key,
|
||||
default=default,
|
||||
raise_if_present=raise_if_present or False,
|
||||
option_removed=False,
|
||||
)
|
||||
|
||||
|
||||
def removed(
|
||||
key: str,
|
||||
default: Any | None = None,
|
||||
raise_if_present: bool | None = True,
|
||||
) -> Callable[[dict], dict]:
|
||||
"""Log key as deprecated and fail the config validation.
|
||||
|
||||
Expected behavior:
|
||||
- Outputs the appropriate error if key is detected and removed from
|
||||
support or raises an exception.
|
||||
"""
|
||||
return _deprecated_or_removed(
|
||||
key,
|
||||
replacement_key=None,
|
||||
default=default,
|
||||
raise_if_present=raise_if_present or False,
|
||||
option_removed=True,
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user