Skip to content

Commit dd988fa

Browse files
JennyPngscbeddCopilot
authored
Use New VerifyTypes and Pyright Checks in CI (#43774)
* cut * debug * huh * double check pip freeze * revert cwd...doesn't seem to change anything * log * pass executable in freeze * clean and run_venv_command fix * clean * add stdout prints and use venv abstraction in pyright * add stdout prints and use venv abstraction in pyright * format * log stdout * add the additional version that should match the requirement that uv and pip is unable to honor * Update eng/tools/azure-sdk-tools/azpysdk/verifytypes.py Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Scott Beddall <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent 59f4deb commit dd988fa

File tree

3 files changed

+105
-80
lines changed

3 files changed

+105
-80
lines changed

eng/pipelines/templates/steps/run_pyright.yml

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,31 @@ steps:
1111
- task: PythonScript@0
1212
displayName: 'Run Pyright'
1313
inputs:
14-
scriptPath: 'scripts/devops_tasks/dispatch_tox.py'
14+
scriptPath: 'eng/scripts/dispatch_checks.py'
1515
arguments: >-
1616
"$(TargetingString)"
17-
--mark_arg="${{ parameters.TestMarkArgument }}"
1817
--service="${{ parameters.ServiceDirectory }}"
19-
--toxenv="pyright"
18+
--check="pyright"
2019
--disable-compatibility-filter
21-
--disablecov
2220
${{ parameters.AdditionalTestArgs }}
21+
env:
22+
TOX_PIP_IMPL: "uv"
23+
VIRTUAL_ENV: ""
24+
PYTHONHOME: ""
2325
condition: and(succeededOrFailed(), ne(variables['Skip.Pyright'],'true'))
2426

2527
- task: PythonScript@0
2628
displayName: 'Run verifytypes'
2729
inputs:
28-
scriptPath: 'scripts/devops_tasks/dispatch_tox.py'
30+
scriptPath: 'eng/scripts/dispatch_checks.py'
2931
arguments: >-
3032
"$(TargetingString)"
31-
--mark_arg="${{ parameters.TestMarkArgument }}"
3233
--service="${{ parameters.ServiceDirectory }}"
33-
--toxenv="verifytypes"
34+
--check="verifytypes"
3435
--disable-compatibility-filter
35-
--disablecov
3636
${{ parameters.AdditionalTestArgs }}
37+
env:
38+
TOX_PIP_IMPL: "uv"
39+
VIRTUAL_ENV: ""
40+
PYTHONHOME: ""
3741
condition: and(succeededOrFailed(), ne(variables['Skip.Verifytypes'],'true'))

eng/tools/azure-sdk-tools/azpysdk/pyright.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,11 @@ def run(self, args: argparse.Namespace) -> int:
134134
commands.extend(paths)
135135

136136
try:
137-
check_call(commands)
137+
self.run_venv_command(executable, commands[1:], package_dir, check=True)
138+
logger.info(f"Pyright check passed for {package_name}.")
138139
except CalledProcessError as error:
140+
logger.error("Pyright reported issues:")
141+
logger.error(error.stdout)
139142
if (
140143
args.next
141144
and in_ci()

eng/tools/azure-sdk-tools/azpysdk/verifytypes.py

Lines changed: 89 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212

1313
from .Check import Check
1414
from ci_tools.functions import install_into_venv
15-
from ci_tools.variables import discover_repo_root, in_ci, set_envvar_defaults, set_envvar_defaults
15+
from ci_tools.scenario.generation import create_package_and_install
16+
from ci_tools.variables import discover_repo_root, in_ci, set_envvar_defaults
1617
from ci_tools.environment_exclusions import is_check_enabled, is_typing_ignored
1718
from ci_tools.functions import get_pip_command
1819
from ci_tools.logging import logger
@@ -21,70 +22,6 @@
2122
REPO_ROOT = discover_repo_root()
2223

2324

24-
def install_from_main(setup_path: str) -> int:
25-
path = pathlib.Path(setup_path)
26-
subdirectory = path.relative_to(REPO_ROOT)
27-
cwd = os.getcwd()
28-
with tempfile.TemporaryDirectory() as temp_dir_name:
29-
os.chdir(temp_dir_name)
30-
try:
31-
subprocess.check_call(["git", "init"], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
32-
subprocess.check_call(
33-
["git", "clone", "--no-checkout", "https://github.com/Azure/azure-sdk-for-python.git", "--depth", "1"],
34-
stdout=subprocess.DEVNULL,
35-
stderr=subprocess.STDOUT,
36-
)
37-
os.chdir("azure-sdk-for-python")
38-
subprocess.check_call(
39-
["git", "sparse-checkout", "init", "--cone"], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
40-
)
41-
subprocess.check_call(
42-
["git", "sparse-checkout", "set", subdirectory], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
43-
)
44-
subprocess.check_call(["git", "checkout", "main"], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
45-
46-
if not os.path.exists(os.path.join(os.getcwd(), subdirectory)):
47-
# code is not checked into main yet, nothing to compare
48-
logger.info(f"{subdirectory} is not checked into main, nothing to compare.")
49-
return 1
50-
51-
os.chdir(subdirectory)
52-
53-
command = get_pip_command() + ["install", ".", "--force-reinstall"]
54-
55-
subprocess.check_call(command, stdout=subprocess.DEVNULL)
56-
finally:
57-
os.chdir(cwd) # allow temp dir to be deleted
58-
return 0
59-
60-
61-
def get_type_complete_score(commands: typing.List[str], check_pytyped: bool = False) -> float:
62-
try:
63-
response = subprocess.run(
64-
commands,
65-
check=True,
66-
capture_output=True,
67-
)
68-
except subprocess.CalledProcessError as e:
69-
if e.returncode != 1:
70-
logger.error(
71-
f"Running verifytypes failed: {e.stderr}. See https://aka.ms/python/typing-guide for information."
72-
)
73-
return -1.0
74-
75-
report = json.loads(e.output)
76-
if check_pytyped:
77-
pytyped_present = report["typeCompleteness"].get("pyTypedPath", None)
78-
if not pytyped_present:
79-
logger.error(f"No py.typed file was found. See https://aka.ms/python/typing-guide for information.")
80-
return -1.0
81-
return report["typeCompleteness"]["completenessScore"]
82-
83-
# library scores 100%
84-
report = json.loads(response.stdout)
85-
return report["typeCompleteness"]["completenessScore"]
86-
87-
8825
class verifytypes(Check):
8926
def __init__(self) -> None:
9027
super().__init__()
@@ -124,6 +61,18 @@ def run(self, args: argparse.Namespace) -> int:
12461
logger.error(f"Failed to install pyright: {e}")
12562
return e.returncode
12663

64+
create_package_and_install(
65+
distribution_directory=staging_directory,
66+
target_setup=package_dir,
67+
skip_install=False,
68+
cache_dir=None,
69+
work_dir=staging_directory,
70+
force_create=False,
71+
package_type="sdist",
72+
pre_download_disabled=False,
73+
python_executable=executable,
74+
)
75+
12776
if in_ci():
12877
if not is_check_enabled(package_dir, "verifytypes") or is_typing_ignored(package_name):
12978
logger.info(
@@ -142,25 +91,27 @@ def run(self, args: argparse.Namespace) -> int:
14291
]
14392

14493
# get type completeness score from current code
145-
score_from_current = get_type_complete_score(commands, check_pytyped=True)
94+
score_from_current = self.get_type_complete_score(executable, commands, package_dir, check_pytyped=True)
14695
if score_from_current == -1.0:
14796
results.append(1)
14897
continue
14998

99+
# show output
150100
try:
151-
subprocess.check_call(commands[:-1])
152-
except subprocess.CalledProcessError:
101+
response = self.run_venv_command(executable, commands[1:-1], package_dir, check=True)
102+
logger.info(response.stdout)
103+
except subprocess.CalledProcessError as e:
153104
logger.warning(
154-
"verifytypes reported issues."
105+
f"verifytypes reported issues: {e.stdout}"
155106
) # we don't fail on verifytypes, only if type completeness score worsens from main
156107

157108
if in_ci():
158109
# get type completeness score from main
159110
logger.info("Getting the type completeness score from the code in main...")
160-
if install_from_main(os.path.abspath(package_dir)) > 0:
111+
if self.install_from_main(os.path.abspath(package_dir), executable) > 0:
161112
continue
162113

163-
score_from_main = get_type_complete_score(commands)
114+
score_from_main = self.get_type_complete_score(executable, commands, package_dir)
164115
if score_from_main == -1.0:
165116
results.append(1)
166117
continue
@@ -177,3 +128,70 @@ def run(self, args: argparse.Namespace) -> int:
177128
)
178129
results.append(1)
179130
return max(results) if results else 0
131+
132+
def install_from_main(self, setup_path: str, python_executable: Optional[str] = None) -> int:
133+
path = pathlib.Path(setup_path)
134+
135+
subdirectory = path.relative_to(REPO_ROOT)
136+
cwd = os.getcwd()
137+
with tempfile.TemporaryDirectory() as temp_dir_name:
138+
os.chdir(temp_dir_name)
139+
try:
140+
subprocess.check_call(["git", "init"], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
141+
subprocess.check_call(
142+
[
143+
"git",
144+
"clone",
145+
"--no-checkout",
146+
"https://github.com/Azure/azure-sdk-for-python.git",
147+
"--depth",
148+
"1",
149+
],
150+
stdout=subprocess.DEVNULL,
151+
stderr=subprocess.STDOUT,
152+
)
153+
os.chdir("azure-sdk-for-python")
154+
subprocess.check_call(
155+
["git", "sparse-checkout", "init", "--cone"], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
156+
)
157+
subprocess.check_call(
158+
["git", "sparse-checkout", "set", subdirectory], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
159+
)
160+
subprocess.check_call(["git", "checkout", "main"], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
161+
162+
if not os.path.exists(os.path.join(os.getcwd(), subdirectory)):
163+
# code is not checked into main yet, nothing to compare
164+
logger.info(f"{subdirectory} is not checked into main, nothing to compare.")
165+
return 1
166+
167+
os.chdir(subdirectory)
168+
169+
command = get_pip_command(python_executable) + ["install", ".", "--force-reinstall"]
170+
171+
subprocess.check_call(command, stdout=subprocess.DEVNULL)
172+
finally:
173+
os.chdir(cwd) # allow temp dir to be deleted
174+
return 0
175+
176+
def get_type_complete_score(
177+
self, executable, commands: typing.List[str], cwd: str, check_pytyped: bool = False
178+
) -> float:
179+
try:
180+
response = self.run_venv_command(executable, commands[1:], cwd, check=True)
181+
except subprocess.CalledProcessError as e:
182+
if e.returncode != 1:
183+
logger.error(
184+
f"Running verifytypes failed: {e.stderr}. See https://aka.ms/python/typing-guide for information."
185+
)
186+
return -1.0
187+
report = json.loads(e.output)
188+
if check_pytyped:
189+
pytyped_present = report["typeCompleteness"].get("pyTypedPath", None)
190+
if not pytyped_present:
191+
logger.error(f"No py.typed file was found. See https://aka.ms/python/typing-guide for information.")
192+
return -1.0
193+
return report["typeCompleteness"]["completenessScore"]
194+
195+
# library scores 100%
196+
report = json.loads(response.stdout)
197+
return report["typeCompleteness"]["completenessScore"]

0 commit comments

Comments
 (0)