diff options
Diffstat (limited to 'doc/tools/doc_status.py')
-rwxr-xr-x | doc/tools/doc_status.py | 351 |
1 files changed, 184 insertions, 167 deletions
diff --git a/doc/tools/doc_status.py b/doc/tools/doc_status.py index e6e6d5f606..629b5a032b 100755 --- a/doc/tools/doc_status.py +++ b/doc/tools/doc_status.py @@ -13,75 +13,74 @@ import xml.etree.ElementTree as ET ################################################################################ flags = { - 'c': platform.platform() != 'Windows', # Disable by default on windows, since we use ANSI escape codes - 'b': False, - 'g': False, - 's': False, - 'u': False, - 'h': False, - 'p': False, - 'o': True, - 'i': False, - 'a': True, - 'e': False, + "c": platform.platform() != "Windows", # Disable by default on windows, since we use ANSI escape codes + "b": False, + "g": False, + "s": False, + "u": False, + "h": False, + "p": False, + "o": True, + "i": False, + "a": True, + "e": False, } flag_descriptions = { - 'c': 'Toggle colors when outputting.', - 'b': 'Toggle showing only not fully described classes.', - 'g': 'Toggle showing only completed classes.', - 's': 'Toggle showing comments about the status.', - 'u': 'Toggle URLs to docs.', - 'h': 'Show help and exit.', - 'p': 'Toggle showing percentage as well as counts.', - 'o': 'Toggle overall column.', - 'i': 'Toggle collapse of class items columns.', - 'a': 'Toggle showing all items.', - 'e': 'Toggle hiding empty items.', + "c": "Toggle colors when outputting.", + "b": "Toggle showing only not fully described classes.", + "g": "Toggle showing only completed classes.", + "s": "Toggle showing comments about the status.", + "u": "Toggle URLs to docs.", + "h": "Show help and exit.", + "p": "Toggle showing percentage as well as counts.", + "o": "Toggle overall column.", + "i": "Toggle collapse of class items columns.", + "a": "Toggle showing all items.", + "e": "Toggle hiding empty items.", } long_flags = { - 'colors': 'c', - 'use-colors': 'c', - - 'bad': 'b', - 'only-bad': 'b', - - 'good': 'g', - 'only-good': 'g', - - 'comments': 's', - 'status': 's', - - 'urls': 'u', - 'gen-url': 'u', - - 'help': 'h', - - 'percent': 'p', - 'use-percentages': 'p', - - 'overall': 'o', - 'use-overall': 'o', - - 'items': 'i', - 'collapse': 'i', - - 'all': 'a', - - 'empty': 'e', + "colors": "c", + "use-colors": "c", + "bad": "b", + "only-bad": "b", + "good": "g", + "only-good": "g", + "comments": "s", + "status": "s", + "urls": "u", + "gen-url": "u", + "help": "h", + "percent": "p", + "use-percentages": "p", + "overall": "o", + "use-overall": "o", + "items": "i", + "collapse": "i", + "all": "a", + "empty": "e", } -table_columns = ['name', 'brief_description', 'description', 'methods', 'constants', 'members', 'signals', 'theme_items'] -table_column_names = ['Name', 'Brief Desc.', 'Desc.', 'Methods', 'Constants', 'Members', 'Signals', 'Theme Items'] +table_columns = [ + "name", + "brief_description", + "description", + "methods", + "constants", + "members", + "signals", + "theme_items", +] +table_column_names = ["Name", "Brief Desc.", "Desc.", "Methods", "Constants", "Members", "Signals", "Theme Items"] 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": [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 } overall_progress_description_weigth = 10 @@ -90,6 +89,7 @@ overall_progress_description_weigth = 10 # Utils # ################################################################################ + def validate_tag(elem, tag): if elem.tag != tag: print('Tag mismatch, expected "' + tag + '", got ' + elem.tag) @@ -97,36 +97,38 @@ def validate_tag(elem, tag): def color(color, string): - if flags['c'] and terminal_supports_color(): - color_format = '' + 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' + color_format += "\033[" + str(code) + "m" + return color_format + string + "\033[0m" else: return string -ansi_escape = re.compile(r'\x1b[^m]*m') + +ansi_escape = re.compile(r"\x1b[^m]*m") def nonescape_len(s): - return len(ansi_escape.sub('', s)) + 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) + supported_platform = p != "Pocket PC" and (p != "win32" or "ANSICON" in os.environ) - is_a_tty = hasattr(sys.stdout, 'isatty') and sys.stdout.isatty() + 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 # ################################################################################ -class ClassStatusProgress: +class ClassStatusProgress: def __init__(self, described=0, total=0): self.described = described self.total = total @@ -143,42 +145,41 @@ class ClassStatusProgress: return self.described >= self.total def to_configured_colored_string(self): - if flags['p']: - return self.to_colored_string('{percent}% ({has}/{total})', '{pad_percent}{pad_described}{s}{pad_total}') + if flags["p"]: + return self.to_colored_string("{percent}% ({has}/{total})", "{pad_percent}{pad_described}{s}{pad_total}") else: return self.to_colored_string() - def to_colored_string(self, format='{has}/{total}', pad_format='{pad_described}{s}{pad_total}'): + def to_colored_string(self, format="{has}/{total}", pad_format="{pad_described}{s}{pad_total}"): ratio = float(self.described) / float(self.total) if self.total != 0 else 1 percent = int(round(100 * ratio)) s = format.format(has=str(self.described), total=str(self.total), percent=str(percent)) if self.described >= self.total: - s = color('part_good', s) + s = color("part_good", s) elif self.described >= self.total / 4 * 3: - s = color('part_mostly_good', s) + s = color("part_mostly_good", s) elif self.described > 0: - s = color('part_problem', s) + s = color("part_problem", s) else: - s = color('part_big_problem', s) + s = color("part_big_problem", s) pad_size = max(len(str(self.described)), len(str(self.total))) - pad_described = ''.ljust(pad_size - len(str(self.described))) - pad_percent = ''.ljust(3 - len(str(percent))) - pad_total = ''.ljust(pad_size - len(str(self.total))) + pad_described = "".ljust(pad_size - len(str(self.described))) + pad_percent = "".ljust(3 - len(str(percent))) + pad_total = "".ljust(pad_size - len(str(self.total))) return pad_format.format(pad_described=pad_described, pad_total=pad_total, pad_percent=pad_percent, s=s) class ClassStatus: - - def __init__(self, name=''): + def __init__(self, name=""): self.name = name self.has_brief_description = True self.has_description = True self.progresses = { - 'methods': ClassStatusProgress(), - 'constants': ClassStatusProgress(), - 'members': ClassStatusProgress(), - 'theme_items': ClassStatusProgress(), - 'signals': ClassStatusProgress() + "methods": ClassStatusProgress(), + "constants": ClassStatusProgress(), + "members": ClassStatusProgress(), + "theme_items": ClassStatusProgress(), + "signals": ClassStatusProgress(), } def __add__(self, other): @@ -208,66 +209,70 @@ class ClassStatus: def make_output(self): output = {} - output['name'] = color('name', self.name) + output["name"] = color("name", self.name) - ok_string = color('part_good', 'OK') - missing_string = color('part_big_problem', 'MISSING') + ok_string = color("part_good", "OK") + missing_string = color("part_big_problem", "MISSING") - output['brief_description'] = ok_string if self.has_brief_description else missing_string - output['description'] = ok_string if self.has_description else missing_string + output["brief_description"] = ok_string if self.has_brief_description else missing_string + output["description"] = ok_string if self.has_description else missing_string description_progress = ClassStatusProgress( (self.has_brief_description + self.has_description) * overall_progress_description_weigth, - 2 * overall_progress_description_weigth + 2 * overall_progress_description_weigth, ) items_progress = ClassStatusProgress() - for k in ['methods', 'constants', 'members', 'signals', 'theme_items']: + for k in ["methods", "constants", "members", "signals", "theme_items"]: items_progress += self.progresses[k] output[k] = self.progresses[k].to_configured_colored_string() - output['items'] = items_progress.to_configured_colored_string() + output["items"] = items_progress.to_configured_colored_string() - output['overall'] = (description_progress + items_progress).to_colored_string(color('bold', '{percent}%'), '{pad_percent}{s}') + output["overall"] = (description_progress + items_progress).to_colored_string( + color("bold", "{percent}%"), "{pad_percent}{s}" + ) - if self.name.startswith('Total'): - output['url'] = color('url', 'https://docs.godotengine.org/en/latest/classes/') - if flags['s']: - output['comment'] = color('part_good', 'ALL OK') + if self.name.startswith("Total"): + output["url"] = color("url", "https://docs.godotengine.org/en/latest/classes/") + if flags["s"]: + output["comment"] = color("part_good", "ALL OK") else: - output['url'] = color('url', 'https://docs.godotengine.org/en/latest/classes/class_{name}.html'.format(name=self.name.lower())) + output["url"] = color( + "url", "https://docs.godotengine.org/en/latest/classes/class_{name}.html".format(name=self.name.lower()) + ) - if flags['s'] and not flags['g'] and self.is_ok(): - output['comment'] = color('part_good', 'ALL OK') + if flags["s"] and not flags["g"] and self.is_ok(): + output["comment"] = color("part_good", "ALL OK") return output @staticmethod def generate_for_class(c): status = ClassStatus() - status.name = c.attrib['name'] + status.name = c.attrib["name"] for tag in list(c): - if tag.tag == 'brief_description': + if tag.tag == "brief_description": status.has_brief_description = len(tag.text.strip()) > 0 - elif tag.tag == 'description': + elif tag.tag == "description": status.has_description = len(tag.text.strip()) > 0 - elif tag.tag in ['methods', 'signals']: + elif tag.tag in ["methods", "signals"]: for sub_tag in list(tag): - descr = sub_tag.find('description') + descr = sub_tag.find("description") status.progresses[tag.tag].increment(len(descr.text.strip()) > 0) - elif tag.tag in ['constants', 'members', 'theme_items']: + elif tag.tag in ["constants", "members", "theme_items"]: for sub_tag in list(tag): if not sub_tag.text is None: status.progresses[tag.tag].increment(len(sub_tag.text.strip()) > 0) - elif tag.tag in ['tutorials']: + elif tag.tag in ["tutorials"]: pass # Ignore those tags for now - elif tag.tag in ['theme_items']: + elif tag.tag in ["theme_items"]: pass # Ignore those tags, since they seem to lack description at all else: @@ -286,63 +291,69 @@ merged_file = "" for arg in sys.argv[1:]: try: - if arg.startswith('--'): + if arg.startswith("--"): flags[long_flags[arg[2:]]] = not flags[long_flags[arg[2:]]] - elif arg.startswith('-'): + elif arg.startswith("-"): for f in arg[1:]: flags[f] = not flags[f] elif os.path.isdir(arg): for f in os.listdir(arg): - if f.endswith('.xml'): - input_file_list.append(os.path.join(arg, f)); + if f.endswith(".xml"): + input_file_list.append(os.path.join(arg, f)) else: input_class_list.append(arg) except KeyError: print("Unknown command line flag: " + arg) sys.exit(1) -if flags['i']: - for r in ['methods', 'constants', 'members', 'signals', 'theme_items']: +if flags["i"]: + for r in ["methods", "constants", "members", "signals", "theme_items"]: index = table_columns.index(r) del table_column_names[index] del table_columns[index] - table_column_names.append('Items') - table_columns.append('items') + table_column_names.append("Items") + table_columns.append("items") -if flags['o'] == (not flags['i']): - table_column_names.append(color('bold', 'Overall')) - table_columns.append('overall') +if flags["o"] == (not flags["i"]): + table_column_names.append(color("bold", "Overall")) + table_columns.append("overall") -if flags['u']: - table_column_names.append('Docs URL') - table_columns.append('url') +if flags["u"]: + table_column_names.append("Docs URL") + table_columns.append("url") ################################################################################ # Help # ################################################################################ -if len(input_file_list) < 1 or flags['h']: - if not flags['h']: - print(color('section', 'Invalid usage') + ': Please specify a classes directory') - print(color('section', 'Usage') + ': doc_status.py [flags] <classes_dir> [class names]') - print('\t< and > signify required parameters, while [ and ] signify optional parameters.') - print(color('section', 'Available flags') + ':') +if len(input_file_list) < 1 or flags["h"]: + if not flags["h"]: + print(color("section", "Invalid usage") + ": Please specify a classes directory") + print(color("section", "Usage") + ": doc_status.py [flags] <classes_dir> [class names]") + print("\t< and > signify required parameters, while [ and ] signify optional parameters.") + print(color("section", "Available flags") + ":") possible_synonym_list = list(long_flags) possible_synonym_list.sort() flag_list = list(flags) flag_list.sort() for flag in flag_list: - synonyms = [color('name', '-' + flag)] + synonyms = [color("name", "-" + flag)] for synonym in possible_synonym_list: if long_flags[synonym] == flag: - synonyms.append(color('name', '--' + synonym)) - - print(('{synonyms} (Currently ' + color('state_' + ('on' if flags[flag] else 'off'), '{value}') + ')\n\t{description}').format( - synonyms=', '.join(synonyms), - value=('on' if flags[flag] else 'off'), - description=flag_descriptions[flag] - )) + synonyms.append(color("name", "--" + synonym)) + + print( + ( + "{synonyms} (Currently " + + color("state_" + ("on" if flags[flag] else "off"), "{value}") + + ")\n\t{description}" + ).format( + synonyms=", ".join(synonyms), + value=("on" if flags[flag] else "off"), + description=flag_descriptions[flag], + ) + ) sys.exit(0) @@ -357,21 +368,21 @@ for file in input_file_list: tree = ET.parse(file) doc = tree.getroot() - if 'version' not in doc.attrib: + if "version" not in doc.attrib: print('Version missing from "doc"') sys.exit(255) - version = doc.attrib['version'] + version = doc.attrib["version"] - if doc.attrib['name'] in class_names: + if doc.attrib["name"] in class_names: continue - class_names.append(doc.attrib['name']) - classes[doc.attrib['name']] = doc + class_names.append(doc.attrib["name"]) + classes[doc.attrib["name"]] = doc class_names.sort() if len(input_class_list) < 1: - input_class_list = ['*'] + input_class_list = ["*"] filtered_classes = set() for pattern in input_class_list: @@ -384,23 +395,23 @@ filtered_classes.sort() ################################################################################ table = [table_column_names] -table_row_chars = '| - ' -table_column_chars = '|' +table_row_chars = "| - " +table_column_chars = "|" -total_status = ClassStatus('Total') +total_status = ClassStatus("Total") for cn in filtered_classes: c = classes[cn] - validate_tag(c, 'class') + validate_tag(c, "class") status = ClassStatus.generate_for_class(c) total_status = total_status + status - if (flags['b'] and status.is_ok()) or (flags['g'] and not status.is_ok()) or (not flags['a']): + if (flags["b"] and status.is_ok()) or (flags["g"] and not status.is_ok()) or (not flags["a"]): continue - if flags['e'] and status.is_empty(): + if flags["e"] and status.is_empty(): continue out = status.make_output() @@ -409,10 +420,10 @@ for cn in filtered_classes: if column in out: row.append(out[column]) else: - row.append('') + row.append("") - if 'comment' in out and out['comment'] != '': - row.append(out['comment']) + if "comment" in out and out["comment"] != "": + row.append(out["comment"]) table.append(row) @@ -421,22 +432,22 @@ for cn in filtered_classes: # Print output table # ################################################################################ -if len(table) == 1 and flags['a']: - print(color('part_big_problem', 'No classes suitable for printing!')) +if len(table) == 1 and flags["a"]: + print(color("part_big_problem", "No classes suitable for printing!")) sys.exit(0) -if len(table) > 2 or not flags['a']: - total_status.name = 'Total = {0}'.format(len(table) - 1) +if len(table) > 2 or not flags["a"]: + total_status.name = "Total = {0}".format(len(table) - 1) out = total_status.make_output() row = [] for column in table_columns: if column in out: row.append(out[column]) else: - row.append('') + row.append("") table.append(row) -if flags['a']: +if flags["a"]: # Duplicate the headers at the bottom of the table so they can be viewed # without having to scroll back to the top. table.append(table_column_names) @@ -451,7 +462,9 @@ for row in table: divider_string = table_row_chars[0] for cell_i in range(len(table[0])): - divider_string += table_row_chars[1] + table_row_chars[2] * (table_column_sizes[cell_i]) + table_row_chars[1] + table_row_chars[0] + divider_string += ( + table_row_chars[1] + table_row_chars[2] * (table_column_sizes[cell_i]) + table_row_chars[1] + table_row_chars[0] + ) print(divider_string) for row_i, row in enumerate(table): @@ -461,7 +474,11 @@ for row_i, row in enumerate(table): if cell_i == 0: row_string += table_row_chars[3] + cell + table_row_chars[3] * (padding_needed - 1) else: - row_string += table_row_chars[3] * int(math.floor(float(padding_needed) / 2)) + cell + table_row_chars[3] * int(math.ceil(float(padding_needed) / 2)) + row_string += ( + table_row_chars[3] * int(math.floor(float(padding_needed) / 2)) + + cell + + table_row_chars[3] * int(math.ceil(float(padding_needed) / 2)) + ) row_string += table_column_chars print(row_string) @@ -474,5 +491,5 @@ for row_i, row in enumerate(table): print(divider_string) -if total_status.is_ok() and not flags['g']: - print('All listed classes are ' + color('part_good', 'OK') + '!') +if total_status.is_ok() and not flags["g"]: + print("All listed classes are " + color("part_good", "OK") + "!") |