This repository has been archived by the owner on Apr 28, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 72
/
__init__.py
97 lines (76 loc) · 3.24 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import io
from typing import Text, Any, Dict
import ruamel.yaml as yaml
def configure_colored_logging(loglevel):
import coloredlogs
field_styles = coloredlogs.DEFAULT_FIELD_STYLES.copy()
field_styles['asctime'] = {}
level_styles = coloredlogs.DEFAULT_LEVEL_STYLES.copy()
level_styles['debug'] = {}
coloredlogs.install(
level=loglevel,
use_chroot=False,
fmt='%(asctime)s %(levelname)-8s %(name)s - %(message)s',
level_styles=level_styles,
field_styles=field_styles)
def fix_yaml_loader() -> None:
"""Ensure that any string read by yaml is represented as unicode."""
def construct_yaml_str(self, node):
# Override the default string handling function
# to always return unicode objects
return self.construct_scalar(node)
yaml.Loader.add_constructor(u'tag:yaml.org,2002:str', construct_yaml_str)
yaml.SafeLoader.add_constructor(u'tag:yaml.org,2002:str',
construct_yaml_str)
def replace_environment_variables():
"""Enable yaml loader to process the environment variables in the yaml."""
import re
import os
# eg. ${USER_NAME}, ${PASSWORD}
env_var_pattern = re.compile(r'^(.*)\$\{(.*)\}(.*)$')
yaml.add_implicit_resolver('!env_var', env_var_pattern)
def env_var_constructor(loader, node):
"""Process environment variables found in the YAML."""
value = loader.construct_scalar(node)
expanded_vars = os.path.expandvars(value)
if '$' in expanded_vars:
not_expanded = [w for w in expanded_vars.split() if '$' in w]
raise ValueError(
"Error when trying to expand the environment variables"
" in '{}'. Please make sure to also set these environment"
" variables: '{}'.".format(value, not_expanded))
return expanded_vars
yaml.SafeConstructor.add_constructor(u'!env_var', env_var_constructor)
def read_yaml(content: Text) -> Dict[Text, Any]:
"""Parses yaml from a text.
Args:
content: A text containing yaml content.
"""
fix_yaml_loader()
replace_environment_variables()
yaml_parser = yaml.YAML(typ="safe")
yaml_parser.version = "1.2"
yaml_parser.unicode_supplementary = True
# noinspection PyUnresolvedReferences
try:
return yaml_parser.load(content) or {}
except yaml.scanner.ScannerError as _:
# A `ruamel.yaml.scanner.ScannerError` might happen due to escaped
# unicode sequences that form surrogate pairs. Try converting the input
# to a parsable format based on
# https://stackoverflow.com/a/52187065/3429596.
content = (content.encode('utf-8')
.decode('raw_unicode_escape')
.encode("utf-16", 'surrogatepass')
.decode('utf-16'))
return yaml_parser.load(content) or {}
def read_file(filename: Text, encoding: Text = "utf-8") -> Any:
"""Read text from a file."""
with io.open(filename, encoding=encoding) as f:
return f.read()
def read_yaml_file(filename: Text) -> Dict[Text, Any]:
"""Parses a yaml file.
Args:
filename: The path to the file which should be read.
"""
return read_yaml(read_file(filename, "utf-8"))