Repository URL to install this package:
|
Version:
0.5.10.dev2+gb5d94239a ▾
|
# -*- coding: utf-8 -*-
# Copyright (c) 2019, Markus Binsteiner
#
# Mozilla Public License, version 2.0 (see LICENSE or https://www.mozilla.org/en-US/MPL/2.0/)
# as well as
# Parity Public License, version 7.0.0 (see https://paritylicense.com/)
import typing
from typing import Any, Mapping, Sequence, Set, Union
import regex as re
import structlog
from regex.regex import Pattern
log = structlog.getLogger()
def create_var_regex(
delimiter_start: Union[str, None] = None, delimiter_end: Union[str, None] = None
) -> Pattern:
if delimiter_start is None:
delimiter_start = "\\$\\{"
# TODO: make this smarter
if delimiter_end is None:
delimiter_end = "\\}"
regex = re.compile(delimiter_start + "\\s*(.+?)\\s*" + delimiter_end)
return regex
def find_var_names_in_obj(
template_obj: Any,
delimiter: Union[Pattern, str, None] = None,
delimiter_end: Union[str, None] = None,
) -> Set[str]:
if isinstance(delimiter, Pattern):
regex = delimiter
else:
regex = create_var_regex(delimiter_start=delimiter, delimiter_end=delimiter_end)
var_names = find_regex_matches_in_obj(template_obj, regex=regex)
return var_names
def replace_var_names_in_obj(
template_obj: Any,
repl_dict: typing.Mapping[str, Any],
delimiter: Union[Pattern, str, None] = None,
delimiter_end: Union[str, None] = None,
ignore_missing_keys: bool = False,
) -> Any:
if isinstance(delimiter, Pattern):
regex = delimiter
else:
regex = create_var_regex(delimiter_start=delimiter, delimiter_end=delimiter_end)
if not template_obj:
return template_obj
if isinstance(template_obj, Mapping):
result: Any = {}
for k, v in template_obj.items():
key = replace_var_names_in_obj(
template_obj=k,
repl_dict=repl_dict,
delimiter=regex,
ignore_missing_keys=ignore_missing_keys,
)
value = replace_var_names_in_obj(
template_obj=v,
repl_dict=repl_dict,
delimiter=regex,
ignore_missing_keys=ignore_missing_keys,
)
result[key] = value
elif isinstance(template_obj, str):
result = replace_var_names_in_string(
template_obj,
repl_dict=repl_dict,
regex=regex,
ignore_missing_keys=ignore_missing_keys,
)
elif isinstance(template_obj, Sequence):
result = []
for item in template_obj:
r = replace_var_names_in_obj(
item,
repl_dict=repl_dict,
delimiter=regex,
ignore_missing_keys=ignore_missing_keys,
)
result.append(r)
else:
result = template_obj
return result
def replace_var_names_in_string(
template_string: str,
repl_dict: typing.Mapping[str, Any],
regex: Pattern,
ignore_missing_keys: bool = False,
) -> str:
def sub(match):
key = match.groups()[0]
if key not in repl_dict.keys():
if not ignore_missing_keys:
raise Exception(
f"Can't insert variable '{key}'. Key not in provided input values, available keys: {', '.join(repl_dict.keys())}"
)
else:
return match[0]
else:
result = repl_dict[key]
return result
result: str = regex.sub(sub, template_string)
return result
def find_regex_matches_in_obj(
source_obj: Any, regex: Pattern, current: Union[Set[str], None] = None
) -> Set[str]:
if current is None:
current = set()
if not source_obj:
return current
if isinstance(source_obj, Mapping):
for k, v in source_obj.items():
find_regex_matches_in_obj(k, regex=regex, current=current)
find_regex_matches_in_obj(v, regex=regex, current=current)
elif isinstance(source_obj, str):
matches = regex.findall(source_obj)
current.update(matches)
elif isinstance(source_obj, Sequence):
for item in source_obj:
find_regex_matches_in_obj(item, regex=regex, current=current)
return current