mirror of
https://github.com/home-assistant/core.git
synced 2025-12-24 21:06:19 +00:00
Split up yaml loaders into multiple files (#23774)
* Start moving parts of yaml utils to own module Move parts of yaml loader out of the single large file and start to create the structure of the yaml loaders in Ansible [0]. [0]: https://github.com/ansible/ansible/tree/devel/lib/ansible/parsing/yaml * Finish yaml migration, update tests and mocks * Move code around to finish the migration * Update the mocks so that `open` is patched in `homeassistant.util.yaml.loader` instead of `homeassistant.util.yaml`. * Updated mypy ignores * Updated external API of `homeasistant.util.yaml`, see below: Checked what part of the api of `homeassistant.util.yaml` was actually called from outside the tests and added an `__ALL__` that contains only these elements. Updated the tests so that references to internal parts of the API (e.g. the yaml module imported into `homeassistant.util.yaml.loader`) are referenced directly from `homeassistant.util.yaml.loader`. In `tests/test_yaml.py` the import `yaml` refers to `homeassistant.util.yaml` and `yaml_loader` refers to `~.loader`. Future work that remains for the next iteration is to create a custom SafeConstructor and refers to that instead of monkey patching `yaml` with custom loaders. * Update mocks in yaml dumper, check_config
This commit is contained in:
committed by
Paulus Schoutsen
parent
118d3bc11c
commit
4004867eda
@@ -8,7 +8,8 @@ from unittest.mock import patch
|
||||
import pytest
|
||||
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.util import yaml
|
||||
from homeassistant.util.yaml import loader as yaml_loader
|
||||
import homeassistant.util.yaml as yaml
|
||||
from homeassistant.config import YAML_CONFIG_FILE, load_yaml_config_file
|
||||
from tests.common import get_test_config_dir, patch_yaml_files
|
||||
|
||||
@@ -16,7 +17,7 @@ from tests.common import get_test_config_dir, patch_yaml_files
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_credstash():
|
||||
"""Mock credstash so it doesn't connect to the internet."""
|
||||
with patch.object(yaml, 'credstash') as mock_credstash:
|
||||
with patch.object(yaml_loader, 'credstash') as mock_credstash:
|
||||
mock_credstash.getSecret.return_value = None
|
||||
yield mock_credstash
|
||||
|
||||
@@ -25,7 +26,7 @@ def test_simple_list():
|
||||
"""Test simple list."""
|
||||
conf = "config:\n - simple\n - list"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert doc['config'] == ["simple", "list"]
|
||||
|
||||
|
||||
@@ -33,7 +34,7 @@ def test_simple_dict():
|
||||
"""Test simple dict."""
|
||||
conf = "key: value"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert doc['key'] == 'value'
|
||||
|
||||
|
||||
@@ -58,7 +59,7 @@ def test_environment_variable():
|
||||
os.environ["PASSWORD"] = "secret_password"
|
||||
conf = "password: !env_var PASSWORD"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert doc['password'] == "secret_password"
|
||||
del os.environ["PASSWORD"]
|
||||
|
||||
@@ -67,7 +68,7 @@ def test_environment_variable_default():
|
||||
"""Test config file with default value for environment variable."""
|
||||
conf = "password: !env_var PASSWORD secret_password"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert doc['password'] == "secret_password"
|
||||
|
||||
|
||||
@@ -76,7 +77,7 @@ def test_invalid_environment_variable():
|
||||
conf = "password: !env_var PASSWORD"
|
||||
with pytest.raises(HomeAssistantError):
|
||||
with io.StringIO(conf) as file:
|
||||
yaml.yaml.safe_load(file)
|
||||
yaml_loader.yaml.safe_load(file)
|
||||
|
||||
|
||||
def test_include_yaml():
|
||||
@@ -84,17 +85,17 @@ def test_include_yaml():
|
||||
with patch_yaml_files({'test.yaml': 'value'}):
|
||||
conf = 'key: !include test.yaml'
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert doc["key"] == "value"
|
||||
|
||||
with patch_yaml_files({'test.yaml': None}):
|
||||
conf = 'key: !include test.yaml'
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert doc["key"] == {}
|
||||
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
@patch('homeassistant.util.yaml.loader.os.walk')
|
||||
def test_include_dir_list(mock_walk):
|
||||
"""Test include dir list yaml."""
|
||||
mock_walk.return_value = [
|
||||
@@ -107,11 +108,11 @@ def test_include_dir_list(mock_walk):
|
||||
}):
|
||||
conf = "key: !include_dir_list /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert doc["key"] == sorted(["one", "two"])
|
||||
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
@patch('homeassistant.util.yaml.loader.os.walk')
|
||||
def test_include_dir_list_recursive(mock_walk):
|
||||
"""Test include dir recursive list yaml."""
|
||||
mock_walk.return_value = [
|
||||
@@ -129,13 +130,13 @@ def test_include_dir_list_recursive(mock_walk):
|
||||
with io.StringIO(conf) as file:
|
||||
assert '.ignore' in mock_walk.return_value[0][1], \
|
||||
"Expecting .ignore in here"
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert 'tmp2' in mock_walk.return_value[0][1]
|
||||
assert '.ignore' not in mock_walk.return_value[0][1]
|
||||
assert sorted(doc["key"]) == sorted(["zero", "one", "two"])
|
||||
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
@patch('homeassistant.util.yaml.loader.os.walk')
|
||||
def test_include_dir_named(mock_walk):
|
||||
"""Test include dir named yaml."""
|
||||
mock_walk.return_value = [
|
||||
@@ -149,11 +150,11 @@ def test_include_dir_named(mock_walk):
|
||||
conf = "key: !include_dir_named /tmp"
|
||||
correct = {'first': 'one', 'second': 'two'}
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert doc["key"] == correct
|
||||
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
@patch('homeassistant.util.yaml.loader.os.walk')
|
||||
def test_include_dir_named_recursive(mock_walk):
|
||||
"""Test include dir named yaml."""
|
||||
mock_walk.return_value = [
|
||||
@@ -172,13 +173,13 @@ def test_include_dir_named_recursive(mock_walk):
|
||||
with io.StringIO(conf) as file:
|
||||
assert '.ignore' in mock_walk.return_value[0][1], \
|
||||
"Expecting .ignore in here"
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert 'tmp2' in mock_walk.return_value[0][1]
|
||||
assert '.ignore' not in mock_walk.return_value[0][1]
|
||||
assert doc["key"] == correct
|
||||
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
@patch('homeassistant.util.yaml.loader.os.walk')
|
||||
def test_include_dir_merge_list(mock_walk):
|
||||
"""Test include dir merge list yaml."""
|
||||
mock_walk.return_value = [['/tmp', [], ['first.yaml', 'second.yaml']]]
|
||||
@@ -189,11 +190,11 @@ def test_include_dir_merge_list(mock_walk):
|
||||
}):
|
||||
conf = "key: !include_dir_merge_list /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert sorted(doc["key"]) == sorted(["one", "two", "three"])
|
||||
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
@patch('homeassistant.util.yaml.loader.os.walk')
|
||||
def test_include_dir_merge_list_recursive(mock_walk):
|
||||
"""Test include dir merge list yaml."""
|
||||
mock_walk.return_value = [
|
||||
@@ -211,14 +212,14 @@ def test_include_dir_merge_list_recursive(mock_walk):
|
||||
with io.StringIO(conf) as file:
|
||||
assert '.ignore' in mock_walk.return_value[0][1], \
|
||||
"Expecting .ignore in here"
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert 'tmp2' in mock_walk.return_value[0][1]
|
||||
assert '.ignore' not in mock_walk.return_value[0][1]
|
||||
assert sorted(doc["key"]) == sorted(["one", "two",
|
||||
"three", "four"])
|
||||
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
@patch('homeassistant.util.yaml.loader.os.walk')
|
||||
def test_include_dir_merge_named(mock_walk):
|
||||
"""Test include dir merge named yaml."""
|
||||
mock_walk.return_value = [['/tmp', [], ['first.yaml', 'second.yaml']]]
|
||||
@@ -231,7 +232,7 @@ def test_include_dir_merge_named(mock_walk):
|
||||
with patch_yaml_files(files):
|
||||
conf = "key: !include_dir_merge_named /tmp"
|
||||
with io.StringIO(conf) as file:
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert doc["key"] == {
|
||||
"key1": "one",
|
||||
"key2": "two",
|
||||
@@ -239,7 +240,7 @@ def test_include_dir_merge_named(mock_walk):
|
||||
}
|
||||
|
||||
|
||||
@patch('homeassistant.util.yaml.os.walk')
|
||||
@patch('homeassistant.util.yaml.loader.os.walk')
|
||||
def test_include_dir_merge_named_recursive(mock_walk):
|
||||
"""Test include dir merge named yaml."""
|
||||
mock_walk.return_value = [
|
||||
@@ -257,7 +258,7 @@ def test_include_dir_merge_named_recursive(mock_walk):
|
||||
with io.StringIO(conf) as file:
|
||||
assert '.ignore' in mock_walk.return_value[0][1], \
|
||||
"Expecting .ignore in here"
|
||||
doc = yaml.yaml.safe_load(file)
|
||||
doc = yaml_loader.yaml.safe_load(file)
|
||||
assert 'tmp2' in mock_walk.return_value[0][1]
|
||||
assert '.ignore' not in mock_walk.return_value[0][1]
|
||||
assert doc["key"] == {
|
||||
@@ -268,12 +269,12 @@ def test_include_dir_merge_named_recursive(mock_walk):
|
||||
}
|
||||
|
||||
|
||||
@patch('homeassistant.util.yaml.open', create=True)
|
||||
@patch('homeassistant.util.yaml.loader.open', create=True)
|
||||
def test_load_yaml_encoding_error(mock_open):
|
||||
"""Test raising a UnicodeDecodeError."""
|
||||
mock_open.side_effect = UnicodeDecodeError('', b'', 1, 0, '')
|
||||
with pytest.raises(HomeAssistantError):
|
||||
yaml.load_yaml('test')
|
||||
yaml_loader.load_yaml('test')
|
||||
|
||||
|
||||
def test_dump():
|
||||
@@ -392,16 +393,16 @@ class TestSecrets(unittest.TestCase):
|
||||
|
||||
def test_secrets_keyring(self):
|
||||
"""Test keyring fallback & get_password."""
|
||||
yaml.keyring = None # Ensure its not there
|
||||
yaml_loader.keyring = None # Ensure its not there
|
||||
yaml_str = 'http:\n api_password: !secret http_pw_keyring'
|
||||
with pytest.raises(yaml.HomeAssistantError):
|
||||
with pytest.raises(HomeAssistantError):
|
||||
load_yaml(self._yaml_path, yaml_str)
|
||||
|
||||
yaml.keyring = FakeKeyring({'http_pw_keyring': 'yeah'})
|
||||
yaml_loader.keyring = FakeKeyring({'http_pw_keyring': 'yeah'})
|
||||
_yaml = load_yaml(self._yaml_path, yaml_str)
|
||||
assert {'http': {'api_password': 'yeah'}} == _yaml
|
||||
|
||||
@patch.object(yaml, 'credstash')
|
||||
@patch.object(yaml_loader, 'credstash')
|
||||
def test_secrets_credstash(self, mock_credstash):
|
||||
"""Test credstash fallback & get_password."""
|
||||
mock_credstash.getSecret.return_value = 'yeah'
|
||||
@@ -413,10 +414,10 @@ class TestSecrets(unittest.TestCase):
|
||||
|
||||
def test_secrets_logger_removed(self):
|
||||
"""Ensure logger: debug was removed."""
|
||||
with pytest.raises(yaml.HomeAssistantError):
|
||||
with pytest.raises(HomeAssistantError):
|
||||
load_yaml(self._yaml_path, 'api_password: !secret logger')
|
||||
|
||||
@patch('homeassistant.util.yaml._LOGGER.error')
|
||||
@patch('homeassistant.util.yaml.loader._LOGGER.error')
|
||||
def test_bad_logger_value(self, mock_error):
|
||||
"""Ensure logger: debug was removed."""
|
||||
yaml.clear_secret_cache()
|
||||
|
||||
Reference in New Issue
Block a user