def test_bind_non_extensions(): dut = DictMentor() with pytest.raises( ValueError, match='Cannot bind extension due to missing interface requirements' ): dut.bind("Not an extension")
def test_load_yaml_with_stream(): import os fn = os.path.join(os.path.dirname(__file__), 'resources/simple.yaml') dut = DictMentor() with open(fn, 'r') as fp: dct = dut.load_yaml(fp) expected = dict(root=dict(a=1, b=2, c=dict(ca=31, cb=32))) assert dct == expected
def test_bind_extensions_via_init(): env = ext.Environment() extres = ext.ExternalResource() dut = DictMentor(env, extres) assert len(dut._extensions) == 2 assert dut._extensions[0] == env assert dut._extensions[1] == extres dut = DictMentor(env) assert len(dut._extensions) == 1 assert dut._extensions[0] == env
def _augment(self, configuration: PartialConfig, base_path: str) -> Any: """Augments the configuration by using dictmentor with `Environment`, `ExternalResource` and `ExternalYamlResource` plguins.""" _ = self # Fake usage assert isinstance(base_path, str) # pnp configuration is probably of list of tasks. dictmentor needs a dict ... # ... let's fake it ;-) cfg = dict(fake_root=configuration) mentor = DictMentor(ext.Environment(fail_on_unset=True), ext.ExternalResource(base_path=base_path), ext.ExternalYamlResource(base_path=base_path)) # Remove the faked dictionary as root level return mentor.augment(cfg)['fake_root']
def make_mentor(config_path): """Creates an instance of the dictmentor with configured plugins.""" from dictmentor import DictMentor, ext # type: ignore return DictMentor( ext.Environment(fail_on_unset=True), ext.ExternalResource(base_path=os.path.dirname(config_path)), ext.ExternalYamlResource(base_path=os.path.dirname(config_path)))
def _configure(self, object_id, node_id): configure_key = str(object_id) + str(node_id) if configure_key not in self.configured: base_topic, config_topic, state_topic = self._topics( object_id, node_id) mentor = DictMentor( ext.Variables(fail_on_unset=True, discovery_prefix=self.discovery_prefix, component=self.component, object_id=object_id, node_id=node_id, base_topic=base_topic, config_topic=config_topic, state_topic=state_topic)) config_augmented = mentor.augment(self.config) self._publish(config_augmented, config_topic, retain=True) self.configured[configure_key] = True
def _configure(self, object_id, node_id): configure_key = str(object_id) + str(node_id) if configure_key not in self.configured: base_topic, config_topic, state_topic, attr_topic = self._topics(object_id, node_id) mentor = DictMentor( ext.Variables( fail_on_unset=True, discovery_prefix=self.discovery_prefix, component=self.component, object_id=object_id, node_id=node_id, base_topic=base_topic, config_topic=config_topic, **{ self.CONST_STATE_TOPIC: state_topic, self.CONST_JSON_ATTRIBUTES_TOPIC: attr_topic } ) ) config_augmented = mentor.augment(self.config) if self.CONST_STATE_TOPIC in config_augmented: self.logger.warning( "%s is part of your config, but will be ignored", self.CONST_STATE_TOPIC ) if self.CONST_JSON_ATTRIBUTES_TOPIC in config_augmented: self.logger.warning( "%s is part of your config, but will be ignored", self.CONST_JSON_ATTRIBUTES_TOPIC ) config_augmented[self.CONST_STATE_TOPIC] = state_topic config_augmented[self.CONST_JSON_ATTRIBUTES_TOPIC] = attr_topic self._publish(config_augmented, config_topic, retain=True) self.configured[configure_key] = True
def test_environment_with_multiple_patterns(): jstr = '{"a": 1, "file_path": "{{var::a}}-{{var::b}}-{{var::c}}"}' res = DictMentor().bind(Variables(a='aval', b='bval', c='cval')).load_yaml(jstr) assert res == {'a': 1, 'file_path': 'aval-bval-cval'}
def test_load_yaml_invalid(): with pytest.raises( TypeError, match="Argument '_yaml' is whether a stream, nor a file, nor a string" ): DictMentor().load_yaml(5)
def test_init_extensions_with_non_iterable(): dut = DictMentor() env = ext.Environment() dut._init_extensions(env) assert len(dut._extensions) == 1 assert dut._extensions[0] == env
def test_environment_with_nested_inline_default(): jstr = '{"a": 1, "file_path": "my_file.{{env::ENVIRONMENT:={{env::DEFAULT}}.cfg}}"}' with modified_environ('ENVIRONMENT', DEFAULT='the_default'): res = DictMentor().bind(Environment()).load_yaml(jstr) assert res == {'a': 1, 'file_path': 'my_file.the_default.cfg'}
# Import DictMentor and extensions import dictmentor.extensions as ext from dictmentor import DictMentor, utils yml = """ statements: my_env: "{{var::my_env}}" home: "{{var::home}}" unknown: "{{var::unknown}}" combined: "{{var::my_env}}@{{var::home}}" """ var_ext = ext.Variables( my_env='development', home="/home/pi", ) result = DictMentor().bind(var_ext).load_yaml(yml) from pprint import pprint pprint(result) # Result: # {'statements': {'combined': 'development@/home/pi', # 'home': '/home/pi', # 'my_env': 'development', # 'unknown': 'none'}}
def test_environment_with_inline_default(): jstr = '{"a": 1, "file_path": "my_file.{{env::ENVIRONMENT:=local}}.cfg"}' with modified_environ('ENVIRONMENT'): res = DictMentor().bind(Environment()).load_yaml(jstr) assert res == {'a': 1, 'file_path': 'my_file.local.cfg'}
def test_environment_with_multiple_patterns(): jstr = '{"a": 1, "file_path": "{{env::A}}-{{env::B}}-{{env::C}}"}' with modified_environ(A='aval', B='bval', C='cval'): res = DictMentor().bind(Environment()).load_yaml(jstr) assert res == {'a': 1, 'file_path': 'aval-bval-cval'}
import os from dictmentor import DictMentor, extensions as ext, utils base_path = os.path.dirname(__file__) dm = DictMentor( ext.Environment(), ext.ExternalResource(base_path=base_path), ext.ExternalYamlResource(base_path=base_path) ) yml = """ products: - external: item1.yaml - external: item2.yaml home_directory: "{{env::HOME}}" extraction_sql: "{{external::products.sql}}" """ with utils.modified_environ(HOME="/home/pi"): res = dm.load_yaml(yml) from pprint import pprint pprint(res) # Result: # {'extraction_sql': '-- Contents of products.sql\nSELECT *\nFROM products\n;', # 'home_directory': '/home/pi', # 'products': [{'item1': {'price': 50, 'stock': 100}}, # {'item2': {'price': 99, 'stock': 10}}]}
# Import DictMentor and extensions import dictmentor.extensions as ext from dictmentor import DictMentor import os base_path = os.path.dirname(__file__) yml = """ statements: external: "inner.yaml" """ result = DictMentor().bind( ext.ExternalYamlResource(base_path=base_path)).load_yaml(yml) from pprint import pprint pprint(result) # Result: # {'statements': {'inner': {'item1': None, # 'item2': {'price': 50}, # 'item3': {'count': 5, 'price': 100, 'sold': 200}}}}
# Import DictMentor and extensions import dictmentor.extensions as ext from dictmentor import DictMentor, utils yml = """ statements: my_env: "{{env::MY_ENV}}" home: "{{env::HOME}}" unknown: "{{env::UNKNOWN}}" with_default: "{{env::UNKNOWN:=the_default}}" """ # Make sure that MY_ENV is set and that UNKNOWN is unset with utils.modified_environ("UNKNOWN", MY_ENV='development'): result = DictMentor().bind(ext.Environment()).load_yaml(yml) from pprint import pprint pprint(result) # Result: # {'statements': {'home': '/home/pi', # 'my_env': 'development', # 'unknown': 'none' # 'with_default': 'the_default'}}