mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
[core] Auto-replace / in entity names with Unicode fraction slash during deprecation period (#13016)
This commit is contained in:
@@ -1981,16 +1981,31 @@ MQTT_COMMAND_COMPONENT_SCHEMA = MQTT_COMPONENT_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Unicode FRACTION SLASH (U+2044) - visually similar to '/' but URL-safe
|
||||||
|
FRACTION_SLASH = "\u2044"
|
||||||
|
|
||||||
|
|
||||||
def _validate_no_slash(value):
|
def _validate_no_slash(value):
|
||||||
"""Validate that a name does not contain '/' characters.
|
"""Validate that a name does not contain '/' characters.
|
||||||
|
|
||||||
The '/' character is used as a path separator in web server URLs,
|
The '/' character is used as a path separator in web server URLs,
|
||||||
so it cannot be used in entity or device names.
|
so it cannot be used in entity or device names.
|
||||||
|
|
||||||
|
During the deprecation period, '/' is automatically replaced with
|
||||||
|
the visually similar Unicode FRACTION SLASH (U+2044) character.
|
||||||
"""
|
"""
|
||||||
if "/" in value:
|
if "/" in value:
|
||||||
raise Invalid(
|
# Remove before 2026.7.0
|
||||||
f"Name cannot contain '/' character (used as URL path separator): {value}"
|
new_value = value.replace("/", FRACTION_SLASH)
|
||||||
|
_LOGGER.warning(
|
||||||
|
"'%s' contains '/' which is reserved as a URL path separator. "
|
||||||
|
"Automatically replacing with '%s' (Unicode FRACTION SLASH). "
|
||||||
|
"Please update your configuration. "
|
||||||
|
"This will become an error in ESPHome 2026.7.0.",
|
||||||
|
value,
|
||||||
|
new_value,
|
||||||
)
|
)
|
||||||
|
return new_value
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
@@ -2019,7 +2034,7 @@ def _validate_entity_name(value):
|
|||||||
f"Maximum length is {NAME_MAX_LENGTH} characters."
|
f"Maximum length is {NAME_MAX_LENGTH} characters."
|
||||||
)
|
)
|
||||||
# Validate no '/' in name for web server URL compatibility
|
# Validate no '/' in name for web server URL compatibility
|
||||||
_validate_no_slash(value)
|
value = _validate_no_slash(value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -510,10 +510,23 @@ def test_string_no_slash__valid(value: str) -> None:
|
|||||||
assert actual == value
|
assert actual == value
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("value", ("has/slash", "a/b/c", "/leading", "trailing/"))
|
@pytest.mark.parametrize(
|
||||||
def test_string_no_slash__slash_rejected(value: str) -> None:
|
("value", "expected"),
|
||||||
with pytest.raises(Invalid, match="cannot contain '/' character"):
|
(
|
||||||
config_validation.string_no_slash(value)
|
("has/slash", "has⁄slash"),
|
||||||
|
("a/b/c", "a⁄b⁄c"),
|
||||||
|
("/leading", "⁄leading"),
|
||||||
|
("trailing/", "trailing⁄"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
def test_string_no_slash__slash_replaced_with_warning(
|
||||||
|
value: str, expected: str, caplog: pytest.LogCaptureFixture
|
||||||
|
) -> None:
|
||||||
|
"""Test that '/' is auto-replaced with fraction slash and warning is logged."""
|
||||||
|
actual = config_validation.string_no_slash(value)
|
||||||
|
assert actual == expected
|
||||||
|
assert "reserved as a URL path separator" in caplog.text
|
||||||
|
assert "will become an error in ESPHome 2026.7.0" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
def test_string_no_slash__long_string_allowed() -> None:
|
def test_string_no_slash__long_string_allowed() -> None:
|
||||||
@@ -532,9 +545,13 @@ def test_validate_entity_name__valid(value: str) -> None:
|
|||||||
assert actual == value
|
assert actual == value
|
||||||
|
|
||||||
|
|
||||||
def test_validate_entity_name__slash_rejected() -> None:
|
def test_validate_entity_name__slash_replaced_with_warning(
|
||||||
with pytest.raises(Invalid, match="cannot contain '/' character"):
|
caplog: pytest.LogCaptureFixture,
|
||||||
config_validation._validate_entity_name("has/slash")
|
) -> None:
|
||||||
|
"""Test that '/' in entity names is auto-replaced with fraction slash."""
|
||||||
|
actual = config_validation._validate_entity_name("has/slash")
|
||||||
|
assert actual == "has⁄slash"
|
||||||
|
assert "reserved as a URL path separator" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
def test_validate_entity_name__max_length() -> None:
|
def test_validate_entity_name__max_length() -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user