-
-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathconftest.py
103 lines (83 loc) · 3.04 KB
/
conftest.py
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# Copyright 2019, 2020, 2022 Matthew Egan Odendahl
# SPDX-License-Identifier: Apache-2.0
import re
from collections.abc import Container
from difflib import context_diff
from doctest import ELLIPSIS
from fnmatch import fnmatch
from textwrap import indent
from sybil import Sybil
from sybil.parsers.doctest import DocTestParser
from hissp.reader import Lissp
LISSP = re.compile(r" *#> .*\n(?: *#\.\..*\n)*")
STRIP_LISSP = re.compile(r"(?m)^ *#(?:> |\.\.)")
class ParseLissp(DocTestParser):
"""
Like Sybil's DocTestParser, but also checks the Lissp compilation.
"""
def __init__(self, *a, **kw):
super().__init__(*a, **kw)
self._EXAMPLE_RE = re.compile(
r"""
(?P<lissp>
(?:^ [ ]* [#]>[ ] .*)
(?:\n [ ]* [#]\.\. .*)*)?
\n?
"""
+ self._EXAMPLE_RE.pattern,
re.MULTILINE | re.VERBOSE,
)
def __call__(self, document, *a, **kw):
assert type(document.text) is str
if document.path.endswith(".lissp"):
document.text = re.sub(
r"(?m)(^ *;+)", lambda m: " " * len(m[1]), document.text
)
return super().__call__(document, *a, **kw)
def lissp(self, source):
lissp = LISSP.match(source)
if not lissp:
return
assert lissp, "\n" + source
lissp = STRIP_LISSP.sub("", lissp.group())
return lissp
def evaluate(self, example, parser=Lissp()):
lissp = self.lissp(example.document.text[example.start : example.end])
if lissp:
python = example.parsed.source
parser.compiler.env = example.namespace
hissp = parser.reads(lissp)
compiled = parser.compiler.compile(hissp) + "\n"
assert norm_gensym_eq(compiled, python), "".join(
[
" \nGENSYM-NORMALIZED DIFF:\n",
*context_diff(
norm_gensyms(python),
norm_gensyms(compiled),
fromfile="expected in doc",
tofile="actually compiled to",
),
"FULL COMPILATION:\n>>> ",
compiled[:-1].replace("\n", "\n... "),
"\n",
]
)
return super().evaluate(example)
def norm_gensym_eq(compiled, python):
"""The special gensym prefix ``_Qz...__`` will match regardless of hash."""
return re.fullmatch(
re.sub(r"_Qz[a-z2-7]+__", r"_Qz[a-z2-7]+__", re.escape(python)), compiled
)
def norm_gensyms(s):
s = re.sub(r"_Qz[a-z2-7]+__", r"_Qzabcdefgh__", s)
return indent(s, " " * 2).splitlines(True)
class Globs(Container):
def __init__(self, *globs):
self.globs = globs
def __contains__(self, item):
return any(fnmatch(item, glob) for glob in self.globs)
pytest_collect_file = Sybil(
parsers=[ParseLissp(optionflags=ELLIPSIS)],
filenames=Globs("*.md", "*.rst", "*.lissp"),
).pytest()
# RELEASE: Run all tests.