Created
February 22, 2022 07:45
-
-
Save cassava/530aecd606f2bae0c3f128a6b5f01284 to your computer and use it in GitHub Desktop.
Fancy YAML proof of concept in Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
from typing import Optional, Dict | |
import os | |
import yaml | |
import jinja2 | |
class FancyLoader(yaml.SafeLoader): | |
def __init__(self, stream): | |
self.definitions = dict() | |
self.add_constructor("!env", self._yaml_tag_env) | |
self.add_constructor("!define", self._yaml_tag_define) | |
self.add_constructor("!ref", self._yaml_tag_ref) | |
self.add_constructor("!template", self._yaml_tag_template) | |
self.add_constructor("!literal", self._yaml_tag_literal) | |
yaml.SafeLoader.__init__(self, stream) | |
def _yaml_tag_env(self, loader, node) -> Optional[str]: | |
value: str = loader.construct_scalar(node) | |
return os.environ.get(value) | |
def _yaml_tag_define(self, loader, node): | |
mapping: Dict = loader.construct_mapping(node) | |
for k, v in mapping.items(): | |
if k in self.definitions: | |
print(f"Warning: overwriting variable {k} = {self.definitions[k]}") | |
self.definitions[k] = v | |
return mapping | |
def _yaml_tag_ref(self, loader, node): | |
value: str = loader.construct_scalar(node) | |
return self.definitions[value] | |
def _yaml_tag_template(self, loader, node): | |
value: str = loader.construct_scalar(node) | |
tmpl = jinja2.Template(value) | |
return tmpl.render(**self.definitions) | |
def _yaml_tag_literal(self, loader, node): | |
value: str = loader.construct_scalar(node) | |
tmpl = jinja2.Template(value) | |
render = tmpl.render(**self.definitions) | |
if render in ["true", "True", "TRUE", "yes", "Yes", "YES"]: | |
return True | |
elif render in ["false", "False", "FALSE", "no", "No", "NO"]: | |
return False | |
elif "." in render: | |
return float(render) | |
else: | |
return int(render) | |
TEST = """ | |
variables: !define | |
what: "World" | |
expr: "!" | |
who: !env "USER" | |
number: 35.45 | |
answer: 42 | |
output: !template "Hello {{who}} to the {{what}}{{expr}}" | |
answer: !ref answer | |
literal: !literal "{{number}}" | |
""" | |
ERROR_1 = """ | |
variables: | |
number: 45 | |
literal: !!int !template "{{number}}" | |
""" | |
if __name__ == "__main__": | |
data = yaml.load(TEST, Loader=FancyLoader) | |
print(yaml.dump(data)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment