# vim: fileencoding=utf-8 # from .base_format import BaseFormat from collections import OrderedDict import re try: from lxml.etree.ElementTree import fromstring except ImportError: from xml.etree.ElementTree import fromstring class PatchFormat(BaseFormat): def __init__(self, document_text: str, multiline=False, dotall=False): processing_methods = OrderedDict() super().__init__(processing_methods) self._format = 'patch' self._multiline_flag = multiline self._dotall_flag = dotall self._parsed_patch = None self._document_to_patch = '' self._FLAG_VALUES = {'True': True, 'False': False, 'true': True, 'false': False, '1': True, '0': False} self._XML_ROOT_LINE = '\ {0}' if not self._parse_patch(document_text): # Какая-то обработка ошибки. print('Error: Can not parse patch document.') def _parse_patch(self, patch_text): xml_patch = self._XML_ROOT_LINE.format(patch_text.strip()) try: self._parsed_patch = fromstring(xml_patch) return True except Exception: # Какая-то обработка ошибки. print('Error: Incorrect text of the template.') return False def execute_format(self, document_to_patch): if not document_to_patch.strip() == '': self._document_to_patch = document_to_patch if self._parse_patch is None: return False else: if not self._patch_document(document_to_patch): error_message = 'Error: Can not run patch.' print(error_message) return False else: after_patch = self._document_to_patch self._document_to_patch = '' return after_patch def _patch_document(self, document_to_patch): patch_iterator = self._parsed_patch.getiterator() PATCH_DOCUMENT_TAGS = ('reg', 'text') patch_element = next(patch_iterator, False) if not patch_element or not patch_element.tag == 'patch': print('Error: Incorrect text of the template.') return False while True: for patch_tag in PATCH_DOCUMENT_TAGS: patch_element = next(patch_iterator, None) if patch_element is None: if patch_tag == 'text': print('Error: Last Text ' 'object is missed.') return False else: break if patch_element.tag == patch_tag: if patch_element.text is not None: element_text = patch_element.text.strip() if element_text == '': error_message = 'Error: Incorrect text of the \ template: <{0}>%s'.format( patch_tag ) print(error_message) return False else: error_message = 'Error: Incorrect text of the \ template: <{0}>'.format( patch_tag ) print(error_message) return False if patch_tag == 'reg': dotall = patch_element.attrib.get('dotall', False) regex_flags = 0 if 'multiline' in patch_element.attrib: multiline = patch_element.attrib['multiline'] if multiline not in self._FLAG_VALUES: error_message = ('Error: Invalid multiline ' 'value.') print(error_message) return False else: multiline = self._FLAG_VALUES[multiline] # Если глобально флаг MULTILINE включен, но в # атрибутах тэга этот флаг присутствует со # значением False -- для этого регулярного # выражения этот флаг также будет False. multiline_global = self._multiline_flag & multiline else: multiline = False multiline_global = self._multiline_flag if multiline_global or multiline: regex_flags |= re.MULTILINE if 'dotall' in patch_element.attrib: dotall = patch_element.attrib['dotall'] if dotall not in self._FLAG_VALUES: error_message = 'Error: Invalid dotall value.' print(error_message) return False else: dotall = self._FLAG_VALUES[dotall] # Если глобально флаг DOTALL включен, но в # атрибутах тэга этот флаг присутствует со # значением False -- для этого регулярного # выражения этот флаг также будет False. dotall_global = self._dotall_flag & dotall else: dotall = False dotall_global = self._dotall_flag if dotall_global or dotall: regex_flags |= re.DOTALL regex_expression = re.compile(element_text, regex_flags) else: text_for_replace = element_text else: if patch_element.tag in PATCH_DOCUMENT_TAGS: error_message = 'Error: <{0}> is expected, \ <{1}> instead.'.format( patch_tag, patch_element.tag ) print(error_message) else: error_message = 'Error: Unknown tag: {0}'.format( patch_element.tag ) print(error_message) # Какая-то обработка ошибки. error_message = 'Error: Incorrect text of the template.' print(error_message) return False else: self._document_to_patch = re.sub(regex_expression, text_for_replace, self._document_to_patch) continue return True