Skip to content

Conversation

charles-zablit
Copy link
Contributor

@charles-zablit charles-zablit commented Sep 4, 2025

This patch replaces list with its typing implementation, i.e list[str] becomes List[str].

Type hinting generic in the standard collection were introduced in Python 3.9, however the minimum supported Python version for lldb is 3.8. This patch will unblock the bots for Ubuntu 20.04, which run on Python 3.8.

@charles-zablit charles-zablit self-assigned this Sep 4, 2025
@charles-zablit charles-zablit added infrastructure Bugs about LLVM infrastructure lldb labels Sep 4, 2025
@llvmbot llvmbot added clang Clang issues not falling into any other category libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. clang:as-a-library libclang and C++ API testing-tools github:workflow third-party:benchmark labels Sep 4, 2025
@llvmbot
Copy link
Member

llvmbot commented Sep 4, 2025

@llvm/pr-subscribers-third-party-benchmark
@llvm/pr-subscribers-github-workflow
@llvm/pr-subscribers-testing-tools
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-lldb

Author: Charles Zablit (charles-zablit)

Changes

This patch replaces any occurences of lower case generic type hints with its typing implementation, i.e list[str] becomes List[str].

Type hinting generic in the standard collection were introduced in Python 3.9, however the minimum supported Python version is 3.8. This patch helps maintaining backwards compatibility with Python versions lower than 3.9 and will unblock the bots for Ubuntu 20.04, which ships with 3.8.


Patch is 34.18 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/156868.diff

23 Files Affected:

  • (modified) .ci/compute_projects.py (+3-4)
  • (modified) .ci/metrics/metrics.py (+3-2)
  • (modified) .github/workflows/commit-access-review.py (+2-2)
  • (modified) clang/bindings/python/clang/cindex.py (+11-9)
  • (modified) clang/docs/tools/dump_ast_matchers.py (+2-1)
  • (modified) cross-project-tests/debuginfo-tests/dexter/dex/dextIR/DextIR.py (+1-1)
  • (modified) libcxx/utils/generate_escaped_output_table.py (+5-5)
  • (modified) libcxx/utils/generate_extended_grapheme_cluster_table.py (+6-6)
  • (modified) libcxx/utils/generate_extended_grapheme_cluster_test.py (+5-5)
  • (modified) libcxx/utils/generate_indic_conjunct_break_table.py (+6-6)
  • (modified) libcxx/utils/generate_width_estimation_table.py (+5-5)
  • (modified) lldb/examples/python/templates/parsed_cmd.py (+3-2)
  • (modified) lldb/packages/Python/lldbsuite/test/decorators.py (+2-1)
  • (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py (+37-37)
  • (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py (+5-5)
  • (modified) lldb/test/API/functionalities/breakpoint/breakpoint_by_line_and_column/TestBreakpointByLineAndColumn.py (+3-1)
  • (modified) lldb/test/API/python_api/target/TestTargetAPI.py (+3-1)
  • (modified) lldb/test/API/terminal/TestSTTYBeforeAndAfter.py (+4-2)
  • (modified) llvm/utils/UpdateTestChecks/common.py (+2-2)
  • (modified) llvm/utils/lldbDataFormatters.py (+3-2)
  • (modified) llvm/utils/spirv-sim/spirv-sim.py (+5-3)
  • (modified) polly/lib/External/isl/isl_test_python.py (+7-6)
  • (modified) third-party/benchmark/tools/strip_asm.py (+2-1)
diff --git a/.ci/compute_projects.py b/.ci/compute_projects.py
index 40dd0507a9eaf..c90ef223843f6 100644
--- a/.ci/compute_projects.py
+++ b/.ci/compute_projects.py
@@ -7,6 +7,7 @@
 """
 
 from collections.abc import Set
+from typing import List
 import pathlib
 import platform
 import sys
@@ -115,8 +116,6 @@
     "lld": "check-lld",
     "flang": "check-flang",
     "libc": "check-libc",
-    "lld": "check-lld",
-    "lldb": "check-lldb",
     "mlir": "check-mlir",
     "openmp": "check-openmp",
     "polly": "check-polly",
@@ -204,7 +203,7 @@ def _compute_runtime_check_targets(projects_to_test: Set[str]) -> Set[str]:
     return check_targets
 
 
-def _get_modified_projects(modified_files: list[str]) -> Set[str]:
+def _get_modified_projects(modified_files: List[str]) -> Set[str]:
     modified_projects = set()
     for modified_file in modified_files:
         path_parts = pathlib.Path(modified_file).parts
@@ -222,7 +221,7 @@ def _get_modified_projects(modified_files: list[str]) -> Set[str]:
     return modified_projects
 
 
-def get_env_variables(modified_files: list[str], platform: str) -> Set[str]:
+def get_env_variables(modified_files: List[str], platform: str) -> Set[str]:
     modified_projects = _get_modified_projects(modified_files)
     projects_to_test = _compute_projects_to_test(modified_projects, platform)
     projects_to_build = _compute_projects_to_build(projects_to_test)
diff --git a/.ci/metrics/metrics.py b/.ci/metrics/metrics.py
index 143e6ab4cf46a..cb6309bd91224 100644
--- a/.ci/metrics/metrics.py
+++ b/.ci/metrics/metrics.py
@@ -1,3 +1,4 @@
+from typing import List, Tuple, Set
 import collections
 import datetime
 import github
@@ -72,8 +73,8 @@ class GaugeMetric:
 
 
 def github_get_metrics(
-    github_repo: github.Repository, last_workflows_seen_as_completed: set[int]
-) -> tuple[list[JobMetrics], int]:
+    github_repo: github.Repository, last_workflows_seen_as_completed: Set[int]
+) -> Tuple[List[JobMetrics], int]:
     """Gets the metrics for specified Github workflows.
 
     This function takes in a list of workflows to track, and optionally the
diff --git a/.github/workflows/commit-access-review.py b/.github/workflows/commit-access-review.py
index 4f539fe98004a..600541556ceba 100644
--- a/.github/workflows/commit-access-review.py
+++ b/.github/workflows/commit-access-review.py
@@ -9,13 +9,13 @@
 #
 # ===------------------------------------------------------------------------===#
 
+from typing import List
 import datetime
 import github
 import re
 import requests
 import time
 import sys
-import re
 
 
 class User:
@@ -64,7 +64,7 @@ def __repr__(self):
 
 def check_manual_requests(
     gh: github.Github, start_date: datetime.datetime
-) -> list[str]:
+) -> List[str]:
     """
     Return a list of users who have been asked since ``start_date`` if they
     want to keep their commit access or if they have applied for commit
diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py
index 824674309d262..353b7c833f86f 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -93,6 +93,8 @@
     Iterator,
     Literal,
     Optional,
+    List,
+    Tuple,
     Sequence,
     Type as TType,
     TypeVar,
@@ -106,9 +108,9 @@
 
     StrPath: TypeAlias = TUnion[str, os.PathLike[str]]
     LibFunc: TypeAlias = TUnion[
-        "tuple[str, Optional[list[Any]]]",
-        "tuple[str, Optional[list[Any]], Any]",
-        "tuple[str, Optional[list[Any]], Any, Callable[..., Any]]",
+        "Tuple[str, Optional[List[Any]]]",
+        "Tuple[str, Optional[List[Any]], Any]",
+        "Tuple[str, Optional[List[Any]], Any, Callable[..., Any]]",
     ]
 
     TSeq = TypeVar("TSeq", covariant=True)
@@ -2216,7 +2218,7 @@ def get_children(self) -> Iterator[Cursor]:
         """Return an iterator for accessing the children of this cursor."""
 
         # FIXME: Expose iteration from CIndex, PR6125.
-        def visitor(child: Cursor, _: Cursor, children: list[Cursor]) -> int:
+        def visitor(child: Cursor, _: Cursor, children: List[Cursor]) -> int:
             # FIXME: Document this assertion in API.
             assert not child.is_null()
 
@@ -2225,7 +2227,7 @@ def visitor(child: Cursor, _: Cursor, children: list[Cursor]) -> int:
             children.append(child)
             return 1  # continue
 
-        children: list[Cursor] = []
+        children: List[Cursor] = []
         conf.lib.clang_visitChildren(self, cursor_visit_callback(visitor), children)
         return iter(children)
 
@@ -2845,7 +2847,7 @@ def visitor(field: Cursor, _: Any) -> Literal[1]:
             fields.append(field)
             return 1  # continue
 
-        fields: list[Cursor] = []
+        fields: List[Cursor] = []
         conf.lib.clang_Type_visitFields(self, fields_visit_callback(visitor), fields)
         return iter(fields)
 
@@ -2860,7 +2862,7 @@ def visitor(base: Cursor, _: Any) -> Literal[1]:
             bases.append(base)
             return 1  # continue
 
-        bases: list[Cursor] = []
+        bases: List[Cursor] = []
         conf.lib.clang_visitCXXBaseClasses(self, fields_visit_callback(visitor), bases)
         return iter(bases)
 
@@ -2875,7 +2877,7 @@ def visitor(method: Cursor, _: Any) -> Literal[1]:
             methods.append(method)
             return 1  # continue
 
-        methods: list[Cursor] = []
+        methods: List[Cursor] = []
         conf.lib.clang_visitCXXMethods(self, fields_visit_callback(visitor), methods)
         return iter(methods)
 
@@ -3992,7 +3994,7 @@ def set_property(self, property, value):
 fields_visit_callback = CFUNCTYPE(c_int, Cursor, py_object)
 
 # Functions strictly alphabetical order.
-FUNCTION_LIST: list[LibFunc] = [
+FUNCTION_LIST: List[LibFunc] = [
     (
         "clang_annotateTokens",
         [TranslationUnit, POINTER(Token), c_uint, POINTER(Cursor)],
diff --git a/clang/docs/tools/dump_ast_matchers.py b/clang/docs/tools/dump_ast_matchers.py
index 46b7bb718ba08..a0e1882a962ec 100755
--- a/clang/docs/tools/dump_ast_matchers.py
+++ b/clang/docs/tools/dump_ast_matchers.py
@@ -6,6 +6,7 @@
 import collections
 import re
 import os
+from typing import Dict
 
 try:
     from urllib.request import urlopen
@@ -185,7 +186,7 @@ def add_matcher(result_type, name, args, comment, is_dyncast=False):
         lookup = result_type + name + esc(args)
 
     if dict.get(lookup) is None or len(dict.get(lookup)) < len(matcher_html):
-        dict[lookup] = matcher_html
+        Dict[lookup] = matcher_html
 
 
 def act_on_decl(declaration, comment, allowed_types):
diff --git a/cross-project-tests/debuginfo-tests/dexter/dex/dextIR/DextIR.py b/cross-project-tests/debuginfo-tests/dexter/dex/dextIR/DextIR.py
index 42500c4b9681d..98e8c93e0aa83 100644
--- a/cross-project-tests/debuginfo-tests/dexter/dex/dextIR/DextIR.py
+++ b/cross-project-tests/debuginfo-tests/dexter/dex/dextIR/DextIR.py
@@ -38,7 +38,7 @@ class DextIR:
     determine the debugging score for a given test.
 
     Args:
-        commands: { name (str), commands (list[CommandIR])
+        commands: { name (str), commands (List[CommandIR])
     """
 
     def __init__(
diff --git a/libcxx/utils/generate_escaped_output_table.py b/libcxx/utils/generate_escaped_output_table.py
index 59dd707ae6126..c618d4035064f 100755
--- a/libcxx/utils/generate_escaped_output_table.py
+++ b/libcxx/utils/generate_escaped_output_table.py
@@ -16,7 +16,7 @@
 from io import StringIO
 from pathlib import Path
 from dataclasses import dataclass
-from typing import Optional
+from typing import Optional, List
 import re
 import sys
 
@@ -60,7 +60,7 @@ def parsePropertyLine(inputLine: str) -> Optional[PropertyRange]:
         return None
 
 
-def compactPropertyRanges(input: list[PropertyRange]) -> list[PropertyRange]:
+def compactPropertyRanges(input: List[PropertyRange]) -> List[PropertyRange]:
     """
     Merges overlapping and consecutive ranges to one range.
 
@@ -242,8 +242,8 @@ def compactPropertyRanges(input: list[PropertyRange]) -> list[PropertyRange]:
 #endif // _LIBCPP___FORMAT_ESCAPED_OUTPUT_TABLE_H"""
 
 
-def property_ranges_to_table(ranges: list[PropertyRange]) -> list[Entry]:
-    result = list[Entry]()
+def property_ranges_to_table(ranges: List[PropertyRange]) -> List[Entry]:
+    result = List[Entry]()
     high = -1
     for range in sorted(ranges, key=lambda x: x.lower):
         # Validate overlapping ranges
@@ -265,7 +265,7 @@ def property_ranges_to_table(ranges: list[PropertyRange]) -> list[Entry]:
 
 
 def generate_cpp_data(
-    ranges: list[PropertyRange], unallocated: int, gap_lower: int, gap_upper: int
+    ranges: List[PropertyRange], unallocated: int, gap_lower: int, gap_upper: int
 ) -> str:
     result = StringIO()
     table = property_ranges_to_table(ranges)
diff --git a/libcxx/utils/generate_extended_grapheme_cluster_table.py b/libcxx/utils/generate_extended_grapheme_cluster_table.py
index eba88a4f48776..1bb598517fa7d 100755
--- a/libcxx/utils/generate_extended_grapheme_cluster_table.py
+++ b/libcxx/utils/generate_extended_grapheme_cluster_table.py
@@ -16,7 +16,7 @@
 from io import StringIO
 from pathlib import Path
 from dataclasses import dataclass
-from typing import Optional
+from typing import Optional, List
 import re
 import sys
 
@@ -54,7 +54,7 @@ def parsePropertyLine(inputLine: str) -> Optional[PropertyRange]:
         return None
 
 
-def compactPropertyRanges(input: list[PropertyRange]) -> list[PropertyRange]:
+def compactPropertyRanges(input: List[PropertyRange]) -> List[PropertyRange]:
     """
     Merges consecutive ranges with the same property to one range.
 
@@ -238,10 +238,10 @@ def compactPropertyRanges(input: list[PropertyRange]) -> list[PropertyRange]:
 
 
 def property_ranges_to_table(
-    ranges: list[PropertyRange], props: list[str]
-) -> list[Entry]:
+    ranges: List[PropertyRange], props: List[str]
+) -> List[Entry]:
     assert len(props) < 16
-    result = list[Entry]()
+    result = List[Entry]()
     high = -1
     for range in sorted(ranges, key=lambda x: x.lower):
         # Validate overlapping ranges
@@ -262,7 +262,7 @@ def property_ranges_to_table(
 cpp_entrytemplate = "    0x{:08x}"
 
 
-def generate_cpp_data(prop_name: str, ranges: list[PropertyRange]) -> str:
+def generate_cpp_data(prop_name: str, ranges: List[PropertyRange]) -> str:
     result = StringIO()
     prop_values = sorted(set(x.prop for x in ranges))
     table = property_ranges_to_table(ranges, prop_values)
diff --git a/libcxx/utils/generate_extended_grapheme_cluster_test.py b/libcxx/utils/generate_extended_grapheme_cluster_test.py
index e0a6003ecd53c..e83fa7e1ce722 100755
--- a/libcxx/utils/generate_extended_grapheme_cluster_test.py
+++ b/libcxx/utils/generate_extended_grapheme_cluster_test.py
@@ -15,17 +15,17 @@
 
 from pathlib import Path
 from dataclasses import dataclass, field
-from typing import Optional, TextIO
+from typing import Optional, TextIO, List
 import sys
 
 
 @dataclass
 class BreakTestItem:
-    code_points: list[int] = field(default_factory=list)
+    code_points: List[int] = field(default_factory=list)
     encoded: str = ""
-    breaks_utf8: list[int] = field(default_factory=list)
-    breaks_utf16: list[int] = field(default_factory=list)
-    breaks_utf32: list[int] = field(default_factory=list)
+    breaks_utf8: List[int] = field(default_factory=list)
+    breaks_utf16: List[int] = field(default_factory=list)
+    breaks_utf32: List[int] = field(default_factory=list)
 
 
 class CommentLine:
diff --git a/libcxx/utils/generate_indic_conjunct_break_table.py b/libcxx/utils/generate_indic_conjunct_break_table.py
index 580d8157ffebf..fc1ab26c42a4c 100755
--- a/libcxx/utils/generate_indic_conjunct_break_table.py
+++ b/libcxx/utils/generate_indic_conjunct_break_table.py
@@ -16,7 +16,7 @@
 from io import StringIO
 from pathlib import Path
 from dataclasses import dataclass
-from typing import Optional
+from typing import Optional, List
 import re
 import sys
 
@@ -54,7 +54,7 @@ def parsePropertyLine(inputLine: str) -> Optional[PropertyRange]:
 
 
 
-def compactPropertyRanges(input: list[PropertyRange]) -> list[PropertyRange]:
+def compactPropertyRanges(input: List[PropertyRange]) -> List[PropertyRange]:
     """
     Merges consecutive ranges with the same property to one range.
 
@@ -231,10 +231,10 @@ def compactPropertyRanges(input: list[PropertyRange]) -> list[PropertyRange]:
 
 
 def property_ranges_to_table(
-    ranges: list[PropertyRange], props: list[str]
-) -> list[Entry]:
+    ranges: List[PropertyRange], props: List[str]
+) -> List[Entry]:
     assert len(props) < 4
-    result = list[Entry]()
+    result = List[Entry]()
     high = -1
     for range in sorted(ranges, key=lambda x: x.lower):
         # Validate overlapping ranges
@@ -255,7 +255,7 @@ def property_ranges_to_table(
 cpp_entrytemplate = "    0x{:08x}"
 
 
-def generate_cpp_data(prop_name: str, ranges: list[PropertyRange]) -> str:
+def generate_cpp_data(prop_name: str, ranges: List[PropertyRange]) -> str:
     result = StringIO()
     prop_values = sorted(set(x.prop for x in ranges))
     table = property_ranges_to_table(ranges, prop_values)
diff --git a/libcxx/utils/generate_width_estimation_table.py b/libcxx/utils/generate_width_estimation_table.py
index f81f0ba77489e..c1b1aa683db63 100644
--- a/libcxx/utils/generate_width_estimation_table.py
+++ b/libcxx/utils/generate_width_estimation_table.py
@@ -16,7 +16,7 @@
 from io import StringIO
 from pathlib import Path
 from dataclasses import dataclass
-from typing import Optional
+from typing import Optional, List
 import re
 import sys
 
@@ -75,7 +75,7 @@ def parsePropertyLine(inputLine: str) -> Optional[PropertyRange]:
         return None
 
 
-def compactPropertyRanges(input: list[PropertyRange]) -> list[PropertyRange]:
+def compactPropertyRanges(input: List[PropertyRange]) -> List[PropertyRange]:
     """
     Merges overlapping and consecutive ranges to one range.
 
@@ -268,14 +268,14 @@ def compactPropertyRanges(input: list[PropertyRange]) -> list[PropertyRange]:
 #endif // _LIBCPP___FORMAT_WIDTH_ESTIMATION_TABLE_H"""
 
 
-def property_ranges_to_table(ranges: list[PropertyRange]) -> list[Entry]:
+def property_ranges_to_table(ranges: List[PropertyRange]) -> List[Entry]:
     # The maximum value that can be encoded in the available bits in the
     # __entries table.
     upper_bound = 0x3FFFF
     # The maximum offset in an __entries entry. Larger offsets will be
     # splitted and stored in multiple entries.
     chunk = 16384
-    result = list[Entry]()
+    result = List[Entry]()
     high = -1
     for range in sorted(ranges, key=lambda x: x.lower):
         # Validate overlapping ranges
@@ -297,7 +297,7 @@ def property_ranges_to_table(ranges: list[PropertyRange]) -> list[Entry]:
 cpp_entrytemplate = "    0x{:08x} /* {:08x} - {:08x} [{:>5}] */"
 
 
-def generate_cpp_data(ranges: list[PropertyRange], upper_bound: int) -> str:
+def generate_cpp_data(ranges: List[PropertyRange], upper_bound: int) -> str:
     result = StringIO()
     table = property_ranges_to_table(ranges)
     result.write(
diff --git a/lldb/examples/python/templates/parsed_cmd.py b/lldb/examples/python/templates/parsed_cmd.py
index 13d6eae405c08..56122881c5396 100644
--- a/lldb/examples/python/templates/parsed_cmd.py
+++ b/lldb/examples/python/templates/parsed_cmd.py
@@ -109,6 +109,7 @@ def handle_argument_completion(self, args, arg_pos, cursor_pos):
 import inspect
 import lldb
 import sys
+from typing import Dict
 from abc import abstractmethod
 
 # Some methods to translate common value types.  Should return a
@@ -350,9 +351,9 @@ def add_option(self, short_option, long_option, help, default,
                 "default" : default}
 
         if enum_values:
-            dict["enum_values"] = enum_values
+            Dict["enum_values"] = enum_values
         if groups:
-            dict["groups"] = groups
+            Dict["groups"] = groups
 
         self.options_dict[long_option] = dict
 
diff --git a/lldb/packages/Python/lldbsuite/test/decorators.py b/lldb/packages/Python/lldbsuite/test/decorators.py
index a391319ca9b0e..ff96673b8e6e3 100644
--- a/lldb/packages/Python/lldbsuite/test/decorators.py
+++ b/lldb/packages/Python/lldbsuite/test/decorators.py
@@ -1,6 +1,7 @@
 # System modules
 from functools import wraps
 from packaging import version
+from typing import List
 import ctypes
 import locale
 import os
@@ -1148,7 +1149,7 @@ def is_feature_enabled():
     return skipTestIfFn(is_feature_enabled)
 
 
-def skipIfBuildType(types: list[str]):
+def skipIfBuildType(types: List[str]):
     """Skip tests if built in a specific CMAKE_BUILD_TYPE.
 
     Supported types include 'Release', 'RelWithDebInfo', 'Debug', 'MinSizeRel'.
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
index 9786678aa53f9..3643c363bd6df 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
@@ -12,12 +12,12 @@
 import sys
 import threading
 import time
-from typing import Any, Optional, Union, BinaryIO, TextIO
+from typing import Any, Optional, Union, BinaryIO, TextIO, List, Dict, Tuple
 
 ## DAP type references
-Event = dict[str, Any]
-Request = dict[str, Any]
-Response = dict[str, Any]
+Event = Dict[str, Any]
+Request = Dict[str, Any]
+Response = Dict[str, Any]
 ProtocolMessage = Union[Event, Request, Response]
 
 
@@ -144,7 +144,7 @@ def __init__(
         self,
         recv: BinaryIO,
         send: BinaryIO,
-        init_commands: list[str],
+        init_commands: List[str],
         log_file: Optional[TextIO] = None,
     ):
         # For debugging test failures, try setting `trace_file = sys.stderr`.
@@ -152,20 +152,20 @@ def __init__(
         self.log_file = log_file
         self.send = send
         self.recv = recv
-        self.recv_packets: list[Optional[ProtocolMessage]] = []
+        self.recv_packets: List[Optional[ProtocolMessage]] = []
         self.recv_condition = threading.Condition()
         self.recv_thread = threading.Thread(target=self._read_packet_thread)
         self.process_event_body = None
         self.exit_status: Optional[int] = None
-        self.capabilities: dict[str, Any] = {}
-        self.progress_events: list[Event] = []
+        self.capabilities: Dict[str, Any] = {}
+        self.progress_events: List[Event] = []
         self.reverse_requests = []
         self.sequence = 1
         self.threads = None
         self.thread_stop_reasons = {}
         self.recv_thread.start()
         self.output_condition = threading.Condition()
-        self.output: dict[str, list[str]] = {}
+        self.output: Dict[str, List[str]] = {}
         self.configuration_done_sent = False
         self.initialized = False
         self.frame_scopes = {}
@@ -319,7 +319,7 @@ def _process_continued(self, all_threads_continued: bool):
         if all_threads_continued:
             self.thread_stop_reasons = {}
 
-    def _update_verified_breakpoints(self, breakpoints: list[Event]):
+    def _update_verified_breakpoints(self, breakpoints: List[Event]):
         for breakpoint in breakpoints:
             if "id" in breakpoint:
                 self.resolved_breakpoints[str(breakpoint["id"])] = breakpoint.get(
@@ -347,7 +347,7 @@ def send_packet(self, command_dict: Request, set_sequence=True):
     def recv_packet(
         self,
         filter_type: Optional[str] = None,
-        filter_event: Optional[Union[str, list[str]]] = None,
+        filter_event: Optional[Union[str, List[str]]] = None,
         timeout: Optional[float] = None,
     ) -> Optional[ProtocolMessage]:
         """Get a JSON packet from the VSCode debug adapter. This function
@@ -435,7 +435,7 @@ def send_recv(self, command):
         return None
 
     def wait_for_event(
-        self, filter: Union[str, list[str]], timeout: Optional[float] = None
+        self, filter: Union[str, List[str]], timeout: Optional[float] = None
     ) -> Optional[Event]:
         """Wait for the first event that matches the filter."""
         return self.recv_packet(
@@ -444,7 +444,7 @@ def wait_for_event(
 
     def wait_for_stopped(
         self, timeout: Optional[float] = None
-    ) -> Optional[list[Event]]:
+    ) -> Optional[List[Event]]:
         stopped_events = []
         stopped_event = self.wait_for_event(
             filter=["stopped", "...
[truncated]

@DavidSpickett
Copy link
Collaborator

from typing import List

Is this something we install or something that's included with Python 3.8+?

Copy link
Contributor

@DeinAlptraum DeinAlptraum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re: Python bindings (clang/bindings/python/clang/cindex.py)
We from __future__ import annotations at the start of cindex.py which lets us use the PEP 585 features (among others) even in Pyhon 3.8.
We have a CI job that runs the libclang-python tests against 3.8 and 3.13, see here:
https://github.com/llvm/llvm-project/actions/workflows/libclang-python-tests.yml
which has always been green with those annotations.

I have also tested this locally, and I can successfully run both the cindex tests and the mypy type checker on it with Python 3.8. (removing the future import produces the problems your PR would have resolved)

Besides, I see no reference to the libclang python tests in the build log you've linked.
I'd thus like to ask you to remove the changes to cindex.py from this PR.

Sidenote regarding the other files (which I'm not maintainer for, so cannot say much about them): consider doing the same thing there, to similarly import from future, instead of changing all generic collection types.

@DeinAlptraum
Copy link
Contributor

@DavidSpickett the typing module is part of the standard library, so there is no need to install it

Copy link
Contributor

@boomanaiden154 boomanaiden154 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you have bots for this, please address specific failures rather than grepping through the entire monorepo for these constructs. A bunch of the files you have hit here (like the ones related to CI) will never be run as part of an LLVM build and are always run with python 3.10+ and thus don't need to be fixed.

@charles-zablit charles-zablit force-pushed the charles-zablit/lldb/fix-3.9-feature branch from 4be53b4 to 0e9fdef Compare September 4, 2025 13:18
@charles-zablit
Copy link
Contributor Author

Thanks for the feedback, I have made sure to keep the changes to a minimum in the new revision.

@DeinAlptraum DeinAlptraum dismissed their stale review September 4, 2025 13:20

The changes I requested have been made. The PR now does not affect the parts I am maintaining anymore, so I am removing myself as reviewer.

@DeinAlptraum DeinAlptraum requested review from DeinAlptraum and removed request for DeinAlptraum September 4, 2025 13:21
Copy link
Contributor

@boomanaiden154 boomanaiden154 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Please wait for one of the LLDB reviewers to stamp before merging.

@DavidSpickett
Copy link
Collaborator

LLDB reviewer here, I am not very familiar with Python typing but -

We from future import annotations at the start of cindex.py which lets us use the PEP 585 features (among others) even in Pyhon 3.8.

Can we do this in the lldb file as well? When the minimum becomes whatever it needs to be to remove that statement, it'll be easy to find.

Also change the title tag to [lldb].

@h-vetinari
Copy link
Contributor

however the minimum supported Python version for lldb is 3.8.

Python 3.8 is EOL since over a year, and python 3.9 will be EOL in a month. The better solution would be to not keep using python past its upstream lifecycle of 5 years, which should be plenty for tip-of-tree.

@charles-zablit charles-zablit force-pushed the charles-zablit/lldb/fix-3.9-feature branch from 0e9fdef to 46503ba Compare September 5, 2025 10:56
Copy link

github-actions bot commented Sep 5, 2025

✅ With the latest revision this PR passed the Python code formatter.

@charles-zablit charles-zablit force-pushed the charles-zablit/lldb/fix-3.9-feature branch from 46503ba to 54f31b5 Compare September 5, 2025 11:02
@charles-zablit charles-zablit changed the title [python] remove Python 3.9 specific typing annotations [lldb] fix Python 3.9+ specific typing annotations Sep 5, 2025
@charles-zablit
Copy link
Contributor Author

LLDB reviewer here, I am not very familiar with Python typing but -

We from future import annotations at the start of cindex.py which lets us use the PEP 585 features (among others) even in Pyhon 3.8.

Can we do this in the lldb file as well? When the minimum becomes whatever it needs to be to remove that statement, it'll be easy to find.

Also change the title tag to [lldb].

Switched to the import from __future__ approach. Using list instead of List has been common practice for a while. As you said, we can remove the annotation once we drop support for 3.8.

Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@charles-zablit charles-zablit merged commit 25ebdfe into llvm:main Sep 5, 2025
9 checks passed
charles-zablit added a commit to charles-zablit/llvm-project that referenced this pull request Sep 5, 2025
This patch replaces `list` with its `typing` implementation, i.e
`list[str]` becomes `List[str]`.

[Type hinting generic in the standard collection were introduced in
Python 3.9](https://peps.python.org/pep-0585/), however the minimum
supported Python version for lldb is 3.8. This patch will unblock the
[bots for Ubuntu
20.04](https://ci.swift.org/view/Swift%20rebranch/job/oss-swift-rebranch-package-ubuntu-20_04/2847/consoleText),
which run on Python 3.8.
charles-zablit added a commit to swiftlang/llvm-project that referenced this pull request Sep 5, 2025
…-3.9-feature-to-21.x

🍒 [lldb] fix Python 3.9+ specific typing annotations (llvm#156868)
@DavidSpickett
Copy link
Collaborator

Python 3.8 is EOL since over a year, and python 3.9 will be EOL in a month. The better solution would be to not keep using python past its upstream lifecycle of 5 years, which should be plenty for tip-of-tree.

I don't have the time to propose an update myself right now but yes this would help.

Last time we updated was 1-2 years ago (https://discourse.llvm.org/t/rfc-upgrading-llvms-minimum-required-python-version/67571). We probably couldn't use the very latest due to various distro timings and so chose something fairly close to EOL even at the time.

@charles-zablit
Copy link
Contributor Author

Python 3.8 is EOL since over a year, and python 3.9 will be EOL in a month. The better solution would be to not keep using python past its upstream lifecycle of 5 years, which should be plenty for tip-of-tree.

I don't have the time to propose an update myself right now but yes this would help.

Last time we updated was 1-2 years ago (https://discourse.llvm.org/t/rfc-upgrading-llvms-minimum-required-python-version/67571). We probably couldn't use the very latest due to various distro timings and so chose something fairly close to EOL even at the time.

In this forum post we set the minimum python to 3.8 for lldb (and not higher) because of Ubuntu (Focal), macOS and Redhat. Now, (Focal) is EOL, macOS uses Python 3.9 and RHEL 9 uses Python 3.9 as well.

@DavidSpickett
Copy link
Collaborator

Yes, Python being embedded into LLDB does mean there are more considerations than the rest of LLVM where it's primarily for running tests.

(though Jonas' work towards using only the stable Python APIs is changing this)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:as-a-library libclang and C++ API clang Clang issues not falling into any other category github:workflow infrastructure Bugs about LLVM infrastructure libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. lldb testing-tools third-party:benchmark
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants