File: pyright.py

package info (click to toggle)
python-azure 20251014%2Bgit-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 766,472 kB
  • sloc: python: 6,314,744; ansic: 804; javascript: 287; makefile: 198; sh: 198; xml: 109
file content (157 lines) | stat: -rw-r--r-- 5,903 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
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
149
150
151
152
153
154
155
156
157
import argparse
import json
import os
import sys

from typing import Optional, List
from subprocess import CalledProcessError, check_call

from .Check import Check
from ci_tools.functions import install_into_venv
from ci_tools.variables import in_ci, set_envvar_defaults
from ci_tools.variables import discover_repo_root
from ci_tools.environment_exclusions import is_check_enabled, is_typing_ignored
from ci_tools.scenario.generation import create_package_and_install

from ci_tools.logging import logger

PYRIGHT_VERSION = "1.1.391"
REPO_ROOT = discover_repo_root()


def get_pyright_config_path(package_dir: str, staging_dir: str) -> str:
    if os.path.exists(os.path.join(package_dir, "pyrightconfig.json")):
        config_path = os.path.join(package_dir, "pyrightconfig.json")
    else:
        config_path = os.path.join(REPO_ROOT, "pyrightconfig.json")

    # read the config and adjust relative paths
    with open(config_path, "r") as f:
        config_text = f.read()
        config_text = config_text.replace('"**', '"../../../../**')
        config = json.loads(config_text)

    # add or update the execution environment
    if config.get("executionEnvironments"):
        config["executionEnvironments"].append({"root": package_dir})
    else:
        config.update({"executionEnvironments": [{"root": package_dir}]})

    pyright_config_path = os.path.join(staging_dir, "pyrightconfig.json")

    with open(pyright_config_path, "w+") as f:
        f.write(json.dumps(config, indent=4))
    return pyright_config_path


class pyright(Check):
    def __init__(self) -> None:
        super().__init__()

    def register(
        self, subparsers: "argparse._SubParsersAction", parent_parsers: Optional[List[argparse.ArgumentParser]] = None
    ) -> None:
        """Register the pyright check. The pyright check installs pyright and runs pyright against the target package."""
        parents = parent_parsers or []
        p = subparsers.add_parser("pyright", parents=parents, help="Run the pyright check")
        p.set_defaults(func=self.run)

        p.add_argument(
            "--next",
            default=False,
            help="Next version of pyright is being tested.",
            required=False,
        )

    def run(self, args: argparse.Namespace) -> int:
        """Run the pyright check command."""
        logger.info("Running pyright check...")

        set_envvar_defaults()
        targeted = self.get_targeted_directories(args)

        results: List[int] = []

        for parsed in targeted:
            package_dir = parsed.folder
            package_name = parsed.name

            executable, staging_directory = self.get_executable(args.isolate, args.command, sys.executable, package_dir)
            logger.info(f"Processing {package_name} for pyright check")

            try:
                if args.next:
                    # use latest version of pyright
                    install_into_venv(executable, ["pyright"], package_dir)
                else:
                    install_into_venv(executable, [f"pyright=={PYRIGHT_VERSION}"], package_dir)
            except CalledProcessError as e:
                logger.error("Failed to install pyright:", e)
                return e.returncode

            create_package_and_install(
                distribution_directory=staging_directory,
                target_setup=package_dir,
                skip_install=False,
                cache_dir=None,
                work_dir=staging_directory,
                force_create=False,
                package_type="sdist",
                pre_download_disabled=False,
                python_executable=executable,
            )

            self.install_dev_reqs(executable, args, package_dir)

            top_level_module = parsed.namespace.split(".")[0]
            paths = [
                os.path.join(package_dir, top_level_module),
            ]

            if not args.next and in_ci() and not is_check_enabled(package_dir, "pyright"):
                logger.info(
                    f"Package {package_name} opts-out of pyright check. See https://aka.ms/python/typing-guide for information."
                )
                continue
            else:
                # check if samples dir exists, if not, skip sample code check
                samples = os.path.exists(os.path.join(package_dir, "samples"))
                generated_samples = os.path.exists(os.path.join(package_dir, "generated_samples"))
                if not samples and not generated_samples:
                    logger.info(f"Package {package_name} does not have a samples directory.")
                else:
                    paths.append(os.path.join(package_dir, "samples" if samples else "generated_samples"))

            config_path = get_pyright_config_path(package_dir, staging_directory)

            commands = [
                executable,
                "-m",
                "pyright",
                "--project",
                config_path,
            ]
            commands.extend(paths)

            try:
                check_call(commands)
            except CalledProcessError as error:
                if (
                    args.next
                    and in_ci()
                    and is_check_enabled(args.target_package, "pyright")
                    and not is_typing_ignored(package_name)
                ):
                    from gh_tools.vnext_issue_creator import create_vnext_issue

                    create_vnext_issue(package_dir, "pyright")

                print("See https://aka.ms/python/typing-guide for information.\n\n")
                results.append(1)

            if args.next and in_ci() and not is_typing_ignored(package_name):
                from gh_tools.vnext_issue_creator import close_vnext_issue

                close_vnext_issue(package_name, "pyright")

        return max(results) if results else 0