Skip to content

Commit 1366e0c

Browse files
authored
Python warning + code cleanup (#4981)
* Enable strict type checking + python code cleanup * Only import typing_extensions when type checking * Fix dotnet version regex * Address PR feedback * Revert get_msbuild_property, add pyrightconfig.json * Fix tracer errors
1 parent 36e0ada commit 1366e0c

24 files changed

+483
-371
lines changed

.vscode/settings.json

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
{
22
"files.exclude": {
3-
"**/__pycache__/": true,
4-
"**/BenchmarkDotNet.Artifacts/": true,
5-
"**/.vs/": true,
6-
"**/artifacts/": true,
7-
"**/bin/": true,
8-
"**/logs/": true,
9-
"**/obj/": true,
10-
"**/packages/": true,
11-
"/tools/": true,
3+
"**/__pycache__/**": true,
4+
"**/.vs/**": true,
5+
"**/bin/**": true,
6+
"**/obj/**": true,
7+
"**/packages/**": true,
8+
"**/.venv/**": true,
9+
"**/.dotnet/**": true,
1210
},
13-
"python.analysis.typeCheckingMode": "standard",
14-
"python.analysis.extraPaths": ["scripts"]
11+
"files.readonlyInclude": {
12+
"/eng/common/**": true,
13+
},
14+
"search.exclude": {
15+
"**/artifacts/**": true,
16+
"**/weblarge3.0/**": true,
17+
},
18+
"python.analysis.diagnosticMode": "workspace"
1519
}

pyrightconfig.json

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
{
2+
"typeCheckingMode": "strict",
3+
"include": ["src/scenarios", "scripts"],
4+
"exclude": [
5+
"**/__pycache__/**",
6+
"**/artifacts/**",
7+
"**/.venv/**",
8+
"**/eng/common/**",
9+
"**/weblarge3.0/**"
10+
],
11+
"pythonVersion": "3.9",
12+
"pythonPlatform": "All",
13+
"deprecateTypingAliases": true,
14+
"reportMissingTypeStubs": "none",
15+
"reportImplicitOverride": "error",
16+
"reportImportCycles": "error",
17+
"reportPropertyTypeMismatch": "error",
18+
"reportUnnecessaryTypeIgnoreComment": "error",
19+
"reportUnreachable": "information",
20+
// Ensure that src/scenarios and scripts are on the path by default for all execution environments
21+
"extraPaths": ["./src/scenarios", "./scripts"],
22+
"executionEnvironments": [
23+
// scripts/tests run relative to the root of the repository
24+
{
25+
"root": "./scripts/tests",
26+
"extraPaths": [ "." ]
27+
},
28+
// Set extra paths to empty as we don't want to accidentally reference src/scenarios from here
29+
{
30+
"root": "./scripts",
31+
"extraPaths": [ ]
32+
},
33+
// All of our scenarios are run by executing python files pre.py, test.py, and post.py from their own directory
34+
// This means we need to mark each scenario folder as a separate execution environment so that pyright is able
35+
// to properly resolve relative imports inside each scenario folder.
36+
{ "root": "./src/scenarios/aspwebtemplate" },
37+
{ "root": "./src/scenarios/bdnandroid" },
38+
{ "root": "./src/scenarios/blazor" },
39+
{ "root": "./src/scenarios/blazoraot" },
40+
{ "root": "./src/scenarios/blazorlocalized" },
41+
{ "root": "./src/scenarios/blazorminapp" },
42+
{ "root": "./src/scenarios/blazorminappaot" },
43+
{ "root": "./src/scenarios/blazorpizza" },
44+
{ "root": "./src/scenarios/blazorpizzaaot" },
45+
{ "root": "./src/scenarios/blazorserverinnerloop" },
46+
{ "root": "./src/scenarios/blazorservertemplate" },
47+
{ "root": "./src/scenarios/blazorwasmdotnetwatch" },
48+
{ "root": "./src/scenarios/blazorwasminnerloop" },
49+
{ "root": "./src/scenarios/classlibtemplate" },
50+
{ "root": "./src/scenarios/crossgen" },
51+
{ "root": "./src/scenarios/crossgen2" },
52+
{ "root": "./src/scenarios/emptyconsolenativeaot" },
53+
{ "root": "./src/scenarios/emptyconsoletemplate" },
54+
{ "root": "./src/scenarios/emptyconsoletemplateinnerloop" },
55+
{ "root": "./src/scenarios/emptyconsoletemplateinnerloopmsbuild" },
56+
{ "root": "./src/scenarios/emptyfsconsoletemplate" },
57+
{ "root": "./src/scenarios/emptyvbconsoletemplate" },
58+
{ "root": "./src/scenarios/fsharpcompilerservice" },
59+
{ "root": "./src/scenarios/genericandroidstartup" },
60+
{ "root": "./src/scenarios/grpctemplate" },
61+
{ "root": "./src/scenarios/helloandroid" },
62+
{ "root": "./src/scenarios/helloios" },
63+
{ "root": "./src/scenarios/mauiandroid" },
64+
{ "root": "./src/scenarios/mauiblazorandroid" },
65+
{ "root": "./src/scenarios/mauiblazordesktop" },
66+
{ "root": "./src/scenarios/mauiblazorios" },
67+
{ "root": "./src/scenarios/mauidesktop" },
68+
{ "root": "./src/scenarios/mauiios" },
69+
{ "root": "./src/scenarios/mauimaccatalyst" },
70+
{ "root": "./src/scenarios/mauisamplecontentandroid" },
71+
{ "root": "./src/scenarios/mstesttemplate" },
72+
{ "root": "./src/scenarios/mvcapptemplate" },
73+
{ "root": "./src/scenarios/mvcdotnetwatch" },
74+
{ "root": "./src/scenarios/mvcinnerloop" },
75+
{ "root": "./src/scenarios/netandroid" },
76+
{ "root": "./src/scenarios/netios" },
77+
{ "root": "./src/scenarios/netstandard2.0" },
78+
{ "root": "./src/scenarios/nunittesttemplate" },
79+
{ "root": "./src/scenarios/paintdotnet" },
80+
{ "root": "./src/scenarios/razorclasslibtemplate" },
81+
{ "root": "./src/scenarios/staticconsoletemplate" },
82+
{ "root": "./src/scenarios/staticfsconsoletemplate" },
83+
{ "root": "./src/scenarios/staticvbconsoletemplate" },
84+
{ "root": "./src/scenarios/staticwinformstemplate" },
85+
{ "root": "./src/scenarios/webapitemplate" },
86+
{ "root": "./src/scenarios/webapptemplate" },
87+
{ "root": "./src/scenarios/weblarge3.0" },
88+
{ "root": "./src/scenarios/windowsforms" },
89+
{ "root": "./src/scenarios/windowsformslarge" },
90+
{ "root": "./src/scenarios/wpf" },
91+
{ "root": "./src/scenarios/wpfsfc" },
92+
{ "root": "./src/scenarios/xunittesttemplate" }
93+
]
94+
}

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
azure.storage.blob==12.13.0
22
azure.storage.queue==12.4.0
33
azure.identity==1.16.1
4-
dataclasses==0.8
54
gitpython<=3.1.41
65
urllib3==1.26.19
76
opentelemetry-api==1.23.0

scripts/benchmarks_ci.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,13 @@
2121
'''
2222

2323
from argparse import ArgumentParser, ArgumentTypeError
24-
from datetime import datetime
2524
import json
2625
from logging import getLogger
2726

2827
import os
2928
import shutil
3029
import sys
31-
from typing import Any, List, Optional
30+
from typing import Any, Optional
3231

3332
from performance.common import get_repo_root_path, validate_supported_runtime, get_artifacts_directory, helixuploadroot
3433
from performance.logger import setup_loggers
@@ -44,11 +43,11 @@
4443
setup_tracing()
4544
tracer = get_tracer()
4645

47-
@tracer.start_as_current_span(name="benchmarks_ci_init_tools") # type: ignore
46+
@tracer.start_as_current_span(name="benchmarks_ci_init_tools")
4847
def init_tools(
4948
architecture: str,
50-
dotnet_versions: List[str],
51-
target_framework_monikers: List[str],
49+
dotnet_versions: list[str],
50+
target_framework_monikers: list[str],
5251
verbose: bool,
5352
azure_feed_url: Optional[str] = None,
5453
internal_build_key: Optional[str] = None) -> None:
@@ -78,9 +77,6 @@ def init_tools(
7877
def add_arguments(parser: ArgumentParser) -> ArgumentParser:
7978
'''Adds new arguments to the specified ArgumentParser object.'''
8079

81-
if not isinstance(parser, ArgumentParser):
82-
raise TypeError('Invalid parser.')
83-
8480
# Download DotNet Cli
8581
dotnet.add_arguments(parser)
8682

@@ -199,7 +195,7 @@ def __is_valid_dotnet_path(dp: str) -> str:
199195
return parser
200196

201197

202-
def __process_arguments(args: List[str]):
198+
def __process_arguments(args: list[str]):
203199
parser = ArgumentParser(
204200
description='Tool to run .NET micro benchmarks',
205201
allow_abbrev=False,
@@ -209,8 +205,8 @@ def __process_arguments(args: List[str]):
209205
add_arguments(parser)
210206
return parser.parse_args(args)
211207

212-
@tracer.start_as_current_span("benchmarks_ci_main") # type: ignore
213-
def main(argv: List[str]):
208+
@tracer.start_as_current_span("benchmarks_ci_main")
209+
def main(argv: list[str]):
214210
validate_supported_runtime()
215211
args = __process_arguments(argv)
216212
verbose = not args.quiet
@@ -223,9 +219,7 @@ def main(argv: List[str]):
223219
if not args.frameworks:
224220
raise Exception("Framework version (-f) must be specified.")
225221

226-
target_framework_monikers = dotnet \
227-
.FrameworkAction \
228-
.get_target_framework_monikers(args.frameworks)
222+
target_framework_monikers = dotnet.get_target_framework_monikers(args.frameworks)
229223
# Acquire necessary tools (dotnet)
230224
if not args.dotnet_path:
231225
init_tools(
@@ -303,7 +297,7 @@ def main(argv: List[str]):
303297
# Create a combined JSON file that contains all the reports
304298
combined_file_prefix = "" if args.partition is None else f"Partition{args.partition}-"
305299
with open(os.path.join(helix_upload_root, f"{combined_file_prefix}combined-perf-lab-report.json"), "w", encoding="utf8") as all_reports_file:
306-
all_reports: List[Any] = []
300+
all_reports: list[Any] = []
307301
for file in glob(reports_globpath, recursive=True):
308302
with open(file, 'r', encoding="utf8") as report_file:
309303
try:

scripts/benchmarks_local.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import platform
44
import shutil
55
import sys
6-
from typing import List, Optional
6+
from typing import Optional
77
import xml.etree.ElementTree as xmlTree
88
from argparse import ArgumentParser, ArgumentTypeError, Namespace
99
from datetime import datetime
@@ -53,7 +53,7 @@ def is_running_as_admin(parsed_args: Namespace) -> bool:
5353
if is_windows(parsed_args):
5454
import ctypes
5555
return ctypes.windll.shell32.IsUserAnAdmin()
56-
return os.getuid() == 0 # type: ignore We know that os.getuid() is a method on Unix-like systems, ignore the pylance unknown type error for getuid.
56+
return os.getuid() == 0
5757

5858
def kill_dotnet_processes(parsed_args: Namespace):
5959
if not parsed_args.kill_dotnet_processes:
@@ -72,10 +72,10 @@ def enum_name_to_enum(enum_type: EnumMeta, enum_name: str):
7272
except KeyError as exc:
7373
raise ArgumentTypeError(f"Invalid run type name {enum_name}.") from exc
7474

75-
def enum_name_list_to_enum_list(enum_type: EnumMeta, enum_name_list: List[str]):
75+
def enum_name_list_to_enum_list(enum_type: EnumMeta, enum_name_list: list[str]):
7676
return [enum_name_to_enum(enum_type, enum_name) for enum_name in enum_name_list]
7777

78-
def check_for_runtype_specified(parsed_args: Namespace, run_types_to_check: List[RunType]) -> bool:
78+
def check_for_runtype_specified(parsed_args: Namespace, run_types_to_check: list[RunType]) -> bool:
7979
for run_type in run_types_to_check:
8080
if run_type.name in parsed_args.run_type_names:
8181
return True
@@ -93,7 +93,7 @@ def copy_directory_contents(src_dir: str, dest_dir: str):
9393
shutil.copy2(os.path.join(src_dirpath, src_filename), dest_dirpath)
9494

9595
# Builds libs and corerun by default
96-
def build_runtime_dependency(parsed_args: Namespace, repo_path: str, subset: str = "clr+libs", configuration: str = "Release", os_override = "", arch_override = "", additional_args: Optional[List[str]] = None):
96+
def build_runtime_dependency(parsed_args: Namespace, repo_path: str, subset: str = "clr+libs", configuration: str = "Release", os_override: str = "", arch_override: str = "", additional_args: Optional[list[str]] = None):
9797
if additional_args is None:
9898
additional_args = []
9999

@@ -117,13 +117,13 @@ def build_runtime_dependency(parsed_args: Namespace, repo_path: str, subset: str
117117
] + additional_args
118118
RunCommand(build_libs_and_corerun_command, verbose=True).run(os.path.join(repo_path, "eng"))
119119

120-
def run_runtime_dotnet(repo_path: str, args: Optional[List[str]] = None):
120+
def run_runtime_dotnet(repo_path: str, args: Optional[list[str]] = None):
121121
if args is None:
122122
args = []
123123
dotnet_command = ["./dotnet.sh"] + args
124124
RunCommand(dotnet_command, verbose=True).run(repo_path)
125125

126-
def generate_layout(parsed_args: Namespace, repo_path: str, additional_args: Optional[List[str]] = None):
126+
def generate_layout(parsed_args: Namespace, repo_path: str, additional_args: Optional[list[str]] = None):
127127
if additional_args is None:
128128
additional_args = []
129129

@@ -264,10 +264,10 @@ def generate_all_runtype_dependencies(parsed_args: Namespace, repo_path: str, co
264264

265265
getLogger().info("Finished generating dependencies for %s run types in %s and stored in %s.", ' '.join(map(str, parsed_args.run_type_names)), repo_path, parsed_args.artifact_storage_path)
266266

267-
def generate_combined_benchmark_ci_args(parsed_args: Namespace, specific_run_type: RunType, all_commits: List[str]) -> List[str]:
267+
def generate_combined_benchmark_ci_args(parsed_args: Namespace, specific_run_type: RunType, all_commits: list[str]) -> list[str]:
268268
getLogger().info("Generating benchmark_ci.py arguments for %s run type using artifacts in %s.", specific_run_type.name, parsed_args.artifact_storage_path)
269269
bdn_args_unescaped: list[str] = []
270-
benchmark_ci_args = [
270+
benchmark_ci_args: list[str] = [
271271
'--architecture', parsed_args.architecture,
272272
'--frameworks', parsed_args.framework,
273273
'--dotnet-path', parsed_args.dotnet_dir_path,
@@ -330,10 +330,10 @@ def generate_combined_benchmark_ci_args(parsed_args: Namespace, specific_run_typ
330330
getLogger().info("Finished generating benchmark_ci.py arguments for %s run type using artifacts in %s.", specific_run_type.name, parsed_args.artifact_storage_path)
331331
return benchmark_ci_args
332332

333-
def generate_single_benchmark_ci_args(parsed_args: Namespace, specific_run_type: RunType, commit: str) -> List[str]:
333+
def generate_single_benchmark_ci_args(parsed_args: Namespace, specific_run_type: RunType, commit: str) -> list[str]:
334334
getLogger().info("Generating benchmark_ci.py arguments for %s run type using artifacts in %s.", specific_run_type.name, parsed_args.artifact_storage_path)
335335
bdn_args_unescaped: list[str] = []
336-
benchmark_ci_args = [
336+
benchmark_ci_args: list[str] = [
337337
'--architecture', parsed_args.architecture,
338338
'--frameworks', parsed_args.framework,
339339
'--csproj', parsed_args.csproj,
@@ -445,7 +445,7 @@ def generate_artifacts_for_commit(parsed_args: Namespace, repo_url: str, repo_di
445445
getLogger().info("Running for %s at %s.", repo_path, commit)
446446

447447
if not os.path.exists(repo_path):
448-
repo = Repo.clone_from(repo_url, repo_path) # type: ignore 'Type of "clone_from" is partially unknown', we know it is a method and returns a Repo
448+
repo = Repo.clone_from(repo_url, repo_path)
449449
repo.git.checkout(commit, '-f')
450450
repo.git.show('HEAD')
451451
else:
@@ -458,7 +458,7 @@ def generate_artifacts_for_commit(parsed_args: Namespace, repo_url: str, repo_di
458458
generate_all_runtype_dependencies(parsed_args, repo_path, commit, (is_local and not parsed_args.skip_local_rebuild) or parsed_args.rebuild_artifacts)
459459

460460
# Run tests on the local machine
461-
def run_benchmarks(parsed_args: Namespace, commits: List[str]) -> None:
461+
def run_benchmarks(parsed_args: Namespace, commits: list[str]) -> None:
462462
# Generate the correct benchmarks_ci.py arguments for the run type
463463
for run_type_meta in enum_name_list_to_enum_list(RunType, parsed_args.run_type_names):
464464
# Run the benchmarks_ci.py test and save results
@@ -505,7 +505,7 @@ def check_references_exist_and_add_branch_commits(repo_url: str, references: lis
505505
repo_combined_path = os.path.join(repo_storage_path, repo_dir)
506506
if not os.path.exists(repo_combined_path):
507507
getLogger().debug("Cloning %s to %s.", repo_url, repo_combined_path)
508-
repo = Repo.clone_from(repo_url, repo_combined_path) # type: ignore 'Type of "clone_from" is partially unknown', we know it is a method and returns a Repo
508+
repo = Repo.clone_from(repo_url, repo_combined_path)
509509
else:
510510
repo = Repo(repo_combined_path)
511511
repo.remotes.origin.fetch()
@@ -564,11 +564,12 @@ def get_default_os():
564564
else:
565565
raise NotImplementedError(f"Unsupported operating system: {system}.")
566566

567-
def __main(args: List[str]):
567+
def __main(args: list[str]):
568568
# Define the ArgumentParser
569569
parser = ArgumentParser(description='Run local benchmarks for the Performance repo.', conflict_handler='resolve')
570570
add_arguments(parser)
571571
parsed_args = parser.parse_args(args)
572+
assert isinstance(parsed_args.artifact_storage_path, str)
572573
parsed_args.dotnet_dir_path = os.path.join(parsed_args.artifact_storage_path, "dotnet")
573574

574575
setup_loggers(verbose=parsed_args.verbose)
@@ -587,9 +588,9 @@ def __main(args: List[str]):
587588

588589
# If list cached builds is specified, list the cached builds and exit
589590
if parsed_args.list_cached_builds:
590-
for folder in os.listdir(parsed_args.artifact_storage_path): # type: ignore warning about folder type being unknown, we know it is a string
591+
for folder in os.listdir(parsed_args.artifact_storage_path):
591592
if any(run_type.name in folder for run_type in RunType):
592-
getLogger().info(folder) # type: ignore We know folder is a string
593+
getLogger().info(folder)
593594
return
594595

595596
# Check to make sure we have something specified to test

scripts/benchmarks_monthly.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
monthly manual performance runs.
77
'''
88

9-
from typing import Dict, List
109
from performance.common import get_machine_architecture
1110
from performance.logger import setup_loggers
1211
from argparse import ArgumentParser
@@ -36,7 +35,7 @@
3635
'net6.0': { 'tfm': 'net6.0' }
3736
}
3837

39-
def get_version_from_name(name: str) -> Dict[str, str]:
38+
def get_version_from_name(name: str) -> dict[str, str]:
4039
if name in VERSIONS:
4140
return VERSIONS[name]
4241

@@ -45,9 +44,6 @@ def get_version_from_name(name: str) -> Dict[str, str]:
4544
def add_arguments(parser: ArgumentParser) -> ArgumentParser:
4645
# Adds new arguments to the specified ArgumentParser object.
4746

48-
if not isinstance(parser, ArgumentParser):
49-
raise TypeError('Invalid parser.')
50-
5147
parser.add_argument(
5248
'versions',
5349
nargs='+',
@@ -114,7 +110,7 @@ def add_arguments(parser: ArgumentParser) -> ArgumentParser:
114110

115111
return parser
116112

117-
def __process_arguments(args: List[str]):
113+
def __process_arguments(args: list[str]):
118114
parser = ArgumentParser(
119115
description='Tool to execute the monthly manual micro benchmark performance runs',
120116
allow_abbrev=False
@@ -123,7 +119,7 @@ def __process_arguments(args: List[str]):
123119
add_arguments(parser)
124120
return parser.parse_args(args)
125121

126-
def __main(argv: List[str]):
122+
def __main(argv: list[str]):
127123
setup_loggers(verbose=True)
128124

129125
args = __process_arguments(argv)

0 commit comments

Comments
 (0)