From 11fc9983688abff0446988ec3215e258e0e573a8 Mon Sep 17 00:00:00 2001 From: Thaddeus Crews Date: Sun, 24 Nov 2024 10:14:16 -0600 Subject: [PATCH] SCons: Integrate `annotations` where relevant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Expand Ruff linter to catch & upgrade legacy type-hint syntax --- core/profiling/SCsub | 5 +- doc/tools/doc_status.py | 26 ++-- doc/tools/make_rst.py | 113 +++++++++--------- methods.py | 14 ++- misc/scripts/char_range_fetch.py | 25 ++-- misc/scripts/ucaps_fetch.py | 13 +- misc/scripts/unicode_ranges_fetch.py | 13 +- .../mono/build_scripts/build_assemblies.py | 4 +- pyproject.toml | 7 +- 9 files changed, 116 insertions(+), 104 deletions(-) mode change 100755 => 100644 doc/tools/make_rst.py diff --git a/core/profiling/SCsub b/core/profiling/SCsub index 1ddc0c05659..80fa6e9a78f 100644 --- a/core/profiling/SCsub +++ b/core/profiling/SCsub @@ -1,8 +1,9 @@ #!/usr/bin/env python +from __future__ import annotations + from misc.utility.scons_hints import * import pathlib -from typing import Tuple import profiling_builders @@ -11,7 +12,7 @@ Import("env") env.add_source_files(env.core_sources, "*.cpp") -def get_profiler_and_path_from_path(path: pathlib.Path) -> Tuple[str, pathlib.Path]: +def get_profiler_and_path_from_path(path: pathlib.Path) -> tuple[str, pathlib.Path]: if not path.is_dir(): print("profiler_path must be empty or point to a directory.") Exit(255) diff --git a/doc/tools/doc_status.py b/doc/tools/doc_status.py index 960778dec98..99de6e9dd4e 100755 --- a/doc/tools/doc_status.py +++ b/doc/tools/doc_status.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +from __future__ import annotations import fnmatch import math @@ -6,7 +7,6 @@ import os import re import sys import xml.etree.ElementTree as ET -from typing import Dict, List, Set sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")) @@ -137,7 +137,7 @@ class ClassStatusProgress: self.described: int = described self.total: int = total - def __add__(self, other: "ClassStatusProgress"): + def __add__(self, other: ClassStatusProgress): return ClassStatusProgress(self.described + other.described, self.total + other.total) def increment(self, described: bool): @@ -178,7 +178,7 @@ class ClassStatus: self.name: str = name self.has_brief_description: bool = True self.has_description: bool = True - self.progresses: Dict[str, ClassStatusProgress] = { + self.progresses: dict[str, ClassStatusProgress] = { "methods": ClassStatusProgress(), "constants": ClassStatusProgress(), "members": ClassStatusProgress(), @@ -188,7 +188,7 @@ class ClassStatus: "constructors": ClassStatusProgress(), } - def __add__(self, other: "ClassStatus"): + def __add__(self, other: ClassStatus): new_status = ClassStatus() new_status.name = self.name new_status.has_brief_description = self.has_brief_description and other.has_brief_description @@ -213,8 +213,8 @@ class ClassStatus: sum += self.progresses[k].total return sum < 1 - def make_output(self) -> Dict[str, str]: - output: Dict[str, str] = {} + def make_output(self) -> dict[str, str]: + output: dict[str, str] = {} output["name"] = color("name", self.name) ok_string = color("part_good", "OK") @@ -295,8 +295,8 @@ class ClassStatus: # Arguments # ################################################################################ -input_file_list: List[str] = [] -input_class_list: List[str] = [] +input_file_list: list[str] = [] +input_class_list: list[str] = [] merged_file: str = "" for arg in sys.argv[1:]: @@ -372,8 +372,8 @@ if len(input_file_list) < 1 or flags["h"]: # Parse class list # ################################################################################ -class_names: List[str] = [] -classes: Dict[str, ET.Element] = {} +class_names: list[str] = [] +classes: dict[str, ET.Element] = {} for file in input_file_list: tree = ET.parse(file) @@ -389,7 +389,7 @@ class_names.sort() if len(input_class_list) < 1: input_class_list = ["*"] -filtered_classes_set: Set[str] = set() +filtered_classes_set: set[str] = set() for pattern in input_class_list: filtered_classes_set |= set(fnmatch.filter(class_names, pattern)) filtered_classes = list(filtered_classes_set) @@ -419,7 +419,7 @@ for cn in filtered_classes: continue out = status.make_output() - row: List[str] = [] + row: list[str] = [] for column in table_columns: if column in out: row.append(out[column]) @@ -456,7 +456,7 @@ if flags["a"]: # without having to scroll back to the top. table.append(table_column_names) -table_column_sizes: List[int] = [] +table_column_sizes: list[int] = [] for row in table: for cell_i, cell in enumerate(row): if cell_i >= len(table_column_sizes): diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py old mode 100755 new mode 100644 index d15e1ae486d..3f704bddd3d --- a/doc/tools/make_rst.py +++ b/doc/tools/make_rst.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # This script makes RST files from the XML class reference for use with the online docs. +from __future__ import annotations import argparse import os @@ -8,7 +9,7 @@ import re import sys import xml.etree.ElementTree as ET from collections import OrderedDict -from typing import Any, Dict, List, Optional, TextIO, Tuple, Union +from typing import Any, TextIO sys.path.insert(0, root_directory := os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")) @@ -90,10 +91,10 @@ BASE_STRINGS = [ # See also `make_rst_class()` and `editor/doc/editor_help.cpp`. "[b]Note:[/b] The returned array is [i]copied[/i] and any changes to it will not update the original property value. See [%s] for more details.", ] -strings_l10n: Dict[str, str] = {} +strings_l10n: dict[str, str] = {} writing_translation = False -CLASS_GROUPS: Dict[str, str] = { +CLASS_GROUPS: dict[str, str] = { "global": "Globals", "node": "Nodes", "resource": "Resources", @@ -101,21 +102,21 @@ CLASS_GROUPS: Dict[str, str] = { "editor": "Editor-only", "variant": "Variant types", } -CLASS_GROUPS_BASE: Dict[str, str] = { +CLASS_GROUPS_BASE: dict[str, str] = { "node": "Node", "resource": "Resource", "object": "Object", "variant": "Variant", } # Sync with editor\register_editor_types.cpp -EDITOR_CLASSES: List[str] = [ +EDITOR_CLASSES: list[str] = [ "FileSystemDock", "ScriptCreateDialog", "ScriptEditor", "ScriptEditorBase", ] # Sync with the types mentioned in https://docs.godotengine.org/en/stable/tutorials/scripting/c_sharp/c_sharp_differences.html -CLASSES_WITH_CSHARP_DIFFERENCES: List[str] = [ +CLASSES_WITH_CSHARP_DIFFERENCES: list[str] = [ "@GlobalScope", "String", "StringName", @@ -147,7 +148,7 @@ CLASSES_WITH_CSHARP_DIFFERENCES: List[str] = [ "Variant", ] -PACKED_ARRAY_TYPES: List[str] = [ +PACKED_ARRAY_TYPES: list[str] = [ "PackedByteArray", "PackedColorArray", "PackedFloat32Array", @@ -425,7 +426,7 @@ class State: self.current_class = "" - def parse_params(self, root: ET.Element, context: str) -> List["ParameterDef"]: + def parse_params(self, root: ET.Element, context: str) -> list[ParameterDef]: param_elements = root.findall("param") params: Any = [None] * len(param_elements) @@ -443,7 +444,7 @@ class State: params[index] = ParameterDef(param_name, type_name, default) - cast: List[ParameterDef] = params + cast: list[ParameterDef] = params return cast @@ -461,7 +462,7 @@ class TagState: class TypeName: - def __init__(self, type_name: str, enum: Optional[str] = None, is_bitfield: bool = False) -> None: + def __init__(self, type_name: str, enum: str | None = None, is_bitfield: bool = False) -> None: self.type_name = type_name self.enum = enum self.is_bitfield = is_bitfield @@ -475,7 +476,7 @@ class TypeName: return make_type(self.type_name, state) @classmethod - def from_element(cls, element: ET.Element) -> "TypeName": + def from_element(cls, element: ET.Element) -> TypeName: return cls(element.attrib["type"], element.get("enum"), element.get("is_bitfield") == "true") @@ -487,8 +488,8 @@ class DefinitionBase: ) -> None: self.definition_name = definition_name self.name = name - self.deprecated: Optional[str] = None - self.experimental: Optional[str] = None + self.deprecated: str | None = None + self.experimental: str | None = None class PropertyDef(DefinitionBase): @@ -496,11 +497,11 @@ class PropertyDef(DefinitionBase): self, name: str, type_name: TypeName, - setter: Optional[str], - getter: Optional[str], - text: Optional[str], - default_value: Optional[str], - overrides: Optional[str], + setter: str | None, + getter: str | None, + text: str | None, + default_value: str | None, + overrides: str | None, ) -> None: super().__init__("property", name) @@ -513,7 +514,7 @@ class PropertyDef(DefinitionBase): class ParameterDef(DefinitionBase): - def __init__(self, name: str, type_name: TypeName, default_value: Optional[str]) -> None: + def __init__(self, name: str, type_name: TypeName, default_value: str | None) -> None: super().__init__("parameter", name) self.type_name = type_name @@ -521,7 +522,7 @@ class ParameterDef(DefinitionBase): class SignalDef(DefinitionBase): - def __init__(self, name: str, parameters: List[ParameterDef], description: Optional[str]) -> None: + def __init__(self, name: str, parameters: list[ParameterDef], description: str | None) -> None: super().__init__("signal", name) self.parameters = parameters @@ -532,9 +533,9 @@ class AnnotationDef(DefinitionBase): def __init__( self, name: str, - parameters: List[ParameterDef], - description: Optional[str], - qualifiers: Optional[str], + parameters: list[ParameterDef], + description: str | None, + qualifiers: str | None, ) -> None: super().__init__("annotation", name) @@ -548,9 +549,9 @@ class MethodDef(DefinitionBase): self, name: str, return_type: TypeName, - parameters: List[ParameterDef], - description: Optional[str], - qualifiers: Optional[str], + parameters: list[ParameterDef], + description: str | None, + qualifiers: str | None, ) -> None: super().__init__("method", name) @@ -561,7 +562,7 @@ class MethodDef(DefinitionBase): class ConstantDef(DefinitionBase): - def __init__(self, name: str, value: str, text: Optional[str], bitfield: bool) -> None: + def __init__(self, name: str, value: str, text: str | None, bitfield: bool) -> None: super().__init__("constant", name) self.value = value @@ -580,7 +581,7 @@ class EnumDef(DefinitionBase): class ThemeItemDef(DefinitionBase): def __init__( - self, name: str, type_name: TypeName, data_name: str, text: Optional[str], default_value: Optional[str] + self, name: str, type_name: TypeName, data_name: str, text: str | None, default_value: str | None ) -> None: super().__init__("theme property", name) @@ -600,17 +601,17 @@ class ClassDef(DefinitionBase): self.constants: OrderedDict[str, ConstantDef] = OrderedDict() self.enums: OrderedDict[str, EnumDef] = OrderedDict() self.properties: OrderedDict[str, PropertyDef] = OrderedDict() - self.constructors: OrderedDict[str, List[MethodDef]] = OrderedDict() - self.methods: OrderedDict[str, List[MethodDef]] = OrderedDict() - self.operators: OrderedDict[str, List[MethodDef]] = OrderedDict() + self.constructors: OrderedDict[str, list[MethodDef]] = OrderedDict() + self.methods: OrderedDict[str, list[MethodDef]] = OrderedDict() + self.operators: OrderedDict[str, list[MethodDef]] = OrderedDict() self.signals: OrderedDict[str, SignalDef] = OrderedDict() - self.annotations: OrderedDict[str, List[AnnotationDef]] = OrderedDict() + self.annotations: OrderedDict[str, list[AnnotationDef]] = OrderedDict() self.theme_items: OrderedDict[str, ThemeItemDef] = OrderedDict() - self.inherits: Optional[str] = None - self.brief_description: Optional[str] = None - self.description: Optional[str] = None - self.tutorials: List[Tuple[str, str]] = [] - self.keywords: Optional[str] = None + self.inherits: str | None = None + self.brief_description: str | None = None + self.description: str | None = None + self.tutorials: list[tuple[str, str]] = [] + self.keywords: str | None = None # Used to match the class with XML source for output filtering purposes. self.filepath: str = "" @@ -656,7 +657,7 @@ class ClassDef(DefinitionBase): # which don't necessarily need C# examples. class ScriptLanguageParityCheck: def __init__(self) -> None: - self.hit_map: OrderedDict[str, List[Tuple[DefinitionBase, str]]] = OrderedDict() + self.hit_map: OrderedDict[str, list[tuple[DefinitionBase, str]]] = OrderedDict() self.hit_count = 0 def add_hit(self, class_name: str, context: DefinitionBase, error: str, state: State) -> None: @@ -727,7 +728,7 @@ def main() -> None: print("Checking for errors in the XML class reference...") - file_list: List[str] = [] + file_list: list[str] = [] for path in args.path: # Cut off trailing slashes so os.path.basename doesn't choke. @@ -751,7 +752,7 @@ def main() -> None: file_list.append(path) - classes: Dict[str, Tuple[ET.Element, str]] = {} + classes: dict[str, tuple[ET.Element, str]] = {} state = State() for cur_file in file_list: @@ -784,7 +785,7 @@ def main() -> None: print("Generating the RST class reference...") - grouped_classes: Dict[str, List[str]] = {} + grouped_classes: dict[str, list[str]] = {} for class_name, class_def in state.classes.items(): if args.filter and not pattern.search(class_def.filepath): @@ -947,7 +948,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: f.write("\n\n") # Descendants - inherited: List[str] = [] + inherited: list[str] = [] for c in state.classes.values(): if c.inherits and c.inherits.strip() == class_name: inherited.append(c.name) @@ -1008,7 +1009,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: ### REFERENCE TABLES ### # Reused container for reference tables. - ml: List[Tuple[Optional[str], ...]] = [] + ml: list[tuple[str | None, ...]] = [] # Properties reference table if len(class_def.properties) > 0: @@ -1544,8 +1545,8 @@ def make_enum(t: str, is_bitfield: bool, state: State) -> str: def make_method_signature( - class_def: ClassDef, definition: Union[AnnotationDef, MethodDef, SignalDef], ref_type: str, state: State -) -> Tuple[str, str]: + class_def: ClassDef, definition: AnnotationDef | MethodDef | SignalDef, ref_type: str, state: State +) -> tuple[str, str]: ret_type = "" if isinstance(definition, MethodDef): @@ -1611,7 +1612,7 @@ def make_setter_signature(class_def: ClassDef, property_def: PropertyDef, state: setter = class_def.methods[property_def.setter][0] # Otherwise we fake it with the information we have available. else: - setter_params: List[ParameterDef] = [] + setter_params: list[ParameterDef] = [] setter_params.append(ParameterDef("value", property_def.type_name, None)) setter = MethodDef(property_def.setter, TypeName("void"), setter_params, None, None) @@ -1628,7 +1629,7 @@ def make_getter_signature(class_def: ClassDef, property_def: PropertyDef, state: getter = class_def.methods[property_def.getter][0] # Otherwise we fake it with the information we have available. else: - getter_params: List[ParameterDef] = [] + getter_params: list[ParameterDef] = [] getter = MethodDef(property_def.getter, property_def.type_name, getter_params, None, None) ret_type, signature = make_method_signature(class_def, getter, "", state) @@ -1727,7 +1728,7 @@ def make_link(url: str, title: str) -> str: return f"`{url} <{url}>`__" -def make_rst_index(grouped_classes: Dict[str, List[str]], dry_run: bool, output_dir: str) -> None: +def make_rst_index(grouped_classes: dict[str, list[str]], dry_run: bool, output_dir: str) -> None: with open( os.devnull if dry_run else os.path.join(output_dir, "index.rst"), "w", encoding="utf-8", newline="\n" ) as f: @@ -1792,7 +1793,7 @@ RESERVED_CROSSLINK_TAGS = [ ] -def is_in_tagset(tag_text: str, tagset: List[str]) -> bool: +def is_in_tagset(tag_text: str, tagset: list[str]) -> bool: for tag in tagset: # Complete match. if tag_text == tag: @@ -1834,7 +1835,7 @@ def get_tag_and_args(tag_text: str) -> TagState: return TagState(tag_text, tag_name, arguments, closing) -def parse_link_target(link_target: str, state: State, context_name: str) -> List[str]: +def parse_link_target(link_target: str, state: State, context_name: str) -> list[str]: if link_target.find(".") != -1: return link_target.split(".") else: @@ -2082,7 +2083,7 @@ def format_text_block( valid_param_context = isinstance(context, (MethodDef, SignalDef, AnnotationDef)) if valid_param_context: - context_params: List[ParameterDef] = context.parameters # type: ignore + context_params: list[ParameterDef] = context.parameters # type: ignore for param_def in context_params: if param_def.name == inside_code_text: print_warning( @@ -2242,7 +2243,7 @@ def format_text_block( state, ) else: - context_params: List[ParameterDef] = context.parameters # type: ignore + context_params: list[ParameterDef] = context.parameters # type: ignore found = False for param_def in context_params: if param_def.name == link_target: @@ -2407,7 +2408,7 @@ def format_text_block( return text -def preformat_text_block(text: str, state: State) -> Optional[str]: +def preformat_text_block(text: str, state: State) -> str | None: result = "" codeblock_tag = "" indent_level = 0 @@ -2457,7 +2458,7 @@ def preformat_text_block(text: str, state: State) -> Optional[str]: return result -def format_context_name(context: Union[DefinitionBase, None]) -> str: +def format_context_name(context: DefinitionBase | None) -> str: context_name: str = "unknown context" if context is not None: context_name = f'{context.definition_name} "{context.name}" description' @@ -2499,7 +2500,7 @@ def escape_rst(text: str, until_pos: int = -1) -> str: return text -def format_table(f: TextIO, data: List[Tuple[Optional[str], ...]], remove_empty_columns: bool = False) -> None: +def format_table(f: TextIO, data: list[tuple[str | None, ...]], remove_empty_columns: bool = False) -> None: if len(data) == 0: return @@ -2544,7 +2545,7 @@ def format_table(f: TextIO, data: List[Tuple[Optional[str], ...]], remove_empty_ f.write("\n") -def sanitize_class_name(dirty_name: str, is_file_name=False) -> str: +def sanitize_class_name(dirty_name: str, is_file_name: bool = False) -> str: if is_file_name: return dirty_name.lower().replace('"', "").replace("/", "--") else: diff --git a/methods.py b/methods.py index 858c7681bbf..3caabfce1be 100644 --- a/methods.py +++ b/methods.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import atexit import contextlib import glob @@ -9,9 +11,9 @@ import sys import textwrap import zlib from collections import OrderedDict -from io import StringIO, TextIOBase +from io import StringIO from pathlib import Path -from typing import Generator, List, Optional, Union, cast +from typing import Generator, TextIO, cast from misc.utility.color import print_error, print_info, print_warning from platform_methods import detect_arch @@ -1553,8 +1555,8 @@ def generate_copyright_header(filename: str) -> str: @contextlib.contextmanager def generated_wrapper( path: str, - guard: Optional[bool] = None, -) -> Generator[TextIOBase, None, None]: + guard: bool | None = None, +) -> Generator[TextIO, None, None]: """ Wrapper class to automatically handle copyright headers and header guards for generated scripts. Meant to be invoked via `with` statement similar to @@ -1626,13 +1628,13 @@ def to_escaped_cstring(value: str) -> str: return value.translate(C_ESCAPE_TABLE) -def to_raw_cstring(value: Union[str, List[str]]) -> str: +def to_raw_cstring(value: str | list[str]) -> str: MAX_LITERAL = 16 * 1024 if isinstance(value, list): value = "\n".join(value) + "\n" - split: List[bytes] = [] + split: list[bytes] = [] offset = 0 encoded = value.encode() diff --git a/misc/scripts/char_range_fetch.py b/misc/scripts/char_range_fetch.py index 899fb9ee789..0f135b2b276 100755 --- a/misc/scripts/char_range_fetch.py +++ b/misc/scripts/char_range_fetch.py @@ -4,10 +4,11 @@ # the Unicode Character Database to the `char_range.inc` file. # NOTE: This script is deliberately not integrated into the build system; # you should run it manually whenever you want to update the data. +from __future__ import annotations import os import sys -from typing import Final, List, Tuple +from typing import Final from urllib.request import urlopen if __name__ == "__main__": @@ -18,20 +19,20 @@ from methods import generate_copyright_header URL: Final[str] = "https://www.unicode.org/Public/16.0.0/ucd/DerivedCoreProperties.txt" -xid_start: List[Tuple[int, int]] = [] -xid_continue: List[Tuple[int, int]] = [] -uppercase_letter: List[Tuple[int, int]] = [] -lowercase_letter: List[Tuple[int, int]] = [] -unicode_letter: List[Tuple[int, int]] = [] +xid_start: list[tuple[int, int]] = [] +xid_continue: list[tuple[int, int]] = [] +uppercase_letter: list[tuple[int, int]] = [] +lowercase_letter: list[tuple[int, int]] = [] +unicode_letter: list[tuple[int, int]] = [] -def merge_ranges(ranges: List[Tuple[int, int]]) -> None: +def merge_ranges(ranges: list[tuple[int, int]]) -> None: if len(ranges) < 2: return last_start: int = ranges[0][0] last_end: int = ranges[0][1] - original_ranges: List[Tuple[int, int]] = ranges[1:] + original_ranges: list[tuple[int, int]] = ranges[1:] ranges.clear() @@ -47,13 +48,13 @@ def merge_ranges(ranges: List[Tuple[int, int]]) -> None: def parse_unicode_data() -> None: - lines: List[str] = [line.decode("utf-8") for line in urlopen(URL)] + lines: list[str] = [line.decode("utf-8") for line in urlopen(URL)] for line in lines: if line.startswith("#") or not line.strip(): continue - split_line: List[str] = line.split(";") + split_line: list[str] = line.split(";") char_range: str = split_line[0].strip() char_property: str = split_line[1].strip().split("#")[0].strip() @@ -63,7 +64,7 @@ def parse_unicode_data() -> None: if ".." in char_range: range_start, range_end = char_range.split("..") - range_tuple: Tuple[int, int] = (int(range_start, 16), int(range_end, 16)) + range_tuple: tuple[int, int] = (int(range_start, 16), int(range_end, 16)) if char_property == "XID_Start": xid_start.append(range_tuple) @@ -87,7 +88,7 @@ def parse_unicode_data() -> None: merge_ranges(unicode_letter) -def make_array(array_name: str, range_list: List[Tuple[int, int]]) -> str: +def make_array(array_name: str, range_list: list[tuple[int, int]]) -> str: result: str = f"\n\nconstexpr inline CharRange {array_name}[] = {{\n" for start, end in range_list: diff --git a/misc/scripts/ucaps_fetch.py b/misc/scripts/ucaps_fetch.py index 8cdecc8727a..84d33abd17a 100755 --- a/misc/scripts/ucaps_fetch.py +++ b/misc/scripts/ucaps_fetch.py @@ -4,10 +4,11 @@ # the Unicode Character Database to the `ucaps.h` file. # NOTE: This script is deliberately not integrated into the build system; # you should run it manually whenever you want to update the data. +from __future__ import annotations import os import sys -from typing import Final, List, Tuple +from typing import Final from urllib.request import urlopen if __name__ == "__main__": @@ -18,15 +19,15 @@ from methods import generate_copyright_header URL: Final[str] = "https://www.unicode.org/Public/16.0.0/ucd/UnicodeData.txt" -lower_to_upper: List[Tuple[str, str]] = [] -upper_to_lower: List[Tuple[str, str]] = [] +lower_to_upper: list[tuple[str, str]] = [] +upper_to_lower: list[tuple[str, str]] = [] def parse_unicode_data() -> None: - lines: List[str] = [line.decode("utf-8") for line in urlopen(URL)] + lines: list[str] = [line.decode("utf-8") for line in urlopen(URL)] for line in lines: - split_line: List[str] = line.split(";") + split_line: list[str] = line.split(";") code_value: str = split_line[0].strip() uppercase_mapping: str = split_line[12].strip() @@ -38,7 +39,7 @@ def parse_unicode_data() -> None: upper_to_lower.append((f"0x{code_value}", f"0x{lowercase_mapping}")) -def make_cap_table(table_name: str, len_name: str, table: List[Tuple[str, str]]) -> str: +def make_cap_table(table_name: str, len_name: str, table: list[tuple[str, str]]) -> str: result: str = f"static const int {table_name}[{len_name}][2] = {{\n" for first, second in table: diff --git a/misc/scripts/unicode_ranges_fetch.py b/misc/scripts/unicode_ranges_fetch.py index b6ef29e98ef..40c7b874cad 100755 --- a/misc/scripts/unicode_ranges_fetch.py +++ b/misc/scripts/unicode_ranges_fetch.py @@ -4,10 +4,11 @@ # the Unicode Character Database to the `char_range.inc` file. # NOTE: This script is deliberately not integrated into the build system; # you should run it manually whenever you want to update the data. +from __future__ import annotations import os import sys -from typing import Final, List, Set, Tuple +from typing import Final from urllib.request import urlopen if __name__ == "__main__": @@ -18,9 +19,9 @@ from methods import generate_copyright_header URL: Final[str] = "https://www.unicode.org/Public/16.0.0/ucd/Blocks.txt" -ranges: List[Tuple[str, str, str]] = [] +ranges: list[tuple[str, str, str]] = [] -exclude_blocks: Set[str] = { +exclude_blocks: set[str] = { "High Surrogates", "High Private Use Surrogates", "Low Surrogates", @@ -33,13 +34,13 @@ exclude_blocks: Set[str] = { def parse_unicode_data() -> None: - lines: List[str] = [line.decode("utf-8") for line in urlopen(URL)] + lines: list[str] = [line.decode("utf-8") for line in urlopen(URL)] for line in lines: if line.startswith("#") or not line.strip(): continue - split_line: List[str] = line.split(";") + split_line: list[str] = line.split(";") char_range: str = split_line[0].strip() block: str = split_line[1].strip() @@ -52,7 +53,7 @@ def parse_unicode_data() -> None: ranges.append((f"0x{range_start}", f"0x{range_end}", block)) -def make_array(array_name: str, ranges: List[Tuple[str, str, str]]) -> str: +def make_array(array_name: str, ranges: list[tuple[str, str, str]]) -> str: result: str = f"static UniRange {array_name}[] = {{\n" for start, end, block in ranges: diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py index 862a479741e..8549c6a6c60 100755 --- a/modules/mono/build_scripts/build_assemblies.py +++ b/modules/mono/build_scripts/build_assemblies.py @@ -1,11 +1,11 @@ #!/usr/bin/python3 +from __future__ import annotations import os import os.path import shlex import subprocess from dataclasses import dataclass -from typing import List, Optional def find_dotnet_cli(): @@ -151,7 +151,7 @@ def find_any_msbuild_tool(mono_prefix): return None -def run_msbuild(tools: ToolsLocation, sln: str, chdir_to: str, msbuild_args: Optional[List[str]] = None): +def run_msbuild(tools: ToolsLocation, sln: str, chdir_to: str, msbuild_args: list[str] | None = None): using_msbuild_mono = False # Preference order: dotnet CLI > Standalone MSBuild > Mono's MSBuild diff --git a/pyproject.toml b/pyproject.toml index ff6f1c3bb3f..6e477f279d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,8 +20,13 @@ target-version = "py38" [tool.ruff.lint] extend-select = [ - "I", # isort + "I", # isort + "UP006", # Use {to} instead of {from} for type annotation + "UP007", # Use `X | Y` for type annotations + "UP037", # Remove quotes from type annotation + "FA", # Future annotations ] +extend-safe-fixes = ["UP006", "UP007", "FA"] [tool.ruff.lint.per-file-ignores] "{SConstruct,SCsub}" = [