feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -3,18 +3,21 @@
import fnmatch
import math
import os
import platform
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__)), "../../"))
from misc.utility.color import STDOUT_COLOR, Ansi, toggle_color
################################################################################
# Config #
################################################################################
flags = {
"c": platform.platform() != "Windows", # Disable by default on windows, since we use ANSI escape codes
"c": STDOUT_COLOR,
"b": False,
"g": False,
"s": False,
@ -85,16 +88,16 @@ table_column_names = [
"Constructors",
]
colors = {
"name": [36], # cyan
"part_big_problem": [4, 31], # underline, red
"part_problem": [31], # red
"part_mostly_good": [33], # yellow
"part_good": [32], # green
"url": [4, 34], # underline, blue
"section": [1, 4], # bold, underline
"state_off": [36], # cyan
"state_on": [1, 35], # bold, magenta/plum
"bold": [1], # bold
"name": [Ansi.CYAN], # cyan
"part_big_problem": [Ansi.RED, Ansi.UNDERLINE], # underline, red
"part_problem": [Ansi.RED], # red
"part_mostly_good": [Ansi.YELLOW], # yellow
"part_good": [Ansi.GREEN], # green
"url": [Ansi.BLUE, Ansi.UNDERLINE], # underline, blue
"section": [Ansi.BOLD, Ansi.UNDERLINE], # bold, underline
"state_off": [Ansi.CYAN], # cyan
"state_on": [Ansi.BOLD, Ansi.MAGENTA], # bold, magenta/plum
"bold": [Ansi.BOLD], # bold
}
overall_progress_description_weight = 10
@ -111,13 +114,8 @@ def validate_tag(elem: ET.Element, tag: str) -> None:
def color(color: str, string: str) -> str:
if flags["c"] and terminal_supports_color():
color_format = ""
for code in colors[color]:
color_format += "\033[" + str(code) + "m"
return color_format + string + "\033[0m"
else:
return string
color_format = "".join([str(x) for x in colors[color]])
return f"{color_format}{string}{Ansi.RESET}"
ansi_escape = re.compile(r"\x1b[^m]*m")
@ -127,16 +125,6 @@ def nonescape_len(s: str) -> int:
return len(ansi_escape.sub("", s))
def terminal_supports_color():
p = sys.platform
supported_platform = p != "Pocket PC" and (p != "win32" or "ANSICON" in os.environ)
is_a_tty = hasattr(sys.stdout, "isatty") and sys.stdout.isatty()
if not supported_platform or not is_a_tty:
return False
return True
################################################################################
# Classes #
################################################################################
@ -342,6 +330,8 @@ if flags["u"]:
table_column_names.append("Docs URL")
table_columns.append("url")
if flags["c"]:
toggle_color(True)
################################################################################
# Help #

View file

@ -10,10 +10,10 @@ import xml.etree.ElementTree as ET
from collections import OrderedDict
from typing import Any, Dict, List, Optional, TextIO, Tuple, Union
# Import hardcoded version information from version.py
root_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")
sys.path.append(root_directory) # Include the root directory
import version # noqa: E402
sys.path.insert(0, root_directory := os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../"))
import version
from misc.utility.color import Ansi, toggle_color
# $DOCS_URL/path/to/page.html(#fragment-tag)
GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$")
@ -90,8 +90,6 @@ BASE_STRINGS = [
]
strings_l10n: Dict[str, str] = {}
STYLES: Dict[str, str] = {}
CLASS_GROUPS: Dict[str, str] = {
"global": "Globals",
"node": "Nodes",
@ -150,7 +148,7 @@ PACKED_ARRAY_TYPES: List[str] = [
"PackedByteArray",
"PackedColorArray",
"PackedFloat32Array",
"Packedfloat64Array",
"PackedFloat64Array",
"PackedInt32Array",
"PackedInt64Array",
"PackedStringArray",
@ -699,31 +697,8 @@ def main() -> None:
)
args = parser.parse_args()
should_color = bool(args.color or sys.stdout.isatty() or os.environ.get("CI"))
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
# <https://github.com/python/cpython/issues/73245>
if should_color and sys.stdout.isatty() and sys.platform == "win32":
try:
from ctypes import WinError, byref, windll # type: ignore
from ctypes.wintypes import DWORD # type: ignore
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
mode = DWORD(0)
if not windll.kernel32.GetConsoleMode(stdout_handle, byref(mode)):
raise WinError()
mode = DWORD(mode.value | 4)
if not windll.kernel32.SetConsoleMode(stdout_handle, mode):
raise WinError()
except Exception:
should_color = False
STYLES["red"] = "\x1b[91m" if should_color else ""
STYLES["green"] = "\x1b[92m" if should_color else ""
STYLES["yellow"] = "\x1b[93m" if should_color else ""
STYLES["bold"] = "\x1b[1m" if should_color else ""
STYLES["regular"] = "\x1b[22m" if should_color else ""
STYLES["reset"] = "\x1b[0m" if should_color else ""
if args.color:
toggle_color(True)
# Retrieve heading translations for the given language.
if not args.dry_run and args.lang != "en":
@ -834,16 +809,16 @@ def main() -> None:
if state.script_language_parity_check.hit_count > 0:
if not args.verbose:
print(
f'{STYLES["yellow"]}{state.script_language_parity_check.hit_count} code samples failed parity check. Use --verbose to get more information.{STYLES["reset"]}'
f"{Ansi.YELLOW}{state.script_language_parity_check.hit_count} code samples failed parity check. Use --verbose to get more information.{Ansi.RESET}"
)
else:
print(
f'{STYLES["yellow"]}{state.script_language_parity_check.hit_count} code samples failed parity check:{STYLES["reset"]}'
f"{Ansi.YELLOW}{state.script_language_parity_check.hit_count} code samples failed parity check:{Ansi.RESET}"
)
for class_name in state.script_language_parity_check.hit_map.keys():
class_hits = state.script_language_parity_check.hit_map[class_name]
print(f'{STYLES["yellow"]}- {len(class_hits)} hits in class "{class_name}"{STYLES["reset"]}')
print(f'{Ansi.YELLOW}- {len(class_hits)} hits in class "{class_name}"{Ansi.RESET}')
for context, error in class_hits:
print(f" - {error} in {format_context_name(context)}")
@ -853,24 +828,22 @@ def main() -> None:
if state.num_warnings >= 2:
print(
f'{STYLES["yellow"]}{state.num_warnings} warnings were found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
f"{Ansi.YELLOW}{state.num_warnings} warnings were found in the class reference XML. Please check the messages above.{Ansi.RESET}"
)
elif state.num_warnings == 1:
print(
f'{STYLES["yellow"]}1 warning was found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
f"{Ansi.YELLOW}1 warning was found in the class reference XML. Please check the messages above.{Ansi.RESET}"
)
if state.num_errors >= 2:
print(
f'{STYLES["red"]}{state.num_errors} errors were found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
f"{Ansi.RED}{state.num_errors} errors were found in the class reference XML. Please check the messages above.{Ansi.RESET}"
)
elif state.num_errors == 1:
print(
f'{STYLES["red"]}1 error was found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
)
print(f"{Ansi.RED}1 error was found in the class reference XML. Please check the messages above.{Ansi.RESET}")
if state.num_warnings == 0 and state.num_errors == 0:
print(f'{STYLES["green"]}No warnings or errors found in the class reference XML.{STYLES["reset"]}')
print(f"{Ansi.GREEN}No warnings or errors found in the class reference XML.{Ansi.RESET}")
if not args.dry_run:
print(f"Wrote reStructuredText files for each class to: {args.output}")
else:
@ -881,12 +854,12 @@ def main() -> None:
def print_error(error: str, state: State) -> None:
print(f'{STYLES["red"]}{STYLES["bold"]}ERROR:{STYLES["regular"]} {error}{STYLES["reset"]}')
print(f"{Ansi.RED}{Ansi.BOLD}ERROR:{Ansi.REGULAR} {error}{Ansi.RESET}")
state.num_errors += 1
def print_warning(warning: str, state: State) -> None:
print(f'{STYLES["yellow"]}{STYLES["bold"]}WARNING:{STYLES["regular"]} {warning}{STYLES["reset"]}')
print(f"{Ansi.YELLOW}{Ansi.BOLD}WARNING:{Ansi.REGULAR} {warning}{Ansi.RESET}")
state.num_warnings += 1
@ -911,7 +884,7 @@ def get_git_branch() -> str:
def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir: str) -> None:
class_name = class_def.name
with open(
os.devnull if dry_run else os.path.join(output_dir, f"class_{class_name.lower()}.rst"),
os.devnull if dry_run else os.path.join(output_dir, f"class_{sanitize_class_name(class_name, True)}.rst"),
"w",
encoding="utf-8",
newline="\n",
@ -937,7 +910,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
f.write(f".. XML source: {source_github_url}.\n\n")
# Document reference id and header.
f.write(f".. _class_{class_name}:\n\n")
f.write(f".. _class_{sanitize_class_name(class_name)}:\n\n")
f.write(make_heading(class_name, "=", False))
f.write(make_deprecated_experimental(class_def, state))
@ -947,15 +920,19 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
# Ascendants
if class_def.inherits:
inherits = class_def.inherits.strip()
f.write(f'**{translate("Inherits:")}** ')
f.write(f"**{translate('Inherits:')}** ")
first = True
while inherits in state.classes:
while inherits is not None:
if not first:
f.write(" **<** ")
else:
first = False
f.write(make_type(inherits, state))
if inherits not in state.classes:
break # Parent unknown.
inode = state.classes[inherits].inherits
if inode:
inherits = inode.strip()
@ -970,7 +947,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
inherited.append(c.name)
if len(inherited):
f.write(f'**{translate("Inherited By:")}** ')
f.write(f"**{translate('Inherited By:')}** ")
for i, child in enumerate(inherited):
if i > 0:
f.write(", ")
@ -1037,13 +1014,11 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
type_rst = property_def.type_name.to_rst(state)
default = property_def.default_value
if default is not None and property_def.overrides:
ref = (
f":ref:`{property_def.overrides}<class_{property_def.overrides}_property_{property_def.name}>`"
)
ref = f":ref:`{property_def.overrides}<class_{sanitize_class_name(property_def.overrides)}_property_{property_def.name}>`"
# Not using translate() for now as it breaks table formatting.
ml.append((type_rst, property_def.name, f"{default} (overrides {ref})"))
else:
ref = f":ref:`{property_def.name}<class_{class_name}_property_{property_def.name}>`"
ref = f":ref:`{property_def.name}<class_{sanitize_class_name(class_name)}_property_{property_def.name}>`"
ml.append((type_rst, ref, default))
format_table(f, ml, True)
@ -1089,7 +1064,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
ml = []
for theme_item_def in class_def.theme_items.values():
ref = f":ref:`{theme_item_def.name}<class_{class_name}_theme_{theme_item_def.data_name}_{theme_item_def.name}>`"
ref = f":ref:`{theme_item_def.name}<class_{sanitize_class_name(class_name)}_theme_{theme_item_def.data_name}_{theme_item_def.name}>`"
ml.append((theme_item_def.type_name.to_rst(state), ref, theme_item_def.default_value))
format_table(f, ml, True)
@ -1110,7 +1085,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
# Create signal signature and anchor point.
signal_anchor = f"class_{class_name}_signal_{signal.name}"
signal_anchor = f"class_{sanitize_class_name(class_name)}_signal_{signal.name}"
f.write(f".. _{signal_anchor}:\n\n")
self_link = f":ref:`🔗<{signal_anchor}>`"
f.write(".. rst-class:: classref-signal\n\n")
@ -1149,7 +1124,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
# Create enumeration signature and anchor point.
enum_anchor = f"enum_{class_name}_{e.name}"
enum_anchor = f"enum_{sanitize_class_name(class_name)}_{e.name}"
f.write(f".. _{enum_anchor}:\n\n")
self_link = f":ref:`🔗<{enum_anchor}>`"
f.write(".. rst-class:: classref-enumeration\n\n")
@ -1162,7 +1137,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
for value in e.values.values():
# Also create signature and anchor point for each enum constant.
f.write(f".. _class_{class_name}_constant_{value.name}:\n\n")
f.write(f".. _class_{sanitize_class_name(class_name)}_constant_{value.name}:\n\n")
f.write(".. rst-class:: classref-enumeration-constant\n\n")
f.write(f"{e.type_name.to_rst(state)} **{value.name}** = ``{value.value}``\n\n")
@ -1195,7 +1170,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
for constant in class_def.constants.values():
# Create constant signature and anchor point.
constant_anchor = f"class_{class_name}_constant_{constant.name}"
constant_anchor = f"class_{sanitize_class_name(class_name)}_constant_{constant.name}"
f.write(f".. _{constant_anchor}:\n\n")
self_link = f":ref:`🔗<{constant_anchor}>`"
f.write(".. rst-class:: classref-constant\n\n")
@ -1235,7 +1210,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
self_link = ""
if i == 0:
annotation_anchor = f"class_{class_name}_annotation_{m.name}"
annotation_anchor = f"class_{sanitize_class_name(class_name)}_annotation_{m.name}"
f.write(f".. _{annotation_anchor}:\n\n")
self_link = f" :ref:`🔗<{annotation_anchor}>`"
@ -1276,7 +1251,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
# Create property signature and anchor point.
property_anchor = f"class_{class_name}_property_{property_def.name}"
property_anchor = f"class_{sanitize_class_name(class_name)}_property_{property_def.name}"
f.write(f".. _{property_anchor}:\n\n")
self_link = f":ref:`🔗<{property_anchor}>`"
f.write(".. rst-class:: classref-property\n\n")
@ -1311,9 +1286,6 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if property_def.text is not None and property_def.text.strip() != "":
f.write(f"{format_text_block(property_def.text.strip(), property_def, state)}\n\n")
if property_def.type_name.type_name in PACKED_ARRAY_TYPES:
tmp = f"[b]Note:[/b] The returned array is [i]copied[/i] and any changes to it will not update the original property value. See [{property_def.type_name.type_name}] for more details."
f.write(f"{format_text_block(tmp, property_def, state)}\n\n")
elif property_def.deprecated is None and property_def.experimental is None:
f.write(".. container:: contribute\n\n\t")
f.write(
@ -1323,6 +1295,11 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
+ "\n\n"
)
# Add copy note to built-in properties returning `Packed*Array`.
if property_def.type_name.type_name in PACKED_ARRAY_TYPES:
copy_note = f"[b]Note:[/b] The returned array is [i]copied[/i] and any changes to it will not update the original property value. See [{property_def.type_name.type_name}] for more details."
f.write(f"{format_text_block(copy_note, property_def, state)}\n\n")
index += 1
# Constructor, Method, Operator descriptions
@ -1342,7 +1319,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
self_link = ""
if i == 0:
constructor_anchor = f"class_{class_name}_constructor_{m.name}"
constructor_anchor = f"class_{sanitize_class_name(class_name)}_constructor_{m.name}"
f.write(f".. _{constructor_anchor}:\n\n")
self_link = f" :ref:`🔗<{constructor_anchor}>`"
@ -1388,7 +1365,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
method_qualifier = ""
if m.name.startswith("_"):
method_qualifier = "private_"
method_anchor = f"class_{class_name}_{method_qualifier}method_{m.name}"
method_anchor = f"class_{sanitize_class_name(class_name)}_{method_qualifier}method_{m.name}"
f.write(f".. _{method_anchor}:\n\n")
self_link = f" :ref:`🔗<{method_anchor}>`"
@ -1429,7 +1406,9 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
# Create operator signature and anchor point.
operator_anchor = f"class_{class_name}_operator_{sanitize_operator_name(m.name, state)}"
operator_anchor = (
f"class_{sanitize_class_name(class_name)}_operator_{sanitize_operator_name(m.name, state)}"
)
for parameter in m.parameters:
operator_anchor += f"_{parameter.type_name.type_name}"
f.write(f".. _{operator_anchor}:\n\n")
@ -1471,7 +1450,9 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
# Create theme property signature and anchor point.
theme_item_anchor = f"class_{class_name}_theme_{theme_item_def.data_name}_{theme_item_def.name}"
theme_item_anchor = (
f"class_{sanitize_class_name(class_name)}_theme_{theme_item_def.data_name}_{theme_item_def.name}"
)
f.write(f".. _{theme_item_anchor}:\n\n")
self_link = f":ref:`🔗<{theme_item_anchor}>`"
f.write(".. rst-class:: classref-themeproperty\n\n")
@ -1507,28 +1488,27 @@ def make_type(klass: str, state: State) -> str:
if klass.find("*") != -1: # Pointer, ignore
return f"``{klass}``"
link_type = klass
is_array = False
def resolve_type(link_type: str) -> str:
if link_type in state.classes:
return f":ref:`{link_type}<class_{sanitize_class_name(link_type)}>`"
else:
print_error(f'{state.current_class}.xml: Unresolved type "{link_type}".', state)
return f"``{link_type}``"
if link_type.endswith("[]"): # Typed array, strip [] to link to contained type.
link_type = link_type[:-2]
is_array = True
if klass.endswith("[]"): # Typed array, strip [] to link to contained type.
return f":ref:`Array<class_Array>`\\[{resolve_type(klass[: -len('[]')])}\\]"
if link_type in state.classes:
type_rst = f":ref:`{link_type}<class_{link_type}>`"
if is_array:
type_rst = f":ref:`Array<class_Array>`\\[{type_rst}\\]"
return type_rst
if klass.startswith("Dictionary["): # Typed dictionary, split elements to link contained types.
parts = klass[len("Dictionary[") : -len("]")].partition(", ")
key = parts[0]
value = parts[2]
return f":ref:`Dictionary<class_Dictionary>`\\[{resolve_type(key)}, {resolve_type(value)}\\]"
print_error(f'{state.current_class}.xml: Unresolved type "{link_type}".', state)
type_rst = f"``{link_type}``"
if is_array:
type_rst = f":ref:`Array<class_Array>`\\[{type_rst}\\]"
return type_rst
return resolve_type(klass)
def make_enum(t: str, is_bitfield: bool, state: State) -> str:
p = t.find(".")
p = t.rfind(".")
if p >= 0:
c = t[0:p]
e = t[p + 1 :]
@ -1546,13 +1526,11 @@ def make_enum(t: str, is_bitfield: bool, state: State) -> str:
if is_bitfield:
if not state.classes[c].enums[e].is_bitfield:
print_error(f'{state.current_class}.xml: Enum "{t}" is not bitfield.', state)
return f"|bitfield|\\[:ref:`{e}<enum_{c}_{e}>`\\]"
return f"|bitfield|\\[:ref:`{e}<enum_{sanitize_class_name(c)}_{e}>`\\]"
else:
return f":ref:`{e}<enum_{c}_{e}>`"
return f":ref:`{e}<enum_{sanitize_class_name(c)}_{e}>`"
# Don't fail for `Vector3.Axis`, as this enum is a special case which is expected not to be resolved.
if f"{c}.{e}" != "Vector3.Axis":
print_error(f'{state.current_class}.xml: Unresolved enum "{t}".', state)
print_error(f'{state.current_class}.xml: Unresolved enum "{t}".', state)
return t
@ -1573,7 +1551,7 @@ def make_method_signature(
if isinstance(definition, MethodDef) and ref_type != "":
if ref_type == "operator":
op_name = definition.name.replace("<", "\\<") # So operator "<" gets correctly displayed.
out += f":ref:`{op_name}<class_{class_def.name}_{ref_type}_{sanitize_operator_name(definition.name, state)}"
out += f":ref:`{op_name}<class_{sanitize_class_name(class_def.name)}_{ref_type}_{sanitize_operator_name(definition.name, state)}"
for parameter in definition.parameters:
out += f"_{parameter.type_name.type_name}"
out += ">`"
@ -1581,9 +1559,9 @@ def make_method_signature(
ref_type_qualifier = ""
if definition.name.startswith("_"):
ref_type_qualifier = "private_"
out += f":ref:`{definition.name}<class_{class_def.name}_{ref_type_qualifier}{ref_type}_{definition.name}>`"
out += f":ref:`{definition.name}<class_{sanitize_class_name(class_def.name)}_{ref_type_qualifier}{ref_type}_{definition.name}>`"
else:
out += f":ref:`{definition.name}<class_{class_def.name}_{ref_type}_{definition.name}>`"
out += f":ref:`{definition.name}<class_{sanitize_class_name(class_def.name)}_{ref_type}_{definition.name}>`"
else:
out += f"**{definition.name}**"
@ -1771,13 +1749,15 @@ def make_rst_index(grouped_classes: Dict[str, List[str]], dry_run: bool, output_
f.write("\n")
if group_name in CLASS_GROUPS_BASE:
f.write(f" class_{CLASS_GROUPS_BASE[group_name].lower()}\n")
f.write(f" class_{sanitize_class_name(CLASS_GROUPS_BASE[group_name], True)}\n")
for class_name in grouped_classes[group_name]:
if group_name in CLASS_GROUPS_BASE and CLASS_GROUPS_BASE[group_name].lower() == class_name.lower():
if group_name in CLASS_GROUPS_BASE and sanitize_class_name(
CLASS_GROUPS_BASE[group_name], True
) == sanitize_class_name(class_name, True):
continue
f.write(f" class_{class_name.lower()}\n")
f.write(f" class_{sanitize_class_name(class_name, True)}\n")
f.write("\n")
@ -2258,7 +2238,9 @@ def format_text_block(
repl_text = target_name
if target_class_name != state.current_class:
repl_text = f"{target_class_name}.{target_name}"
tag_text = f":ref:`{repl_text}<class_{target_class_name}{ref_type}_{target_name}>`"
if tag_state.name == "method":
repl_text = f"{repl_text}()"
tag_text = f":ref:`{repl_text}<class_{sanitize_class_name(target_class_name)}{ref_type}_{target_name}>`"
escape_pre = True
escape_post = True
@ -2562,7 +2544,7 @@ def format_table(f: TextIO, data: List[Tuple[Optional[str], ...]], remove_empty_
for i, text in enumerate(row):
if column_sizes[i] == 0 and remove_empty_columns:
continue
row_text += f' {(text or "").ljust(column_sizes[i])} |'
row_text += f" {(text or '').ljust(column_sizes[i])} |"
row_text += "\n"
f.write(f" {row_text}")
@ -2571,6 +2553,13 @@ 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:
if is_file_name:
return dirty_name.lower().replace('"', "").replace("/", "--")
else:
return dirty_name.replace('"', "").replace("/", "_").replace(".", "_")
def sanitize_operator_name(dirty_name: str, state: State) -> str:
clear_name = dirty_name.replace("operator ", "")