from __future__ import absolute_import # Copyright (c) 2010-2013 Simplistix Ltd # # See license.txt for more details. import os import re import textwrap from manuel import Manuel from testfixtures import diff FILEBLOCK_START = re.compile(r'^\.\.\s*topic::?\s*(.+)\b', re.MULTILINE) FILEBLOCK_END = re.compile(r'(\n\Z|\n(?=\S))') CLASS = re.compile(r'\s+:class:\s*(read|write)-file') class FileBlock(object): def __init__(self, path, content, action): self.path, self.content, self.action = path, content, action class FileResult(object): passed = True expected = None actual = None class Files(Manuel): """ A `Manuel `__ plugin that parses certain ReST sections to read and write files in the configured :class:`TempDirectory`. :param name: This is the name of the :class:`TempDirectory` to use in the Manual global namespace (ie: `globs`). """ def __init__(self, name): self.name = name Manuel.__init__(self, parsers=[self.parse], evaluaters=[self.evaluate], formatters=[self.format]) def parse(self, document): for region in document.find_regions(FILEBLOCK_START, FILEBLOCK_END): lines = region.source.splitlines() class_ = CLASS.match(lines[1]) if not class_: continue index = 3 if lines[index].strip() == '::': index += 1 source = textwrap.dedent('\n'.join(lines[index:])).lstrip() if source[-1] != '\n': source += '\n' region.parsed = FileBlock( region.start_match.group(1), source, class_.group(1) ) document.claim_region(region) def evaluate(self, region, document, globs): if not isinstance(region.parsed, FileBlock): return block = region.parsed dir = globs[self.name] result = region.evaluated = FileResult() if block.action == 'read': actual = dir.read(block.path, 'ascii').replace(os.linesep, '\n') if actual != block.content: result.passed = False result.path = block.path result.expected = block.content result.actual = actual if block.action == 'write': dir.write(block.path, block.content, 'ascii') def format(self, document): for region in document: result = region.evaluated if not isinstance(result, FileResult): continue if not result.passed: region.formatted = diff( result.expected, result.actual, 'File "%s", line %i:' % (document.location, region.lineno), 'Reading from "%s":' % result.path ) return