sqlmesh.utils.yaml
1from __future__ import annotations 2 3import getpass 4import io 5import typing as t 6from decimal import Decimal 7from os import getenv 8from pathlib import Path 9 10from ruamel import yaml 11from ruamel.yaml.constructor import SafeConstructor 12 13from sqlmesh.core.constants import VAR 14from sqlmesh.utils.errors import SQLMeshError 15from sqlmesh.utils.jinja import ENVIRONMENT, create_var 16 17JINJA_METHODS = { 18 "env_var": lambda key, default=None: getenv(key, default), 19 "user": lambda: getpass.getuser(), 20} 21 22 23def YAML(typ: t.Optional[str] = "safe") -> yaml.YAML: 24 yaml_obj = yaml.YAML(typ=typ) 25 26 # Ruamel doesn't know how to serialize Decimal values. This is problematic when, 27 # e.g., we're trying to auto-generate a unit test whose body contains Decimal data. 28 # This is a best-effort approach to solve this by serializing them as strings. 29 yaml_obj.representer.add_representer( 30 Decimal, lambda dumper, data: dumper.represent_str(str(data)) 31 ) 32 33 return yaml_obj 34 35 36class SafeConstructorOverride(SafeConstructor): 37 def check_mapping_key( 38 self, 39 node: t.Any, 40 key_node: t.Any, 41 mapping: t.Any, 42 key: t.Any, 43 value: t.Any, 44 ) -> bool: 45 """This function normally returns True if key is unique. 46 47 It is only used by the construct_mapping function. By always returning True, 48 keys will always be updated and so the last value will be kept for mappings. 49 """ 50 return True 51 52 53def load( 54 source: str | Path, 55 raise_if_empty: bool = True, 56 render_jinja: bool = True, 57 allow_duplicate_keys: bool = False, 58 variables: t.Optional[t.Dict[str, t.Any]] = None, 59 keep_last_duplicate_key: bool = False, 60) -> t.Dict: 61 """Loads a YAML object from either a raw string or a file.""" 62 path: t.Optional[Path] = None 63 64 if isinstance(source, Path): 65 path = source 66 with open(source, "r", encoding="utf-8") as file: 67 source = file.read() 68 69 if render_jinja: 70 source = ENVIRONMENT.from_string(source).render( 71 { 72 **JINJA_METHODS, 73 VAR: create_var(variables or {}), 74 } 75 ) 76 77 yaml = YAML() 78 if allow_duplicate_keys and keep_last_duplicate_key: 79 yaml.Constructor = SafeConstructorOverride 80 yaml.allow_duplicate_keys = allow_duplicate_keys 81 contents = yaml.load(source) 82 if contents is None: 83 if raise_if_empty: 84 error_path = f" '{path}'" if path else "" 85 raise SQLMeshError(f"YAML source{error_path} can't be empty.") 86 return {} 87 88 return contents 89 90 91@t.overload 92def dump(value: t.Any, stream: io.IOBase) -> None: ... 93 94 95@t.overload 96def dump(value: t.Any) -> str: ... 97 98 99def dump(value: t.Any, stream: t.Optional[io.IOBase] = None) -> t.Optional[str]: 100 """Dumps a ruamel.yaml loaded object and converts it into a string or writes it to a stream.""" 101 result = io.StringIO() 102 YAML(typ=None).dump(value, stream or result) 103 return None if stream else result.getvalue()
JINJA_METHODS =
{'env_var': <function <lambda>>, 'user': <function <lambda>>}
def
YAML(typ: Optional[str] = 'safe') -> ruamel.yaml.main.YAML:
24def YAML(typ: t.Optional[str] = "safe") -> yaml.YAML: 25 yaml_obj = yaml.YAML(typ=typ) 26 27 # Ruamel doesn't know how to serialize Decimal values. This is problematic when, 28 # e.g., we're trying to auto-generate a unit test whose body contains Decimal data. 29 # This is a best-effort approach to solve this by serializing them as strings. 30 yaml_obj.representer.add_representer( 31 Decimal, lambda dumper, data: dumper.represent_str(str(data)) 32 ) 33 34 return yaml_obj
class
SafeConstructorOverride(ruamel.yaml.constructor.SafeConstructor):
37class SafeConstructorOverride(SafeConstructor): 38 def check_mapping_key( 39 self, 40 node: t.Any, 41 key_node: t.Any, 42 mapping: t.Any, 43 key: t.Any, 44 value: t.Any, 45 ) -> bool: 46 """This function normally returns True if key is unique. 47 48 It is only used by the construct_mapping function. By always returning True, 49 keys will always be updated and so the last value will be kept for mappings. 50 """ 51 return True
def
check_mapping_key( self, node: Any, key_node: Any, mapping: Any, key: Any, value: Any) -> bool:
38 def check_mapping_key( 39 self, 40 node: t.Any, 41 key_node: t.Any, 42 mapping: t.Any, 43 key: t.Any, 44 value: t.Any, 45 ) -> bool: 46 """This function normally returns True if key is unique. 47 48 It is only used by the construct_mapping function. By always returning True, 49 keys will always be updated and so the last value will be kept for mappings. 50 """ 51 return True
This function normally returns True if key is unique.
It is only used by the construct_mapping function. By always returning True, keys will always be updated and so the last value will be kept for mappings.
Inherited Members
- ruamel.yaml.constructor.BaseConstructor
- BaseConstructor
- yaml_multi_constructors
- loader
- yaml_base_dict_type
- yaml_base_list_type
- constructed_objects
- recursive_objects
- state_generators
- deep_construct
- allow_duplicate_keys
- composer
- resolver
- scanner
- check_data
- get_data
- get_single_data
- construct_document
- construct_object
- construct_non_recursive_object
- construct_sequence
- check_set_key
- construct_pairs
- add_constructor
- add_multi_constructor
- add_default_constructor
- ruamel.yaml.constructor.SafeConstructor
- construct_scalar
- flatten_mapping
- construct_mapping
- construct_yaml_null
- bool_values
- construct_yaml_bool
- construct_yaml_int
- inf_value
- nan_value
- construct_yaml_float
- construct_yaml_binary
- timestamp_regexp
- construct_yaml_timestamp
- construct_yaml_omap
- construct_yaml_pairs
- construct_yaml_set
- construct_yaml_str
- construct_yaml_seq
- construct_yaml_map
- construct_yaml_object
- construct_undefined
- yaml_constructors
def
load( source: str | pathlib.Path, raise_if_empty: bool = True, render_jinja: bool = True, allow_duplicate_keys: bool = False, variables: Optional[Dict[str, Any]] = None, keep_last_duplicate_key: bool = False) -> Dict:
54def load( 55 source: str | Path, 56 raise_if_empty: bool = True, 57 render_jinja: bool = True, 58 allow_duplicate_keys: bool = False, 59 variables: t.Optional[t.Dict[str, t.Any]] = None, 60 keep_last_duplicate_key: bool = False, 61) -> t.Dict: 62 """Loads a YAML object from either a raw string or a file.""" 63 path: t.Optional[Path] = None 64 65 if isinstance(source, Path): 66 path = source 67 with open(source, "r", encoding="utf-8") as file: 68 source = file.read() 69 70 if render_jinja: 71 source = ENVIRONMENT.from_string(source).render( 72 { 73 **JINJA_METHODS, 74 VAR: create_var(variables or {}), 75 } 76 ) 77 78 yaml = YAML() 79 if allow_duplicate_keys and keep_last_duplicate_key: 80 yaml.Constructor = SafeConstructorOverride 81 yaml.allow_duplicate_keys = allow_duplicate_keys 82 contents = yaml.load(source) 83 if contents is None: 84 if raise_if_empty: 85 error_path = f" '{path}'" if path else "" 86 raise SQLMeshError(f"YAML source{error_path} can't be empty.") 87 return {} 88 89 return contents
Loads a YAML object from either a raw string or a file.
def
dump(value: Any, stream: Optional[io.IOBase] = None) -> Optional[str]:
100def dump(value: t.Any, stream: t.Optional[io.IOBase] = None) -> t.Optional[str]: 101 """Dumps a ruamel.yaml loaded object and converts it into a string or writes it to a stream.""" 102 result = io.StringIO() 103 YAML(typ=None).dump(value, stream or result) 104 return None if stream else result.getvalue()
Dumps a ruamel.yaml loaded object and converts it into a string or writes it to a stream.