You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
7.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# vim: fileencoding=utf-8
#
from .base_format import BaseFormat, FormatError
from collections import OrderedDict
import re
try:
from lxml.etree.ElementTree import fromstring
except ImportError:
from xml.etree.ElementTree import fromstring
class PatchFormat(BaseFormat):
FORMAT = 'patch'
FORMAT_PARAMETERS = {'multiline', 'dotall', 'comment'}
def __init__(self, document_text: str, multiline=False, dotall=False,
comment_symbol=''):
processing_methods = OrderedDict()
super().__init__(processing_methods)
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 = '<?xml version="1.0" encoding="utf-8"?>\
<patch>{0}</patch>'
self._parse_patch(document_text)
def _parse_patch(self, patch_text):
'''Метод, составляющий из текста шаблона xml документ и разбирающий его
с помощью lxml.'''
xml_patch = self._XML_ROOT_LINE.format(patch_text.strip())
try:
self._parsed_patch = fromstring(xml_patch)
except Exception:
raise FormatError('can not parse patch document')
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):
raise FormatError('Error: Can not run patch.')
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':
raise FormatError('incorrect text of the template')
while True:
for patch_tag in PATCH_DOCUMENT_TAGS:
patch_element = next(patch_iterator, None)
if patch_element is None:
if patch_tag == 'text':
raise FormatError('last <text>Text</text> '
'object is missed.')
else:
break
if patch_element.tag == patch_tag:
if patch_element.text is not None:
element_text = patch_element.text.strip()
if element_text == '':
raise FormatError(
("Error: Incorrect text of the "
"template: <{0}>%s</{0}>").format(
patch_tag
))
else:
raise FormatError("Error: Incorrect text of the "
"template: <{0}></{0}>").format(
patch_tag
)
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:
raise FormatError('invalid multiline value')
else:
multiline = self._FLAG_VALUES[multiline]
# Если глобально флаг MULTILINE включен, но в
# атрибутах тэга <reg> этот флаг присутствует со
# значением 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:
raise FormatError('invalid dotall value')
else:
dotall = self._FLAG_VALUES[dotall]
# Если глобально флаг DOTALL включен, но в
# атрибутах тэга <reg> этот флаг присутствует со
# значением 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 = '<{0}> is expected, <{1}> instead.'.\
format(patch_tag,
patch_element.tag)
else:
error_message = 'unknown tag: {0}'.format(
patch_element.tag
)
raise ("incorrect text of the template: {}".format(
error_message))
else:
self._document_to_patch = re.sub(regex_expression,
text_for_replace,
self._document_to_patch)
continue
return True