File: sybil.py

package info (click to toggle)
python-testfixtures 9.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,036 kB
  • sloc: python: 10,373; makefile: 76; sh: 9
file content (68 lines) | stat: -rw-r--r-- 2,422 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import os
import textwrap
from dataclasses import dataclass
from typing import Iterable

from sybil import Document, Region, Example
from sybil.parsers.rest.lexers import DirectiveLexer

from testfixtures import diff


@dataclass
class FileBlock:
    path: str
    content: str
    action: str


class FileParser:
    """
    A `Sybil <http://sybil.readthedocs.io>`__ parser that
    parses certain ReST sections to read and write files in the
    configured :class:`~testfixtures.TempDirectory`.

    :param name: This is the name of the :class:`~testfixtures.TempDirectory` to use
                 in the Sybil test namespace.
    """

    def __init__(self, name: str):
        self.name = name
        self.lexer = DirectiveLexer('topic', arguments='.+')

    def __call__(self, document: Document) -> Iterable[Region]:
        for region in self.lexer(document):
            options = region.lexemes.get('options')
            if options is not None:
                class_ = options.get('class')
                if class_ in ('read-file', 'write-file'):
                    lines = region.lexemes['source'].splitlines(keepends=True)
                    index = 0
                    if lines[index].strip() == '::':
                        index += 1
                    source = textwrap.dedent(''.join(lines[index:])).lstrip()
                    if source[-1] != '\n':
                        source += '\n'
                    region.parsed = FileBlock(
                        path=region.lexemes['arguments'],
                        content=source,
                        action=class_.split('-')[0]
                    )
                    region.evaluator = self.evaluate
                    yield region

    def evaluate(self, example: Example) -> str | None:
        block: FileBlock = example.parsed
        temp_directory = example.namespace[self.name]
        if block.action == 'read':
            actual = temp_directory.as_path(block.path).read_text().replace(os.linesep, '\n')
            if actual != block.content:
                return diff(
                    block.content,
                    actual,
                    'File %r, line %i:' % (example.path, example.line),
                    'Reading from "%s":' % temp_directory.as_string(block.path)
                )
        if block.action == 'write':
            temp_directory.write(block.path, block.content)
        return None