File: run_verifytypes.py

package info (click to toggle)
python-azure 20230112%2Bgit-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 749,544 kB
  • sloc: python: 6,815,827; javascript: 287; makefile: 195; xml: 109; sh: 105
file content (143 lines) | stat: -rw-r--r-- 4,959 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
#!/usr/bin/env python

# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

# This script is used to execute verifytypes within a tox environment. It additionally installs
# the latest release of a package (if it exists) and compares its type completeness score with
# that of the current code. If type completeness worsens from the last release, the check fails.

import subprocess
import json
import argparse
import os
import logging
import sys

from ci_tools.environment_exclusions import is_ignored_package, VERIFYTYPES_OPT_OUT

logging.getLogger().setLevel(logging.INFO)


def install_editable(setup_path):
    commands = [sys.executable, "-m", "pip", "install", "-e", setup_path]
    subprocess.check_call(commands)


def install_latest_release(package_name):
    from pypi_tools.pypi import PyPIClient

    client = PyPIClient()

    try:
        latest_version = str(client.get_ordered_versions(package_name)[-1])
    except (IndexError, KeyError):
        logging.info(f"No released packages for {package_name} on PyPi yet.")
        latest_version = None

    if latest_version:
        packages = [f"{package_name}=={latest_version}"]
        commands = [
            sys.executable,
            "-m",
            "pip",
            "install",
        ]

        commands.extend(packages)
        subprocess.check_call(commands)
    return latest_version


def get_type_complete_score(commands, check_pytyped=False):
    try:
        response = subprocess.run(
            commands,
            check=True,
            capture_output=True,
        )
    except subprocess.CalledProcessError as e:
        if e.returncode != 1:
            logging.info(
                f"Running verifytypes failed: {e.stderr}. See https://aka.ms/python/typing-guide for information."
            )
            exit(1)

        report = json.loads(e.output)
        if check_pytyped:
            pytyped_present = report["typeCompleteness"].get("pyTypedPath", None)
            if not pytyped_present:
                print(
                    f"No py.typed file was found. See aka.ms/python/typing-guide for information."
                )
                exit(1)
        return report["typeCompleteness"]["completenessScore"]

    # library scores 100%
    report = json.loads(response.stdout)
    return report["typeCompleteness"]["completenessScore"]


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Run pyright verifytypes against target folder. "
    )

    parser.add_argument(
        "-t",
        "--target",
        dest="target_package",
        help="The target package directory on disk. The target module passed to run pyright will be <target_package>/azure.",
        required=True,
    )

    args = parser.parse_args()
    package_name = os.path.basename(os.path.abspath(args.target_package))
    module = package_name.replace("-", ".")
    setup_path = os.path.abspath(args.target_package)

    if package_name in VERIFYTYPES_OPT_OUT or is_ignored_package(package_name):
        logging.info(
            f"{package_name} opts-out of verifytypes check. See https://aka.ms/python/typing-guide for information."
        )
        exit(0)

    commands = [
        sys.executable,
        "-m",
        "pyright",
        "--verifytypes",
        module,
        "--ignoreexternal",
        "--outputjson",
    ]

    # get type completeness score from latest release
    latest_version = install_latest_release(package_name)
    if latest_version:
        score_from_released = get_type_complete_score(commands)
    else:
        score_from_released = None

    # get type completeness score from current code
    install_editable(setup_path)
    score_from_current = get_type_complete_score(commands, check_pytyped=True)

    try:
        subprocess.check_call(commands[:-1])
    except subprocess.CalledProcessError:
        pass  # we don't fail on verifytypes, only if type completeness score worsens from last release

    if score_from_released is not None:
        score_from_released_rounded = round(score_from_released * 100, 1)
        score_from_current_rounded = round(score_from_current * 100, 1)
        print("\n-----Type completeness score comparison-----\n")
        print(f"Previous release ({latest_version}): {score_from_released_rounded}%")
        if score_from_current_rounded < score_from_released_rounded:
            print(
                f"\nERROR: The type completeness score of {package_name} has decreased since the last release. "
                f"See the above output for areas to improve. See https://aka.ms/python/typing-guide for information."
            )
            exit(1)