Add better handling of deprecated configs (#20565)
* Add better handling of deprecated configs * Embed the call to has_at_most_one_key in deprecated * Add tests for checking the deprecated logs * Add thoroughly documented tests * Always check has_at_most_one_key * Fix typing * Move logging helpers to homea new logging helper * Lint * Rename to KeywordMessage instead of BraceMessage * Remove unneeded KeywordStyleAdapter * Lint * Use dict directly rather than dict.keys() when creating set * Patch the version in unit tests, update logging and use parse_version * Re-add KeywordStyleAdapter and fix tests * Lint * Lint
This commit is contained in:
parent
ee3631e93e
commit
d5fad33599
5 changed files with 487 additions and 40 deletions
|
@ -5,6 +5,7 @@ import os
|
|||
from socket import _GLOBAL_DEFAULT_TIMEOUT
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import homeassistant
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
|
@ -275,7 +276,6 @@ def test_time_period():
|
|||
{}, {'wrong_key': -10}
|
||||
)
|
||||
for value in options:
|
||||
|
||||
with pytest.raises(vol.MultipleInvalid):
|
||||
schema(value)
|
||||
|
||||
|
@ -489,26 +489,323 @@ def test_datetime():
|
|||
schema('2016-11-23T18:59:08')
|
||||
|
||||
|
||||
def test_deprecated(caplog):
|
||||
"""Test deprecation log."""
|
||||
schema = vol.Schema({
|
||||
@pytest.fixture
|
||||
def schema():
|
||||
"""Create a schema used for testing deprecation."""
|
||||
return vol.Schema({
|
||||
'venus': cv.boolean,
|
||||
'mars': cv.boolean
|
||||
'mars': cv.boolean,
|
||||
'jupiter': cv.boolean
|
||||
})
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def version(monkeypatch):
|
||||
"""Patch the version used for testing to 0.5.0."""
|
||||
monkeypatch.setattr(homeassistant.const, '__version__', '0.5.0')
|
||||
|
||||
|
||||
def test_deprecated_with_no_optionals(caplog, schema):
|
||||
"""
|
||||
Test deprecation behaves correctly when optional params are None.
|
||||
|
||||
Expected behavior:
|
||||
- Outputs the appropriate deprecation warning if key is detected
|
||||
- Processes schema without changing any values
|
||||
- No warning or difference in output if key is not provided
|
||||
"""
|
||||
deprecated_schema = vol.All(
|
||||
cv.deprecated('mars'),
|
||||
schema
|
||||
)
|
||||
|
||||
deprecated_schema({'venus': True})
|
||||
# pylint: disable=len-as-condition
|
||||
assert len(caplog.records) == 0
|
||||
|
||||
deprecated_schema({'mars': True})
|
||||
test_data = {'mars': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 1
|
||||
assert caplog.records[0].name == __name__
|
||||
assert ("The 'mars' option (with value 'True') is deprecated, "
|
||||
"please remove it from your configuration.") in caplog.text
|
||||
"please remove it from your configuration") in caplog.text
|
||||
assert test_data == output
|
||||
|
||||
caplog.clear()
|
||||
assert len(caplog.records) == 0
|
||||
|
||||
test_data = {'venus': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 0
|
||||
assert test_data == output
|
||||
|
||||
|
||||
def test_deprecated_with_replacement_key(caplog, schema):
|
||||
"""
|
||||
Test deprecation behaves correctly when only a replacement key is provided.
|
||||
|
||||
Expected behavior:
|
||||
- Outputs the appropriate deprecation warning if key is detected
|
||||
- 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 or difference in output if neither key nor
|
||||
replacement_key are provided
|
||||
"""
|
||||
deprecated_schema = vol.All(
|
||||
cv.deprecated('mars', replacement_key='jupiter'),
|
||||
schema
|
||||
)
|
||||
|
||||
test_data = {'mars': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 1
|
||||
assert ("The 'mars' option (with value 'True') is deprecated, "
|
||||
"please replace it with 'jupiter'") in caplog.text
|
||||
assert {'jupiter': True} == output
|
||||
|
||||
caplog.clear()
|
||||
assert len(caplog.records) == 0
|
||||
|
||||
test_data = {'jupiter': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 0
|
||||
assert test_data == output
|
||||
|
||||
test_data = {'venus': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 0
|
||||
assert test_data == output
|
||||
|
||||
|
||||
def test_deprecated_with_invalidation_version(caplog, schema, version):
|
||||
"""
|
||||
Test deprecation behaves correctly with only an invalidation_version.
|
||||
|
||||
Expected behavior:
|
||||
- Outputs the appropriate deprecation warning if key is detected
|
||||
- Processes schema without changing any values
|
||||
- No warning or difference in output if key is not provided
|
||||
- Once the invalidation_version is crossed, raises vol.Invalid if key
|
||||
is detected
|
||||
"""
|
||||
deprecated_schema = vol.All(
|
||||
cv.deprecated('mars', invalidation_version='1.0.0'),
|
||||
schema
|
||||
)
|
||||
|
||||
message = ("The 'mars' option (with value 'True') is deprecated, "
|
||||
"please remove it from your configuration. "
|
||||
"This option will become invalid in version 1.0.0")
|
||||
|
||||
test_data = {'mars': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 1
|
||||
assert message in caplog.text
|
||||
assert test_data == output
|
||||
|
||||
caplog.clear()
|
||||
assert len(caplog.records) == 0
|
||||
|
||||
test_data = {'venus': False}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 0
|
||||
assert test_data == output
|
||||
|
||||
invalidated_schema = vol.All(
|
||||
cv.deprecated('mars', invalidation_version='0.1.0'),
|
||||
schema
|
||||
)
|
||||
test_data = {'mars': True}
|
||||
with pytest.raises(vol.MultipleInvalid) as exc_info:
|
||||
invalidated_schema(test_data)
|
||||
assert ("The 'mars' option (with value 'True') is deprecated, "
|
||||
"please remove it from your configuration. This option will "
|
||||
"become invalid in version 0.1.0") == str(exc_info.value)
|
||||
|
||||
|
||||
def test_deprecated_with_replacement_key_and_invalidation_version(
|
||||
caplog, schema, version
|
||||
):
|
||||
"""
|
||||
Test deprecation behaves with a replacement key & invalidation_version.
|
||||
|
||||
Expected behavior:
|
||||
- Outputs the appropriate deprecation warning if key is detected
|
||||
- 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 or difference in output if neither key nor
|
||||
replacement_key are provided
|
||||
- Once the invalidation_version is crossed, raises vol.Invalid if key
|
||||
is detected
|
||||
"""
|
||||
deprecated_schema = vol.All(
|
||||
cv.deprecated(
|
||||
'mars', replacement_key='jupiter', invalidation_version='1.0.0'
|
||||
),
|
||||
schema
|
||||
)
|
||||
|
||||
warning = ("The 'mars' option (with value 'True') is deprecated, "
|
||||
"please replace it with 'jupiter'. This option will become "
|
||||
"invalid in version 1.0.0")
|
||||
|
||||
test_data = {'mars': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 1
|
||||
assert warning in caplog.text
|
||||
assert {'jupiter': True} == output
|
||||
|
||||
caplog.clear()
|
||||
assert len(caplog.records) == 0
|
||||
|
||||
test_data = {'jupiter': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 0
|
||||
assert test_data == output
|
||||
|
||||
test_data = {'venus': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 0
|
||||
assert test_data == output
|
||||
|
||||
invalidated_schema = vol.All(
|
||||
cv.deprecated(
|
||||
'mars', replacement_key='jupiter', invalidation_version='0.1.0'
|
||||
),
|
||||
schema
|
||||
)
|
||||
test_data = {'mars': True}
|
||||
with pytest.raises(vol.MultipleInvalid) as exc_info:
|
||||
invalidated_schema(test_data)
|
||||
assert ("The 'mars' option (with value 'True') is deprecated, "
|
||||
"please replace it with 'jupiter'. This option will become "
|
||||
"invalid in version 0.1.0") == str(exc_info.value)
|
||||
|
||||
|
||||
def test_deprecated_with_default(caplog, schema):
|
||||
"""
|
||||
Test deprecation behaves correctly with a default value.
|
||||
|
||||
This is likely a scenario that would never occur.
|
||||
|
||||
Expected behavior:
|
||||
- Behaves identically as when the default value was not present
|
||||
"""
|
||||
deprecated_schema = vol.All(
|
||||
cv.deprecated('mars', default=False),
|
||||
schema
|
||||
)
|
||||
|
||||
test_data = {'mars': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 1
|
||||
assert caplog.records[0].name == __name__
|
||||
assert ("The 'mars' option (with value 'True') is deprecated, "
|
||||
"please remove it from your configuration") in caplog.text
|
||||
assert test_data == output
|
||||
|
||||
caplog.clear()
|
||||
assert len(caplog.records) == 0
|
||||
|
||||
test_data = {'venus': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 0
|
||||
assert test_data == output
|
||||
|
||||
|
||||
def test_deprecated_with_replacement_key_and_default(caplog, schema):
|
||||
"""
|
||||
Test deprecation behaves correctly when only a replacement key is provided.
|
||||
|
||||
Expected behavior:
|
||||
- Outputs the appropriate deprecation warning if key is detected
|
||||
- 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
|
||||
"""
|
||||
deprecated_schema = vol.All(
|
||||
cv.deprecated('mars', replacement_key='jupiter', default=False),
|
||||
schema
|
||||
)
|
||||
|
||||
test_data = {'mars': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 1
|
||||
assert ("The 'mars' option (with value 'True') is deprecated, "
|
||||
"please replace it with 'jupiter'") in caplog.text
|
||||
assert {'jupiter': True} == output
|
||||
|
||||
caplog.clear()
|
||||
assert len(caplog.records) == 0
|
||||
|
||||
test_data = {'jupiter': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 0
|
||||
assert test_data == output
|
||||
|
||||
test_data = {'venus': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 0
|
||||
assert {'venus': True, 'jupiter': False} == output
|
||||
|
||||
|
||||
def test_deprecated_with_replacement_key_invalidation_version_default(
|
||||
caplog, schema, version
|
||||
):
|
||||
"""
|
||||
Test deprecation with a replacement key, invalidation_version & default.
|
||||
|
||||
Expected behavior:
|
||||
- Outputs the appropriate deprecation warning if key is detected
|
||||
- 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
|
||||
- Once the invalidation_version is crossed, raises vol.Invalid if key
|
||||
is detected
|
||||
"""
|
||||
deprecated_schema = vol.All(
|
||||
cv.deprecated(
|
||||
'mars', replacement_key='jupiter', invalidation_version='1.0.0',
|
||||
default=False
|
||||
),
|
||||
schema
|
||||
)
|
||||
|
||||
test_data = {'mars': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 1
|
||||
assert ("The 'mars' option (with value 'True') is deprecated, "
|
||||
"please replace it with 'jupiter'. This option will become "
|
||||
"invalid in version 1.0.0") in caplog.text
|
||||
assert {'jupiter': True} == output
|
||||
|
||||
caplog.clear()
|
||||
assert len(caplog.records) == 0
|
||||
|
||||
test_data = {'jupiter': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 0
|
||||
assert test_data == output
|
||||
|
||||
test_data = {'venus': True}
|
||||
output = deprecated_schema(test_data.copy())
|
||||
assert len(caplog.records) == 0
|
||||
assert {'venus': True, 'jupiter': False} == output
|
||||
|
||||
invalidated_schema = vol.All(
|
||||
cv.deprecated(
|
||||
'mars', replacement_key='jupiter', invalidation_version='0.1.0'
|
||||
),
|
||||
schema
|
||||
)
|
||||
test_data = {'mars': True}
|
||||
with pytest.raises(vol.MultipleInvalid) as exc_info:
|
||||
invalidated_schema(test_data)
|
||||
assert ("The 'mars' option (with value 'True') is deprecated, "
|
||||
"please replace it with 'jupiter'. This option will become "
|
||||
"invalid in version 0.1.0") == str(exc_info.value)
|
||||
|
||||
|
||||
def test_key_dependency():
|
||||
|
@ -530,6 +827,18 @@ def test_key_dependency():
|
|||
schema(value)
|
||||
|
||||
|
||||
def test_has_at_most_one_key():
|
||||
"""Test has_at_most_one_key validator."""
|
||||
schema = vol.Schema(cv.has_at_most_one_key('beer', 'soda'))
|
||||
|
||||
for value in (None, [], {'beer': None, 'soda': None}):
|
||||
with pytest.raises(vol.MultipleInvalid):
|
||||
schema(value)
|
||||
|
||||
for value in ({}, {'beer': None}, {'soda': None}):
|
||||
schema(value)
|
||||
|
||||
|
||||
def test_has_at_least_one_key():
|
||||
"""Test has_at_least_one_key validator."""
|
||||
schema = vol.Schema(cv.has_at_least_one_key('beer', 'soda'))
|
||||
|
@ -582,7 +891,7 @@ def test_matches_regex():
|
|||
schema(" nrtd ")
|
||||
|
||||
test_str = "This is a test including uiae."
|
||||
assert(schema(test_str) == test_str)
|
||||
assert (schema(test_str) == test_str)
|
||||
|
||||
|
||||
def test_is_regex():
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue