Comments and exceptions are added for all format modules.

packages
Иванов Денис 4 years ago
parent 9f8723f2c7
commit 803b9c5ae8

@ -38,17 +38,20 @@ class BaseFormat():
self._line_timer = 0 self._line_timer = 0
def _lines_to_dictionary(self, document_lines): def _lines_to_dictionary(self, document_lines):
'''Основной метод для парсинга документа. Принимает список строк,
к каждой строке применяет парсеры, определенные для некоторого формата.
Первый парсер, которому удается разобрать строку используется для
формирования словаря.'''
# print('Lines processing...') # print('Lines processing...')
for line in document_lines: for line in document_lines:
# print(self._line_timer, '\t', line) # print(self._line_timer, '\t', line)
for processing_method in self._processing_methods: for processing_method in self._processing_methods:
processing_method(line) try:
processing_method(line)
if self._fatal_error_flag: except FormatError as error:
# Действия если файл невозможно разобрать.
self._document_dictionary = OrderedDict() self._document_dictionary = OrderedDict()
raise FormatError('line {} is not correct.'. raise FormatError("can not parse line: {}, reason: {}".
format(self._line_timer)) format(line, str(error)))
if self._is_match(): if self._is_match():
if self._is_ready_to_update(): if self._is_ready_to_update():
@ -57,27 +60,34 @@ class BaseFormat():
else: else:
# Действия если не удалось разобрать строку. # Действия если не удалось разобрать строку.
self._document_dictionary = OrderedDict() self._document_dictionary = OrderedDict()
raise FormatError('line {} is not correct.'. raise FormatError('can not parse line: {}'.
format(self._line_timer)) format(line))
self._line_timer += 1
if self._need_finish: if self._need_finish:
self._finish_method() self._finish_method()
def _parse_xml_to_dictionary(self, xml_document_text): def _parse_xml_to_dictionary(self, xml_document_text):
'''Метод для парсинга xml файлов.
Файлы xml предварительно не разбиваются на строки, а разбираются с
помощью модуля lxml. Перевод в словарь осуществляется методами формата,
рекурсивно вызывающимися в зависимости от типа тега.'''
root = fromstring(xml_document_text) root = fromstring(xml_document_text)
self._document_dictionary = self._processing_methods[root.tag](root) self._document_dictionary = self._processing_methods[root.tag](root)
def print_dictionary(self): def print_dictionary(self):
'''Метод для отладки.'''
pprint(self._document_dictionary) pprint(self._document_dictionary)
def join_template(self, template): def join_template(self, template):
'''Метод запускающий наложение шаблона.'''
self._join(self._document_dictionary, self._join(self._document_dictionary,
template._document_dictionary, template._document_dictionary,
self._join_before) self._join_before)
def _get_list_of_logic_lines(self, text): def _get_list_of_logic_lines(self, text):
'''Метод разбивающий документ на список логических строк -- то есть
учитывающий при разбиении возможность разбиение одной строки на
несколько с помощью бэкслеша. В некоторых форматах переопределен.'''
list_of_lines = [] list_of_lines = []
lines_to_join = [] lines_to_join = []
for line in text.splitlines(): for line in text.splitlines():
@ -94,6 +104,8 @@ class BaseFormat():
return list_of_lines return list_of_lines
def _join(self, original, template, join_before): def _join(self, original, template, join_before):
'''Основной метод для наложения шаблонов путем объединения их словарей
выполняемого рекурсивно.'''
if template == OrderedDict(): if template == OrderedDict():
return return
if join_before: if join_before:
@ -205,6 +217,8 @@ class BaseFormat():
original.move_to_end(key_value, last=False) original.move_to_end(key_value, last=False)
def make_template(self, template): def make_template(self, template):
'''Метод для запуска генерации шаблонов путем сравнения пары исходных
файлов.'''
full_diff, set_to_check = self.compare_dictionaries( full_diff, set_to_check = self.compare_dictionaries(
self._document_dictionary, self._document_dictionary,
template._document_dictionary template._document_dictionary
@ -214,6 +228,8 @@ class BaseFormat():
return template_object return template_object
def compare_dictionaries(self, dict_1, dict_2): def compare_dictionaries(self, dict_1, dict_2):
'''Основной метод для генерации шаблонов путем сравнения пары исходных
файлов. Работает рекурсивно.'''
to_remove_dictionary = OrderedDict() to_remove_dictionary = OrderedDict()
to_add_dictionary = OrderedDict() to_add_dictionary = OrderedDict()
to_replace_dictionary = OrderedDict() to_replace_dictionary = OrderedDict()
@ -289,6 +305,8 @@ class BaseFormat():
@property @property
def document_text(self): def document_text(self):
'''Метод для получения текста документа. Использует jinja2 для
рендеринга документа.'''
file_loader = PackageLoader('calculate.templates.format', file_loader = PackageLoader('calculate.templates.format',
self.TEMPLATES_DIRECTORY) self.TEMPLATES_DIRECTORY)
formats_environment = Environment(loader=file_loader, formats_environment = Environment(loader=file_loader,
@ -303,12 +321,20 @@ class BaseFormat():
return document_text return document_text
def _finish_method(self): def _finish_method(self):
'''Метод для выполнения заключительных действий парсинга.
Переопределяется в форматах. Вызывается при self._need_finish = True'''
pass pass
def _is_ready_to_update(self): def _is_ready_to_update(self):
'''Метод для проверки флага self._ready_to_update, указывающего, что
сформированная форматом секция документа, находящаяся в
self._item_to_add, может быть добавлена в словарь документа.'''
is_ready, self._ready_to_update = self._ready_to_update, False is_ready, self._ready_to_update = self._ready_to_update, False
return is_ready return is_ready
def _is_match(self): def _is_match(self):
'''Метод для проверки флага self._is_match, указывающего что текущий
парсер, использованный форматом, смог распарсить строку и использовать
другие парсеры не нужно.'''
is_match, self._match = self._match, False is_match, self._match = self._match, False
return is_match return is_match

@ -11,6 +11,9 @@ from pyparsing import originalTextFor, OneOrMore, Word, alphanums, Literal,\
class BINDFormat(BaseFormat): class BINDFormat(BaseFormat):
'''Класс формата BIND. В отличие от большинства других форматов обрабатывает
документ не построчно, а напрямую применяя парсер ко всему тексту
документа.'''
FORMAT = 'bind' FORMAT = 'bind'
EXECUTABLE = False EXECUTABLE = False
@ -36,6 +39,9 @@ class BINDFormat(BaseFormat):
self._parse_text(document_text) self._parse_text(document_text)
def _initialize_parser(self): def _initialize_parser(self):
'''Метод для инициализации парсеров. Для данного формата парсеры
инициализируется при создании экземпляра формата, поскольку настройка
парсеров зависит от того, включен ли флаг ignore_comments.'''
left_brace = Literal('{') left_brace = Literal('{')
right_brace = Literal('}') right_brace = Literal('}')
semicolon = Literal(';') semicolon = Literal(';')
@ -211,13 +217,20 @@ class BINDFormat(BaseFormat):
self._document_parser = OneOrMore(block_item) self._document_parser = OneOrMore(block_item)
def _parse_text(self, text): def _parse_text(self, text):
'''Метод для запуска разбора документа.'''
parsing_result = self._document_parser.parseString(text, parseAll=True) parsing_result = self._document_parser.parseString(text, parseAll=True)
list_of_elements = parsing_result.asList() list_of_elements = parsing_result.asList()
# На выходе парсера получаем список словарей секций, который затем
# преобразуем в словарь документа.
for part in list_of_elements: for part in list_of_elements:
self._join_dictionary(self._document_dictionary, self._join_dictionary(self._document_dictionary,
part) part)
def _join_dictionary(self, out_dictionary, dictionary_to_add): def _join_dictionary(self, out_dictionary, dictionary_to_add):
'''Метод для преобразования результата парсинга в итоговый словарь.
Работает рекурсивно. Умеет объединять секции с одинаковыми названиями.
'''
for key in dictionary_to_add: for key in dictionary_to_add:
if dictionary_to_add == OrderedDict(): if dictionary_to_add == OrderedDict():
return return
@ -230,6 +243,8 @@ class BINDFormat(BaseFormat):
out_dictionary[key] = dictionary_to_add[key] out_dictionary[key] = dictionary_to_add[key]
def _add_plain_line(self, current_parse): def _add_plain_line(self, current_parse):
'''Метод используемый в парсере простых строк, состоящих только из
имени параметра и опционально из его значения.'''
name = tuple(current_parse.name.asList()) name = tuple(current_parse.name.asList())
if not current_parse.parameter == '': if not current_parse.parameter == '':
value = current_parse.parameter value = current_parse.parameter
@ -241,14 +256,17 @@ class BINDFormat(BaseFormat):
return OrderedDict({name: [value]}) return OrderedDict({name: [value]})
def _add_include_line(self, current_parse): def _add_include_line(self, current_parse):
'''Метод используемый в парсере директивы include.'''
name = current_parse.asList() name = current_parse.asList()
return OrderedDict({tuple(name): ['']}) return OrderedDict({tuple(name): ['']})
def _add_ipline(self, current_parse): def _add_ipline(self, current_parse):
'''Метод используемый в парсере ip адресов.'''
ip_value = current_parse.IP ip_value = current_parse.IP
return OrderedDict({tuple(ip_value): ['']}) return OrderedDict({tuple(ip_value): ['']})
def _add_inet_specline(self, current_parse): def _add_inet_specline(self, current_parse):
'''Метод используемый в парсере директивы inet_spec.'''
# Удаляем пробельные символы из второго параметра директивы. # Удаляем пробельные символы из второго параметра директивы.
current_parse.name.parameter = current_parse.name.parameter.strip() current_parse.name.parameter = current_parse.name.parameter.strip()
block_name = tuple(current_parse.name.asList()) block_name = tuple(current_parse.name.asList())
@ -261,6 +279,9 @@ class BINDFormat(BaseFormat):
return OrderedDict({block_name: content}) return OrderedDict({block_name: content})
def _add_param_block(self, current_parse): def _add_param_block(self, current_parse):
'''Метод используемый в парсере блоков параметров. Использует
рекурсивный метод self._join_dictionary для построения словаря блока
параметров. Учитывает возможность наличия вложенных блоков.'''
block_name = tuple(current_parse.name.asList()) block_name = tuple(current_parse.name.asList())
block_content = current_parse.content.asList() block_content = current_parse.content.asList()
content = OrderedDict({'#': []}) content = OrderedDict({'#': []})
@ -270,6 +291,9 @@ class BINDFormat(BaseFormat):
return OrderedDict({block_name: content}) return OrderedDict({block_name: content})
def _add_comments_to_paramline(self, current_parse): def _add_comments_to_paramline(self, current_parse):
'''Метод используемый в парсере директив вместе с относящимися к ним
комментариями. Закрепляет комментарии за данным параметром в итоговом
словаре.'''
[parameter] = current_parse.value.asList() [parameter] = current_parse.value.asList()
comments = current_parse.comments comments = current_parse.comments
if parameter == OrderedDict(): if parameter == OrderedDict():
@ -288,6 +312,9 @@ class BINDFormat(BaseFormat):
return parameter return parameter
def _add_comments_to_block(self, current_parse): def _add_comments_to_block(self, current_parse):
'''Метод используемый в парсере блоков директив вместе с относящимися
к ним комментариями. Закрепляет комментарии за данным параметром в
итоговом словаре.'''
[value] = current_parse.value [value] = current_parse.value
[block_name] = value [block_name] = value
block = value[block_name] block = value[block_name]
@ -301,6 +328,9 @@ class BINDFormat(BaseFormat):
return value return value
def _create_comment_list(self, current_parse): def _create_comment_list(self, current_parse):
'''Метод используемый в парсере комментариев. Формирует из обнаруженных
комментариев список, который затем закрепляется за блоком или
параметром.'''
comments_list = [] comments_list = []
comments = current_parse.asList() comments = current_parse.asList()
for comment in comments: for comment in comments:

@ -12,10 +12,15 @@ class CompizFormat(BaseFormat):
EXECUTABLE = False EXECUTABLE = False
_initialized = False _initialized = False
_comment_symbol = ''
def __init__(self, document_text: str, ignore_comments=False, def __new__(cls, *args, **kwargs):
join_before=False, comment_symbol=''): if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str,
ignore_comments=False,
join_before=False):
processing_methods = [self._parse_comment_line, processing_methods = [self._parse_comment_line,
self._parse_section_line, self._parse_section_line,
self._parse_parameter_line, self._parse_parameter_line,
@ -31,8 +36,6 @@ class CompizFormat(BaseFormat):
self._current_section_name = '' self._current_section_name = ''
self._last_comments_list = [] self._last_comments_list = []
if not self._initialized or comment_symbol != self._comment_symbol:
self._initialize_parser(comment_symbol)
if document_text == '': if document_text == '':
self._document_dictionary = OrderedDict() self._document_dictionary = OrderedDict()
@ -41,7 +44,8 @@ class CompizFormat(BaseFormat):
self._lines_to_dictionary(document_lines) self._lines_to_dictionary(document_lines)
@classmethod @classmethod
def _initialize_parser(cls, comment_symbol): def _initialize_parser(cls):
'''Метод для инициализации парсеров.'''
section_name = originalTextFor( section_name = originalTextFor(
OneOrMore(Word(alphanums+'_')) OneOrMore(Word(alphanums+'_'))
) )
@ -54,8 +58,8 @@ class CompizFormat(BaseFormat):
+ Literal(']').suppress())('section_name') + Literal(']').suppress())('section_name')
parameter_name = originalTextFor( parameter_name = originalTextFor(
OneOrMore(Word(printables, OneOrMore(Word(printables,
excludeChars='=')) excludeChars='='))
) )
parameter_value = Word(printables) parameter_value = Word(printables)
@ -71,24 +75,16 @@ class CompizFormat(BaseFormat):
+ parameter_name('name') + parameter_name('name')
+ restOfLine.suppress())('parameter_name') + restOfLine.suppress())('parameter_name')
if not comment_symbol: cls._comment_line = originalTextFor(
cls._comment_line = originalTextFor( Literal('#')
Literal('#') + ZeroOrMore(Word(
+ ZeroOrMore(Word( printables
printables + pyparsing_unicode.alphanums))
+ pyparsing_unicode.alphanums)) )('comment')
)('comment')
else:
cls._comment_line = originalTextFor(
(Literal('#') | Literal(comment_symbol))
+ ZeroOrMore(Word(
printables
+ pyparsing_unicode.alphanums))
)('comment')
cls._initialized = True cls._initialized = True
def _parse_section_line(self, line): def _parse_section_line(self, line):
'''Метод для парсинга строк содержащих имя секции.'''
try: try:
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
parsing_result = self._section_line.parseString(line) parsing_result = self._section_line.parseString(line)
@ -117,6 +113,7 @@ class CompizFormat(BaseFormat):
return return
def _parse_parameter_line(self, line): def _parse_parameter_line(self, line):
'''Метод для парсинга строк содержащих параметр.'''
try: try:
parsing_result = self._parameter_line.parseString(line) parsing_result = self._parameter_line.parseString(line)
self._match = True self._match = True
@ -132,6 +129,9 @@ class CompizFormat(BaseFormat):
return return
def _parse_to_delete_line(self, line): def _parse_to_delete_line(self, line):
'''Метод для парсинга строк, подлежащих удалению, т.е. для которых
указано имя параметра со знаком !, и опционально присутствует значение
параметра.'''
try: try:
parsing_result = self._parameter_to_delete.parseString(line) parsing_result = self._parameter_to_delete.parseString(line)
self._match = True self._match = True
@ -148,6 +148,7 @@ class CompizFormat(BaseFormat):
return return
def _parse_comment_line(self, line): def _parse_comment_line(self, line):
'''Метод для парсинга строк содержащих комментарий.'''
try: try:
parsing_result = self._comment_line.parseString(line) parsing_result = self._comment_line.parseString(line)
self._match = True self._match = True
@ -158,6 +159,8 @@ class CompizFormat(BaseFormat):
return return
def _finish_method(self): def _finish_method(self):
'''Метод для завершения парсинга. В данном случае добавляет в итоговый
словарь последнюю разобранную секцию.'''
if self._current_section_name in self._document_dictionary.keys(): if self._current_section_name in self._document_dictionary.keys():
self._document_dictionary[self._current_section_name].update( self._document_dictionary[self._current_section_name].update(
self._current_section self._current_section

@ -13,6 +13,12 @@ class ContentsFormat(BaseFormat):
_initialized = False _initialized = False
def __new__(cls, *args, **kwargs):
'''Метод для инициализации парсеров.'''
if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str, def __init__(self, document_text: str,
ignore_comments=False, ignore_comments=False,
join_before=False, join_before=False,
@ -25,6 +31,11 @@ class ContentsFormat(BaseFormat):
self._ignore_comments = ignore_comments self._ignore_comments = ignore_comments
self._join_before = join_before self._join_before = join_before
# флаг для указания режима, в котором работает формат.
# Если True => формат работает для наложения шаблонов;
# Если False => формат работает для получения словаря, используемого
# модулем package.
self._template_parser_flag = template_parser self._template_parser_flag = template_parser
if not self._initialized: if not self._initialized:
@ -67,6 +78,7 @@ class ContentsFormat(BaseFormat):
cls._initialized = True cls._initialized = True
def _parse_sym_line(self, line): def _parse_sym_line(self, line):
'''Метод для разбора строк типа sym.'''
try: try:
parsing_result = self.sym_line.parseString(line) parsing_result = self.sym_line.parseString(line)
self._match = True self._match = True
@ -88,6 +100,7 @@ class ContentsFormat(BaseFormat):
return return
def _parse_dir_line(self, line): def _parse_dir_line(self, line):
'''Метод для разбора строк типа dir.'''
try: try:
parsing_result = self.dir_line.parseString(line) parsing_result = self.dir_line.parseString(line)
self._match = True self._match = True
@ -105,6 +118,7 @@ class ContentsFormat(BaseFormat):
return return
def _parse_obj_line(self, line): def _parse_obj_line(self, line):
'''Метод для разбора строк типа obj.'''
try: try:
parsing_result = self.obj_line.parseString(line) parsing_result = self.obj_line.parseString(line)
self._match = True self._match = True
@ -127,6 +141,10 @@ class ContentsFormat(BaseFormat):
@property @property
def document_text(self): def document_text(self):
'''Метод для получения текста результирующего документа.
Представляет собой переопределение соответствующего метода базового
класса, посколько в данном случае нужно учитывать режим работы формата.
'''
file_loader = PackageLoader('calculate.templates.format', file_loader = PackageLoader('calculate.templates.format',
self.TEMPLATES_DIRECTORY) self.TEMPLATES_DIRECTORY)
formats_environment = Environment(loader=file_loader, formats_environment = Environment(loader=file_loader,

@ -10,7 +10,7 @@ class DiffFormat(BaseFormat):
FORMAT = 'diff' FORMAT = 'diff'
EXECUTABLE = True EXECUTABLE = True
def __init__(self, document_text: str, comment_symbol=''): def __init__(self, document_text: str):
self._patch_text = document_text self._patch_text = document_text
self._root_path = '' self._root_path = ''
self._last_level = 0 self._last_level = 0
@ -19,18 +19,19 @@ class DiffFormat(BaseFormat):
self._changed_files_list = [] self._changed_files_list = []
def execute_format(self, root_path): def execute_format(self, root_path):
print '''Метод для запуска работы формата.'''
if path.exists(root_path): if path.exists(root_path):
self._root_path = root_path self._root_path = root_path
else: else:
raise FormatError('Root path does not exist.') raise FormatError('root path does not exist')
if self._patch_text: if self._patch_text:
return self._patch_document() return self._patch_document()
else: else:
raise FormatError('Empty patch file.') raise FormatError('empty patch file')
def _patch_document(self): def _patch_document(self):
'''Метод, производящий наложение патча путем запуска процесса patch.'''
for level in range(0, 4): for level in range(0, 4):
patch_dry_run = Process('patch', '--dry-run', patch_dry_run = Process('patch', '--dry-run',
'-p{}'.format(level), cwd=self._root_path) '-p{}'.format(level), cwd=self._root_path)
@ -44,19 +45,16 @@ class DiffFormat(BaseFormat):
if patch_dry_run.success(): if patch_dry_run.success():
return '' return ''
else: else:
raise FormatError('Correction failed.') raise FormatError('correction failed')
self._last_level = level self._last_level = level
patch_run = Process('patch', '-p{}'.format(level), cwd=self._root_path) patch_run = Process('patch', '-p{}'.format(level), cwd=self._root_path)
patch_run.write(self._patch_text) patch_run.write(self._patch_text)
if patch_run.success(): if patch_run.success():
print('patch run is successful...')
for line in patch_run: for line in patch_run:
if line.startswith('patching file'): if line.startswith('patching file'):
self._changed_files_list.append(line[13:].strip()) self._changed_files_list.append(line[13:].strip())
return patch_run.read() return patch_run.read()
else: else:
print('patch run is no successful...')
print(patch_run.read_error())
return '' return ''

@ -16,8 +16,14 @@ class DovecotFormat(BaseFormat):
_initialized = False _initialized = False
_comment_symbol = '' _comment_symbol = ''
def __init__(self, document_text: str, ignore_comments=False, def __new__(cls, *args, **kwargs):
join_before=False, comment_symbol=''): if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str,
ignore_comments=False,
join_before=False):
processing_methods = [self._parse_comment_line, processing_methods = [self._parse_comment_line,
self._parse_section_start_line, self._parse_section_start_line,
self._parse_include_line, self._parse_include_line,
@ -35,8 +41,6 @@ class DovecotFormat(BaseFormat):
self._current_section_name = '' self._current_section_name = ''
self._last_comments_list = [] self._last_comments_list = []
if not self._initialized or comment_symbol != self._comment_symbol:
self._initialize_parser(comment_symbol)
if document_text == '': if document_text == '':
self._document_dictionary = OrderedDict() self._document_dictionary = OrderedDict()
@ -45,28 +49,19 @@ class DovecotFormat(BaseFormat):
self._lines_to_dictionary(document_lines) self._lines_to_dictionary(document_lines)
@classmethod @classmethod
def _initialize_parser(cls, comment_symbol=''): def _initialize_parser(cls):
# Знаки пунктуации и действий. # Знаки пунктуации и действий.
left_brace = Literal('{') left_brace = Literal('{')
right_brace = Literal('}') right_brace = Literal('}')
action_symbols = (Literal('!') | Literal('-')) action_symbols = (Literal('!') | Literal('-'))
if not comment_symbol: cls._comment_line_parser = originalTextFor(
cls._comment_line_parser = originalTextFor( Literal('#')
Literal('#') + ZeroOrMore(Word(
+ ZeroOrMore(Word( printables
printables + pyparsing_unicode.alphanums)
+ pyparsing_unicode.alphanums) )
) )('comment')
)('comment')
else:
cls._comment_line_parser = originalTextFor(
(Literal('#') | Literal(comment_symbol))
+ ZeroOrMore(Word(
printables
+ pyparsing_unicode.alphanums)
)
)('comment')
# Для парсинга строк с началом секций. # Для парсинга строк с началом секций.
section = Word(alphas, alphanums+'-_', excludeChars='{}') section = Word(alphas, alphanums+'-_', excludeChars='{}')
@ -96,9 +91,10 @@ class DovecotFormat(BaseFormat):
)('value')) )('value'))
# Для парсинга строк с параметрами, подлежащими удалению. # Для парсинга строк с параметрами, подлежащими удалению.
cls._parameter_to_delete_parser = (action_symbols('action') cls._parameter_to_delete_parser = (
+ parameter_name action_symbols('action')
+ Optional(Literal('=')).suppress() + parameter_name
+ Optional(Literal('=')).suppress()
) )
# Для парсинга строк, содержащих директиву !include. # Для парсинга строк, содержащих директиву !include.
@ -107,7 +103,8 @@ class DovecotFormat(BaseFormat):
include_line_plain = (Optional(~action_symbols, default='')('action') include_line_plain = (Optional(~action_symbols, default='')('action')
+ include('keyword') + Word(printables)('value')) + include('keyword') + Word(printables)('value'))
include_line_to_delete = (action_symbols('action') + include('keyword') include_line_to_delete = (action_symbols('action')
+ include('keyword')
+ Word(printables)('value')) + Word(printables)('value'))
cls._include_line_parser = (include_line_plain | cls._include_line_parser = (include_line_plain |

@ -9,7 +9,7 @@ class JSONFormat(BaseFormat):
FORMAT = 'json' FORMAT = 'json'
def __init__(self, document_text: str, ignore_comments=False, def __init__(self, document_text: str, ignore_comments=False,
join_before=False, comment_symbol=''): join_before=False):
processing_methods = [] processing_methods = []
super().__init__(processing_methods) super().__init__(processing_methods)
self._ignore_comments = ignore_comments self._ignore_comments = ignore_comments
@ -22,10 +22,14 @@ class JSONFormat(BaseFormat):
self._text_to_dictionary(document_text) self._text_to_dictionary(document_text)
def _text_to_dictionary(self, json_file_text): def _text_to_dictionary(self, json_file_text):
'''Метод для получения словаря документа, переопределяющий метод
базового класса.'''
self._document_dictionary = json.loads(json_file_text, self._document_dictionary = json.loads(json_file_text,
object_pairs_hook=OrderedDict) object_pairs_hook=OrderedDict)
@property @property
def document_text(self): def document_text(self):
'''Метод для получения текста документа, переопределяющий метод
базового класса.'''
json_file_text = json.dumps(self._document_dictionary, indent=4) json_file_text = json.dumps(self._document_dictionary, indent=4)
return json_file_text return json_file_text

@ -12,8 +12,14 @@ class KDEFormat(BaseFormat):
_initialized = False _initialized = False
def __init__(self, document_text: str, ignore_comments=False, def __new__(cls, *args, **kwargs):
join_before=False, comment_symbol=''): if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str,
ignore_comments=False,
join_before=False):
processing_methods = [self._parse_comment_line, processing_methods = [self._parse_comment_line,
self._parse_section_line, self._parse_section_line,
self._parse_parameter_line, self._parse_parameter_line,
@ -29,8 +35,6 @@ class KDEFormat(BaseFormat):
self._current_section_name = '' self._current_section_name = ''
self._last_comments_list = [] self._last_comments_list = []
if not self._initialized:
self._initialize_parser()
if document_text == '': if document_text == '':
self._document_dictionary = OrderedDict() self._document_dictionary = OrderedDict()
@ -40,6 +44,7 @@ class KDEFormat(BaseFormat):
@classmethod @classmethod
def _initialize_parser(cls): def _initialize_parser(cls):
'''Метод для инициализации парсеров.'''
action_symbols = (Literal('!') | Literal('-')) action_symbols = (Literal('!') | Literal('-'))
section_name_part_content = originalTextFor((OneOrMore( section_name_part_content = originalTextFor((OneOrMore(
Word(alphanums+':')))) Word(alphanums+':'))))
@ -79,6 +84,7 @@ class KDEFormat(BaseFormat):
cls._initialized = True cls._initialized = True
def _parse_section_line(self, line): def _parse_section_line(self, line):
'''Метод для парсинга строк содержащих название секции.'''
try: try:
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
parsing_result = self._section_line.parseString(line) parsing_result = self._section_line.parseString(line)
@ -107,6 +113,7 @@ class KDEFormat(BaseFormat):
return return
def _parse_parameter_line(self, line): def _parse_parameter_line(self, line):
'''Метод для парсинга строк содержащих обычный параметр.'''
try: try:
parsing_result = self._parameter_line.parseString(line) parsing_result = self._parameter_line.parseString(line)
self._match = True self._match = True
@ -122,6 +129,9 @@ class KDEFormat(BaseFormat):
return return
def _parse_to_delete_line(self, line): def _parse_to_delete_line(self, line):
'''Метод для парсинга строк, подлежащих удалению, т.е. для которых
указано имя параметра со знаком !, и опционально присутствует значение
параметра.'''
try: try:
parsing_result = self._parameter_to_delete.parseString(line) parsing_result = self._parameter_to_delete.parseString(line)
self._match = True self._match = True
@ -138,6 +148,7 @@ class KDEFormat(BaseFormat):
return return
def _parse_comment_line(self, line): def _parse_comment_line(self, line):
'''Метод для парсинга строк содержащих комментарий.'''
try: try:
parsing_result = self._comment_line.parseString(line) parsing_result = self._comment_line.parseString(line)
self._match = True self._match = True
@ -148,6 +159,8 @@ class KDEFormat(BaseFormat):
return return
def _finish_method(self): def _finish_method(self):
'''Метод для завершения парсинга. В данном случае добавляет в итоговый
словарь последнюю разобранную секцию.'''
if self._current_section_name in self._document_dictionary.keys(): if self._current_section_name in self._document_dictionary.keys():
self._document_dictionary[self._current_section_name].update( self._document_dictionary[self._current_section_name].update(
self._current_section self._current_section

@ -12,8 +12,14 @@ class KernelFormat(BaseFormat):
_initialized = False _initialized = False
def __init__(self, document_text: str, ignore_comments=False, def __new__(cls, *args, **kwargs):
join_before=False, comment_symbol=''): if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str,
ignore_comments=False,
join_before=False):
processing_methods = [self._parse_comment_line, processing_methods = [self._parse_comment_line,
self._parse_parameter_line, self._parse_parameter_line,
self._parse_to_delete_line] self._parse_to_delete_line]
@ -24,8 +30,6 @@ class KernelFormat(BaseFormat):
self._comments_processing = True self._comments_processing = True
self._last_comments_list = [] self._last_comments_list = []
if not self._initialized:
self._initialize_parser()
if document_text == '': if document_text == '':
self._document_dictionary = OrderedDict() self._document_dictionary = OrderedDict()
@ -35,6 +39,7 @@ class KernelFormat(BaseFormat):
@classmethod @classmethod
def _initialize_parser(cls): def _initialize_parser(cls):
'''Метод для инициализации парсеров.'''
parameter_name = Word(alphanums+'_')('parameter_name') parameter_name = Word(alphanums+'_')('parameter_name')
parameter_value = originalTextFor( parameter_value = originalTextFor(
@ -63,6 +68,7 @@ class KernelFormat(BaseFormat):
cls._initialized = True cls._initialized = True
def _parse_parameter_line(self, line): def _parse_parameter_line(self, line):
'''Метод для парсинга строк содержащих параметр.'''
try: try:
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
parsing_result = self._parameter_line.parseString(line) parsing_result = self._parameter_line.parseString(line)
@ -80,6 +86,9 @@ class KernelFormat(BaseFormat):
return return
def _parse_to_delete_line(self, line): def _parse_to_delete_line(self, line):
'''Метод для парсинга строк, подлежащих удалению, т.е. для которых
указано имя параметра со знаком !, и опционально присутствует значение
параметра.'''
try: try:
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
parsing_result = self._parameter_to_delete.parseString(line) parsing_result = self._parameter_to_delete.parseString(line)
@ -99,6 +108,7 @@ class KernelFormat(BaseFormat):
return return
def _parse_comment_line(self, line): def _parse_comment_line(self, line):
'''Метод для парсинга строк содержащих комментарий.'''
try: try:
result = self._comment_line.parseString(line) result = self._comment_line.parseString(line)
self._match = True self._match = True

@ -13,10 +13,14 @@ class LDAPFormat(BaseFormat):
_initialized = False _initialized = False
def __new__(cls, *args, **kwargs):
if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str, def __init__(self, document_text: str,
ignore_comments=False, ignore_comments=False,
join_before=False, join_before=False):
comment_symbol=''):
processing_methods = [self._parse_comment_line, processing_methods = [self._parse_comment_line,
self._parse_type_line, self._parse_type_line,
self._parse_access_line, self._parse_access_line,
@ -43,8 +47,6 @@ class LDAPFormat(BaseFormat):
self._current_type = ('', 'global') self._current_type = ('', 'global')
self._last_comments_list = [] self._last_comments_list = []
if not self._initialized:
self._initialize_parser()
if document_text == '': if document_text == '':
self._document_dictionary = OrderedDict() self._document_dictionary = OrderedDict()
@ -54,6 +56,7 @@ class LDAPFormat(BaseFormat):
@classmethod @classmethod
def _initialize_parser(cls): def _initialize_parser(cls):
'''Метод для инициализации парсеров.'''
cls._comment_line = originalTextFor( cls._comment_line = originalTextFor(
Literal('#') Literal('#')
+ ZeroOrMore(Word(printables + ZeroOrMore(Word(printables
@ -215,6 +218,9 @@ class LDAPFormat(BaseFormat):
cls._initialized = True cls._initialized = True
def _get_list_of_logic_lines(self, text): def _get_list_of_logic_lines(self, text):
'''Метод для разбиения исходного документа на список логических строк,
то есть с учетом того, что строка ldap файла начинающаяся с отступа
является продолжением предыдущей.'''
list_of_lines = [] list_of_lines = []
lines_to_join = [] lines_to_join = []
for line in text.splitlines(): for line in text.splitlines():
@ -239,6 +245,8 @@ class LDAPFormat(BaseFormat):
return list_of_lines return list_of_lines
def _parse_type_line(self, line): def _parse_type_line(self, line):
'''Метод для парсинга строк с объявлением областей backend или database
'''
try: try:
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
parsing_result = self._type_line.parseString(line) parsing_result = self._type_line.parseString(line)
@ -273,8 +281,7 @@ class LDAPFormat(BaseFormat):
def _parse_notunique_line(self, line): def _parse_notunique_line(self, line):
'''Метод для парсинга строк c директивами неуникальными для секции. '''Метод для парсинга строк c директивами неуникальными для секции.
Аргументы: line -- строка, которую нужно распарсить. Их приходится парсить полностью как ключ словаря.'''
'''
try: try:
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
parsing_result = self._not_unique_parser.parseString(line) parsing_result = self._not_unique_parser.parseString(line)
@ -293,9 +300,7 @@ class LDAPFormat(BaseFormat):
def _parse_access_line(self, line): def _parse_access_line(self, line):
'''Метод для парсинга строк содержащих конструкцию '''Метод для парсинга строк содержащих конструкцию
access to <what> by <who>|<access level>|<control>. access to <what> by <who>|<access level>|<control>.'''
Аргументы: line -- строка, которую нужно распарсить.
'''
try: try:
parsing_result = self._access_line_parser.parseString(line) parsing_result = self._access_line_parser.parseString(line)
self._match = True self._match = True
@ -335,9 +340,7 @@ class LDAPFormat(BaseFormat):
def _parse_access_line_to_delete(self, line): def _parse_access_line_to_delete(self, line):
'''Метод для парсинга строк, предписывающих удаление конструкций '''Метод для парсинга строк, предписывающих удаление конструкций
access to, если указано только ее название и значение What. access to, если указано только ее название и значение What.'''
Аргументы: line -- строка, которую нужно распарсить.
'''
try: try:
parsing_result = self._access_line_to_delete_parser.parseString( parsing_result = self._access_line_to_delete_parser.parseString(
line line
@ -357,9 +360,7 @@ class LDAPFormat(BaseFormat):
def _parse_syncrepl_line(self, line): def _parse_syncrepl_line(self, line):
'''Метод для парсинга строк содержащих конструкцию syncrepl '''Метод для парсинга строк содержащих конструкцию syncrepl
rep=<ReplicaID>. rep=<ReplicaID>.'''
Аргументы: line -- строка, которую нужно распарсить.
'''
try: try:
parsing_result = self._syncrepl_line_parser.parseString(line) parsing_result = self._syncrepl_line_parser.parseString(line)
self._match = True self._match = True
@ -398,9 +399,7 @@ class LDAPFormat(BaseFormat):
def _parse_syncrepl_line_to_delete(self, line): def _parse_syncrepl_line_to_delete(self, line):
'''Метод для парсинга строк, предписывающих удаление конструкций '''Метод для парсинга строк, предписывающих удаление конструкций
syncrepl rid=<ReplicaID>, если указано только ее название и значение syncrepl rid=<ReplicaID>, если указано только ее название и значение
ReplicaID. ReplicaID.'''
Аргументы: line -- строка, которую нужно распарсить.
'''
try: try:
parsing_result = self._syncrepl_line_to_delete_parser.parseString( parsing_result = self._syncrepl_line_to_delete_parser.parseString(
line line
@ -419,9 +418,7 @@ class LDAPFormat(BaseFormat):
return return
def _parse_index_line(self, line): def _parse_index_line(self, line):
'''Метод для парсинга строк с директивами index. '''Метод для парсинга строк с директивами index.'''
Аргументы: line -- строка, которую нужно распарсить.
'''
try: try:
parsing_result = self._index_line_parser.parseString(line) parsing_result = self._index_line_parser.parseString(line)
self._match = True self._match = True
@ -438,9 +435,7 @@ class LDAPFormat(BaseFormat):
def _parse_index_line_to_delete(self, line): def _parse_index_line_to_delete(self, line):
'''Метод для парсинга строк, предписывающих удаление директив index, '''Метод для парсинга строк, предписывающих удаление директив index,
если указано только из имя, но отсутвует значение. если указано только из имя, но отсутвует значение.'''
Аргументы: line -- строка, которую нужно распарсить.
'''
try: try:
parsing_result = self._index_line_to_delete_parser.parseString( parsing_result = self._index_line_to_delete_parser.parseString(
line line
@ -460,9 +455,7 @@ class LDAPFormat(BaseFormat):
def _parse_plain_directive_line(self, line): def _parse_plain_directive_line(self, line):
'''Метод для парсинга строк с простыми уникальными для секции '''Метод для парсинга строк с простыми уникальными для секции
директивами. директивами.'''
Аргументы: line -- строка, которую нужно распарсить.
'''
try: try:
parsing_result = self._directive_line_parser.parseString(line) parsing_result = self._directive_line_parser.parseString(line)
self._match = True self._match = True
@ -478,9 +471,7 @@ class LDAPFormat(BaseFormat):
def _parse_plain_directive_line_to_delete(self, line): def _parse_plain_directive_line_to_delete(self, line):
'''Метод для парсинга строк, предписывающих удаление простых уникальных '''Метод для парсинга строк, предписывающих удаление простых уникальных
директив, если указано только их имя, но отсутствует значение. директив, если указано только их имя, но отсутствует значение.'''
Аргументы: line -- строка, которую нужно распарсить.
'''
try: try:
parsing_result = self._directive_line_to_delete_parser.parseString( parsing_result = self._directive_line_to_delete_parser.parseString(
line line
@ -501,8 +492,7 @@ class LDAPFormat(BaseFormat):
def _parse_comment_line(self, line): def _parse_comment_line(self, line):
'''Метод для парсинга строк с комментариями и добавления их в список '''Метод для парсинга строк с комментариями и добавления их в список
комментариев _last_comments_list, предназначенный для сбора комментариев _last_comments_list, предназначенный для сбора
комментариев и последующего их присваивания параметрам и секциям. комментариев и последующего их присваивания параметрам и секциям.'''
Аргументы: line -- строка, которую нужно распарсить.'''
try: try:
parsing_result = self._comment_line.parseString(line) parsing_result = self._comment_line.parseString(line)
self._match = True self._match = True
@ -522,6 +512,8 @@ class LDAPFormat(BaseFormat):
return return
def _finish_method(self): def _finish_method(self):
'''Метод для завершения парсинга. В данном случае добавляет в итоговый
словарь последнюю разобранную область.'''
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
if self._current_type in self._document_dictionary.keys(): if self._current_type in self._document_dictionary.keys():
self._document_dictionary[self._current_type].update( self._document_dictionary[self._current_type].update(

@ -12,10 +12,14 @@ class OpenRCFormat(BaseFormat):
_initialized = False _initialized = False
def __new__(cls, *args, **kwargs):
if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str, def __init__(self, document_text: str,
ignore_comments=False, ignore_comments=False,
join_before=False, join_before=False):
comment_symbol=''):
processing_methods = [self._parse_comment_line, processing_methods = [self._parse_comment_line,
self._parse_parameter_line, self._parse_parameter_line,
self._parse_to_delete_line] self._parse_to_delete_line]
@ -25,8 +29,6 @@ class OpenRCFormat(BaseFormat):
self._comments_processing = True self._comments_processing = True
self._last_comments_list = [] self._last_comments_list = []
if not self._initialized:
self._initialize_parser()
if document_text == '': if document_text == '':
self._document_dictionary = OrderedDict() self._document_dictionary = OrderedDict()
@ -36,6 +38,7 @@ class OpenRCFormat(BaseFormat):
@classmethod @classmethod
def _initialize_parser(cls): def _initialize_parser(cls):
'''Метод для инициализации парсеров.'''
parameter_name = Word(printables, excludeChars='=') parameter_name = Word(printables, excludeChars='=')
parameter_value = originalTextFor(OneOrMore(Word(printables))) parameter_value = originalTextFor(OneOrMore(Word(printables)))
@ -61,6 +64,7 @@ class OpenRCFormat(BaseFormat):
cls._initialized = True cls._initialized = True
def _parse_parameter_line(self, line): def _parse_parameter_line(self, line):
'''Метод для парсинга строк содержащих параметр.'''
try: try:
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
parsing_result = self._parameter_line.parseString(line) parsing_result = self._parameter_line.parseString(line)
@ -79,6 +83,9 @@ class OpenRCFormat(BaseFormat):
return return
def _parse_to_delete_line(self, line): def _parse_to_delete_line(self, line):
'''Метод для парсинга строк, подлежащих удалению, т.е. для которых
указано имя параметра со знаком !, и опционально присутствует значение
параметра.'''
try: try:
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
parsing_result = self._parameter_to_delete.parseString(line) parsing_result = self._parameter_to_delete.parseString(line)
@ -98,6 +105,7 @@ class OpenRCFormat(BaseFormat):
return return
def _parse_comment_line(self, line): def _parse_comment_line(self, line):
'''Метод для парсинга строк содержащих комментарий.'''
try: try:
result = self._comment_line.parseString(line) result = self._comment_line.parseString(line)
self._match = True self._match = True

@ -1,6 +1,6 @@
# vim: fileencoding=utf-8 # vim: fileencoding=utf-8
# #
from .base_format import BaseFormat from .base_format import BaseFormat, FormatError
from collections import OrderedDict from collections import OrderedDict
import re import re
try: try:
@ -33,21 +33,19 @@ class PatchFormat(BaseFormat):
self._XML_ROOT_LINE = '<?xml version="1.0" encoding="utf-8"?>\ self._XML_ROOT_LINE = '<?xml version="1.0" encoding="utf-8"?>\
<patch>{0}</patch>' <patch>{0}</patch>'
if not self._parse_patch(document_text): self._parse_patch(document_text)
# Какая-то обработка ошибки.
print('Error: Can not parse patch document.')
def _parse_patch(self, patch_text): def _parse_patch(self, patch_text):
'''Метод, составляющий из текста шаблона xml документ и разбирающий его
с помощью lxml.'''
xml_patch = self._XML_ROOT_LINE.format(patch_text.strip()) xml_patch = self._XML_ROOT_LINE.format(patch_text.strip())
try: try:
self._parsed_patch = fromstring(xml_patch) self._parsed_patch = fromstring(xml_patch)
return True
except Exception: except Exception:
# Какая-то обработка ошибки. raise FormatError('can not parse patch document')
print('Error: Incorrect text of the template.')
return False
def execute_format(self, document_to_patch): def execute_format(self, document_to_patch):
'''Метод для запуска наложения патча.'''
if not document_to_patch.strip() == '': if not document_to_patch.strip() == '':
self._document_to_patch = document_to_patch self._document_to_patch = document_to_patch
@ -55,24 +53,23 @@ class PatchFormat(BaseFormat):
return False return False
else: else:
if not self._patch_document(document_to_patch): if not self._patch_document(document_to_patch):
error_message = 'Error: Can not run patch.' raise FormatError('Error: Can not run patch.')
print(error_message)
return False
else: else:
after_patch = self._document_to_patch after_patch = self._document_to_patch
self._document_to_patch = '' self._document_to_patch = ''
# Пока что возвращает результат наложения шаблона, это временно
return after_patch return after_patch
def _patch_document(self, document_to_patch): def _patch_document(self, document_to_patch):
'''Метод, обходящий теги шаблона и использующий указанные в нем
регулярные выражения.'''
patch_iterator = self._parsed_patch.getiterator() patch_iterator = self._parsed_patch.getiterator()
PATCH_DOCUMENT_TAGS = ('reg', 'text') PATCH_DOCUMENT_TAGS = ('reg', 'text')
patch_element = next(patch_iterator, False) patch_element = next(patch_iterator, False)
if not patch_element or not patch_element.tag == 'patch': if not patch_element or not patch_element.tag == 'patch':
print('Error: Incorrect text of the template.') raise FormatError('incorrect text of the template')
return False
while True: while True:
for patch_tag in PATCH_DOCUMENT_TAGS: for patch_tag in PATCH_DOCUMENT_TAGS:
@ -80,9 +77,8 @@ class PatchFormat(BaseFormat):
if patch_element is None: if patch_element is None:
if patch_tag == 'text': if patch_tag == 'text':
print('Error: Last <text>Text</text> ' raise FormatError('last <text>Text</text> '
'object is missed.') 'object is missed.')
return False
else: else:
break break
@ -90,19 +86,16 @@ class PatchFormat(BaseFormat):
if patch_element.text is not None: if patch_element.text is not None:
element_text = patch_element.text.strip() element_text = patch_element.text.strip()
if element_text == '': if element_text == '':
error_message = 'Error: Incorrect text of the \ raise FormatError(
template: <{0}>%s</{0}>'.format( ("Error: Incorrect text of the "
"template: <{0}>%s</{0}>").format(
patch_tag patch_tag
) ))
print(error_message)
return False
else: else:
error_message = 'Error: Incorrect text of the \ raise FormatError("Error: Incorrect text of the "
template: <{0}></{0}>'.format( "template: <{0}></{0}>").format(
patch_tag patch_tag
) )
print(error_message)
return False
if patch_tag == 'reg': if patch_tag == 'reg':
dotall = patch_element.attrib.get('dotall', False) dotall = patch_element.attrib.get('dotall', False)
@ -111,10 +104,7 @@ class PatchFormat(BaseFormat):
if 'multiline' in patch_element.attrib: if 'multiline' in patch_element.attrib:
multiline = patch_element.attrib['multiline'] multiline = patch_element.attrib['multiline']
if multiline not in self._FLAG_VALUES: if multiline not in self._FLAG_VALUES:
error_message = ('Error: Invalid multiline ' raise FormatError('invalid multiline value')
'value.')
print(error_message)
return False
else: else:
multiline = self._FLAG_VALUES[multiline] multiline = self._FLAG_VALUES[multiline]
@ -133,9 +123,7 @@ class PatchFormat(BaseFormat):
if 'dotall' in patch_element.attrib: if 'dotall' in patch_element.attrib:
dotall = patch_element.attrib['dotall'] dotall = patch_element.attrib['dotall']
if dotall not in self._FLAG_VALUES: if dotall not in self._FLAG_VALUES:
error_message = 'Error: Invalid dotall value.' raise FormatError('invalid dotall value')
print(error_message)
return False
else: else:
dotall = self._FLAG_VALUES[dotall] dotall = self._FLAG_VALUES[dotall]
@ -157,21 +145,15 @@ class PatchFormat(BaseFormat):
text_for_replace = element_text text_for_replace = element_text
else: else:
if patch_element.tag in PATCH_DOCUMENT_TAGS: if patch_element.tag in PATCH_DOCUMENT_TAGS:
error_message = 'Error: <{0}> is expected, \ error_message = '<{0}> is expected, <{1}> instead.'.\
<{1}> instead.'.format( format(patch_tag,
patch_tag, patch_element.tag)
patch_element.tag
)
print(error_message)
else: else:
error_message = 'Error: Unknown tag: {0}'.format( error_message = 'unknown tag: {0}'.format(
patch_element.tag patch_element.tag
) )
print(error_message) raise ("incorrect text of the template: {}".format(
# Какая-то обработка ошибки. error_message))
error_message = 'Error: Incorrect text of the template.'
print(error_message)
return False
else: else:
self._document_to_patch = re.sub(regex_expression, self._document_to_patch = re.sub(regex_expression,
text_for_replace, text_for_replace,

@ -12,10 +12,14 @@ class PostfixFormat(BaseFormat):
_initialized = False _initialized = False
def __new__(cls, *args, **kwargs):
if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str, def __init__(self, document_text: str,
ignore_comments=False, ignore_comments=False,
join_before=False, join_before=False):
comment_symbol=''):
processing_methods = [self._parse_comment_line, processing_methods = [self._parse_comment_line,
self._parse_parameter_line, self._parse_parameter_line,
self._parse_to_delete_line] self._parse_to_delete_line]
@ -25,8 +29,6 @@ class PostfixFormat(BaseFormat):
self._comments_processing = True self._comments_processing = True
self._last_comments_list = [] self._last_comments_list = []
if not self._initialized:
self._initialize_parser()
if document_text == '': if document_text == '':
self._document_dictionary = OrderedDict() self._document_dictionary = OrderedDict()
@ -36,6 +38,7 @@ class PostfixFormat(BaseFormat):
@classmethod @classmethod
def _initialize_parser(cls): def _initialize_parser(cls):
'''Метод для инициализации парсеров.'''
parameter_name = Word(alphanums+'_') parameter_name = Word(alphanums+'_')
parameter_value = originalTextFor(OneOrMore(Word(printables))) parameter_value = originalTextFor(OneOrMore(Word(printables)))
@ -61,6 +64,7 @@ class PostfixFormat(BaseFormat):
)('comment') )('comment')
def _parse_parameter_line(self, line): def _parse_parameter_line(self, line):
'''Метод для парсинга строк содержащих параметр.'''
try: try:
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
parsing_result = self._parameter_line.parseString(line) parsing_result = self._parameter_line.parseString(line)
@ -78,6 +82,9 @@ class PostfixFormat(BaseFormat):
return return
def _parse_to_delete_line(self, line): def _parse_to_delete_line(self, line):
'''Метод для парсинга строк, подлежащих удалению, т.е. для которых
указано имя параметра со знаком !, и опционально присутствует значение
параметра.'''
try: try:
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
parsing_result = self._parameter_to_delete.parseString(line) parsing_result = self._parameter_to_delete.parseString(line)
@ -96,6 +103,7 @@ class PostfixFormat(BaseFormat):
return return
def _parse_comment_line(self, line): def _parse_comment_line(self, line):
'''Метод для парсинга строк содержащих комментарий.'''
try: try:
parsing_result = self._comment_line.parseString(line) parsing_result = self._comment_line.parseString(line)
self._match = True self._match = True

@ -12,6 +12,11 @@ class ProcmailFormat(BaseFormat):
_initialized = False _initialized = False
def __new__(cls, *args, **kwargs):
if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str, def __init__(self, document_text: str,
ignore_comments=False, ignore_comments=False,
join_before=True, join_before=True,
@ -25,8 +30,6 @@ class ProcmailFormat(BaseFormat):
self._comments_processing = True self._comments_processing = True
self._last_comments_list = [] self._last_comments_list = []
if not self._initialized:
self._initialize_parser()
if document_text == '': if document_text == '':
self._document_dictionary = OrderedDict() self._document_dictionary = OrderedDict()
@ -36,6 +39,7 @@ class ProcmailFormat(BaseFormat):
@classmethod @classmethod
def _initialize_parser(cls): def _initialize_parser(cls):
'''Метод для инициализации парсеров.'''
parameter_name = Word(alphanums+'_.') parameter_name = Word(alphanums+'_.')
parameter_value = originalTextFor(OneOrMore(Word(printables))) parameter_value = originalTextFor(OneOrMore(Word(printables)))
@ -64,6 +68,7 @@ class ProcmailFormat(BaseFormat):
cls._initialized = True cls._initialized = True
def _parse_parameter_line(self, line): def _parse_parameter_line(self, line):
'''Метод для парсинга строк содержащих параметр.'''
try: try:
parsing_result = self._parameter_line.parseString(line) parsing_result = self._parameter_line.parseString(line)
self._match = True self._match = True
@ -80,6 +85,9 @@ class ProcmailFormat(BaseFormat):
return return
def _parse_to_delete_line(self, line): def _parse_to_delete_line(self, line):
'''Метод для парсинга строк, подлежащих удалению, т.е. для которых
указано имя параметра со знаком !, и опционально присутствует значение
параметра.'''
try: try:
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
parsing_result = self._parameter_to_delete.parseString(line) parsing_result = self._parameter_to_delete.parseString(line)
@ -98,6 +106,7 @@ class ProcmailFormat(BaseFormat):
return return
def _parse_comment_line(self, line): def _parse_comment_line(self, line):
'''Метод для парсинга строк содержащих комментарий.'''
try: try:
parsing_result = self._comment_line.parseString(line) parsing_result = self._comment_line.parseString(line)
self._match = True self._match = True

@ -1,6 +1,6 @@
# vim: fileencoding=utf-8 # vim: fileencoding=utf-8
# #
from .base_format import BaseFormat from .base_format import BaseFormat, FormatError
from jinja2 import Environment, PackageLoader from jinja2 import Environment, PackageLoader
from collections import OrderedDict from collections import OrderedDict
from pyparsing import originalTextFor, Literal, ZeroOrMore, Word, printables,\ from pyparsing import originalTextFor, Literal, ZeroOrMore, Word, printables,\
@ -9,10 +9,21 @@ from pyparsing import originalTextFor, Literal, ZeroOrMore, Word, printables,\
class ProFTPDFormat(BaseFormat): class ProFTPDFormat(BaseFormat):
'''Класс формата ProFTPD. В отличие от других форматов, при разборе
вложенных на несколько уровней блоков, в итоговый словарь добавляются не
вложенные на несколько уровней словари, а отдельные объекты этих блоков,
содержащие в названии последовательность имен тегов, к которым они
относятся.
'''
FORMAT = 'proftpd' FORMAT = 'proftpd'
_initialized = False _initialized = False
def __new__(cls, *args, **kwargs):
if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str, def __init__(self, document_text: str,
ignore_comments=False, ignore_comments=False,
join_before=False, join_before=False,
@ -36,8 +47,6 @@ class ProFTPDFormat(BaseFormat):
self._actions_stack = [] self._actions_stack = []
self._last_comments_list = [] self._last_comments_list = []
if not self._initialized:
self._initialize_parser()
if document_text == '': if document_text == '':
self._document_dictionary = OrderedDict() self._document_dictionary = OrderedDict()
@ -47,6 +56,7 @@ class ProFTPDFormat(BaseFormat):
@classmethod @classmethod
def _initialize_parser(cls): def _initialize_parser(cls):
'''Метод для инициализации парсеров.'''
left_angle_bracket = Literal('<') left_angle_bracket = Literal('<')
right_angle_bracket = Literal('>') right_angle_bracket = Literal('>')
slash = Literal('/') slash = Literal('/')
@ -200,6 +210,7 @@ class ProFTPDFormat(BaseFormat):
cls._initialized = True cls._initialized = True
def _parse_section_start_line(self, line): def _parse_section_start_line(self, line):
'''Метод для разбора тега открывающего секцию.'''
try: try:
parsing_result = self._section_start_parser.parseString(line) parsing_result = self._section_start_parser.parseString(line)
self._match = True self._match = True
@ -212,6 +223,7 @@ class ProFTPDFormat(BaseFormat):
return return
def _parse_section_end_line(self, line): def _parse_section_end_line(self, line):
'''Метод для разбора тега закрывающего секцию.'''
try: try:
parsing_result = self._section_end_parser.parseString(line) parsing_result = self._section_end_parser.parseString(line)
self._match = True self._match = True
@ -221,14 +233,14 @@ class ProFTPDFormat(BaseFormat):
directive = tuple(parsing_result.directive) directive = tuple(parsing_result.directive)
if not current_section[1] != directive: if not current_section[1] != directive:
# Здесь будет кидаться исключение. raise FormatError("incorrect end tag </{}>, expected </{}>".
self._fatal_error_flag = True format(directive, current_section))
return
except ParseException: except ParseException:
return return
def _parse_plain_directive_line(self, line): def _parse_plain_directive_line(self, line):
'''Метод для разбора строк состоящих из имени параметра и его значения.
'''
try: try:
parsing_result = self._plain_directive_parser.parseString(line) parsing_result = self._plain_directive_parser.parseString(line)
self._match = True self._match = True
@ -258,6 +270,8 @@ class ProFTPDFormat(BaseFormat):
return return
def _parse_to_delete_plain_directive_line(self, line): def _parse_to_delete_plain_directive_line(self, line):
'''Метод для разбора строк с параметрами, подлежащими удалению, то есть
содержащих имя параметра с символом ! и, опционально, его значение.'''
try: try:
parsing_result = self._delete_plain_directive_parser.parseString( parsing_result = self._delete_plain_directive_parser.parseString(
line line
@ -283,6 +297,9 @@ class ProFTPDFormat(BaseFormat):
return return
def _parse_single_key_directive_line(self, line): def _parse_single_key_directive_line(self, line):
'''Метод для разбора строк с директивами, состоящих лишь из одного
имени директивы.
'''
try: try:
parsing_result = self._single_key_directive_parser.parseString( parsing_result = self._single_key_directive_parser.parseString(
line line
@ -314,6 +331,9 @@ class ProFTPDFormat(BaseFormat):
return return
def _parse_double_key_directive_line(self, line): def _parse_double_key_directive_line(self, line):
'''Метод для разбора директив, добавление в словарь которых возможно
посредством формирования ключа из названия директивы и последующего за
ней значения.'''
try: try:
parsing_result = self._double_key_directive_parser.parseString( parsing_result = self._double_key_directive_parser.parseString(
line line
@ -345,6 +365,8 @@ class ProFTPDFormat(BaseFormat):
return return
def _parse_to_delete_double_key_directive_line(self, line): def _parse_to_delete_double_key_directive_line(self, line):
'''Метод для разбора директив, подлежащих удалению, ключи которых
формируются из названия директивы и последующего за ней значения.'''
try: try:
parsing_result = self._delete_double_key_directive_parser.\ parsing_result = self._delete_double_key_directive_parser.\
parseString(line) parseString(line)
@ -369,6 +391,9 @@ class ProFTPDFormat(BaseFormat):
return return
def _parse_full_key_directive_line(self, line): def _parse_full_key_directive_line(self, line):
'''Метод для разбора строк с директивами, из имен которых невозможно
составить уникальный ключ для итогового словаря. Такие директивы
разбираем полностью как ключ для пустого значения в словаре.'''
try: try:
parsing_result = self._full_key_directive_parser.parseString(line) parsing_result = self._full_key_directive_parser.parseString(line)
self._match = True self._match = True
@ -398,6 +423,7 @@ class ProFTPDFormat(BaseFormat):
return return
def _parse_comment_line(self, line): def _parse_comment_line(self, line):
'''Метод для разбора строк, содержащих комментарии.'''
try: try:
result = self._comment_line.parseString(line) result = self._comment_line.parseString(line)
self._match = True self._match = True

@ -10,10 +10,14 @@ class SambaFormat(BaseFormat):
FORMAT = 'samba' FORMAT = 'samba'
_initialized = False _initialized = False
def __new__(cls, *args, **kwargs):
if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str, def __init__(self, document_text: str,
ignore_comments=False, ignore_comments=False,
join_before=False, join_before=False):
comment_symbol=''):
processing_methods = [self._parse_comment_line, processing_methods = [self._parse_comment_line,
self._parse_section_line, self._parse_section_line,
self._parse_parameter_line, self._parse_parameter_line,
@ -30,8 +34,6 @@ class SambaFormat(BaseFormat):
self._join_before = join_before self._join_before = join_before
self._last_comments_list = [] self._last_comments_list = []
if not self._initialized:
self._initialize_parser()
if document_text == '': if document_text == '':
self._document_dictionary = OrderedDict() self._document_dictionary = OrderedDict()
@ -80,6 +82,7 @@ class SambaFormat(BaseFormat):
cls._initialized = True cls._initialized = True
def _parse_section_line(self, line): def _parse_section_line(self, line):
'''Метод для парсинга строк содержащих имя секции.'''
try: try:
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
parsing_result = self._section_line.parseString(line) parsing_result = self._section_line.parseString(line)
@ -107,6 +110,7 @@ class SambaFormat(BaseFormat):
return return
def _parse_parameter_line(self, line): def _parse_parameter_line(self, line):
'''Метод для парсинга строк содержащих параметр.'''
try: try:
parsing_result = self._parameter_line.parseString(line) parsing_result = self._parameter_line.parseString(line)
self._match = True self._match = True
@ -123,6 +127,9 @@ class SambaFormat(BaseFormat):
return return
def _parse_to_delete_line(self, line): def _parse_to_delete_line(self, line):
'''Метод для парсинга строк, подлежащих удалению, т.е. для которых
указано имя параметра со знаком !, и опционально присутствует значение
параметра.'''
try: try:
parsing_result = self._parameter_to_delete.parseString(line) parsing_result = self._parameter_to_delete.parseString(line)
self._match = True self._match = True
@ -140,6 +147,7 @@ class SambaFormat(BaseFormat):
return return
def _parse_comment_line(self, line): def _parse_comment_line(self, line):
'''Метод для парсинга строк содержащих комментарий.'''
try: try:
parsing_result = self._comment_line.parseString(line) parsing_result = self._comment_line.parseString(line)
self._match = True self._match = True
@ -150,6 +158,8 @@ class SambaFormat(BaseFormat):
return return
def _finish_method(self): def _finish_method(self):
'''Метод для завершения парсинга. В данном случае добавляет в итоговый
словарь последнюю разобранную секцию.'''
self._item_to_add = OrderedDict() self._item_to_add = OrderedDict()
if self._current_section_name in self._document_dictionary.keys(): if self._current_section_name in self._document_dictionary.keys():
self._document_dictionary[self._current_section_name].update( self._document_dictionary[self._current_section_name].update(

@ -14,6 +14,13 @@ except ImportError:
class XMLGConfFormat(BaseFormat): class XMLGConfFormat(BaseFormat):
FORMAT = 'xml_gconf' FORMAT = 'xml_gconf'
_initialized = False
def __new__(cls, *args, **kwargs):
if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str): def __init__(self, document_text: str):
processing_methods = OrderedDict({'gconf': self._gconf, processing_methods = OrderedDict({'gconf': self._gconf,
'entry': self._entry, 'entry': self._entry,
@ -30,14 +37,18 @@ class XMLGConfFormat(BaseFormat):
self._parse_xml_to_dictionary(document_text) self._parse_xml_to_dictionary(document_text)
def _initialize_parser(self): @classmethod
def _initialize_parser(cls):
'''Метод для инициализации парсерa.'''
action_symbols = (Literal('!') | Literal('-')) action_symbols = (Literal('!') | Literal('-'))
name = originalTextFor(OneOrMore(Word(printables))) name = originalTextFor(OneOrMore(Word(printables)))
self._node_name = Optional(action_symbols)('action') + name('name') cls._node_name = Optional(action_symbols)('action') + name('name')
cls._initialized = True
def _entry(self, xml_element): def _entry(self, xml_element):
'''Метод для парсинга тега entry.'''
try: try:
element_items = OrderedDict(xml_element.attrib) element_items = OrderedDict(xml_element.attrib)
@ -71,6 +82,7 @@ class XMLGConfFormat(BaseFormat):
return OrderedDict() return OrderedDict()
def _gconf(self, xml_element): def _gconf(self, xml_element):
'''Метод для парсинга тега gconf.'''
output_dictionary = OrderedDict() output_dictionary = OrderedDict()
element_name = ('', xml_element.tag) element_name = ('', xml_element.tag)
for child in xml_element: for child in xml_element:
@ -81,6 +93,7 @@ class XMLGConfFormat(BaseFormat):
return OrderedDict({element_name: output_dictionary}) return OrderedDict({element_name: output_dictionary})
def _dir(self, xml_element): def _dir(self, xml_element):
'''Метод для парсинга тега dir.'''
output_dictionary = OrderedDict() output_dictionary = OrderedDict()
try: try:
parsing_result = self._node_name.parseString( parsing_result = self._node_name.parseString(
@ -101,6 +114,7 @@ class XMLGConfFormat(BaseFormat):
return OrderedDict({element_name: output_dictionary}) return OrderedDict({element_name: output_dictionary})
def _longdesc(self, xml_element): def _longdesc(self, xml_element):
'''Метод для парсинга тега longdesc.'''
element_name = ('', 'longdesc') element_name = ('', 'longdesc')
description = xml_element.text description = xml_element.text
@ -112,6 +126,7 @@ class XMLGConfFormat(BaseFormat):
return OrderedDict({element_name: ''}) return OrderedDict({element_name: ''})
def _local_schema(self, xml_element): def _local_schema(self, xml_element):
'''Метод для парсинга тега local_schema.'''
output_dictionary = OrderedDict() output_dictionary = OrderedDict()
try: try:
element_name = ('', xml_element.tag, element_name = ('', xml_element.tag,
@ -129,6 +144,7 @@ class XMLGConfFormat(BaseFormat):
return OrderedDict({element_name: output_dictionary}) return OrderedDict({element_name: output_dictionary})
def _stringvalue(self, xml_element): def _stringvalue(self, xml_element):
'''Метод для парсинга тега stringvalue.'''
element_name = ('', 'stringvalue') element_name = ('', 'stringvalue')
value = xml_element.text value = xml_element.text
@ -140,6 +156,7 @@ class XMLGConfFormat(BaseFormat):
return OrderedDict({element_name: ''}) return OrderedDict({element_name: ''})
def _default(self, xml_element): def _default(self, xml_element):
'''Уже не акутальный метод, вместо него теперь _unknown'''
output_dictionary = OrderedDict() output_dictionary = OrderedDict()
element_name = ('', xml_element.tag, *xml_element.items()) element_name = ('', xml_element.tag, *xml_element.items())
@ -151,6 +168,7 @@ class XMLGConfFormat(BaseFormat):
return OrderedDict({element_name: output_dictionary}) return OrderedDict({element_name: output_dictionary})
def _li(self, xml_element): def _li(self, xml_element):
'''Метод для разбора элементов с тегом li.'''
child = next(iter(xml_element)) child = next(iter(xml_element))
list_element = self._processing_methods.get(child.tag, list_element = self._processing_methods.get(child.tag,
@ -166,6 +184,8 @@ class XMLGConfFormat(BaseFormat):
@property @property
def document_text(self): def document_text(self):
'''Метод для получения исходного текста документа. Использует
рекурсивный метод _build_section.'''
gconf_header = next(iter(self._document_dictionary)) gconf_header = next(iter(self._document_dictionary))
root = Element('gconf') root = Element('gconf')
@ -180,6 +200,9 @@ class XMLGConfFormat(BaseFormat):
return xml_document return xml_document
def _build_section(self, current_element, dictionary): def _build_section(self, current_element, dictionary):
'''Метод для перевода словаря xml-документа обратно в текст документа.
Для этого рекурсивно строит дерево xml-документа пригодное работы lxml.
'''
for dict_element in dictionary.keys(): for dict_element in dictionary.keys():
element_tag = dict_element[1] element_tag = dict_element[1]
element_attributes = OrderedDict({key: value for key, value in element_attributes = OrderedDict({key: value for key, value in

@ -14,6 +14,13 @@ except ImportError:
class XMLXfceFormat(BaseFormat): class XMLXfceFormat(BaseFormat):
FORMAT = 'xml_xfce' FORMAT = 'xml_xfce'
_initialized = False
def __new__(cls, *args, **kwargs):
if not cls._initialized:
cls._initialize_parser()
return super().__new__(cls)
def __init__(self, document_text: str, ignore_comments=False): def __init__(self, document_text: str, ignore_comments=False):
processing_methods = OrderedDict({'channel': self._channel, processing_methods = OrderedDict({'channel': self._channel,
'property': self._property, 'property': self._property,
@ -27,19 +34,22 @@ class XMLXfceFormat(BaseFormat):
else: else:
self._parse_xml_to_dictionary(document_text) self._parse_xml_to_dictionary(document_text)
def _initialize_parser(self): @classmethod
def _initialize_parser(cls):
'''Метод для инициализации парсерa.'''
action_symbols = (Literal('!') | Literal('-')) action_symbols = (Literal('!') | Literal('-'))
name = originalTextFor(OneOrMore(Word(printables))) name = originalTextFor(OneOrMore(Word(printables)))
self._node_name = Optional(action_symbols)('action') + name('name') cls._node_name = Optional(action_symbols)('action') + name('name')
# Кортежи с названиями атрибутов различных элементов. # Кортежи с названиями атрибутов различных элементов.
self._ELEMENT_ATTRIBUTES = ('tag', 'name', 'type', 'value') cls._ELEMENT_ATTRIBUTES = ('tag', 'name', 'type', 'value')
self._CHANNEL_ATTRIBUTES = ('tag', 'name', 'version') cls._CHANNEL_ATTRIBUTES = ('tag', 'name', 'version')
self._VALUE_ATTRIBUTES = ('tag', 'type', 'value') cls._VALUE_ATTRIBUTES = ('tag', 'type', 'value')
def _property(self, xml_element): def _property(self, xml_element):
'''Метод для парсинга тега property.'''
try: try:
parsing_result = self._node_name.parseString( parsing_result = self._node_name.parseString(
xml_element.attrib['name'] xml_element.attrib['name']
@ -77,6 +87,7 @@ class XMLXfceFormat(BaseFormat):
return OrderedDict({element_name: output}) return OrderedDict({element_name: output})
def _value(self, xml_element): def _value(self, xml_element):
'''Метод для парсинга тега value.'''
try: try:
value = (xml_element.tag, value = (xml_element.tag,
xml_element.attrib['type'], xml_element.attrib['type'],
@ -87,6 +98,7 @@ class XMLXfceFormat(BaseFormat):
return value return value
def _channel(self, xml_element): def _channel(self, xml_element):
'''Метод для парсинга тега channel.'''
output_dictionary = OrderedDict() output_dictionary = OrderedDict()
try: try:
parsing_result = self._node_name.parseString( parsing_result = self._node_name.parseString(
@ -114,6 +126,8 @@ class XMLXfceFormat(BaseFormat):
@property @property
def document_text(self): def document_text(self):
'''Метод для получения исходного текста документа. Использует
рекурсивный метод _build_section.'''
channel = next(iter(self._document_dictionary.keys())) channel = next(iter(self._document_dictionary.keys()))
channel_head = OrderedDict( channel_head = OrderedDict(
{key: value for key, value in {key: value for key, value in
@ -132,6 +146,9 @@ class XMLXfceFormat(BaseFormat):
return xml_document return xml_document
def _build_section(self, current_element, dictionary): def _build_section(self, current_element, dictionary):
'''Метод для перевода словаря xml-документа обратно в текст документа.
Для этого рекурсивно строит дерево xml-документа пригодное работы lxml.
'''
for dict_element in dictionary.keys(): for dict_element in dictionary.keys():
element_head = OrderedDict({key: value for key, value in element_head = OrderedDict({key: value for key, value in
zip(self._ELEMENT_ATTRIBUTES, zip(self._ELEMENT_ATTRIBUTES,

@ -139,45 +139,6 @@ class TestParsingMethods:
compiz_object = CompizFormat(document_text) compiz_object = CompizFormat(document_text)
assert compiz_object._document_dictionary == result assert compiz_object._document_dictionary == result
def test_if_comment_parameter_is_set_for_template__format_object_will_parse_comments_with_comment_symbol_from_this_parameter(self):
document_text = '''
# Comment
[Added Associations]
@ Comment1
application/illustrator=zzz-gimp.desktop
application/pdf=evince.desktop;
@ Comment2
# Comment3
application/rtf=libreoffice-writer.desktop;
[Other Section]
@Comment
!application/vnd.oasis.opendocument.spreadsheet=calculate-calc.desktop;
'''
section_1 = OrderedDict({'#': ['# Comment'],
('', 'application/illustrator'):
['@ Comment1',
'zzz-gimp.desktop'],
('', 'application/pdf'):
['evince.desktop;'],
('', 'application/rtf'):
['@ Comment2',
'# Comment3',
'libreoffice-writer.desktop;']})
section_2 = OrderedDict({('!', 'application/vnd.oasis.opendocument.spreadsheet'):
['@Comment',
"calculate-calc.desktop;"]})
result = OrderedDict({('', 'Added Associations'): section_1,
('', 'Other Section'): section_2})
compiz_object = CompizFormat(document_text, comment_symbol='@')
assert compiz_object._document_dictionary == result
def test_if_the_ignore_comments_flag_is_set__the_parser_ignores_all_comments(self): def test_if_the_ignore_comments_flag_is_set__the_parser_ignores_all_comments(self):
document_text = ''' document_text = '''
# Comment # Comment

Loading…
Cancel
Save