1"""Sanity test for proper python syntax."""
2from __future__ import (absolute_import, division, print_function)
3__metaclass__ = type
4
5import os
6
7from .. import types as t
8
9from ..sanity import (
10    SanityMultipleVersion,
11    SanityMessage,
12    SanityFailure,
13    SanitySuccess,
14    SanityTargets,
15    SANITY_ROOT,
16)
17
18from ..target import (
19    TestTarget,
20)
21
22from ..util import (
23    SubprocessError,
24    display,
25    find_python,
26    parse_to_list_of_dict,
27    is_subdir,
28)
29
30from ..util_common import (
31    run_command,
32)
33
34from ..config import (
35    SanityConfig,
36)
37
38
39class CompileTest(SanityMultipleVersion):
40    """Sanity test for proper python syntax."""
41    def filter_targets(self, targets):  # type: (t.List[TestTarget]) -> t.List[TestTarget]
42        """Return the given list of test targets, filtered to include only those relevant for the test."""
43        return [target for target in targets if os.path.splitext(target.path)[1] == '.py' or is_subdir(target.path, 'bin')]
44
45    def test(self, args, targets, python_version):
46        """
47        :type args: SanityConfig
48        :type targets: SanityTargets
49        :type python_version: str
50        :rtype: TestResult
51        """
52        settings = self.load_processor(args, python_version)
53
54        paths = [target.path for target in targets.include]
55
56        cmd = [find_python(python_version), os.path.join(SANITY_ROOT, 'compile', 'compile.py')]
57
58        data = '\n'.join(paths)
59
60        display.info(data, verbosity=4)
61
62        try:
63            stdout, stderr = run_command(args, cmd, data=data, capture=True)
64            status = 0
65        except SubprocessError as ex:
66            stdout = ex.stdout
67            stderr = ex.stderr
68            status = ex.status
69
70        if stderr:
71            raise SubprocessError(cmd=cmd, status=status, stderr=stderr, stdout=stdout)
72
73        if args.explain:
74            return SanitySuccess(self.name, python_version=python_version)
75
76        pattern = r'^(?P<path>[^:]*):(?P<line>[0-9]+):(?P<column>[0-9]+): (?P<message>.*)$'
77
78        results = parse_to_list_of_dict(pattern, stdout)
79
80        results = [SanityMessage(
81            message=r['message'],
82            path=r['path'].replace('./', ''),
83            line=int(r['line']),
84            column=int(r['column']),
85        ) for r in results]
86
87        results = settings.process_errors(results, paths)
88
89        if results:
90            return SanityFailure(self.name, messages=results, python_version=python_version)
91
92        return SanitySuccess(self.name, python_version=python_version)
93