From 1593e6aa5b18e46c09842aebd1d11d0b2aeeb55e Mon Sep 17 00:00:00 2001 From: tqchen Date: Thu, 26 Feb 2026 13:00:18 +0000 Subject: [PATCH 1/7] [REFACTOR][PYTHON] Modernize annotations with ruff UP rules This PR enables ruff pyupgrade (UP) rules with py310 target, auto-fixing ~5600 annotation modernizations (PEP 585 generics, PEP 604 unions, deprecated typing imports). Also removes from __future__ import annotations from ir/module.py and rmsnorm.py, bumps requires-python to >=3.10, and removes absolute_import aliases from topi/contrib files. --- ci/jenkins/generate.py | 5 +- ci/scripts/github/github_cc_reviewers.py | 3 +- ci/scripts/github/github_commenter.py | 12 +- ci/scripts/github/github_docs_comment.py | 6 +- .../github/github_skipped_tests_comment.py | 10 +- ci/scripts/github/github_tag_teams.py | 16 +- ci/scripts/github/github_tvmbot.py | 37 +-- ci/scripts/github/ping_reviewers.py | 5 +- ci/scripts/github/update_branch.py | 6 +- ci/scripts/jenkins/check_pr.py | 5 +- ci/scripts/jenkins/cmd_utils.py | 3 +- ci/scripts/jenkins/determine_docker_images.py | 4 +- ci/scripts/jenkins/git_skip_ci_globs.py | 3 +- ci/scripts/jenkins/git_utils.py | 22 +- ci/scripts/jenkins/http_utils.py | 4 +- ci/scripts/jenkins/open_docker_update_pr.py | 13 +- ci/scripts/jenkins/pytest_wrapper.py | 9 +- ci/scripts/jenkins/s3.py | 7 +- ci/scripts/jenkins/should_rebuild_docker.py | 8 +- ci/scripts/jenkins/should_run_slow_tests.py | 3 +- docs/conf.py | 3 +- docs/download_3rdparty_embeds.py | 34 +-- docs/how_to/tutorials/optimize_llm.py | 5 +- pyproject.toml | 13 +- python/tvm/arith/analyzer.py | 5 +- python/tvm/arith/pattern.py | 4 +- python/tvm/contrib/cc.py | 3 +- python/tvm/contrib/cutlass/build.py | 6 +- python/tvm/contrib/cutlass/library.py | 4 +- python/tvm/contrib/download.py | 2 +- python/tvm/contrib/hexagon/build.py | 33 +- python/tvm/contrib/hexagon/meta_schedule.py | 16 +- python/tvm/contrib/hexagon/pytest_plugin.py | 5 +- python/tvm/contrib/hexagon/session.py | 19 +- python/tvm/contrib/hexagon/tools.py | 9 +- .../tvm/contrib/msc/core/codegen/codegen.py | 19 +- .../tvm/contrib/msc/core/codegen/sources.py | 4 +- .../contrib/msc/core/frontend/translate.py | 28 +- .../contrib/msc/core/gym/agent/base_agent.py | 18 +- .../msc/core/gym/agent/search_agent.py | 10 +- .../msc/core/gym/control/controller.py | 6 +- .../contrib/msc/core/gym/control/service.py | 38 +-- .../msc/core/gym/environment/base_env.py | 22 +- .../msc/core/gym/environment/method.py | 12 +- .../msc/core/gym/environment/prune_env.py | 6 +- .../msc/core/gym/environment/quantize_env.py | 4 +- python/tvm/contrib/msc/core/ir/graph.py | 67 ++-- python/tvm/contrib/msc/core/runtime/hook.py | 10 +- python/tvm/contrib/msc/core/runtime/jit.py | 26 +- python/tvm/contrib/msc/core/runtime/runner.py | 85 +++--- python/tvm/contrib/msc/core/tools/configer.py | 6 +- .../msc/core/tools/distill/distiller.py | 16 +- .../contrib/msc/core/tools/distill/method.py | 6 +- python/tvm/contrib/msc/core/tools/execute.py | 17 +- .../contrib/msc/core/tools/prune/configer.py | 4 +- .../contrib/msc/core/tools/prune/method.py | 6 +- .../contrib/msc/core/tools/prune/pruner.py | 28 +- .../msc/core/tools/quantize/configer.py | 4 +- .../contrib/msc/core/tools/quantize/method.py | 4 +- .../msc/core/tools/quantize/quantizer.py | 12 +- python/tvm/contrib/msc/core/tools/tool.py | 69 ++--- .../contrib/msc/core/tools/track/method.py | 4 +- .../contrib/msc/core/tools/track/tracker.py | 6 +- .../tvm/contrib/msc/core/transform/pattern.py | 30 +- .../contrib/msc/core/transform/transform.py | 6 +- .../tvm/contrib/msc/core/utils/arguments.py | 8 +- python/tvm/contrib/msc/core/utils/dataset.py | 20 +- python/tvm/contrib/msc/core/utils/expr.py | 5 +- python/tvm/contrib/msc/core/utils/file.py | 22 +- python/tvm/contrib/msc/core/utils/info.py | 20 +- python/tvm/contrib/msc/core/utils/log.py | 9 +- python/tvm/contrib/msc/core/utils/message.py | 7 +- .../tvm/contrib/msc/core/utils/namespace.py | 6 +- python/tvm/contrib/msc/core/utils/register.py | 4 +- .../framework/tensorflow/codegen/codegen.py | 8 +- .../tensorflow/frontend/translate.py | 14 +- .../framework/tensorflow/runtime/runner.py | 20 +- .../msc/framework/tensorrt/codegen/codegen.py | 26 +- .../msc/framework/tensorrt/codegen/sources.py | 4 +- .../framework/tensorrt/frontend/translate.py | 12 +- .../msc/framework/tensorrt/runtime/runner.py | 6 +- .../tensorrt/tools/quantize/method.py | 10 +- .../tensorrt/tools/quantize/quantizer.py | 14 +- .../framework/tensorrt/tools/track/tracker.py | 8 +- .../framework/tensorrt/transform/pattern.py | 34 +-- .../framework/tensorrt/transform/transform.py | 4 +- .../msc/framework/torch/codegen/codegen.py | 8 +- .../msc/framework/torch/frontend/translate.py | 12 +- .../msc/framework/torch/runtime/jit.py | 18 +- .../msc/framework/torch/runtime/runner.py | 22 +- .../torch/tools/distill/distiller.py | 4 +- .../framework/torch/tools/distill/method.py | 10 +- .../msc/framework/tvm/codegen/codegen.py | 8 +- .../msc/framework/tvm/runtime/runner.py | 18 +- .../framework/tvm/tools/quantize/method.py | 4 +- .../framework/tvm/tools/quantize/quantizer.py | 12 +- .../msc/framework/tvm/tools/track/tracker.py | 12 +- python/tvm/contrib/msc/pipeline/dynamic.py | 32 +- python/tvm/contrib/msc/pipeline/manager.py | 18 +- python/tvm/contrib/msc/pipeline/pipeline.py | 36 +-- python/tvm/contrib/msc/pipeline/utils.py | 23 +- python/tvm/contrib/msc/pipeline/worker.py | 30 +- python/tvm/contrib/msc/pipeline/wrapper.py | 18 +- python/tvm/contrib/msc/plugin/build.py | 36 +-- .../tvm/contrib/msc/plugin/codegen/codegen.py | 25 +- .../tvm/contrib/msc/plugin/codegen/sources.py | 4 +- python/tvm/contrib/msc/plugin/register.py | 3 +- python/tvm/contrib/msc/plugin/utils.py | 4 +- python/tvm/contrib/ndk.py | 5 +- python/tvm/contrib/nvcc.py | 7 +- python/tvm/contrib/rpc.py | 2 - python/tvm/contrib/tar.py | 2 - python/tvm/contrib/tvmjs.py | 15 +- python/tvm/contrib/utils.py | 2 +- python/tvm/driver/build_module.py | 18 +- python/tvm/exec/disco_worker.py | 2 +- python/tvm/ir/analysis.py | 4 +- python/tvm/ir/expr.py | 12 +- python/tvm/ir/function.py | 3 +- python/tvm/ir/global_info.py | 2 +- python/tvm/ir/instrument.py | 3 +- python/tvm/ir/module.py | 18 +- python/tvm/ir/supply.py | 2 +- python/tvm/ir/transform.py | 12 +- python/tvm/relax/analysis/analysis.py | 44 +-- .../relax/analysis/estimate_memory_usage.py | 3 +- .../backend/adreno/transform/transform.py | 4 +- python/tvm/relax/backend/contrib/nnapi.py | 29 +- python/tvm/relax/backend/cuda/cublas.py | 10 +- python/tvm/relax/backend/cuda/cudnn.py | 2 +- python/tvm/relax/backend/cuda/cutlass.py | 4 +- python/tvm/relax/backend/cuda/flashinfer.py | 13 +- .../tvm/relax/backend/dispatch_sort_scan.py | 3 +- .../tvm/relax/backend/gpu_generic/cumsum.py | 3 +- .../tvm/relax/backend/gpu_generic/sampling.py | 4 +- python/tvm/relax/backend/pattern_registry.py | 22 +- python/tvm/relax/backend/patterns.py | 28 +- python/tvm/relax/backend/rocm/hipblas.py | 4 +- python/tvm/relax/backend/utils.py | 4 +- python/tvm/relax/base_py_module.py | 50 ++- python/tvm/relax/binding_rewrite.py | 4 +- python/tvm/relax/block_builder.py | 29 +- python/tvm/relax/distributed/global_info.py | 10 +- python/tvm/relax/distributed/struct_info.py | 3 +- python/tvm/relax/dpl/context.py | 4 +- python/tvm/relax/dpl/pattern.py | 71 ++--- python/tvm/relax/dpl/rewrite.py | 10 +- python/tvm/relax/exec_builder.py | 11 +- python/tvm/relax/expr.py | 191 ++++++------ python/tvm/relax/expr_functor.py | 114 +++---- python/tvm/relax/frontend/common.py | 4 +- python/tvm/relax/frontend/nn/_tensor_op.py | 8 +- python/tvm/relax/frontend/nn/core.py | 93 +++--- python/tvm/relax/frontend/nn/exporter.py | 40 +-- python/tvm/relax/frontend/nn/extern.py | 24 +- python/tvm/relax/frontend/nn/llm/kv_cache.py | 50 +-- .../frontend/nn/llm/position_embedding.py | 33 +- python/tvm/relax/frontend/nn/llm/tree_attn.py | 14 +- python/tvm/relax/frontend/nn/modules.py | 86 +++--- python/tvm/relax/frontend/nn/op.py | 189 ++++++------ python/tvm/relax/frontend/nn/spec.py | 44 +-- python/tvm/relax/frontend/nn/subroutine.py | 2 +- python/tvm/relax/frontend/nn/torch.py | 13 +- .../tvm/relax/frontend/onnx/onnx_frontend.py | 69 ++--- .../stablehlo/stablehlo_translator.py | 19 +- .../torch/base_fx_graph_translator.py | 204 ++++++------- python/tvm/relax/frontend/torch/dynamo.py | 3 +- .../torch/exported_program_translator.py | 38 ++- .../tvm/relax/frontend/torch/fx_translator.py | 18 +- python/tvm/relax/op/_op_gradient.py | 101 +++--- python/tvm/relax/op/base.py | 66 ++-- python/tvm/relax/op/builtin/builtin.py | 8 +- python/tvm/relax/op/create.py | 78 +++-- python/tvm/relax/op/datatype.py | 6 +- .../tvm/relax/op/distributed/distributed.py | 8 +- python/tvm/relax/op/grad/grad.py | 26 +- python/tvm/relax/op/image/image.py | 18 +- python/tvm/relax/op/index.py | 8 +- python/tvm/relax/op/linear_algebra.py | 10 +- python/tvm/relax/op/manipulate.py | 62 ++-- python/tvm/relax/op/memory/memory.py | 14 +- python/tvm/relax/op/memory/view.py | 10 +- python/tvm/relax/op/nn/nn.py | 170 +++++------ python/tvm/relax/op/search.py | 6 +- python/tvm/relax/op/set.py | 14 +- python/tvm/relax/op/statistical.py | 26 +- python/tvm/relax/op/vm/vm.py | 16 +- python/tvm/relax/pipeline.py | 5 +- python/tvm/relax/relax_to_pyfunc_converter.py | 98 +++--- python/tvm/relax/struct_info.py | 40 +-- python/tvm/relax/testing/ast_printer.py | 2 +- python/tvm/relax/testing/lib_comparator.py | 6 +- python/tvm/relax/testing/nn.py | 38 ++- python/tvm/relax/testing/transform.py | 15 +- python/tvm/relax/testing/vm.py | 4 +- python/tvm/relax/training/loss.py | 26 +- python/tvm/relax/training/optimizer.py | 18 +- python/tvm/relax/training/setup_trainer.py | 8 +- python/tvm/relax/training/trainer.py | 34 +-- python/tvm/relax/training/utils.py | 6 +- .../transform/attach_external_modules.py | 4 +- .../relax/transform/ipc_allreduce_rewrite.py | 10 +- .../relax/transform/lazy_transform_params.py | 8 +- .../relax/transform/legalize_ops/common.py | 6 +- .../relax/transform/legalize_ops/create.py | 6 +- .../transform/legalize_ops/linear_algebra.py | 4 +- .../transform/legalize_ops/manipulate.py | 16 +- python/tvm/relax/transform/legalize_ops/nn.py | 3 +- .../tvm/relax/transform/legalize_ops/qdq.py | 12 +- .../transform/legalize_ops/statistical.py | 14 +- python/tvm/relax/transform/transform.py | 85 +++--- python/tvm/relax/type_converter.py | 11 +- python/tvm/relax/utils.py | 34 +-- python/tvm/relax/vm_build.py | 30 +- python/tvm/rpc/client.py | 4 +- python/tvm/rpc/server_ios_launcher.py | 16 +- python/tvm/runtime/_tensor.py | 6 +- python/tvm/runtime/disco/session.py | 19 +- python/tvm/runtime/executable.py | 9 +- python/tvm/runtime/module.py | 4 +- python/tvm/runtime/params.py | 2 +- python/tvm/runtime/profiling/__init__.py | 9 +- python/tvm/runtime/script_printer.py | 56 ++-- python/tvm/runtime/support.py | 2 +- python/tvm/runtime/vm.py | 35 +-- python/tvm/s_tir/analysis/__init__.py | 26 +- python/tvm/s_tir/data_layout.py | 6 +- python/tvm/s_tir/dlight/adreno/convolution.py | 8 +- python/tvm/s_tir/dlight/adreno/fallback.py | 8 +- .../s_tir/dlight/adreno/layout_transform.py | 8 +- python/tvm/s_tir/dlight/adreno/utils.py | 5 +- .../s_tir/dlight/analysis/common_analysis.py | 37 ++- python/tvm/s_tir/dlight/analysis/gemv.py | 8 +- .../tvm/s_tir/dlight/base/common_schedules.py | 10 +- python/tvm/s_tir/dlight/base/schedule_rule.py | 8 +- python/tvm/s_tir/dlight/base/transform.py | 6 +- python/tvm/s_tir/dlight/base/utils.py | 12 +- python/tvm/s_tir/dlight/benchmark/bench.py | 49 ++- python/tvm/s_tir/dlight/benchmark/extract.py | 39 ++- python/tvm/s_tir/dlight/benchmark/utils.py | 14 +- python/tvm/s_tir/dlight/cpu/gemv.py | 8 +- python/tvm/s_tir/dlight/gpu/fallback.py | 10 +- python/tvm/s_tir/dlight/gpu/gemv.py | 15 +- .../tvm/s_tir/dlight/gpu/general_reduction.py | 4 +- python/tvm/s_tir/dlight/gpu/low_batch_gemv.py | 28 +- python/tvm/s_tir/dlight/gpu/matmul.py | 35 ++- python/tvm/s_tir/dlight/gpu/reduction.py | 16 +- python/tvm/s_tir/dlight/gpu/rmsnorm.py | 4 +- python/tvm/s_tir/dlight/gpu/transpose.py | 4 +- python/tvm/s_tir/meta_schedule/arg_info.py | 8 +- .../s_tir/meta_schedule/builder/builder.py | 23 +- .../meta_schedule/builder/local_builder.py | 35 +-- .../meta_schedule/cost_model/cost_model.py | 29 +- .../meta_schedule/cost_model/mlp_model.py | 50 +-- .../meta_schedule/cost_model/random_model.py | 18 +- .../meta_schedule/cost_model/xgb_model.py | 64 ++-- .../s_tir/meta_schedule/database/database.py | 81 +++-- .../meta_schedule/database/json_database.py | 7 +- .../database/schedule_fn_database.py | 2 +- .../tvm/s_tir/meta_schedule/extracted_task.py | 6 +- .../feature_extractor/feature_extractor.py | 15 +- .../random_feature_extractor.py | 8 +- python/tvm/s_tir/meta_schedule/logging.py | 25 +- .../measure_callback/measure_callback.py | 23 +- .../s_tir/meta_schedule/mutator/mutator.py | 19 +- .../meta_schedule/post_optimization/space.py | 10 +- .../meta_schedule/post_optimization/utils.py | 5 +- .../s_tir/meta_schedule/postproc/postproc.py | 15 +- python/tvm/s_tir/meta_schedule/profiler.py | 4 +- .../s_tir/meta_schedule/relax_integration.py | 44 +-- .../tvm/s_tir/meta_schedule/runner/config.py | 10 +- .../meta_schedule/runner/local_runner.py | 56 ++-- .../s_tir/meta_schedule/runner/rpc_runner.py | 76 ++--- .../tvm/s_tir/meta_schedule/runner/runner.py | 25 +- .../tvm/s_tir/meta_schedule/runner/utils.py | 21 +- .../schedule/cuda/layout_transform.py | 39 ++- .../schedule_rule/add_rfactor.py | 4 +- .../meta_schedule/schedule_rule/auto_bind.py | 4 +- .../schedule_rule/auto_inline.py | 4 +- .../schedule_rule/cross_thread_reduction.py | 4 +- .../schedule_rule/multi_level_tiling.py | 47 +-- .../parallel_vectorize_unroll.py | 4 +- .../schedule_rule/schedule_rule.py | 19 +- .../search_strategy/search_strategy.py | 37 +-- .../space_generator/space_generator.py | 65 ++-- .../space_generator/space_generator_union.py | 4 +- .../task_scheduler/task_scheduler.py | 43 +-- .../testing/custom_builder_runner.py | 6 +- .../meta_schedule/testing/dummy_object.py | 7 +- .../meta_schedule/testing/space_generation.py | 27 +- .../meta_schedule/testing/te_workload.py | 35 ++- .../s_tir/meta_schedule/testing/tune_te.py | 3 +- .../s_tir/meta_schedule/testing/tune_utils.py | 12 +- .../testing/validate_database.py | 57 ++-- .../s_tir/meta_schedule/tir_integration.py | 34 +-- python/tvm/s_tir/meta_schedule/tune.py | 10 +- .../tvm/s_tir/meta_schedule/tune_context.py | 30 +- python/tvm/s_tir/meta_schedule/utils.py | 17 +- python/tvm/s_tir/sblock_dependence_info.py | 6 +- python/tvm/s_tir/sblock_scope.py | 8 +- python/tvm/s_tir/schedule/_type_checker.py | 63 ++-- python/tvm/s_tir/schedule/analysis.py | 12 +- python/tvm/s_tir/schedule/instruction.py | 18 +- python/tvm/s_tir/schedule/schedule.py | 287 +++++++++--------- python/tvm/s_tir/schedule/state.py | 15 +- python/tvm/s_tir/schedule/testing.py | 9 +- python/tvm/s_tir/schedule/trace.py | 32 +- python/tvm/s_tir/schedule/transform.py | 4 +- python/tvm/s_tir/tensor_intrin/cuda.py | 24 +- python/tvm/s_tir/tensor_intrin/metal.py | 12 +- python/tvm/script/highlight.py | 14 +- python/tvm/script/ir_builder/base.py | 9 +- python/tvm/script/ir_builder/ir/ir.py | 14 +- .../script/ir_builder/relax/distributed/ir.py | 20 +- python/tvm/script/ir_builder/relax/ir.py | 27 +- .../script/ir_builder/tir/external_kernel.py | 22 +- python/tvm/script/ir_builder/tir/frame.py | 4 +- python/tvm/script/ir_builder/tir/ir.py | 157 +++++----- python/tvm/script/ir_builder/tir/triton.py | 12 +- python/tvm/script/ir_builder/tir/utils.py | 5 +- python/tvm/script/parser/core/diagnostics.py | 3 +- python/tvm/script/parser/core/dispatch.py | 21 +- python/tvm/script/parser/core/doc.py | 23 +- python/tvm/script/parser/core/entry.py | 12 +- python/tvm/script/parser/core/evaluator.py | 56 ++-- python/tvm/script/parser/core/parser.py | 43 +-- python/tvm/script/parser/core/utils.py | 11 +- python/tvm/script/parser/ir/entry.py | 4 +- python/tvm/script/parser/relax/dist.py | 16 +- python/tvm/script/parser/relax/entry.py | 112 ++++--- python/tvm/script/parser/relax/parser.py | 16 +- python/tvm/script/parser/tir/entry.py | 6 +- python/tvm/script/parser/tir/operation.py | 6 +- python/tvm/script/parser/tir/parser.py | 20 +- python/tvm/script/printer/doc.py | 73 ++--- python/tvm/script/printer/doc_printer.py | 6 +- python/tvm/target/codegen.py | 4 +- python/tvm/target/detect_target.py | 4 +- python/tvm/target/tag_registry/registry.py | 6 +- python/tvm/target/target.py | 12 +- python/tvm/te/operation.py | 13 +- python/tvm/testing/plugin.py | 2 +- python/tvm/testing/runner.py | 23 +- python/tvm/testing/utils.py | 18 +- python/tvm/tir/analysis/analysis.py | 5 +- python/tvm/tir/buffer.py | 8 +- python/tvm/tir/build.py | 14 +- python/tvm/tir/expr.py | 130 ++++---- python/tvm/tir/function.py | 27 +- python/tvm/tir/functor.py | 194 ++++++------ python/tvm/tir/op.py | 16 +- python/tvm/tir/pipeline.py | 4 +- python/tvm/tir/stmt.py | 124 ++++---- python/tvm/tir/transform/function_pass.py | 12 +- python/tvm/tir/transform/transform.py | 2 +- python/tvm/topi/broadcast.py | 2 - python/tvm/topi/gpu/scan.py | 28 +- python/tvm/topi/image/__init__.py | 2 - python/tvm/topi/image/dilation2d.py | 2 - python/tvm/topi/index_put.py | 2 +- python/tvm/topi/nn/__init__.py | 2 - python/tvm/topi/nn/batch_norm.py | 15 +- python/tvm/topi/nn/bitserial_conv2d.py | 4 +- python/tvm/topi/nn/bnn.py | 2 - python/tvm/topi/nn/conv1d_transpose.py | 4 +- python/tvm/topi/nn/conv2d.py | 30 +- python/tvm/topi/nn/conv3d_transpose.py | 2 +- python/tvm/topi/nn/correlation.py | 2 +- python/tvm/topi/nn/depthwise_conv2d.py | 6 +- python/tvm/topi/nn/elemwise.py | 2 - python/tvm/topi/nn/fifo_buffer.py | 2 - python/tvm/topi/nn/mapping.py | 2 - python/tvm/topi/nn/pad.py | 2 - python/tvm/topi/nn/utils.py | 8 +- python/tvm/topi/reduction.py | 4 +- python/tvm/topi/scan.py | 20 +- python/tvm/topi/tensor.py | 7 +- python/tvm/topi/testing/__init__.py | 2 - python/tvm/topi/testing/attention_python.py | 6 +- python/tvm/topi/testing/conv1d_ncw_python.py | 4 +- python/tvm/topi/testing/matrix_set_diag.py | 2 +- python/tvm/topi/testing/poolnd_python.py | 27 +- python/tvm/topi/transform.py | 4 +- python/tvm/topi/utils.py | 4 +- python/tvm/topi/vision/nms.py | 2 +- tests/conda/build-environment.yaml | 2 +- tests/python/arith/test_arith_intset.py | 2 +- tests/python/ci/test_tvmbot.py | 18 +- tests/python/ci/test_utils.py | 4 +- .../codegen/test_target_codegen_cuda_fp8.py | 9 +- tests/python/contrib/test_cutlass_gemm.py | 9 +- .../contrib/test_hexagon/benchmark_util.py | 2 +- .../contrib/test_hexagon/pytest_util.py | 13 +- .../test_hexagon/test_2d_physical_buffers.py | 2 +- .../test_hexagon/test_benchmark_maxpool2d.py | 3 +- .../contrib/test_msc/test_translate_relax.py | 6 +- .../test_msc/test_translate_tensorrt.py | 2 +- .../contrib/test_msc/test_translate_torch.py | 4 +- tests/python/disco/test_nvshmem.py | 3 +- .../ir/analysis/test_collect_call_map.py | 3 +- .../nightly/test_nnapi/infrastructure.py | 8 +- .../python/nightly/test_nnapi/test_network.py | 4 +- tests/python/nightly/test_nnapi/test_ops.py | 4 +- .../test_distributed_tvmscript_parser.py | 4 +- .../test_runtime_builtin_kv_cache_transfer.py | 20 +- tests/python/relax/test_analysis.py | 3 +- ...est_analysis_computable_at_compile_time.py | 3 +- .../relax/test_analysis_detect_recursion.py | 3 +- tests/python/relax/test_ast_printer.py | 3 +- tests/python/relax/test_dataflow_inplace.py | 3 +- .../python/relax/test_expr_args_converter.py | 13 +- tests/python/relax/test_frontend_nn_jit.py | 7 +- .../python/relax/test_frontend_nn_modules.py | 5 +- tests/python/relax/test_frontend_onnx.py | 42 +-- tests/python/relax/test_frontend_stablehlo.py | 17 +- tests/python/relax/test_op_binary.py | 2 +- .../python/relax/test_op_gradient_numeric.py | 9 +- tests/python/relax/test_op_search.py | 2 +- tests/python/relax/test_op_statistical.py | 2 +- tests/python/relax/test_op_unary.py | 2 +- ...me_builtin_paged_attention_kv_cache_cpu.py | 19 +- ...tin_paged_attention_kv_cache_flashinfer.py | 7 +- ...paged_attention_kv_cache_mla_flashinfer.py | 5 +- ...uiltin_paged_attention_kv_cache_mla_tir.py | 5 +- ...me_builtin_paged_attention_kv_cache_tir.py | 19 +- .../relax/test_runtime_builtin_rnn_state.py | 4 +- .../relax/test_runtime_sampling_flashinfer.py | 3 +- .../relax/test_training_optimizer_numeric.py | 12 +- .../relax/test_transform_few_shot_tuning.py | 7 +- .../test_transform_legalize_ops_unary.py | 2 +- ...test_transform_update_param_struct_info.py | 5 +- tests/python/relax/test_tvmscript_parser.py | 4 +- .../test_tvmscript_parser_op_arith_cmp.py | 6 +- .../relax/test_tvmscript_parser_op_create.py | 5 +- .../test_tvmscript_parser_op_datatype.py | 5 +- .../relax/test_tvmscript_parser_op_grad.py | 5 +- .../relax/test_tvmscript_parser_op_image.py | 5 +- .../relax/test_tvmscript_parser_op_index.py | 5 +- ...test_tvmscript_parser_op_linear_algebra.py | 5 +- .../test_tvmscript_parser_op_manipulate.py | 5 +- .../relax/test_tvmscript_parser_op_nn.py | 5 +- .../relax/test_tvmscript_parser_op_search.py | 5 +- .../relax/test_tvmscript_parser_op_set.py | 5 +- .../relax/test_tvmscript_parser_op_sort.py | 5 +- .../test_tvmscript_parser_op_statistical.py | 5 +- .../relax/test_tvmscript_parser_op_vision.py | 5 +- tests/python/relax/test_vm_build.py | 4 +- tests/python/relax/test_vm_multi_device.py | 4 +- .../test_meta_schedule_builder.py | 7 +- .../test_meta_schedule_cost_model.py | 13 +- .../test_meta_schedule_database.py | 31 +- .../test_meta_schedule_feature_extractor.py | 9 +- ...ule_feature_extractor_per_store_feature.py | 4 +- .../test_meta_schedule_measure_callback.py | 23 +- ...t_meta_schedule_mutator_mutate_parallel.py | 3 +- ..._meta_schedule_mutator_mutate_tile_size.py | 3 +- ...est_meta_schedule_mutator_mutate_unroll.py | 3 +- .../test_meta_schedule_post_order_apply.py | 11 +- .../test_meta_schedule_runner.py | 36 +-- ...chedule_schedule_rule_apply_custom_rule.py | 3 +- .../test_meta_schedule_search_strategy.py | 13 +- ...pace_cuda_async_multiple_initialization.py | 10 +- .../test_meta_schedule_task_scheduler.py | 3 +- .../schedule/test_tir_schedule_analysis.py | 5 +- .../testing/test_type_annotation_checker.py | 25 +- tests/python/tir-base/test_tir_imm_values.py | 8 +- tests/python/tir-base/test_tir_ops.py | 2 +- .../test_tvmscript_printer_underlining.py | 3 +- tests/scripts/ci.py | 41 +-- tests/scripts/release/gather_prs.py | 5 +- 470 files changed, 4227 insertions(+), 4642 deletions(-) diff --git a/ci/jenkins/generate.py b/ci/jenkins/generate.py index 8baafa708e13..af9dfbc92f6b 100644 --- a/ci/jenkins/generate.py +++ b/ci/jenkins/generate.py @@ -22,7 +22,6 @@ import textwrap from dataclasses import dataclass from pathlib import Path -from typing import List, Optional import jinja2 from data import data @@ -41,7 +40,7 @@ class Change: @dataclass class ChangeData: - diff: Optional[str] + diff: str | None content: str destination: Path source: Path @@ -53,7 +52,7 @@ def lines_without_generated_tag(content): ] -def change_type(lines: List[str]) -> Change: +def change_type(lines: list[str]) -> Change: """ Return True if 'line' only edits an image tag or if 'line' is not a changed line in a diff diff --git a/ci/scripts/github/github_cc_reviewers.py b/ci/scripts/github/github_cc_reviewers.py index 1bee762bf153..017878740f28 100755 --- a/ci/scripts/github/github_cc_reviewers.py +++ b/ci/scripts/github/github_cc_reviewers.py @@ -23,7 +23,6 @@ import re import sys from pathlib import Path -from typing import List from urllib import error # Hackery to enable importing of utils from ci/scripts/jenkins @@ -33,7 +32,7 @@ from git_utils import GitHubRepo, git, parse_remote -def find_reviewers(body: str) -> List[str]: +def find_reviewers(body: str) -> list[str]: print(f"Parsing body:\n{body}") matches = re.findall(r"(cc( @[-A-Za-z0-9]+)+)", body, flags=re.MULTILINE) matches = [full for full, last in matches] diff --git a/ci/scripts/github/github_commenter.py b/ci/scripts/github/github_commenter.py index 5b5893b82977..b193dc3b9525 100644 --- a/ci/scripts/github/github_commenter.py +++ b/ci/scripts/github/github_commenter.py @@ -21,7 +21,7 @@ import re import sys from pathlib import Path -from typing import Any, Dict, List, Optional, Tuple +from typing import Any # Hackery to enable importing of utils from ci/scripts/jenkins REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent @@ -36,13 +36,13 @@ class BotCommentBuilder: ALLOWLIST_USERS = {"driazati", "gigiblender", "areusch"} - def __init__(self, github: GitHubRepo, data: Dict[str, Any]): + def __init__(self, github: GitHubRepo, data: dict[str, Any]): self.github = github self.pr_number = data["number"] self.comment_data = data["comments"]["nodes"] self.author = data["author"]["login"] - def find_bot_comment(self) -> Optional[Dict[str, Any]]: + def find_bot_comment(self) -> dict[str, Any] | None: """ Return the existing bot comment or None if it does not exist """ @@ -57,7 +57,7 @@ def find_bot_comment(self) -> Optional[Dict[str, Any]]: logging.info("No existing comment found") return None - def find_existing_body(self) -> Dict[str, str]: + def find_existing_body(self) -> dict[str, str]: """ Find existing dynamic bullet point items """ @@ -84,7 +84,7 @@ def find_existing_body(self) -> Dict[str, str]: logging.info(f"Found body items: {items}") return items - def _post_comment(self, body_items: Dict[str, str]): + def _post_comment(self, body_items: dict[str, str]): comment = BOT_COMMENT_START + "\n\n" + WELCOME_TEXT + "\n\n" for key, content in body_items.items(): line = self.start_key(key) + "\n * " + content.strip() + self.end_key(key) @@ -118,7 +118,7 @@ def start_key(self, key: str) -> str: def end_key(self, key: str) -> str: return f"" - def post_items(self, items: List[Tuple[str, str]]): + def post_items(self, items: list[tuple[str, str]]): """ Update or post bullet points in the PR based on 'items' which is a list of (key, text) pairs diff --git a/ci/scripts/github/github_docs_comment.py b/ci/scripts/github/github_docs_comment.py index 9422e3c3acfa..287e73653644 100755 --- a/ci/scripts/github/github_docs_comment.py +++ b/ci/scripts/github/github_docs_comment.py @@ -16,14 +16,14 @@ # specific language governing permissions and limitations # under the License. -from typing import Any, Dict +from typing import Any def build_docs_url(base_url_docs, pr_number, build_number): return f"{base_url_docs}/PR-{pr_number!s}/{build_number!s}/docs/index.html" -def find_target_url(pr_head: Dict[str, Any]): +def find_target_url(pr_head: dict[str, Any]): for status in pr_head["statusCheckRollup"]["contexts"]["nodes"]: if status.get("context", "") == "tvm-ci/pr-head": return status["targetUrl"] @@ -39,7 +39,7 @@ def get_pr_and_build_numbers(target_url): return {"pr_number": pr_number, "build_number": build_number} -def get_doc_url(pr: Dict[str, Any], base_docs_url: str = "https://pr-docs.tlcpack.ai") -> str: +def get_doc_url(pr: dict[str, Any], base_docs_url: str = "https://pr-docs.tlcpack.ai") -> str: pr_head = pr["commits"]["nodes"][0]["commit"] target_url = find_target_url(pr_head) pr_and_build = get_pr_and_build_numbers(target_url) diff --git a/ci/scripts/github/github_skipped_tests_comment.py b/ci/scripts/github/github_skipped_tests_comment.py index 74224195c550..10789f75615b 100755 --- a/ci/scripts/github/github_skipped_tests_comment.py +++ b/ci/scripts/github/github_skipped_tests_comment.py @@ -21,7 +21,7 @@ import os import subprocess from pathlib import Path -from typing import Any, Dict, Optional +from typing import Any from xml.etree import ElementTree @@ -154,7 +154,7 @@ def build_comment( return text -def find_target_url(pr_head: Dict[str, Any]): +def find_target_url(pr_head: dict[str, Any]): for status in pr_head["statusCheckRollup"]["contexts"]["nodes"]: if status.get("context", "") == "tvm-ci/pr-head": return status["targetUrl"] @@ -163,14 +163,14 @@ def find_target_url(pr_head: Dict[str, Any]): def get_skipped_tests_comment( - pr: Dict[str, Any], + pr: dict[str, Any], github, s3_prefix: str = "tvm-jenkins-artifacts-prod", jenkins_prefix: str = "ci.tlcpack.ai", pr_test_report_dir: str = "pr-reports", main_test_report_dir: str = "main-reports", - common_commit_sha: Optional[str] = None, - common_main_build: Optional[Dict[str, Any]] = None, + common_commit_sha: str | None = None, + common_main_build: dict[str, Any] | None = None, additional_tests_to_check_file: str = "required_tests_to_run.json", ) -> str: pr_head = pr["commits"]["nodes"][0]["commit"] diff --git a/ci/scripts/github/github_tag_teams.py b/ci/scripts/github/github_tag_teams.py index 81956cedd7fe..f2c2102a93b5 100755 --- a/ci/scripts/github/github_tag_teams.py +++ b/ci/scripts/github/github_tag_teams.py @@ -24,7 +24,7 @@ import re import sys from pathlib import Path -from typing import Any, Dict, List, Optional, Tuple +from typing import Any # Hackery to enable importing of utils from ci/scripts/jenkins REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent @@ -36,7 +36,7 @@ GITHUB_NAME_REGEX = r"@[a-zA-Z0-9-]+" -def parse_line(line: str) -> Tuple[str, List[str]]: +def parse_line(line: str) -> tuple[str, list[str]]: line = line.lstrip(" -") line = line.split() @@ -86,7 +86,7 @@ def fetch_issue(github: GitHubRepo, issue_number: int): return r -def parse_teams(r: Dict[str, Any], issue_number: int) -> Dict[str, str]: +def parse_teams(r: dict[str, Any], issue_number: int) -> dict[str, str]: """ Fetch an issue and parse out series of tagged people from the issue body and comments @@ -131,11 +131,11 @@ def add_tag(tag, users): return {k.lower(): v for k, v in result.items() if k.strip()} -def tags_from_labels(labels: List[Dict[str, Any]]) -> List[str]: +def tags_from_labels(labels: list[dict[str, Any]]) -> list[str]: return [label["name"] for label in labels] -def add_ccs_to_body(body: str, to_cc: List[str]) -> str: +def add_ccs_to_body(body: str, to_cc: list[str]) -> str: lines = body.split("\n") cc_line_idx = None @@ -174,8 +174,8 @@ def gen_cc_line(users): def determine_users_to_cc( - issue: Dict[str, Any], github: GitHubRepo, team_issue: str, issue_data: Optional[Dict[str, Any]] -) -> List[str]: + issue: dict[str, Any], github: GitHubRepo, team_issue: str, issue_data: dict[str, Any] | None +) -> list[str]: if issue_data is None: issue_data = fetch_issue(github, issue_number=int(team_issue)) @@ -205,7 +205,7 @@ def determine_users_to_cc( return to_cc -def get_tags(pr_data: Dict[str, Any], github: GitHubRepo, team_issue: int) -> str: +def get_tags(pr_data: dict[str, Any], github: GitHubRepo, team_issue: int) -> str: to_cc = determine_users_to_cc( issue=pr_data, github=github, team_issue=team_issue, issue_data=None ) diff --git a/ci/scripts/github/github_tvmbot.py b/ci/scripts/github/github_tvmbot.py index 0d8981b1ba3b..24308cd77cb0 100755 --- a/ci/scripts/github/github_tvmbot.py +++ b/ci/scripts/github/github_tvmbot.py @@ -25,8 +25,9 @@ import sys import traceback import warnings +from collections.abc import Callable from pathlib import Path -from typing import Any, Callable, Dict, List, Optional, Union +from typing import Any # Hackery to enable importing of utils from ci/scripts/jenkins REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent @@ -35,9 +36,9 @@ from cmd_utils import init_log from git_utils import GitHubRepo, git, parse_remote, post -Review = Dict[str, Any] -CIJob = Dict[str, Any] -Comment = Dict[str, Any] +Review = dict[str, Any] +CIJob = dict[str, Any] +Comment = dict[str, Any] CommentChecker = Callable[[Comment], bool] EXPECTED_JOBS = ["tvm-ci/pr-head"] @@ -194,7 +195,7 @@ def __init__( owner: str, repo: str, dry_run: bool = False, - raw_data: Optional[Dict[str, Any]] = None, + raw_data: dict[str, Any] | None = None, ): self.owner = owner self.number = number @@ -242,7 +243,7 @@ def checker(obj, parent_key): def __repr__(self): return json.dumps(self.raw, indent=2) - def react(self, comment: Dict[str, Any], content: str): + def react(self, comment: dict[str, Any], content: str): """ React with a thumbs up to a comment """ @@ -256,7 +257,7 @@ def react(self, comment: Dict[str, Any], content: str): def head_commit(self): return self.raw["commits"]["nodes"][0]["commit"] - def co_authors(self) -> List[str]: + def co_authors(self) -> list[str]: authors = [] for commit in self.raw["authorCommits"]["nodes"]: # Co-authors always come after the main author according to the @@ -271,7 +272,7 @@ def co_authors(self) -> List[str]: def head_oid(self): return self.head_commit()["oid"] - def ci_jobs(self) -> List[CIJob]: + def ci_jobs(self) -> list[CIJob]: """ Get a list of all CI jobs (GitHub Actions and other) in a unified format """ @@ -310,14 +311,14 @@ def ci_jobs(self) -> List[CIJob]: logging.info(f"Found CI jobs for {self.head_commit()['oid']} {to_json_str(jobs)}") return jobs - def reviews(self) -> List[Review]: + def reviews(self) -> list[Review]: return self.raw["reviews"]["nodes"] - def head_commit_reviews(self) -> List[Review]: + def head_commit_reviews(self) -> list[Review]: """ Find reviews associated with the head commit """ - commits_to_review_status: Dict[str, List[Review]] = {} + commits_to_review_status: dict[str, list[Review]] = {} for review in self.reviews(): if not review["authorCanPushToRepository"]: @@ -347,13 +348,13 @@ def fetch_data(self): }, )["data"]["repository"]["pullRequest"] - def search_collaborator(self, user: str) -> List[Dict[str, Any]]: + def search_collaborator(self, user: str) -> list[dict[str, Any]]: """ Query GitHub for collaborators matching 'user' """ return self.search_users(user, COLLABORATORS_QUERY)["collaborators"]["nodes"] - def search_users(self, user: str, query: str) -> List[Dict[str, Any]]: + def search_users(self, user: str, query: str) -> list[dict[str, Any]]: return self.github.graphql( query=query, variables={ @@ -363,7 +364,7 @@ def search_users(self, user: str, query: str) -> List[Dict[str, Any]]: }, )["data"]["repository"] - def search_mentionable_users(self, user: str) -> List[Dict[str, Any]]: + def search_mentionable_users(self, user: str) -> list[dict[str, Any]]: return self.search_users(user, MENTIONABLE_QUERY)["mentionableUsers"]["nodes"] def comment(self, text: str) -> None: @@ -449,7 +450,7 @@ def merge(self) -> None: def author(self) -> str: return self.raw["author"]["login"] - def find_failed_ci_jobs(self) -> List[CIJob]: + def find_failed_ci_jobs(self) -> list[CIJob]: # NEUTRAL is GitHub Action's way of saying cancelled return [ job @@ -457,7 +458,7 @@ def find_failed_ci_jobs(self) -> List[CIJob]: if job["status"] not in {"SUCCESS", "SUCCESSFUL", "SKIPPED"} ] - def find_missing_expected_jobs(self) -> List[str]: + def find_missing_expected_jobs(self) -> list[str]: # Map of job name: has seen in completed jobs seen_expected_jobs = {name: False for name in EXPECTED_JOBS} logging.info(f"Expected to see jobs: {seen_expected_jobs}") @@ -485,7 +486,7 @@ def trigger_gha_ci(self, sha: str) -> None: ) logging.info(f"Successful workflow_dispatch: {r}") - def merge_if_passed_checks(self) -> Optional[Dict[str, Any]]: + def merge_if_passed_checks(self) -> dict[str, Any] | None: failed_ci_jobs = self.find_failed_ci_jobs() all_ci_passed = len(failed_ci_jobs) == 0 has_one_approval = False @@ -576,7 +577,7 @@ def rerun_github_actions(self) -> None: else: raise e - def comment_failure(self, msg: str, exceptions: Union[Exception, List[Exception]]): + def comment_failure(self, msg: str, exceptions: Exception | list[Exception]): if not isinstance(exceptions, list): exceptions = [exceptions] diff --git a/ci/scripts/github/ping_reviewers.py b/ci/scripts/github/ping_reviewers.py index abe2ac06779f..bd1f434c10ba 100755 --- a/ci/scripts/github/ping_reviewers.py +++ b/ci/scripts/github/ping_reviewers.py @@ -24,7 +24,6 @@ import sys import textwrap from pathlib import Path -from typing import List, Optional # Hackery to enable importing of utils from ci/scripts/jenkins REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent @@ -35,7 +34,7 @@ GIT_DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" -def prs_query(user: str, repo: str, cursor: Optional[str] = None): +def prs_query(user: str, repo: str, cursor: str | None = None): after = "" if cursor is not None: after = f', before:"{cursor}"' @@ -86,7 +85,7 @@ def prs_query(user: str, repo: str, cursor: Optional[str] = None): """ -def find_reviewers(body: str) -> List[str]: +def find_reviewers(body: str) -> list[str]: matches = re.findall(r"(cc( @[-A-Za-z0-9]+)+)", body, flags=re.MULTILINE) matches = [full for full, last in matches] diff --git a/ci/scripts/github/update_branch.py b/ci/scripts/github/update_branch.py index 62552989ae74..e5195f7c67f4 100755 --- a/ci/scripts/github/update_branch.py +++ b/ci/scripts/github/update_branch.py @@ -22,7 +22,7 @@ import os import sys from pathlib import Path -from typing import Any, Dict, Optional +from typing import Any # Hackery to enable importing of utils from ci/scripts/jenkins REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent @@ -58,7 +58,7 @@ """ -def commits_query(user: str, repo: str, cursor: Optional[str] = None): +def commits_query(user: str, repo: str, cursor: str | None = None): """ Create a GraphQL query to find the last N commits along with their statuses and some metadata (paginated after 'cursor') @@ -101,7 +101,7 @@ def commits_query(user: str, repo: str, cursor: Optional[str] = None): ] -def commit_passed_ci(commit: Dict[str, Any]) -> bool: +def commit_passed_ci(commit: dict[str, Any]) -> bool: """ Returns true if all of a commit's statuses are SUCCESS """ diff --git a/ci/scripts/jenkins/check_pr.py b/ci/scripts/jenkins/check_pr.py index 445c636fea9d..683c3fdd6ddb 100755 --- a/ci/scripts/jenkins/check_pr.py +++ b/ci/scripts/jenkins/check_pr.py @@ -21,8 +21,9 @@ import os import re import textwrap +from collections.abc import Callable from dataclasses import dataclass -from typing import Any, Callable, List +from typing import Any from cmd_utils import init_log, tags_from_title from git_utils import GitHubRepo, git, parse_remote @@ -82,7 +83,7 @@ def trailing_period(s: str): ] -def run_checks(checks: List[Check], s: str, name: str) -> bool: +def run_checks(checks: list[Check], s: str, name: str) -> bool: print(f"Running checks for {name}") print(textwrap.indent(s, prefix=" ")) passed = True diff --git a/ci/scripts/jenkins/cmd_utils.py b/ci/scripts/jenkins/cmd_utils.py index 4b33ce44d261..e1cd8e9b20e9 100644 --- a/ci/scripts/jenkins/cmd_utils.py +++ b/ci/scripts/jenkins/cmd_utils.py @@ -21,7 +21,6 @@ import subprocess import sys from pathlib import Path -from typing import List REPO_ROOT = Path(__file__).resolve().parent.parent.parent.parent assert (REPO_ROOT / "Jenkinsfile").exists @@ -102,7 +101,7 @@ def _default_popen_flags(self): } -def tags_from_title(title: str) -> List[str]: +def tags_from_title(title: str) -> list[str]: tags = re.findall(r"\[(.*?)\]", title) tags = [t.strip() for t in tags] return tags diff --git a/ci/scripts/jenkins/determine_docker_images.py b/ci/scripts/jenkins/determine_docker_images.py index a0d5b633e536..fed3ab79cc0e 100755 --- a/ci/scripts/jenkins/determine_docker_images.py +++ b/ci/scripts/jenkins/determine_docker_images.py @@ -23,7 +23,7 @@ import logging import urllib.error from pathlib import Path -from typing import Any, Dict +from typing import Any from cmd_utils import REPO_ROOT, init_log from http_utils import get @@ -35,7 +35,7 @@ TVM_CI_ECR = "477529581014.dkr.ecr.us-west-2.amazonaws.com" -def docker_api(url: str, use_pagination: bool = False) -> Dict[str, Any]: +def docker_api(url: str, use_pagination: bool = False) -> dict[str, Any]: """ Run a paginated fetch from the public Docker Hub API """ diff --git a/ci/scripts/jenkins/git_skip_ci_globs.py b/ci/scripts/jenkins/git_skip_ci_globs.py index dca941e7c843..651bbeac7c55 100755 --- a/ci/scripts/jenkins/git_skip_ci_globs.py +++ b/ci/scripts/jenkins/git_skip_ci_globs.py @@ -19,7 +19,6 @@ import argparse import fnmatch -from typing import Optional from git_utils import git @@ -36,7 +35,7 @@ ] -def match_any(f: str) -> Optional[str]: +def match_any(f: str) -> str | None: for glob in globs: if fnmatch.fnmatch(f, glob): return glob diff --git a/ci/scripts/jenkins/git_utils.py b/ci/scripts/jenkins/git_utils.py index 05301a046ac0..b16e3f7aa320 100644 --- a/ci/scripts/jenkins/git_utils.py +++ b/ci/scripts/jenkins/git_utils.py @@ -23,7 +23,7 @@ import os import re import subprocess -from typing import Any, Dict, List, Optional, Tuple +from typing import Any from urllib import error, request DRY_RUN = object() @@ -35,7 +35,7 @@ def compress_query(query: str) -> str: return query -def post(url: str, body: Optional[Any] = None, auth: Optional[Tuple[str, str]] = None): +def post(url: str, body: Any | None = None, auth: tuple[str, str] | None = None): logging.info(f"Requesting POST to {url} with {body}") headers = {} req = request.Request(url, headers=headers, method="POST") @@ -80,7 +80,7 @@ def headers(self): def dry_run(self) -> bool: return self.token == DRY_RUN - def graphql(self, query: str, variables: Optional[Dict[str, str]] = None) -> Dict[str, Any]: + def graphql(self, query: str, variables: dict[str, str] | None = None) -> dict[str, Any]: query = compress_query(query) if variables is None: variables = {} @@ -106,7 +106,7 @@ def testing_response(self, method: str, url: str) -> Any: logging.info(f"Unknown URL in dry run: {key}") return {} - def _request(self, full_url: str, body: Dict[str, Any], method: str) -> Dict[str, Any]: + def _request(self, full_url: str, body: dict[str, Any], method: str) -> dict[str, Any]: if self.dry_run(): logging.info(f"Dry run, would have requested a {method} to {full_url} with {body}") return self.testing_response(method, full_url) @@ -134,16 +134,16 @@ def _request(self, full_url: str, body: Dict[str, Any], method: str) -> Dict[str return response - def put(self, url: str, data: Dict[str, Any]) -> Dict[str, Any]: + def put(self, url: str, data: dict[str, Any]) -> dict[str, Any]: return self._request(self.base + url, data, method="PUT") - def patch(self, url: str, data: Dict[str, Any]) -> Dict[str, Any]: + def patch(self, url: str, data: dict[str, Any]) -> dict[str, Any]: return self._request(self.base + url, data, method="PATCH") - def post(self, url: str, data: Dict[str, Any]) -> Dict[str, Any]: + def post(self, url: str, data: dict[str, Any]) -> dict[str, Any]: return self._request(self.base + url, data, method="POST") - def get(self, url: str) -> Dict[str, Any]: + def get(self, url: str) -> dict[str, Any]: if self.dry_run(): logging.info(f"Dry run, would have requested a GET to {url}") return self.testing_response("GET", url) @@ -154,7 +154,7 @@ def get(self, url: str) -> Dict[str, Any]: response = json.loads(response.read()) return response - def delete(self, url: str) -> Dict[str, Any]: + def delete(self, url: str) -> dict[str, Any]: if self.dry_run(): logging.info(f"Dry run, would have requested a DELETE to {url}") return self.testing_response("DELETE", url) @@ -166,7 +166,7 @@ def delete(self, url: str) -> Dict[str, Any]: return response -def parse_remote(remote: str) -> Tuple[str, str]: +def parse_remote(remote: str) -> tuple[str, str]: """ Get a GitHub (user, repo) pair out of a git remote """ @@ -197,7 +197,7 @@ def git(command, **kwargs): return proc.stdout.strip() -def find_ccs(body: str) -> List[str]: +def find_ccs(body: str) -> list[str]: matches = re.findall(r"(cc( @[-A-Za-z0-9]+)+)", body, flags=re.MULTILINE) matches = [full for full, last in matches] diff --git a/ci/scripts/jenkins/http_utils.py b/ci/scripts/jenkins/http_utils.py index e006c48d477c..05e1b71f24d6 100644 --- a/ci/scripts/jenkins/http_utils.py +++ b/ci/scripts/jenkins/http_utils.py @@ -18,11 +18,11 @@ import json import logging -from typing import Any, Dict, Optional +from typing import Any from urllib import request -def get(url: str, headers: Optional[Dict[str, str]] = None) -> Dict[str, Any]: +def get(url: str, headers: dict[str, str] | None = None) -> dict[str, Any]: logging.info(f"Requesting GET to {url}") if headers is None: headers = {} diff --git a/ci/scripts/jenkins/open_docker_update_pr.py b/ci/scripts/jenkins/open_docker_update_pr.py index 6809d2c4d916..a948750082e8 100755 --- a/ci/scripts/jenkins/open_docker_update_pr.py +++ b/ci/scripts/jenkins/open_docker_update_pr.py @@ -23,7 +23,8 @@ import os import re import shlex -from typing import Any, Callable, Dict, List, Optional +from collections.abc import Callable +from typing import Any from urllib import error from cmd_utils import REPO_ROOT, Sh, init_log @@ -37,10 +38,10 @@ BRANCH = "nightly-docker-update" -def _testing_docker_api(data: Dict[str, Any]) -> Callable[[str], Dict[str, Any]]: +def _testing_docker_api(data: dict[str, Any]) -> Callable[[str], dict[str, Any]]: """Returns a function that can be used in place of docker_api""" - def mock(url: str) -> Dict[str, Any]: + def mock(url: str) -> dict[str, Any]: if url in data: return data[url] else: @@ -54,11 +55,11 @@ def parse_docker_date(d: str) -> datetime.datetime: return datetime.datetime.strptime(d, "%Y-%m-%dT%H:%M:%S.%fZ") -def check_tag(tag: Dict[str, Any]) -> bool: +def check_tag(tag: dict[str, Any]) -> bool: return re.match(r"^[0-9]+-[0-9]+-[a-z0-9]+$", tag["name"]) is not None -def latest_tag(user: str, repo: str) -> List[Dict[str, Any]]: +def latest_tag(user: str, repo: str) -> list[dict[str, Any]]: """ Queries Docker Hub and finds the most recent tag for the specified image/repo pair """ @@ -73,7 +74,7 @@ def latest_tag(user: str, repo: str) -> List[Dict[str, Any]]: return results[-1] -def latest_tlcpackstaging_image(source: str) -> Optional[str]: +def latest_tlcpackstaging_image(source: str) -> str | None: """ Finds the latest full tag to use in the Jenkinsfile or returns None if no update is needed diff --git a/ci/scripts/jenkins/pytest_wrapper.py b/ci/scripts/jenkins/pytest_wrapper.py index fc00fc8159b8..a66781029350 100755 --- a/ci/scripts/jenkins/pytest_wrapper.py +++ b/ci/scripts/jenkins/pytest_wrapper.py @@ -22,7 +22,6 @@ import textwrap import urllib.parse from pathlib import Path -from typing import List, Optional import junitparser from cmd_utils import init_log @@ -42,7 +41,7 @@ def classname_to_file(classname: str) -> str: return classname.replace(".", "/") + ".py" -def failed_test_ids() -> List[str]: +def failed_test_ids() -> list[str]: FAILURE_TYPES = (junitparser.Failure, junitparser.Error) junit_dir = REPO_ROOT / "build" / "pytest-results" failed_node_ids = [] @@ -62,7 +61,7 @@ def failed_test_ids() -> List[str]: return list(set(failed_node_ids)) -def repro_command(build_type: str, failed_node_ids: List[str]) -> Optional[str]: +def repro_command(build_type: str, failed_node_ids: list[str]) -> str | None: """ Parse available JUnit XML files and output a command that users can run to reproduce CI failures locally @@ -72,7 +71,7 @@ def repro_command(build_type: str, failed_node_ids: List[str]) -> Optional[str]: return f"python3 tests/scripts/ci.py {build_type} {test_args_str}" -def make_issue_url(failed_node_ids: List[str]) -> str: +def make_issue_url(failed_node_ids: list[str]) -> str: names = [f"`{node_id}`" for node_id in failed_node_ids] run_url = os.getenv("RUN_DISPLAY_URL", "") test_bullets = [f" - `{node_id}`" for node_id in failed_node_ids] @@ -92,7 +91,7 @@ def make_issue_url(failed_node_ids: List[str]) -> str: return "https://github.com/apache/tvm/issues/new?" + urllib.parse.urlencode(params) -def show_failure_help(failed_suites: List[str]) -> None: +def show_failure_help(failed_suites: list[str]) -> None: failed_node_ids = failed_test_ids() if len(failed_node_ids) == 0: diff --git a/ci/scripts/jenkins/s3.py b/ci/scripts/jenkins/s3.py index 414348f9e562..dd44490b1e12 100755 --- a/ci/scripts/jenkins/s3.py +++ b/ci/scripts/jenkins/s3.py @@ -21,7 +21,6 @@ import re from enum import Enum from pathlib import Path -from typing import List from cmd_utils import REPO_ROOT, Sh, init_log @@ -40,7 +39,7 @@ def show_md5(item: str) -> None: sh.run(f"md5sum {item}") -def parse_output_files(stdout: str) -> List[str]: +def parse_output_files(stdout: str) -> list[str]: """ Grab the list of downloaded files from the output of 'aws s3 cp'. Lines look like: @@ -59,7 +58,7 @@ def parse_output_files(stdout: str) -> List[str]: return files -def chmod(files: List[str]) -> None: +def chmod(files: list[str]) -> None: """ S3 has no concept of file permissions so add them back in here to every file """ @@ -70,7 +69,7 @@ def chmod(files: List[str]) -> None: SH.run(f"chmod +x {' '.join(to_chmod)}") -def s3(source: str, destination: str, recursive: bool) -> List[str]: +def s3(source: str, destination: str, recursive: bool) -> list[str]: """ Send or download the source to the destination in S3 """ diff --git a/ci/scripts/jenkins/should_rebuild_docker.py b/ci/scripts/jenkins/should_rebuild_docker.py index 238bea04ef20..0c608dc43a80 100755 --- a/ci/scripts/jenkins/should_rebuild_docker.py +++ b/ci/scripts/jenkins/should_rebuild_docker.py @@ -21,7 +21,7 @@ import json import logging import subprocess -from typing import Any, Dict, List +from typing import Any from cmd_utils import Sh, init_log from http_utils import get @@ -31,7 +31,7 @@ TEST_DATA = None -def docker_api(url: str) -> Dict[str, Any]: +def docker_api(url: str) -> dict[str, Any]: """ Run a paginated fetch from the public Docker Hub API """ @@ -81,7 +81,7 @@ def does_commit_exist(hash: str) -> bool: raise RuntimeError(f"Unexpected failure when running: {cmd}") -def find_hash_for_tag(tag: Dict[str, Any]) -> str: +def find_hash_for_tag(tag: dict[str, Any]) -> str: """ Split the hash off of a name like -