aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/parso/py3/tests/conftest.py
blob: 9e7dec62dfe671a9cdfb6e09a5cc20dc6bdbe733 (plain) (blame)
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import re 
import tempfile 
import shutil 
import logging 
import os 
from pathlib import Path 
 
import pytest 
import yatest.common 
 
import parso 
from parso import cache 
from parso.utils import parse_version_string 
 
collect_ignore = ["setup.py"] 
 
_SUPPORTED_VERSIONS = '3.6', '3.7', '3.8', '3.9', '3.10' 
 
 
@pytest.fixture(scope='session') 
def clean_parso_cache(): 
    """ 
    Set the default cache directory to a temporary directory during tests. 
 
    Note that you can't use built-in `tmpdir` and `monkeypatch` 
    fixture here because their scope is 'function', which is not used 
    in 'session' scope fixture. 
 
    This fixture is activated in ../pytest.ini. 
    """ 
    old = cache._default_cache_path 
    tmp = tempfile.mkdtemp(prefix='parso-test-') 
    cache._default_cache_path = Path(tmp) 
    yield 
    cache._default_cache_path = old 
    shutil.rmtree(tmp) 
 
 
def pytest_addoption(parser): 
    parser.addoption("--logging", "-L", action='store_true', 
                     help="Enables the logging output.") 
 
 
def pytest_generate_tests(metafunc): 
    if 'normalizer_issue_case' in metafunc.fixturenames: 
        base_dir = os.path.join(yatest.common.test_source_path(), 'normalizer_issue_files') 
 
        cases = list(colllect_normalizer_tests(base_dir)) 
        metafunc.parametrize( 
            'normalizer_issue_case', 
            cases, 
            ids=[c.name for c in cases] 
        ) 
    elif 'each_version' in metafunc.fixturenames: 
        metafunc.parametrize('each_version', _SUPPORTED_VERSIONS) 
    elif 'version_ge_py38' in metafunc.fixturenames: 
        ge38 = set(_SUPPORTED_VERSIONS) - {'3.6', '3.7'} 
        metafunc.parametrize('version_ge_py38', sorted(ge38)) 
 
 
class NormalizerIssueCase: 
    """ 
    Static Analysis cases lie in the static_analysis folder. 
    The tests also start with `#!`, like the goto_definition tests. 
    """ 
    def __init__(self, path): 
        self.path = path 
        self.name = os.path.basename(path) 
        match = re.search(r'python([\d.]+)\.py', self.name) 
        self.python_version = match and match.group(1) 
 
 
def colllect_normalizer_tests(base_dir): 
    for f_name in os.listdir(base_dir): 
        if f_name.endswith(".py"): 
            path = os.path.join(base_dir, f_name) 
            yield NormalizerIssueCase(path) 
 
 
def pytest_configure(config): 
    if config.option.logging: 
        root = logging.getLogger() 
        root.setLevel(logging.DEBUG) 
 
        #ch = logging.StreamHandler(sys.stdout) 
        #ch.setLevel(logging.DEBUG) 
        #formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 
        #ch.setFormatter(formatter) 
 
        #root.addHandler(ch) 
 
 
class Checker: 
    def __init__(self, version, is_passing): 
        self.version = version 
        self._is_passing = is_passing 
        self.grammar = parso.load_grammar(version=self.version) 
 
    def parse(self, code): 
        if self._is_passing: 
            return parso.parse(code, version=self.version, error_recovery=False) 
        else: 
            self._invalid_syntax(code) 
 
    def _invalid_syntax(self, code): 
        with pytest.raises(parso.ParserSyntaxError): 
            module = parso.parse(code, version=self.version, error_recovery=False) 
            # For debugging 
            print(module.children) 
 
    def get_error(self, code): 
        errors = list(self.grammar.iter_errors(self.grammar.parse(code))) 
        assert bool(errors) != self._is_passing 
        if errors: 
            return errors[0] 
 
    def get_error_message(self, code): 
        error = self.get_error(code) 
        if error is None: 
            return 
        return error.message 
 
    def assert_no_error_in_passing(self, code): 
        if self._is_passing: 
            module = self.grammar.parse(code) 
            assert not list(self.grammar.iter_errors(module)) 
 
 
@pytest.fixture 
def works_not_in_py(each_version): 
    return Checker(each_version, False) 
 
 
@pytest.fixture 
def works_in_py(each_version): 
    return Checker(each_version, True) 
 
 
@pytest.fixture 
def works_ge_py38(each_version): 
    version_info = parse_version_string(each_version) 
    return Checker(each_version, version_info >= (3, 8)) 
 
 
@pytest.fixture 
def works_ge_py39(each_version): 
    version_info = parse_version_string(each_version) 
    return Checker(each_version, version_info >= (3, 9))