import _io class template_exception(Exception): pass class template: def __init__(self, content: str | _io.TextIOWrapper, check: bool = True): self.__template = None self.__rendered = None self.__properties = dict() if type(content) is str: self.__template = content if type(content) is _io.TextIOWrapper: self.__template = content.read() if self.__template is None: raise Exception("Template content must be string or file.") if check is True: self.__prepare_template() @property def separators(self) -> [str, str]: return "<>" def __prepare_template(self) -> None: template = self.template start, end = self.separators count = 0 current = 0 while True: current_start = template.find(start, count) if current_start == -1: break current = current_start + len(start) current_end = template.find(end, count) current_after = current_end + len(end) if current > current_end: found = "Close char before start char on " + str(current) raise template_exception(found) key = template[current:current_end] key = key.strip() if len(key) == 0: raise template_exception("Empty key on " + str(current)) before = template[:current_start] after = template[current_after:] template = before + start + key + end + after count = current + len(key) + len(end) self.__template = template @property def template(self) -> str: return self.__template def get(self, name: str) -> str: if not type(name) is str: raise Exception("Name of the key must be str.") if not name in self.__properties: raise Exception("Key " + name + " not exists in properties.") return self.__properties[name] def set(self, name: str, value: str | int | float) -> template: if not type(name) is str: raise Exception("Name of the attribute must be str.") if type(value) is str: self.__properties[name] = value return self if type(value) is int or type(value) is float: self.__properties[name] = str(value) return self raise Exception("Value to set must be str, int or float.") def clone(self) -> template: return template(self.template, False) def __key(self, target: str) -> str: start, end = self.separators return start + target + end def render(self) -> str: if not self.__rendered is None: return self.__rendered template = self.template for name, value in self.__properties.items(): template = template.replace(self.__key(name), value) self.__rendered = template return self.render()