1
0
mirror of https://github.com/godotengine/godot.git synced 2025-12-02 16:48:55 +00:00

SCons: Integrate annotations where relevant

• Expand Ruff linter to catch & upgrade legacy type-hint syntax
This commit is contained in:
Thaddeus Crews
2024-11-24 10:14:16 -06:00
parent 235a32ad11
commit 11fc998368
9 changed files with 116 additions and 104 deletions

View File

@@ -1,8 +1,9 @@
#!/usr/bin/env python #!/usr/bin/env python
from __future__ import annotations
from misc.utility.scons_hints import * from misc.utility.scons_hints import *
import pathlib import pathlib
from typing import Tuple
import profiling_builders import profiling_builders
@@ -11,7 +12,7 @@ Import("env")
env.add_source_files(env.core_sources, "*.cpp") 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(): if not path.is_dir():
print("profiler_path must be empty or point to a directory.") print("profiler_path must be empty or point to a directory.")
Exit(255) Exit(255)

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from __future__ import annotations
import fnmatch import fnmatch
import math import math
@@ -6,7 +7,6 @@ import os
import re import re
import sys import sys
import xml.etree.ElementTree as ET 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__)), "../../")) 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.described: int = described
self.total: int = total self.total: int = total
def __add__(self, other: "ClassStatusProgress"): def __add__(self, other: ClassStatusProgress):
return ClassStatusProgress(self.described + other.described, self.total + other.total) return ClassStatusProgress(self.described + other.described, self.total + other.total)
def increment(self, described: bool): def increment(self, described: bool):
@@ -178,7 +178,7 @@ class ClassStatus:
self.name: str = name self.name: str = name
self.has_brief_description: bool = True self.has_brief_description: bool = True
self.has_description: bool = True self.has_description: bool = True
self.progresses: Dict[str, ClassStatusProgress] = { self.progresses: dict[str, ClassStatusProgress] = {
"methods": ClassStatusProgress(), "methods": ClassStatusProgress(),
"constants": ClassStatusProgress(), "constants": ClassStatusProgress(),
"members": ClassStatusProgress(), "members": ClassStatusProgress(),
@@ -188,7 +188,7 @@ class ClassStatus:
"constructors": ClassStatusProgress(), "constructors": ClassStatusProgress(),
} }
def __add__(self, other: "ClassStatus"): def __add__(self, other: ClassStatus):
new_status = ClassStatus() new_status = ClassStatus()
new_status.name = self.name new_status.name = self.name
new_status.has_brief_description = self.has_brief_description and other.has_brief_description 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 sum += self.progresses[k].total
return sum < 1 return sum < 1
def make_output(self) -> Dict[str, str]: def make_output(self) -> dict[str, str]:
output: Dict[str, str] = {} output: dict[str, str] = {}
output["name"] = color("name", self.name) output["name"] = color("name", self.name)
ok_string = color("part_good", "OK") ok_string = color("part_good", "OK")
@@ -295,8 +295,8 @@ class ClassStatus:
# Arguments # # Arguments #
################################################################################ ################################################################################
input_file_list: List[str] = [] input_file_list: list[str] = []
input_class_list: List[str] = [] input_class_list: list[str] = []
merged_file: str = "" merged_file: str = ""
for arg in sys.argv[1:]: for arg in sys.argv[1:]:
@@ -372,8 +372,8 @@ if len(input_file_list) < 1 or flags["h"]:
# Parse class list # # Parse class list #
################################################################################ ################################################################################
class_names: List[str] = [] class_names: list[str] = []
classes: Dict[str, ET.Element] = {} classes: dict[str, ET.Element] = {}
for file in input_file_list: for file in input_file_list:
tree = ET.parse(file) tree = ET.parse(file)
@@ -389,7 +389,7 @@ class_names.sort()
if len(input_class_list) < 1: if len(input_class_list) < 1:
input_class_list = ["*"] input_class_list = ["*"]
filtered_classes_set: Set[str] = set() filtered_classes_set: set[str] = set()
for pattern in input_class_list: for pattern in input_class_list:
filtered_classes_set |= set(fnmatch.filter(class_names, pattern)) filtered_classes_set |= set(fnmatch.filter(class_names, pattern))
filtered_classes = list(filtered_classes_set) filtered_classes = list(filtered_classes_set)
@@ -419,7 +419,7 @@ for cn in filtered_classes:
continue continue
out = status.make_output() out = status.make_output()
row: List[str] = [] row: list[str] = []
for column in table_columns: for column in table_columns:
if column in out: if column in out:
row.append(out[column]) row.append(out[column])
@@ -456,7 +456,7 @@ if flags["a"]:
# without having to scroll back to the top. # without having to scroll back to the top.
table.append(table_column_names) table.append(table_column_names)
table_column_sizes: List[int] = [] table_column_sizes: list[int] = []
for row in table: for row in table:
for cell_i, cell in enumerate(row): for cell_i, cell in enumerate(row):
if cell_i >= len(table_column_sizes): if cell_i >= len(table_column_sizes):

113
doc/tools/make_rst.py Executable file → Normal file
View File

@@ -1,6 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# This script makes RST files from the XML class reference for use with the online docs. # This script makes RST files from the XML class reference for use with the online docs.
from __future__ import annotations
import argparse import argparse
import os import os
@@ -8,7 +9,7 @@ import re
import sys import sys
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from collections import OrderedDict 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__)), "../../")) 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`. # 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.", "[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 writing_translation = False
CLASS_GROUPS: Dict[str, str] = { CLASS_GROUPS: dict[str, str] = {
"global": "Globals", "global": "Globals",
"node": "Nodes", "node": "Nodes",
"resource": "Resources", "resource": "Resources",
@@ -101,21 +102,21 @@ CLASS_GROUPS: Dict[str, str] = {
"editor": "Editor-only", "editor": "Editor-only",
"variant": "Variant types", "variant": "Variant types",
} }
CLASS_GROUPS_BASE: Dict[str, str] = { CLASS_GROUPS_BASE: dict[str, str] = {
"node": "Node", "node": "Node",
"resource": "Resource", "resource": "Resource",
"object": "Object", "object": "Object",
"variant": "Variant", "variant": "Variant",
} }
# Sync with editor\register_editor_types.cpp # Sync with editor\register_editor_types.cpp
EDITOR_CLASSES: List[str] = [ EDITOR_CLASSES: list[str] = [
"FileSystemDock", "FileSystemDock",
"ScriptCreateDialog", "ScriptCreateDialog",
"ScriptEditor", "ScriptEditor",
"ScriptEditorBase", "ScriptEditorBase",
] ]
# Sync with the types mentioned in https://docs.godotengine.org/en/stable/tutorials/scripting/c_sharp/c_sharp_differences.html # 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", "@GlobalScope",
"String", "String",
"StringName", "StringName",
@@ -147,7 +148,7 @@ CLASSES_WITH_CSHARP_DIFFERENCES: List[str] = [
"Variant", "Variant",
] ]
PACKED_ARRAY_TYPES: List[str] = [ PACKED_ARRAY_TYPES: list[str] = [
"PackedByteArray", "PackedByteArray",
"PackedColorArray", "PackedColorArray",
"PackedFloat32Array", "PackedFloat32Array",
@@ -425,7 +426,7 @@ class State:
self.current_class = "" 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") param_elements = root.findall("param")
params: Any = [None] * len(param_elements) params: Any = [None] * len(param_elements)
@@ -443,7 +444,7 @@ class State:
params[index] = ParameterDef(param_name, type_name, default) params[index] = ParameterDef(param_name, type_name, default)
cast: List[ParameterDef] = params cast: list[ParameterDef] = params
return cast return cast
@@ -461,7 +462,7 @@ class TagState:
class TypeName: 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.type_name = type_name
self.enum = enum self.enum = enum
self.is_bitfield = is_bitfield self.is_bitfield = is_bitfield
@@ -475,7 +476,7 @@ class TypeName:
return make_type(self.type_name, state) return make_type(self.type_name, state)
@classmethod @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") return cls(element.attrib["type"], element.get("enum"), element.get("is_bitfield") == "true")
@@ -487,8 +488,8 @@ class DefinitionBase:
) -> None: ) -> None:
self.definition_name = definition_name self.definition_name = definition_name
self.name = name self.name = name
self.deprecated: Optional[str] = None self.deprecated: str | None = None
self.experimental: Optional[str] = None self.experimental: str | None = None
class PropertyDef(DefinitionBase): class PropertyDef(DefinitionBase):
@@ -496,11 +497,11 @@ class PropertyDef(DefinitionBase):
self, self,
name: str, name: str,
type_name: TypeName, type_name: TypeName,
setter: Optional[str], setter: str | None,
getter: Optional[str], getter: str | None,
text: Optional[str], text: str | None,
default_value: Optional[str], default_value: str | None,
overrides: Optional[str], overrides: str | None,
) -> None: ) -> None:
super().__init__("property", name) super().__init__("property", name)
@@ -513,7 +514,7 @@ class PropertyDef(DefinitionBase):
class ParameterDef(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) super().__init__("parameter", name)
self.type_name = type_name self.type_name = type_name
@@ -521,7 +522,7 @@ class ParameterDef(DefinitionBase):
class SignalDef(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) super().__init__("signal", name)
self.parameters = parameters self.parameters = parameters
@@ -532,9 +533,9 @@ class AnnotationDef(DefinitionBase):
def __init__( def __init__(
self, self,
name: str, name: str,
parameters: List[ParameterDef], parameters: list[ParameterDef],
description: Optional[str], description: str | None,
qualifiers: Optional[str], qualifiers: str | None,
) -> None: ) -> None:
super().__init__("annotation", name) super().__init__("annotation", name)
@@ -548,9 +549,9 @@ class MethodDef(DefinitionBase):
self, self,
name: str, name: str,
return_type: TypeName, return_type: TypeName,
parameters: List[ParameterDef], parameters: list[ParameterDef],
description: Optional[str], description: str | None,
qualifiers: Optional[str], qualifiers: str | None,
) -> None: ) -> None:
super().__init__("method", name) super().__init__("method", name)
@@ -561,7 +562,7 @@ class MethodDef(DefinitionBase):
class ConstantDef(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) super().__init__("constant", name)
self.value = value self.value = value
@@ -580,7 +581,7 @@ class EnumDef(DefinitionBase):
class ThemeItemDef(DefinitionBase): class ThemeItemDef(DefinitionBase):
def __init__( 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: ) -> None:
super().__init__("theme property", name) super().__init__("theme property", name)
@@ -600,17 +601,17 @@ class ClassDef(DefinitionBase):
self.constants: OrderedDict[str, ConstantDef] = OrderedDict() self.constants: OrderedDict[str, ConstantDef] = OrderedDict()
self.enums: OrderedDict[str, EnumDef] = OrderedDict() self.enums: OrderedDict[str, EnumDef] = OrderedDict()
self.properties: OrderedDict[str, PropertyDef] = OrderedDict() self.properties: OrderedDict[str, PropertyDef] = OrderedDict()
self.constructors: OrderedDict[str, List[MethodDef]] = OrderedDict() self.constructors: OrderedDict[str, list[MethodDef]] = OrderedDict()
self.methods: OrderedDict[str, List[MethodDef]] = OrderedDict() self.methods: OrderedDict[str, list[MethodDef]] = OrderedDict()
self.operators: OrderedDict[str, List[MethodDef]] = OrderedDict() self.operators: OrderedDict[str, list[MethodDef]] = OrderedDict()
self.signals: OrderedDict[str, SignalDef] = 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.theme_items: OrderedDict[str, ThemeItemDef] = OrderedDict()
self.inherits: Optional[str] = None self.inherits: str | None = None
self.brief_description: Optional[str] = None self.brief_description: str | None = None
self.description: Optional[str] = None self.description: str | None = None
self.tutorials: List[Tuple[str, str]] = [] self.tutorials: list[tuple[str, str]] = []
self.keywords: Optional[str] = None self.keywords: str | None = None
# Used to match the class with XML source for output filtering purposes. # Used to match the class with XML source for output filtering purposes.
self.filepath: str = "" self.filepath: str = ""
@@ -656,7 +657,7 @@ class ClassDef(DefinitionBase):
# which don't necessarily need C# examples. # which don't necessarily need C# examples.
class ScriptLanguageParityCheck: class ScriptLanguageParityCheck:
def __init__(self) -> None: 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 self.hit_count = 0
def add_hit(self, class_name: str, context: DefinitionBase, error: str, state: State) -> None: 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...") print("Checking for errors in the XML class reference...")
file_list: List[str] = [] file_list: list[str] = []
for path in args.path: for path in args.path:
# Cut off trailing slashes so os.path.basename doesn't choke. # Cut off trailing slashes so os.path.basename doesn't choke.
@@ -751,7 +752,7 @@ def main() -> None:
file_list.append(path) file_list.append(path)
classes: Dict[str, Tuple[ET.Element, str]] = {} classes: dict[str, tuple[ET.Element, str]] = {}
state = State() state = State()
for cur_file in file_list: for cur_file in file_list:
@@ -784,7 +785,7 @@ def main() -> None:
print("Generating the RST class reference...") 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(): for class_name, class_def in state.classes.items():
if args.filter and not pattern.search(class_def.filepath): 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") f.write("\n\n")
# Descendants # Descendants
inherited: List[str] = [] inherited: list[str] = []
for c in state.classes.values(): for c in state.classes.values():
if c.inherits and c.inherits.strip() == class_name: if c.inherits and c.inherits.strip() == class_name:
inherited.append(c.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 ### ### REFERENCE TABLES ###
# Reused container for reference tables. # Reused container for reference tables.
ml: List[Tuple[Optional[str], ...]] = [] ml: list[tuple[str | None, ...]] = []
# Properties reference table # Properties reference table
if len(class_def.properties) > 0: 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( def make_method_signature(
class_def: ClassDef, definition: Union[AnnotationDef, MethodDef, SignalDef], ref_type: str, state: State class_def: ClassDef, definition: AnnotationDef | MethodDef | SignalDef, ref_type: str, state: State
) -> Tuple[str, str]: ) -> tuple[str, str]:
ret_type = "" ret_type = ""
if isinstance(definition, MethodDef): 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] setter = class_def.methods[property_def.setter][0]
# Otherwise we fake it with the information we have available. # Otherwise we fake it with the information we have available.
else: else:
setter_params: List[ParameterDef] = [] setter_params: list[ParameterDef] = []
setter_params.append(ParameterDef("value", property_def.type_name, None)) setter_params.append(ParameterDef("value", property_def.type_name, None))
setter = MethodDef(property_def.setter, TypeName("void"), setter_params, None, 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] getter = class_def.methods[property_def.getter][0]
# Otherwise we fake it with the information we have available. # Otherwise we fake it with the information we have available.
else: else:
getter_params: List[ParameterDef] = [] getter_params: list[ParameterDef] = []
getter = MethodDef(property_def.getter, property_def.type_name, getter_params, None, None) getter = MethodDef(property_def.getter, property_def.type_name, getter_params, None, None)
ret_type, signature = make_method_signature(class_def, getter, "", state) 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}>`__" 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( with open(
os.devnull if dry_run else os.path.join(output_dir, "index.rst"), "w", encoding="utf-8", newline="\n" os.devnull if dry_run else os.path.join(output_dir, "index.rst"), "w", encoding="utf-8", newline="\n"
) as f: ) 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: for tag in tagset:
# Complete match. # Complete match.
if tag_text == tag: 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) 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: if link_target.find(".") != -1:
return link_target.split(".") return link_target.split(".")
else: else:
@@ -2082,7 +2083,7 @@ def format_text_block(
valid_param_context = isinstance(context, (MethodDef, SignalDef, AnnotationDef)) valid_param_context = isinstance(context, (MethodDef, SignalDef, AnnotationDef))
if valid_param_context: 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: for param_def in context_params:
if param_def.name == inside_code_text: if param_def.name == inside_code_text:
print_warning( print_warning(
@@ -2242,7 +2243,7 @@ def format_text_block(
state, state,
) )
else: else:
context_params: List[ParameterDef] = context.parameters # type: ignore context_params: list[ParameterDef] = context.parameters # type: ignore
found = False found = False
for param_def in context_params: for param_def in context_params:
if param_def.name == link_target: if param_def.name == link_target:
@@ -2407,7 +2408,7 @@ def format_text_block(
return text return text
def preformat_text_block(text: str, state: State) -> Optional[str]: def preformat_text_block(text: str, state: State) -> str | None:
result = "" result = ""
codeblock_tag = "" codeblock_tag = ""
indent_level = 0 indent_level = 0
@@ -2457,7 +2458,7 @@ def preformat_text_block(text: str, state: State) -> Optional[str]:
return result return result
def format_context_name(context: Union[DefinitionBase, None]) -> str: def format_context_name(context: DefinitionBase | None) -> str:
context_name: str = "unknown context" context_name: str = "unknown context"
if context is not None: if context is not None:
context_name = f'{context.definition_name} "{context.name}" description' 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 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: if len(data) == 0:
return return
@@ -2544,7 +2545,7 @@ def format_table(f: TextIO, data: List[Tuple[Optional[str], ...]], remove_empty_
f.write("\n") 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: if is_file_name:
return dirty_name.lower().replace('"', "").replace("/", "--") return dirty_name.lower().replace('"', "").replace("/", "--")
else: else:

View File

@@ -1,3 +1,5 @@
from __future__ import annotations
import atexit import atexit
import contextlib import contextlib
import glob import glob
@@ -9,9 +11,9 @@ import sys
import textwrap import textwrap
import zlib import zlib
from collections import OrderedDict from collections import OrderedDict
from io import StringIO, TextIOBase from io import StringIO
from pathlib import Path 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 misc.utility.color import print_error, print_info, print_warning
from platform_methods import detect_arch from platform_methods import detect_arch
@@ -1553,8 +1555,8 @@ def generate_copyright_header(filename: str) -> str:
@contextlib.contextmanager @contextlib.contextmanager
def generated_wrapper( def generated_wrapper(
path: str, path: str,
guard: Optional[bool] = None, guard: bool | None = None,
) -> Generator[TextIOBase, None, None]: ) -> Generator[TextIO, None, None]:
""" """
Wrapper class to automatically handle copyright headers and header guards Wrapper class to automatically handle copyright headers and header guards
for generated scripts. Meant to be invoked via `with` statement similar to 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) 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 MAX_LITERAL = 16 * 1024
if isinstance(value, list): if isinstance(value, list):
value = "\n".join(value) + "\n" value = "\n".join(value) + "\n"
split: List[bytes] = [] split: list[bytes] = []
offset = 0 offset = 0
encoded = value.encode() encoded = value.encode()

View File

@@ -4,10 +4,11 @@
# the Unicode Character Database to the `char_range.inc` file. # the Unicode Character Database to the `char_range.inc` file.
# NOTE: This script is deliberately not integrated into the build system; # NOTE: This script is deliberately not integrated into the build system;
# you should run it manually whenever you want to update the data. # you should run it manually whenever you want to update the data.
from __future__ import annotations
import os import os
import sys import sys
from typing import Final, List, Tuple from typing import Final
from urllib.request import urlopen from urllib.request import urlopen
if __name__ == "__main__": 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" URL: Final[str] = "https://www.unicode.org/Public/16.0.0/ucd/DerivedCoreProperties.txt"
xid_start: List[Tuple[int, int]] = [] xid_start: list[tuple[int, int]] = []
xid_continue: List[Tuple[int, int]] = [] xid_continue: list[tuple[int, int]] = []
uppercase_letter: List[Tuple[int, int]] = [] uppercase_letter: list[tuple[int, int]] = []
lowercase_letter: List[Tuple[int, int]] = [] lowercase_letter: list[tuple[int, int]] = []
unicode_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: if len(ranges) < 2:
return return
last_start: int = ranges[0][0] last_start: int = ranges[0][0]
last_end: int = ranges[0][1] last_end: int = ranges[0][1]
original_ranges: List[Tuple[int, int]] = ranges[1:] original_ranges: list[tuple[int, int]] = ranges[1:]
ranges.clear() ranges.clear()
@@ -47,13 +48,13 @@ def merge_ranges(ranges: List[Tuple[int, int]]) -> None:
def parse_unicode_data() -> 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: for line in lines:
if line.startswith("#") or not line.strip(): if line.startswith("#") or not line.strip():
continue continue
split_line: List[str] = line.split(";") split_line: list[str] = line.split(";")
char_range: str = split_line[0].strip() char_range: str = split_line[0].strip()
char_property: str = split_line[1].strip().split("#")[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: if ".." in char_range:
range_start, range_end = char_range.split("..") 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": if char_property == "XID_Start":
xid_start.append(range_tuple) xid_start.append(range_tuple)
@@ -87,7 +88,7 @@ def parse_unicode_data() -> None:
merge_ranges(unicode_letter) 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" result: str = f"\n\nconstexpr inline CharRange {array_name}[] = {{\n"
for start, end in range_list: for start, end in range_list:

View File

@@ -4,10 +4,11 @@
# the Unicode Character Database to the `ucaps.h` file. # the Unicode Character Database to the `ucaps.h` file.
# NOTE: This script is deliberately not integrated into the build system; # NOTE: This script is deliberately not integrated into the build system;
# you should run it manually whenever you want to update the data. # you should run it manually whenever you want to update the data.
from __future__ import annotations
import os import os
import sys import sys
from typing import Final, List, Tuple from typing import Final
from urllib.request import urlopen from urllib.request import urlopen
if __name__ == "__main__": 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" URL: Final[str] = "https://www.unicode.org/Public/16.0.0/ucd/UnicodeData.txt"
lower_to_upper: List[Tuple[str, str]] = [] lower_to_upper: list[tuple[str, str]] = []
upper_to_lower: List[Tuple[str, str]] = [] upper_to_lower: list[tuple[str, str]] = []
def parse_unicode_data() -> 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: for line in lines:
split_line: List[str] = line.split(";") split_line: list[str] = line.split(";")
code_value: str = split_line[0].strip() code_value: str = split_line[0].strip()
uppercase_mapping: str = split_line[12].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}")) 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" result: str = f"static const int {table_name}[{len_name}][2] = {{\n"
for first, second in table: for first, second in table:

View File

@@ -4,10 +4,11 @@
# the Unicode Character Database to the `char_range.inc` file. # the Unicode Character Database to the `char_range.inc` file.
# NOTE: This script is deliberately not integrated into the build system; # NOTE: This script is deliberately not integrated into the build system;
# you should run it manually whenever you want to update the data. # you should run it manually whenever you want to update the data.
from __future__ import annotations
import os import os
import sys import sys
from typing import Final, List, Set, Tuple from typing import Final
from urllib.request import urlopen from urllib.request import urlopen
if __name__ == "__main__": 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" 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 Surrogates",
"High Private Use Surrogates", "High Private Use Surrogates",
"Low Surrogates", "Low Surrogates",
@@ -33,13 +34,13 @@ exclude_blocks: Set[str] = {
def parse_unicode_data() -> 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: for line in lines:
if line.startswith("#") or not line.strip(): if line.startswith("#") or not line.strip():
continue continue
split_line: List[str] = line.split(";") split_line: list[str] = line.split(";")
char_range: str = split_line[0].strip() char_range: str = split_line[0].strip()
block: str = split_line[1].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)) 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" result: str = f"static UniRange {array_name}[] = {{\n"
for start, end, block in ranges: for start, end, block in ranges:

View File

@@ -1,11 +1,11 @@
#!/usr/bin/python3 #!/usr/bin/python3
from __future__ import annotations
import os import os
import os.path import os.path
import shlex import shlex
import subprocess import subprocess
from dataclasses import dataclass from dataclasses import dataclass
from typing import List, Optional
def find_dotnet_cli(): def find_dotnet_cli():
@@ -151,7 +151,7 @@ def find_any_msbuild_tool(mono_prefix):
return None 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 using_msbuild_mono = False
# Preference order: dotnet CLI > Standalone MSBuild > Mono's MSBuild # Preference order: dotnet CLI > Standalone MSBuild > Mono's MSBuild

View File

@@ -21,7 +21,12 @@ target-version = "py38"
[tool.ruff.lint] [tool.ruff.lint]
extend-select = [ 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] [tool.ruff.lint.per-file-ignores]
"{SConstruct,SCsub}" = [ "{SConstruct,SCsub}" = [