Merge pull request #64545 from asmaloney/doc-fstring-make_rst

[doc] Use f-strings throughout make_rst.py
This commit is contained in:
Rémi Verschelde 2022-08-30 21:34:37 +02:00 committed by GitHub
commit f6714581cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -19,7 +19,7 @@ import version
# $DOCS_URL/path/to/page.html(#fragment-tag) # $DOCS_URL/path/to/page.html(#fragment-tag)
GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$") GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$")
# Based on reStructedText inline markup recognition rules # Based on reStructuredText inline markup recognition rules
# https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules # https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules
MARKUP_ALLOWED_PRECEDENT = " -:/'\"<([{" MARKUP_ALLOWED_PRECEDENT = " -:/'\"<([{"
MARKUP_ALLOWED_SUBSEQUENT = " -.,:;!?\\/'\")]}>" MARKUP_ALLOWED_SUBSEQUENT = " -.,:;!?\\/'\")]}>"
@ -98,7 +98,7 @@ class State:
property_name = property.attrib["name"] property_name = property.attrib["name"]
if property_name in class_def.properties: if property_name in class_def.properties:
print_error('{}.xml: Duplicate property "{}".'.format(class_name, property_name), self) print_error(f'{class_name}.xml: Duplicate property "{property_name}".', self)
continue continue
type_name = TypeName.from_element(property) type_name = TypeName.from_element(property)
@ -106,7 +106,7 @@ class State:
getter = property.get("getter") or None getter = property.get("getter") or None
default_value = property.get("default") or None default_value = property.get("default") or None
if default_value is not None: if default_value is not None:
default_value = "``{}``".format(default_value) default_value = f"``{default_value}``"
overrides = property.get("overrides") or None overrides = property.get("overrides") or None
property_def = PropertyDef( property_def = PropertyDef(
@ -211,7 +211,7 @@ class State:
constant_def = ConstantDef(constant_name, value, constant.text, is_bitfield) constant_def = ConstantDef(constant_name, value, constant.text, is_bitfield)
if enum is None: if enum is None:
if constant_name in class_def.constants: if constant_name in class_def.constants:
print_error('{}.xml: Duplicate constant "{}".'.format(class_name, constant_name), self) print_error(f'{class_name}.xml: Duplicate constant "{constant_name}".', self)
continue continue
class_def.constants[constant_name] = constant_def class_def.constants[constant_name] = constant_def
@ -255,7 +255,7 @@ class State:
signal_name = signal.attrib["name"] signal_name = signal.attrib["name"]
if signal_name in class_def.signals: if signal_name in class_def.signals:
print_error('{}.xml: Duplicate signal "{}".'.format(class_name, signal_name), self) print_error(f'{class_name}.xml: Duplicate signal "{signal_name}".', self)
continue continue
params = self.parse_params(signal, "signal") params = self.parse_params(signal, "signal")
@ -278,16 +278,14 @@ class State:
theme_item_id = "{}_{}".format(theme_item_data_name, theme_item_name) theme_item_id = "{}_{}".format(theme_item_data_name, theme_item_name)
if theme_item_id in class_def.theme_items: if theme_item_id in class_def.theme_items:
print_error( print_error(
'{}.xml: Duplicate theme item "{}" of type "{}".'.format( f'{class_name}.xml: Duplicate theme item "{theme_item_name}" of type "{theme_item_data_name}".',
class_name, theme_item_name, theme_item_data_name
),
self, self,
) )
continue continue
default_value = theme_item.get("default") or None default_value = theme_item.get("default") or None
if default_value is not None: if default_value is not None:
default_value = "``{}``".format(default_value) default_value = f"``{default_value}``"
theme_item_def = ThemeItemDef( theme_item_def = ThemeItemDef(
theme_item_name, theme_item_name,
@ -320,9 +318,7 @@ class State:
if param_name.strip() == "" or param_name.startswith("_unnamed_arg"): if param_name.strip() == "" or param_name.startswith("_unnamed_arg"):
print_error( print_error(
'{}.xml: Empty argument name in {} "{}" at position {}.'.format( f'{self.current_class}.xml: Empty argument name in {context} "{root.attrib["name"]}" at position {param_index}.',
self.current_class, context, root.attrib["name"], param_index
),
self, self,
) )
@ -540,7 +536,7 @@ def main() -> None:
if entry.msgid in BASE_STRINGS: if entry.msgid in BASE_STRINGS:
strings_l10n[entry.msgid] = entry.msgstr strings_l10n[entry.msgid] = entry.msgstr
else: else:
print('No PO file at "{}" for language "{}".'.format(lang_file, args.lang)) print(f'No PO file at "{lang_file}" for language "{args.lang}".')
print("Checking for errors in the XML class reference...") print("Checking for errors in the XML class reference...")
@ -563,7 +559,7 @@ def main() -> None:
elif os.path.isfile(path): elif os.path.isfile(path):
if not path.endswith(".xml"): if not path.endswith(".xml"):
print('Got non-.xml file "{}" in input, skipping.'.format(path)) print(f'Got non-.xml file "{path}" in input, skipping.')
continue continue
file_list.append(path) file_list.append(path)
@ -575,17 +571,17 @@ def main() -> None:
try: try:
tree = ET.parse(cur_file) tree = ET.parse(cur_file)
except ET.ParseError as e: except ET.ParseError as e:
print_error("{}: Parse error while reading the file: {}".format(cur_file, e), state) print_error(f"{cur_file}: Parse error while reading the file: {e}", state)
continue continue
doc = tree.getroot() doc = tree.getroot()
if "version" not in doc.attrib: if "version" not in doc.attrib:
print_error('{}: "version" attribute missing from "doc".'.format(cur_file), state) print_error(f'{cur_file}: "version" attribute missing from "doc".', state)
continue continue
name = doc.attrib["name"] name = doc.attrib["name"]
if name in classes: if name in classes:
print_error('{}: Duplicate class "{}".'.format(cur_file, name), state) print_error(f'{cur_file}: Duplicate class "{name}".', state)
continue continue
classes[name] = (doc, cur_file) classes[name] = (doc, cur_file)
@ -594,7 +590,7 @@ def main() -> None:
try: try:
state.parse_class(data[0], data[1]) state.parse_class(data[0], data[1])
except Exception as e: except Exception as e:
print_error("{}.xml: Exception while parsing class: {}".format(name, e), state) print_error(f"{name}.xml: Exception while parsing class: {e}", state)
state.sort_classes() state.sort_classes()
@ -615,33 +611,25 @@ def main() -> None:
if state.num_warnings >= 2: if state.num_warnings >= 2:
print( print(
"{}{} warnings were found in the class reference XML. Please check the messages above.{}".format( f'{STYLES["yellow"]}{state.num_warnings} warnings were found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
STYLES["yellow"], state.num_warnings, STYLES["reset"]
)
) )
elif state.num_warnings == 1: elif state.num_warnings == 1:
print( print(
"{}1 warning was found in the class reference XML. Please check the messages above.{}".format( f'{STYLES["yellow"]}1 warning was found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
STYLES["yellow"], STYLES["reset"]
)
) )
if state.num_errors == 0: if state.num_errors == 0:
print("{}No errors found in the class reference XML.{}".format(STYLES["green"], STYLES["reset"])) print(f'{STYLES["green"]}No errors found in the class reference XML.{STYLES["reset"]}')
if not args.dry_run: if not args.dry_run:
print("Wrote reStructuredText files for each class to: %s" % args.output) print(f"Wrote reStructuredText files for each class to: {args.output}")
else: else:
if state.num_errors >= 2: if state.num_errors >= 2:
print( print(
"{}{} errors were found in the class reference XML. Please check the messages above.{}".format( f'{STYLES["red"]}{state.num_errors} errors were found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
STYLES["red"], state.num_errors, STYLES["reset"]
)
) )
else: else:
print( print(
"{}1 error was found in the class reference XML. Please check the messages above.{}".format( f'{STYLES["red"]}1 error was found in the class reference XML. Please check the messages above.{STYLES["reset"]}'
STYLES["red"], STYLES["reset"]
)
) )
exit(1) exit(1)
@ -650,12 +638,12 @@ def main() -> None:
def print_error(error: str, state: State) -> None: def print_error(error: str, state: State) -> None:
print("{}{}ERROR:{} {}{}".format(STYLES["red"], STYLES["bold"], STYLES["regular"], error, STYLES["reset"])) print(f'{STYLES["red"]}{STYLES["bold"]}ERROR:{STYLES["regular"]} {error}{STYLES["reset"]}')
state.num_errors += 1 state.num_errors += 1
def print_warning(error: str, state: State) -> None: def print_warning(warning: str, state: State) -> None:
print("{}{}WARNING:{} {}{}".format(STYLES["yellow"], STYLES["bold"], STYLES["regular"], error, STYLES["reset"])) print(f'{STYLES["yellow"]}{STYLES["bold"]}WARNING:{STYLES["regular"]} {warning}{STYLES["reset"]}')
state.num_warnings += 1 state.num_warnings += 1
@ -676,7 +664,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if dry_run: if dry_run:
f = open(os.devnull, "w", encoding="utf-8") f = open(os.devnull, "w", encoding="utf-8")
else: else:
f = open(os.path.join(output_dir, "class_" + class_name.lower() + ".rst"), "w", encoding="utf-8") f = open(os.path.join(output_dir, f"class_{class_name.lower()}.rst"), "w", encoding="utf-8")
# Remove the "Edit on Github" button from the online docs page. # Remove the "Edit on Github" button from the online docs page.
f.write(":github_url: hide\n\n") f.write(":github_url: hide\n\n")
@ -689,23 +677,23 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
git_branch = version.docs git_branch = version.docs
source_xml_path = os.path.relpath(class_def.filepath, root_directory).replace("\\", "/") source_xml_path = os.path.relpath(class_def.filepath, root_directory).replace("\\", "/")
source_github_url = "https://github.com/godotengine/godot/tree/{}/{}".format(git_branch, source_xml_path) source_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/{source_xml_path}"
generator_github_url = "https://github.com/godotengine/godot/tree/{}/doc/tools/make_rst.py".format(git_branch) generator_github_url = f"https://github.com/godotengine/godot/tree/{git_branch}/doc/tools/make_rst.py"
f.write(".. DO NOT EDIT THIS FILE!!!\n") f.write(".. DO NOT EDIT THIS FILE!!!\n")
f.write(".. Generated automatically from Godot engine sources.\n") f.write(".. Generated automatically from Godot engine sources.\n")
f.write(".. Generator: " + generator_github_url + ".\n") f.write(f".. Generator: {generator_github_url}.\n")
f.write(".. XML source: " + source_github_url + ".\n\n") f.write(f".. XML source: {source_github_url}.\n\n")
# Document reference id and header. # Document reference id and header.
f.write(".. _class_" + class_name + ":\n\n") f.write(f".. _class_{class_name}:\n\n")
f.write(make_heading(class_name, "=", False)) f.write(make_heading(class_name, "=", False))
# Inheritance tree # Inheritance tree
# Ascendants # Ascendants
if class_def.inherits: if class_def.inherits:
inherits = class_def.inherits.strip() inherits = class_def.inherits.strip()
f.write("**" + translate("Inherits:") + "** ") f.write(f'**{translate("Inherits:")}** ')
first = True first = True
while inherits in state.classes: while inherits in state.classes:
if not first: if not first:
@ -728,7 +716,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
inherited.append(c.name) inherited.append(c.name)
if len(inherited): if len(inherited):
f.write("**" + translate("Inherited By:") + "** ") f.write(f'**{translate("Inherited By:")}** ')
for i, child in enumerate(inherited): for i, child in enumerate(inherited):
if i > 0: if i > 0:
f.write(", ") f.write(", ")
@ -737,18 +725,18 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
# Brief description # Brief description
if class_def.brief_description is not None: if class_def.brief_description is not None:
f.write(format_text_block(class_def.brief_description.strip(), class_def, state) + "\n\n") f.write(f"{format_text_block(class_def.brief_description.strip(), class_def, state)}\n\n")
# Class description # Class description
if class_def.description is not None and class_def.description.strip() != "": if class_def.description is not None and class_def.description.strip() != "":
f.write(make_heading("Description", "-")) f.write(make_heading("Description", "-"))
f.write(format_text_block(class_def.description.strip(), class_def, state) + "\n\n") f.write(f"{format_text_block(class_def.description.strip(), class_def, state)}\n\n")
# Online tutorials # Online tutorials
if len(class_def.tutorials) > 0: if len(class_def.tutorials) > 0:
f.write(make_heading("Tutorials", "-")) f.write(make_heading("Tutorials", "-"))
for url, title in class_def.tutorials: for url, title in class_def.tutorials:
f.write("- " + make_link(url, title) + "\n\n") f.write(f"- {make_link(url, title)}\n\n")
# Properties overview # Properties overview
if len(class_def.properties) > 0: if len(class_def.properties) > 0:
@ -758,11 +746,11 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
type_rst = property_def.type_name.to_rst(state) type_rst = property_def.type_name.to_rst(state)
default = property_def.default_value default = property_def.default_value
if default is not None and property_def.overrides: if default is not None and property_def.overrides:
ref = ":ref:`{1}<class_{1}_property_{0}>`".format(property_def.name, property_def.overrides) ref = f":ref:`{property_def.overrides}<class_{property_def.overrides}_property_{property_def.name}>`"
# Not using translate() for now as it breaks table formatting. # Not using translate() for now as it breaks table formatting.
ml.append((type_rst, property_def.name, default + " " + "(overrides %s)" % ref)) ml.append((type_rst, property_def.name, f"{default} (overrides {ref})"))
else: else:
ref = ":ref:`{0}<class_{1}_property_{0}>`".format(property_def.name, class_name) ref = f":ref:`{property_def.name}<class_{class_name}_property_{property_def.name}>`"
ml.append((type_rst, ref, default)) ml.append((type_rst, ref, default))
format_table(f, ml, True) format_table(f, ml, True)
@ -796,9 +784,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
f.write(make_heading("Theme Properties", "-")) f.write(make_heading("Theme Properties", "-"))
pl: List[Tuple[Optional[str], ...]] = [] pl: List[Tuple[Optional[str], ...]] = []
for theme_item_def in class_def.theme_items.values(): for theme_item_def in class_def.theme_items.values():
ref = ":ref:`{0}<class_{2}_theme_{1}_{0}>`".format( ref = f":ref:`{theme_item_def.name}<class_{class_name}_theme_{theme_item_def.data_name}_{theme_item_def.name}>`"
theme_item_def.name, theme_item_def.data_name, class_name
)
pl.append((theme_item_def.type_name.to_rst(state), ref, theme_item_def.default_value)) pl.append((theme_item_def.type_name.to_rst(state), ref, theme_item_def.default_value))
format_table(f, pl, True) format_table(f, pl, True)
@ -811,12 +797,12 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if index != 0: if index != 0:
f.write("----\n\n") f.write("----\n\n")
f.write(".. _class_{}_signal_{}:\n\n".format(class_name, signal.name)) f.write(f".. _class_{class_name}_signal_{signal.name}:\n\n")
_, signature = make_method_signature(class_def, signal, "", state) _, signature = make_method_signature(class_def, signal, "", state)
f.write("- {}\n\n".format(signature)) f.write(f"- {signature}\n\n")
if signal.description is not None and signal.description.strip() != "": if signal.description is not None and signal.description.strip() != "":
f.write(format_text_block(signal.description.strip(), signal, state) + "\n\n") f.write(f"{format_text_block(signal.description.strip(), signal, state)}\n\n")
index += 1 index += 1
@ -829,24 +815,24 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if index != 0: if index != 0:
f.write("----\n\n") f.write("----\n\n")
f.write(".. _enum_{}_{}:\n\n".format(class_name, e.name)) f.write(f".. _enum_{class_name}_{e.name}:\n\n")
# Sphinx seems to divide the bullet list into individual <ul> tags if we weave the labels into it. # Sphinx seems to divide the bullet list into individual <ul> tags if we weave the labels into it.
# As such I'll put them all above the list. Won't be perfect but better than making the list visually broken. # As such I'll put them all above the list. Won't be perfect but better than making the list visually broken.
# As to why I'm not modifying the reference parser to directly link to the _enum label: # As to why I'm not modifying the reference parser to directly link to the _enum label:
# If somebody gets annoyed enough to fix it, all existing references will magically improve. # If somebody gets annoyed enough to fix it, all existing references will magically improve.
for value in e.values.values(): for value in e.values.values():
f.write(".. _class_{}_constant_{}:\n\n".format(class_name, value.name)) f.write(f".. _class_{class_name}_constant_{value.name}:\n\n")
if e.is_bitfield: if e.is_bitfield:
f.write("flags **{}**:\n\n".format(e.name)) f.write(f"flags **{e.name}**:\n\n")
else: else:
f.write("enum **{}**:\n\n".format(e.name)) f.write(f"enum **{e.name}**:\n\n")
for value in e.values.values(): for value in e.values.values():
f.write("- **{}** = **{}**".format(value.name, value.value)) f.write(f"- **{value.name}** = **{value.value}**")
if value.text is not None and value.text.strip() != "": if value.text is not None and value.text.strip() != "":
# If value.text contains a bullet point list, each entry needs additional indentation # If value.text contains a bullet point list, each entry needs additional indentation
f.write(" --- " + indent_bullets(format_text_block(value.text.strip(), value, state))) f.write(f" --- {indent_bullets(format_text_block(value.text.strip(), value, state))}")
f.write("\n\n") f.write("\n\n")
@ -858,12 +844,12 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
# Sphinx seems to divide the bullet list into individual <ul> tags if we weave the labels into it. # Sphinx seems to divide the bullet list into individual <ul> tags if we weave the labels into it.
# As such I'll put them all above the list. Won't be perfect but better than making the list visually broken. # As such I'll put them all above the list. Won't be perfect but better than making the list visually broken.
for constant in class_def.constants.values(): for constant in class_def.constants.values():
f.write(".. _class_{}_constant_{}:\n\n".format(class_name, constant.name)) f.write(f".. _class_{class_name}_constant_{constant.name}:\n\n")
for constant in class_def.constants.values(): for constant in class_def.constants.values():
f.write("- **{}** = **{}**".format(constant.name, constant.value)) f.write(f"- **{constant.name}** = **{constant.value}**")
if constant.text is not None and constant.text.strip() != "": if constant.text is not None and constant.text.strip() != "":
f.write(" --- " + format_text_block(constant.text.strip(), constant, state)) f.write(f" --- {format_text_block(constant.text.strip(), constant, state)}")
f.write("\n\n") f.write("\n\n")
@ -878,13 +864,13 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
f.write("----\n\n") f.write("----\n\n")
if i == 0: if i == 0:
f.write(".. _class_{}_annotation_{}:\n\n".format(class_name, m.name)) f.write(f".. _class_{class_name}_annotation_{m.name}:\n\n")
_, signature = make_method_signature(class_def, m, "", state) _, signature = make_method_signature(class_def, m, "", state)
f.write("- {}\n\n".format(signature)) f.write(f"- {signature}\n\n")
if m.description is not None and m.description.strip() != "": if m.description is not None and m.description.strip() != "":
f.write(format_text_block(m.description.strip(), m, state) + "\n\n") f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
index += 1 index += 1
@ -900,23 +886,23 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if index != 0: if index != 0:
f.write("----\n\n") f.write("----\n\n")
f.write(".. _class_{}_property_{}:\n\n".format(class_name, property_def.name)) f.write(f".. _class_{class_name}_property_{property_def.name}:\n\n")
f.write("- {} **{}**\n\n".format(property_def.type_name.to_rst(state), property_def.name)) f.write(f"- {property_def.type_name.to_rst(state)} **{property_def.name}**\n\n")
info: List[Tuple[Optional[str], ...]] = [] info: List[Tuple[Optional[str], ...]] = []
# Not using translate() for now as it breaks table formatting. # Not using translate() for now as it breaks table formatting.
if property_def.default_value is not None: if property_def.default_value is not None:
info.append(("*" + "Default" + "*", property_def.default_value)) info.append(("*Default*", property_def.default_value))
if property_def.setter is not None and not property_def.setter.startswith("_"): if property_def.setter is not None and not property_def.setter.startswith("_"):
info.append(("*" + "Setter" + "*", property_def.setter + "(" + "value" + ")")) info.append(("*Setter*", f"{property_def.setter}(value)"))
if property_def.getter is not None and not property_def.getter.startswith("_"): if property_def.getter is not None and not property_def.getter.startswith("_"):
info.append(("*" + "Getter" + "*", property_def.getter + "()")) info.append(("*Getter*", f"{property_def.getter}()"))
if len(info) > 0: if len(info) > 0:
format_table(f, info) format_table(f, info)
if property_def.text is not None and property_def.text.strip() != "": if property_def.text is not None and property_def.text.strip() != "":
f.write(format_text_block(property_def.text.strip(), property_def, state) + "\n\n") f.write(f"{format_text_block(property_def.text.strip(), property_def, state)}\n\n")
index += 1 index += 1
@ -931,13 +917,13 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
f.write("----\n\n") f.write("----\n\n")
if i == 0: if i == 0:
f.write(".. _class_{}_constructor_{}:\n\n".format(class_name, m.name)) f.write(f".. _class_{class_name}_constructor_{m.name}:\n\n")
ret_type, signature = make_method_signature(class_def, m, "", state) ret_type, signature = make_method_signature(class_def, m, "", state)
f.write("- {} {}\n\n".format(ret_type, signature)) f.write(f"- {ret_type} {signature}\n\n")
if m.description is not None and m.description.strip() != "": if m.description is not None and m.description.strip() != "":
f.write(format_text_block(m.description.strip(), m, state) + "\n\n") f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
index += 1 index += 1
@ -951,13 +937,13 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
f.write("----\n\n") f.write("----\n\n")
if i == 0: if i == 0:
f.write(".. _class_{}_method_{}:\n\n".format(class_name, m.name)) f.write(f".. _class_{class_name}_method_{m.name}:\n\n")
ret_type, signature = make_method_signature(class_def, m, "", state) ret_type, signature = make_method_signature(class_def, m, "", state)
f.write("- {} {}\n\n".format(ret_type, signature)) f.write(f"- {ret_type} {signature}\n\n")
if m.description is not None and m.description.strip() != "": if m.description is not None and m.description.strip() != "":
f.write(format_text_block(m.description.strip(), m, state) + "\n\n") f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
index += 1 index += 1
@ -972,16 +958,14 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if i == 0: if i == 0:
f.write( f.write(
".. _class_{}_operator_{}_{}:\n\n".format( f".. _class_{class_name}_operator_{sanitize_operator_name(m.name, state)}_{m.return_type.type_name}:\n\n"
class_name, sanitize_operator_name(m.name, state), m.return_type.type_name
)
) )
ret_type, signature = make_method_signature(class_def, m, "", state) ret_type, signature = make_method_signature(class_def, m, "", state)
f.write("- {} {}\n\n".format(ret_type, signature)) f.write(f"- {ret_type} {signature}\n\n")
if m.description is not None and m.description.strip() != "": if m.description is not None and m.description.strip() != "":
f.write(format_text_block(m.description.strip(), m, state) + "\n\n") f.write(f"{format_text_block(m.description.strip(), m, state)}\n\n")
index += 1 index += 1
@ -994,19 +978,19 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
if index != 0: if index != 0:
f.write("----\n\n") f.write("----\n\n")
f.write(".. _class_{}_theme_{}_{}:\n\n".format(class_name, theme_item_def.data_name, theme_item_def.name)) f.write(f".. _class_{class_name}_theme_{theme_item_def.data_name}_{theme_item_def.name}:\n\n")
f.write("- {} **{}**\n\n".format(theme_item_def.type_name.to_rst(state), theme_item_def.name)) f.write(f"- {theme_item_def.type_name.to_rst(state)} **{theme_item_def.name}**\n\n")
info = [] info = []
if theme_item_def.default_value is not None: if theme_item_def.default_value is not None:
# Not using translate() for now as it breaks table formatting. # Not using translate() for now as it breaks table formatting.
info.append(("*" + "Default" + "*", theme_item_def.default_value)) info.append(("*Default*", theme_item_def.default_value))
if len(info) > 0: if len(info) > 0:
format_table(f, info) format_table(f, info)
if theme_item_def.text is not None and theme_item_def.text.strip() != "": if theme_item_def.text is not None and theme_item_def.text.strip() != "":
f.write(format_text_block(theme_item_def.text.strip(), theme_item_def, state) + "\n\n") f.write(f"{format_text_block(theme_item_def.text.strip(), theme_item_def, state)}\n\n")
index += 1 index += 1
@ -1020,8 +1004,8 @@ def make_type(klass: str, state: State) -> str:
if link_type.endswith("[]"): # Typed array, strip [] to link to contained type. if link_type.endswith("[]"): # Typed array, strip [] to link to contained type.
link_type = link_type[:-2] link_type = link_type[:-2]
if link_type in state.classes: if link_type in state.classes:
return ":ref:`{}<class_{}>`".format(klass, link_type) return f":ref:`{klass}<class_{link_type}>`"
print_error('{}.xml: Unresolved type "{}".'.format(state.current_class, klass), state) print_error(f'{state.current_class}.xml: Unresolved type "{klass}".', state)
return klass return klass
@ -1041,11 +1025,11 @@ def make_enum(t: str, state: State) -> str:
c = "@GlobalScope" c = "@GlobalScope"
if c in state.classes and e in state.classes[c].enums: if c in state.classes and e in state.classes[c].enums:
return ":ref:`{0}<enum_{1}_{0}>`".format(e, c) return f":ref:`{e}<enum_{c}_{e}>`"
# Don't fail for `Vector3.Axis`, as this enum is a special case which is expected not to be resolved. # Don't fail for `Vector3.Axis`, as this enum is a special case which is expected not to be resolved.
if "{}.{}".format(c, e) != "Vector3.Axis": if f"{c}.{e}" != "Vector3.Axis":
print_error('{}.xml: Unresolved enum "{}".'.format(state.current_class, t), state) print_error(f'{state.current_class}.xml: Unresolved enum "{t}".', state)
return t return t
@ -1067,17 +1051,12 @@ def make_method_signature(
if is_method_def and ref_type != "": if is_method_def and ref_type != "":
if ref_type == "operator": if ref_type == "operator":
out += ":ref:`{0}<class_{1}_{2}_{3}_{4}>` ".format( op_name = definition.name.replace("<", "\\<") # So operator "<" gets correctly displayed.
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)}_{definition.return_type.type_name}>` "
class_def.name,
ref_type,
sanitize_operator_name(definition.name, state),
definition.return_type.type_name,
)
else: else:
out += ":ref:`{0}<class_{1}_{2}_{0}>` ".format(definition.name, class_def.name, ref_type) out += f":ref:`{definition.name}<class_{class_def.name}_{ref_type}_{definition.name}>` "
else: else:
out += "**{}** ".format(definition.name) out += f"**{definition.name}** "
out += "**(**" out += "**(**"
for i, arg in enumerate(definition.parameters): for i, arg in enumerate(definition.parameters):
@ -1086,10 +1065,10 @@ def make_method_signature(
else: else:
out += " " out += " "
out += "{} {}".format(arg.type_name.to_rst(state), arg.name) out += f"{arg.type_name.to_rst(state)} {arg.name}"
if arg.default_value is not None: if arg.default_value is not None:
out += "=" + arg.default_value out += f"={arg.default_value}"
if qualifiers is not None and "vararg" in qualifiers: if qualifiers is not None and "vararg" in qualifiers:
if len(definition.parameters) > 0: if len(definition.parameters) > 0:
@ -1103,7 +1082,7 @@ def make_method_signature(
# Use substitutions for abbreviations. This is used to display tooltips on hover. # Use substitutions for abbreviations. This is used to display tooltips on hover.
# See `make_footer()` for descriptions. # See `make_footer()` for descriptions.
for qualifier in qualifiers.split(): for qualifier in qualifiers.split():
out += " |" + qualifier + "|" out += f" |{qualifier}|"
return ret_type, out return ret_type, out
@ -1114,22 +1093,29 @@ def make_heading(title: str, underline: str, l10n: bool = True) -> str:
if new_title != title: if new_title != title:
title = new_title title = new_title
underline *= 2 # Double length to handle wide chars. underline *= 2 # Double length to handle wide chars.
return title + "\n" + (underline * len(title)) + "\n\n" return f"{title}\n{(underline * len(title))}\n\n"
def make_footer() -> str: def make_footer() -> str:
# Generate reusable abbreviation substitutions. # Generate reusable abbreviation substitutions.
# This way, we avoid bloating the generated rST with duplicate abbreviations. # This way, we avoid bloating the generated rST with duplicate abbreviations.
# fmt: off virtual_msg = translate("This method should typically be overridden by the user to have any effect.")
return ( const_msg = translate("This method has no side effects. It doesn't modify any of the instance's member variables.")
".. |virtual| replace:: :abbr:`virtual (" + translate("This method should typically be overridden by the user to have any effect.") + ")`\n" vararg_msg = translate("This method accepts any number of arguments after the ones described here.")
".. |const| replace:: :abbr:`const (" + translate("This method has no side effects. It doesn't modify any of the instance's member variables.") + ")`\n" constructor_msg = translate("This method is used to construct a type.")
".. |vararg| replace:: :abbr:`vararg (" + translate("This method accepts any number of arguments after the ones described here.") + ")`\n" static_msg = translate(
".. |constructor| replace:: :abbr:`constructor (" + translate("This method is used to construct a type.") + ")`\n" "This method doesn't need an instance to be called, so it can be called directly using the class name."
".. |static| replace:: :abbr:`static (" + translate("This method doesn't need an instance to be called, so it can be called directly using the class name.") + ")`\n" )
".. |operator| replace:: :abbr:`operator (" + translate("This method describes a valid operator to use with this type as left-hand operand.") + ")`\n" operator_msg = translate("This method describes a valid operator to use with this type as left-hand operand.")
return (
f".. |virtual| replace:: :abbr:`virtual ({virtual_msg})`\n"
f".. |const| replace:: :abbr:`const ({const_msg})`\n"
f".. |vararg| replace:: :abbr:`vararg ({vararg_msg})`\n"
f".. |constructor| replace:: :abbr:`constructor ({constructor_msg})`\n"
f".. |static| replace:: :abbr:`static ({static_msg})`\n"
f".. |operator| replace:: :abbr:`operator ({operator_msg})`\n"
) )
# fmt: on
def make_link(url: str, title: str) -> str: def make_link(url: str, title: str) -> str:
@ -1141,20 +1127,20 @@ def make_link(url: str, title: str) -> str:
# `#calling-javascript-from-script in Exporting For Web` # `#calling-javascript-from-script in Exporting For Web`
# Or use the title if provided. # Or use the title if provided.
if title != "": if title != "":
return "`" + title + " <../" + groups[0] + ".html" + groups[1] + ">`__" return f"`{title} <../{groups[0]}.html{groups[1]}>`__"
return "`" + groups[1] + " <../" + groups[0] + ".html" + groups[1] + ">`__ in :doc:`../" + groups[0] + "`" return f"`{groups[1]} <../{groups[0]}.html{groups[1]}>`__ in :doc:`../{groups[0]}`"
elif match.lastindex == 1: elif match.lastindex == 1:
# Doc reference, for example: # Doc reference, for example:
# `Math` # `Math`
if title != "": if title != "":
return ":doc:`" + title + " <../" + groups[0] + ">`" return f":doc:`{title} <../{groups[0]}>`"
return ":doc:`../" + groups[0] + "`" return f":doc:`../{groups[0]}`"
# External link, for example: # External link, for example:
# `http://enet.bespin.org/usergroup0.html` # `http://enet.bespin.org/usergroup0.html`
if title != "": if title != "":
return "`" + title + " <" + url + ">`__" return f"`{title} <{url}>`__"
return "`" + url + " <" + url + ">`__" return f"`{url} <{url}>`__"
# Formatting helpers. # Formatting helpers.
@ -1209,12 +1195,12 @@ def format_text_block(
result = format_codeblock(block_type, post_text, indent_level, state) result = format_codeblock(block_type, post_text, indent_level, state)
if result is None: if result is None:
return "" return ""
text = pre_text + result[0] text = f"{pre_text}{result[0]}"
pos += result[1] - indent_level pos += result[1] - indent_level
# Handle normal text # Handle normal text
else: else:
text = pre_text + "\n\n" + post_text text = f"{pre_text}\n\n{post_text}"
pos += 2 - indent_level pos += 2 - indent_level
next_brac_pos = text.find("[") next_brac_pos = text.find("[")
@ -1248,13 +1234,13 @@ def format_text_block(
if tag_text in state.classes: if tag_text in state.classes:
if tag_text == state.current_class: if tag_text == state.current_class:
# Don't create a link to the same class, format it as inline code. # Don't create a link to the same class, format it as inline code.
tag_text = "``{}``".format(tag_text) tag_text = f"``{tag_text}``"
else: else:
tag_text = make_type(tag_text, state) tag_text = make_type(tag_text, state)
escape_pre = True escape_pre = True
escape_post = True escape_post = True
# Tag is a cross-reference or a formating directive. # Tag is a cross-reference or a formatting directive.
else: else:
cmd = tag_text cmd = tag_text
space_pos = tag_text.find(" ") space_pos = tag_text.find(" ")
@ -1282,13 +1268,11 @@ def format_text_block(
else: else:
if cmd.startswith("/"): if cmd.startswith("/"):
print_warning( print_warning(
'{}.xml: Potential error inside of a code tag, found a string that looks like a closing tag "[{}]" in {}.'.format( f'{state.current_class}.xml: Potential error inside of a code tag, found a string that looks like a closing tag "[{cmd}]" in {context_name}.',
state.current_class, cmd, context_name
),
state, state,
) )
tag_text = "[" + tag_text + "]" tag_text = f"[{tag_text}]"
# Entering codeblocks and inline code tags. # Entering codeblocks and inline code tags.
@ -1307,18 +1291,14 @@ def format_text_block(
if cmd == "gdscript": if cmd == "gdscript":
if not inside_code_tabs: if not inside_code_tabs:
print_error( print_error(
"{}.xml: GDScript code block is used outside of [codeblocks] in {}.".format( f"{state.current_class}.xml: GDScript code block is used outside of [codeblocks] in {context_name}.",
state.current_class, cmd, context_name
),
state, state,
) )
tag_text = "\n .. code-tab:: gdscript\n" tag_text = "\n .. code-tab:: gdscript\n"
elif cmd == "csharp": elif cmd == "csharp":
if not inside_code_tabs: if not inside_code_tabs:
print_error( print_error(
"{}.xml: C# code block is used outside of [codeblocks] in {}.".format( f"{state.current_class}.xml: C# code block is used outside of [codeblocks] in {context_name}.",
state.current_class, cmd, context_name
),
state, state,
) )
tag_text = "\n .. code-tab:: csharp\n" tag_text = "\n .. code-tab:: csharp\n"
@ -1345,7 +1325,7 @@ def format_text_block(
if link_target == "": if link_target == "":
print_error( print_error(
'{}.xml: Empty cross-reference link "{}" in {}.'.format(state.current_class, cmd, context_name), f'{state.current_class}.xml: Empty cross-reference link "{cmd}" in {context_name}.',
state, state,
) )
tag_text = "" tag_text = ""
@ -1364,9 +1344,7 @@ def format_text_block(
ss = link_target.split(".") ss = link_target.split(".")
if len(ss) > 2: if len(ss) > 2:
print_error( print_error(
'{}.xml: Bad reference "{}" in {}.'.format( f'{state.current_class}.xml: Bad reference "{link_target}" in {context_name}.',
state.current_class, link_target, context_name
),
state, state,
) )
class_param, method_param = ss class_param, method_param = ss
@ -1386,63 +1364,50 @@ def format_text_block(
if cmd.startswith("method") and method_param not in class_def.methods: if cmd.startswith("method") and method_param not in class_def.methods:
print_error( print_error(
'{}.xml: Unresolved method reference "{}" in {}.'.format( f'{state.current_class}.xml: Unresolved method reference "{link_target}" in {context_name}.',
state.current_class, link_target, context_name
),
state, state,
) )
elif cmd.startswith("constructor") and method_param not in class_def.constructors: elif cmd.startswith("constructor") and method_param not in class_def.constructors:
print_error( print_error(
'{}.xml: Unresolved constructor reference "{}" in {}.'.format( f'{state.current_class}.xml: Unresolved constructor reference "{link_target}" in {context_name}.',
state.current_class, link_target, context_name
),
state, state,
) )
elif cmd.startswith("operator") and method_param not in class_def.operators: elif cmd.startswith("operator") and method_param not in class_def.operators:
print_error( print_error(
'{}.xml: Unresolved operator reference "{}" in {}.'.format( f'{state.current_class}.xml: Unresolved operator reference "{link_target}" in {context_name}.',
state.current_class, link_target, context_name
),
state, state,
) )
elif cmd.startswith("member") and method_param not in class_def.properties: elif cmd.startswith("member") and method_param not in class_def.properties:
print_error( print_error(
'{}.xml: Unresolved member reference "{}" in {}.'.format( f'{state.current_class}.xml: Unresolved member reference "{link_target}" in {context_name}.',
state.current_class, link_target, context_name
),
state, state,
) )
elif cmd.startswith("signal") and method_param not in class_def.signals: elif cmd.startswith("signal") and method_param not in class_def.signals:
print_error( print_error(
'{}.xml: Unresolved signal reference "{}" in {}.'.format( f'{state.current_class}.xml: Unresolved signal reference "{link_target}" in {context_name}.',
state.current_class, link_target, context_name
),
state, state,
) )
elif cmd.startswith("annotation") and method_param not in class_def.annotations: elif cmd.startswith("annotation") and method_param not in class_def.annotations:
print_error( print_error(
'{}.xml: Unresolved annotation reference "{}" in {}.'.format( f'{state.current_class}.xml: Unresolved annotation reference "{link_target}" in {context_name}.',
state.current_class, link_target, context_name
),
state, state,
) )
elif cmd.startswith("theme_item"): elif cmd.startswith("theme_item"):
if method_param not in class_def.theme_items: if method_param not in class_def.theme_items:
print_error( print_error(
'{}.xml: Unresolved theme item reference "{}" in {}.'.format( f'{state.current_class}.xml: Unresolved theme item reference "{link_target}" in {context_name}.',
state.current_class, link_target, context_name
),
state, state,
) )
else: else:
# Needs theme data type to be properly linked, which we cannot get without a class. # Needs theme data type to be properly linked, which we cannot get without a class.
ref_type = "_theme_{}".format(class_def.theme_items[method_param].data_name) name = class_def.theme_items[method_param].data_name
ref_type = f"_theme_{name}"
elif cmd.startswith("constant"): elif cmd.startswith("constant"):
found = False found = False
@ -1468,24 +1433,20 @@ def format_text_block(
if not found: if not found:
print_error( print_error(
'{}.xml: Unresolved constant reference "{}" in {}.'.format( f'{state.current_class}.xml: Unresolved constant reference "{link_target}" in {context_name}.',
state.current_class, link_target, context_name
),
state, state,
) )
else: else:
print_error( print_error(
'{}.xml: Unresolved type reference "{}" in method reference "{}" in {}.'.format( f'{state.current_class}.xml: Unresolved type reference "{class_param}" in method reference "{link_target}" in {context_name}.',
state.current_class, class_param, link_target, context_name
),
state, state,
) )
repl_text = method_param repl_text = method_param
if class_param != state.current_class: if class_param != state.current_class:
repl_text = "{}.{}".format(class_param, method_param) repl_text = f"{class_param}.{method_param}"
tag_text = ":ref:`{}<class_{}{}_{}>`".format(repl_text, class_param, ref_type, method_param) tag_text = f":ref:`{repl_text}<class_{class_param}{ref_type}_{method_param}>`"
escape_pre = True escape_pre = True
escape_post = True escape_post = True
@ -1502,9 +1463,7 @@ def format_text_block(
) )
if not valid_context: if not valid_context:
print_error( print_error(
'{}.xml: Argument reference "{}" used outside of method, signal, or annotation context in {}.'.format( f'{state.current_class}.xml: Argument reference "{link_target}" used outside of method, signal, or annotation context in {context_name}.',
state.current_class, link_target, context_name
),
state, state,
) )
else: else:
@ -1516,13 +1475,11 @@ def format_text_block(
break break
if not found: if not found:
print_error( print_error(
'{}.xml: Unresolved argument reference "{}" in {}.'.format( f'{state.current_class}.xml: Unresolved argument reference "{link_target}" in {context_name}.',
state.current_class, link_target, context_name
),
state, state,
) )
tag_text = "``{}``".format(link_target) tag_text = f"``{link_target}``"
# Formatting directives. # Formatting directives.
@ -1534,9 +1491,7 @@ def format_text_block(
endurl_pos = text.find("[/url]", endq_pos + 1) endurl_pos = text.find("[/url]", endq_pos + 1)
if endurl_pos == -1: if endurl_pos == -1:
print_error( print_error(
"{}.xml: Tag depth mismatch for [url]: no closing [/url] in {}.".format( f"{state.current_class}.xml: Tag depth mismatch for [url]: no closing [/url] in {context_name}.",
state.current_class, context_name
),
state, state,
) )
break break
@ -1556,7 +1511,7 @@ def format_text_block(
continue continue
else: else:
print_error( print_error(
'{}.xml: Misformatted [url] tag "{}" in {}.'.format(state.current_class, cmd, context_name), f'{state.current_class}.xml: Misformatted [url] tag "{cmd}" in {context_name}.',
state, state,
) )
@ -1613,18 +1568,14 @@ def format_text_block(
# Invalid syntax checks. # Invalid syntax checks.
elif cmd.startswith("/"): elif cmd.startswith("/"):
print_error( print_error(f'{state.current_class}.xml: Unrecognized closing tag "{cmd}" in {context_name}.', state)
'{}.xml: Unrecognized closing tag "{}" in {}.'.format(state.current_class, cmd, context_name), state
)
tag_text = "[" + tag_text + "]" tag_text = f"[{tag_text}]"
else: else:
print_error( print_error(f'{state.current_class}.xml: Unrecognized opening tag "{cmd}" in {context_name}.', state)
'{}.xml: Unrecognized opening tag "{}" in {}.'.format(state.current_class, cmd, context_name), state
)
tag_text = "``{}``".format(tag_text) tag_text = f"``{tag_text}``"
escape_pre = True escape_pre = True
escape_post = True escape_post = True
@ -1640,7 +1591,7 @@ def format_text_block(
iter_pos = post_text.find("*", iter_pos, next_brac_pos) iter_pos = post_text.find("*", iter_pos, next_brac_pos)
if iter_pos == -1: if iter_pos == -1:
break break
post_text = post_text[:iter_pos] + "\*" + post_text[iter_pos + 1 :] post_text = f"{post_text[:iter_pos]}\*{post_text[iter_pos + 1 :]}"
iter_pos += 2 iter_pos += 2
iter_pos = 0 iter_pos = 0
@ -1649,7 +1600,7 @@ def format_text_block(
if iter_pos == -1: if iter_pos == -1:
break break
if not post_text[iter_pos + 1].isalnum(): # don't escape within a snake_case word if not post_text[iter_pos + 1].isalnum(): # don't escape within a snake_case word
post_text = post_text[:iter_pos] + "\_" + post_text[iter_pos + 1 :] post_text = f"{post_text[:iter_pos]}\_{post_text[iter_pos + 1 :]}"
iter_pos += 2 iter_pos += 2
else: else:
iter_pos += 1 iter_pos += 1
@ -1659,9 +1610,7 @@ def format_text_block(
if tag_depth > 0: if tag_depth > 0:
print_error( print_error(
"{}.xml: Tag depth mismatch: too many (or too little) open/close tags in {}.".format( f"{state.current_class}.xml: Tag depth mismatch: too many (or too few) open/close tags in {context_name}.",
state.current_class, context_name
),
state, state,
) )
@ -1671,7 +1620,7 @@ def format_text_block(
def format_context_name(context: Union[DefinitionBase, None]) -> str: def format_context_name(context: Union[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 = '{} "{}" description'.format(context.definition_name, context.name) context_name = f'{context.definition_name} "{context.name}" description'
return context_name return context_name
@ -1683,7 +1632,7 @@ def escape_rst(text: str, until_pos: int = -1) -> str:
pos = text.find("\\", pos, until_pos) pos = text.find("\\", pos, until_pos)
if pos == -1: if pos == -1:
break break
text = text[:pos] + "\\\\" + text[pos + 1 :] text = f"{text[:pos]}\\\\{text[pos + 1 :]}"
pos += 2 pos += 2
# Escape * character to avoid interpreting it as emphasis # Escape * character to avoid interpreting it as emphasis
@ -1692,7 +1641,7 @@ def escape_rst(text: str, until_pos: int = -1) -> str:
pos = text.find("*", pos, until_pos) pos = text.find("*", pos, until_pos)
if pos == -1: if pos == -1:
break break
text = text[:pos] + "\*" + text[pos + 1 :] text = f"{text[:pos]}\*{text[pos + 1 :]}"
pos += 2 pos += 2
# Escape _ character at the end of a word to avoid interpreting it as an inline hyperlink # Escape _ character at the end of a word to avoid interpreting it as an inline hyperlink
@ -1702,7 +1651,7 @@ def escape_rst(text: str, until_pos: int = -1) -> str:
if pos == -1: if pos == -1:
break break
if not text[pos + 1].isalnum(): # don't escape within a snake_case word if not text[pos + 1].isalnum(): # don't escape within a snake_case word
text = text[:pos] + "\_" + text[pos + 1 :] text = f"{text[:pos]}\_{text[pos + 1 :]}"
pos += 2 pos += 2
else: else:
pos += 1 pos += 1
@ -1713,10 +1662,10 @@ def escape_rst(text: str, until_pos: int = -1) -> str:
def format_codeblock(code_type: str, post_text: str, indent_level: int, state: State) -> Union[Tuple[str, int], None]: def format_codeblock(code_type: str, post_text: str, indent_level: int, state: State) -> Union[Tuple[str, int], None]:
end_pos = post_text.find("[/" + code_type + "]") end_pos = post_text.find("[/" + code_type + "]")
if end_pos == -1: if end_pos == -1:
print_error("{}.xml: [" + code_type + "] without a closing tag.".format(state.current_class), state) print_error(f"{state.current_class}.xml: [{code_type}] without a closing tag.", state)
return None return None
code_text = post_text[len("[" + code_type + "]") : end_pos] code_text = post_text[len(f"[{code_type}]") : end_pos]
post_text = post_text[end_pos:] post_text = post_text[end_pos:]
# Remove extraneous tabs # Remove extraneous tabs
@ -1732,19 +1681,17 @@ def format_codeblock(code_type: str, post_text: str, indent_level: int, state: S
if to_skip > indent_level: if to_skip > indent_level:
print_error( print_error(
"{}.xml: Four spaces should be used for indentation within [{}].".format( f"{state.current_class}.xml: Four spaces should be used for indentation within [{code_type}].",
state.current_class, code_type
),
state, state,
) )
if len(code_text[code_pos + to_skip + 1 :]) == 0: if len(code_text[code_pos + to_skip + 1 :]) == 0:
code_text = code_text[:code_pos] + "\n" code_text = f"{code_text[:code_pos]}\n"
code_pos += 1 code_pos += 1
else: else:
code_text = code_text[:code_pos] + "\n " + code_text[code_pos + to_skip + 1 :] code_text = f"{code_text[:code_pos]}\n {code_text[code_pos + to_skip + 1 :]}"
code_pos += 5 - to_skip code_pos += 5 - to_skip
return ("\n[" + code_type + "]" + code_text + post_text, len("\n[" + code_type + "]" + code_text)) return (f"\n[{code_type}]{code_text}{post_text}", len(f"\n[{code_type}]{code_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[Optional[str], ...]], remove_empty_columns: bool = False) -> None:
@ -1771,7 +1718,7 @@ def format_table(f: TextIO, data: List[Tuple[Optional[str], ...]], remove_empty_
for i, text in enumerate(row): for i, text in enumerate(row):
if column_sizes[i] == 0 and remove_empty_columns: if column_sizes[i] == 0 and remove_empty_columns:
continue continue
row_text += " " + (text or "").ljust(column_sizes[i]) + " |" row_text += f' {(text or "").ljust(column_sizes[i])} |'
row_text += "\n" row_text += "\n"
f.write(row_text) f.write(row_text)
f.write(sep) f.write(sep)
@ -1831,7 +1778,7 @@ def sanitize_operator_name(dirty_name: str, state: State) -> str:
else: else:
clear_name = "xxx" clear_name = "xxx"
print_error('Unsupported operator type "{}", please add the missing rule.'.format(dirty_name), state) print_error(f'Unsupported operator type "{dirty_name}", please add the missing rule.', state)
return clear_name return clear_name
@ -1850,7 +1797,7 @@ def indent_bullets(text: str) -> str:
pos += 1 pos += 1
if pos < len(line) and line[pos] in bullet_points: if pos < len(line) and line[pos] in bullet_points:
lines[line_index] = line[:pos] + "\t" + line[pos:] lines[line_index] = f"{line[:pos]}\t{line[pos:]}"
return "".join(lines) return "".join(lines)