From f95f099eb2337c9e367bb46f61324b709c42973e Mon Sep 17 00:00:00 2001 From: Jorge Araya Navarro Date: Sat, 26 Sep 2015 23:55:00 -0600 Subject: Adding the new Python file This script works different compared to the other, for instance, it requires Python 3.x to run. It also have more sophisticate flags to run. And finally this file conforms to PEP8. This script is not finished yet, though. --- tools/docdump/makedocs.py | 184 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 tools/docdump/makedocs.py (limited to 'tools/docdump') diff --git a/tools/docdump/makedocs.py b/tools/docdump/makedocs.py new file mode 100644 index 0000000000..d11515e94a --- /dev/null +++ b/tools/docdump/makedocs.py @@ -0,0 +1,184 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +# +# makedocs.py: Generate documentation for Open Project Wiki +# +# Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. +# +# Contributor: Jorge Araya Navarro +# + +import re +import argparse +import logging +from os import path +from itertools import izip_longest +from xml.etree import ElementTree + +logging.basicConfig(level=logging.INFO) + + +def getxmlfloc(): + """ Returns the supposed location of the XML file + """ + filepath = path.dirname(path.abspath(__file__)) + return path.join(filepath, "class_list.xml") + + +def sortkey(c): + """ Symbols are first, letters second + """ + if "_" == c.attrib["name"][0]: + return True + else: + return c.attrib["name"] + + +def toOP(text): + """ Convert commands in text to Open Project commands + """ + # We are going to do something very complicated with all HTML commands + # sadly, some commands are embedded inside other commands, so some steps + # are needed before converting some commands to Textile markup + groups = re.finditer((r'\[html (?P/?\w+/?)(\]| |=)?(\]| |=)?(?P\w+)?(\]| |=)?(?P"[^"]+")?/?\]'), text) + alignstr = "" + for group in groups: + gd = group.groupdict() + if gd["command"] == "br/": + text = text.replace(group.group(0), "\n\n", 1) + elif gd["command"] == "div": + if gd["value"] == '"center"': + alignstr = "{display:block; margin-left:auto; margin-right:auto;}" + elif gd["value"] == '"left"': + alignstr = "<" + elif gd["value"] == '"right"': + alignstr = ">" + text = text.replace(group.group(0), "\n\n", 1) + elif gd["command"] == "/div": + alignstr = "" + text = text.replace(group.group(0), "\n\n", 1) + elif gd["command"] == "img": + text = text.replace(group.group(0), "!{align}{src}!".format( + align=alignstr, src=gd["value"].strip('"')), 1) + elif gd["command"] == "b" or gd["command"] == "/b": + text = text.replace(group.group(0), "*", 1) + elif gd["command"] == "i" or gd["command"] == "/i": + text = text.replace(group.group(0), "_", 1) + elif gd["command"] == "u" or gd["command"] == "/u": + text = text.replace(group.group(0), "+", 1) + # TODO: Process other non-html commands + return text + "\n\n" + +desc = "Generates documentation from a XML file to different markup languages" + +parser = argparse.ArgumentParser(description=desc) +parser.add_argument("--input", dest="xmlfp", default=getxmlfloc(), + help="Input XML file, default: {}".format(getxmlfloc())) +parser.add_argument("--output-dir", dest="outputdir", required=True, + help="Output directory for generated files") +# TODO: add an option for outputting different markup formats + +args = parser.parse_args() +# Let's check if the file and output directory exists +if not path.isfile(args.xmlfp): + logging.critical("File not found: {}".format(args.xmlfp)) + exit(1) +elif not path.isdir(args.outputdir): + logging.critical("Path does not exist: {}".format(args.outputdir)) + exit(1) + +# Let's begin +tree = ElementTree.parse(args.xmlfp) +root = tree.getroot() + +# Check version attribute exists in +if "version" not in root.attrib: + logging.critical("'s version attribute missing") + exit(1) + +version = root.attrib["version"] +classes = sorted(root, key=sortkey) +# first column is always longer, second column of classes should be shorter +zclasses = izip_longest(classes[:len(classes) / 2 + 1], + classes[len(classes) / 2 + 1:], + fillvalue="") + +# We write the class_list file and also each class file at once +with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl: + # Write header of table + fcl.write("|^.\n") + fcl.write("|_. Index symbol |_. Class name " + "|_. Index symbol |_. Class name |\n") + fcl.write("|-.\n") + + indexletterl = "" + indexletterr = "" + for gdclassl, gdclassr in zclasses: + # write a row # + # write the index symbol column, left + if indexletterl != gdclassl.attrib["name"][0]: + indexletterl = gdclassl.attrib["name"][0] + fcl.write("| *{}* |".format(indexletterl.upper())) + else: + # empty cell + fcl.write("| |") + # write the class name column, left + fcl.write("\"{name}({title})\":/class_{link}".format( + name=gdclassl.attrib["name"], + title="Go to page of class " + gdclassl.attrib["name"], + link="class_" + gdclassl.attrib["name"].lower())) + + # write the index symbol column, right + if isinstance(gdclassr, ElementTree.Element): + if indexletterr != gdclassr.attrib["name"][0]: + indexletterr = gdclassr.attrib["name"][0] + fcl.write("| *{}* |".format(indexletterr.upper())) + else: + # empty cell + fcl.write("| |") + # We are dealing with an empty string + else: + # two empty cell + fcl.write("| | |\n") + # We won't get the name of the class since there is no ElementTree + # object for the right side of the tuple, so we iterate the next + # tuple instead + continue + + # write the class name column (if any), right + fcl.write("\"{name}({title})\":/{link} |\n".format( + name=gdclassr.attrib["name"], + title="Go to page of class " + gdclassr.attrib["name"], + link=gdclassr.attrib["name"].lower())) + + # row written # + # now, let's write each class page for each class + for gdclass in [gdclassl, gdclassr]: + if not isinstance(ElementTree.Element, gdclass): + continue + + classname = gdclass.attrib["name"] + with open(path.join(args.outputdir, "{}.txt".format( + classname.lower())), "wb") as clsf: + # First level header with the name of the class + clsf.write("h1. {}\n".format(classname)) + # lay the attributes + if "inherits" in gdclass.attrib: + inh = gdclass.attrib["inherits"].strip() + clsf.write( + "*Inherits:* \"{name}({title})\":/class_{link}\n". + format( + name=classname, + title="Go to page of class " + classname, + link=classname.lower())) + if "category" in gdclass.attrib: + clsf.write("*Category:* {}". + format(gdclass.attrib["category"].strip())) + # lay child nodes + for gdchild in gdclass.iter(): + if gdchild.tag == "brief_description": + clsf.write("h2. Brief Description\n") + clsf.write(toOP(gdchild.text.strip())) + # convert commands in text -- cgit v1.2.3 From 7a008afc67cbbdc26e38477621856c04193280b6 Mon Sep 17 00:00:00 2001 From: Jorge Araya Navarro Date: Sun, 27 Sep 2015 19:25:13 -0600 Subject: XML to Open Project Wiki implemented --- tools/docdump/makedocs.py | 264 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 229 insertions(+), 35 deletions(-) (limited to 'tools/docdump') diff --git a/tools/docdump/makedocs.py b/tools/docdump/makedocs.py index d11515e94a..81469eed9c 100644 --- a/tools/docdump/makedocs.py +++ b/tools/docdump/makedocs.py @@ -9,16 +9,47 @@ # Contributor: Jorge Araya Navarro # +# IMPORTANT NOTICE: +# If you are going to modify anything from this file, please be sure to follow +# the Style Guide for Python Code or often called "PEP8". To do this +# automagically just install autopep8: +# +# $ sudo pip3 install autopep8 +# +# and run: +# +# $ autopep8 makedocs.py +# +# Before committing your changes. Also be sure to delete any trailing +# whitespace you may left. +# +# TODO: +# * Refactor code. Refactor strings. +# * Adapt this script for generating content in other markup formats like +# DokuWiki, Markdown, etc. +# * Because people will translate class_list.xml, we should implement +# internalization. +# +# Also check other TODO entries in this script for more information on what is +# left to do. + import re import argparse import logging from os import path -from itertools import izip_longest +from itertools import zip_longest from xml.etree import ElementTree +# add an option to change the verbosity logging.basicConfig(level=logging.INFO) +def tb(string): + """ Return a byte representation of a string + """ + return bytes(string, "UTF-8") + + def getxmlfloc(): """ Returns the supposed location of the XML file """ @@ -30,7 +61,7 @@ def sortkey(c): """ Symbols are first, letters second """ if "_" == c.attrib["name"][0]: - return True + return "A" else: return c.attrib["name"] @@ -50,7 +81,8 @@ def toOP(text): text = text.replace(group.group(0), "\n\n", 1) elif gd["command"] == "div": if gd["value"] == '"center"': - alignstr = "{display:block; margin-left:auto; margin-right:auto;}" + alignstr = ("{display:block; margin-left:auto;" + " margin-right:auto;}") elif gd["value"] == '"left"': alignstr = "<" elif gd["value"] == '"right"': @@ -68,9 +100,115 @@ def toOP(text): text = text.replace(group.group(0), "_", 1) elif gd["command"] == "u" or gd["command"] == "/u": text = text.replace(group.group(0), "+", 1) - # TODO: Process other non-html commands + # Process other non-html commands + groups = re.finditer((r'\[method ((?P[aA0-zZ9_]+)(?:\.))' + r'?(?P[aA0-zZ9_]+)\]'), text) + for group in groups: + gd = group.groupdict() + if gd["class"]: + replacewith = ("\"{gclass}.{method}(Go " + "to page {gclass}, section {method})\"" + ":/class_{lkclass}#{lkmethod}". + format(gclass=gd["class"], + method=gd["method"], + lkclass=gd["class"].lower(), + lkmethod=gd["method"].lower())) + else: + # The method is located in the same wiki page + replacewith = ("\"{method}(Jump to method" + " {method})\":#{lkmethod}". + format(method=gd["method"], + lkmethod=gd["method"].lower())) + + text = text.replace(group.group(0), replacewith, 1) + # Finally, [Classes] are around brackets, make them direct links + groups = re.finditer(r'\[(?P[az0-AZ0_]+)\]', text) + for group in groups: + gd = group.groupdict() + replacewith = ("\"{gclass}(Go to page of class" + " {gclass})\":/class_{lkclass}". + format(gclass=gd["class"], + lkclass=gd["class"].lower())) + text = text.replace(group.group(0), replacewith, 1) + return text + "\n\n" + +def mkfn(node, is_signal=False): + """ Return a string containing a unsorted item for a function + """ + finalstr = "" + name = node.attrib["name"] + rtype = node.find("return") + if rtype: + rtype = rtype.attrib["type"] + else: + rtype = "void" + # write the return type and the function name first + finalstr += "* " + # return type + if not is_signal: + if rtype != "void": + finalstr += " \"{rtype}({title})\":/class_{link} ".format( + rtype=rtype, + title="Go to page of class " + rtype, + link=rtype.lower()) + else: + finalstr += " void " + + # function name + if not is_signal: + finalstr += "\"*{funcname}*({title})\":#{link} ( ".format( + funcname=name, + title="Jump to description for node " + name, + link=name.lower()) + else: + # Signals have no description + finalstr += "*{funcname}* (".format(funcname=name) + # loop for the arguments of the function, if any + args = [] + for arg in sorted( + node.iter(tag="argument"), + key=lambda a: int(a.attrib["index"])): + + twd = "{type} {name}={default}" + tnd = "{type} {name}" + tlk = ("\"*{cls}*(Go to page of class {cls})" + "\":/class_{lcls}") + ntype = arg.attrib["type"] + nname = arg.attrib["name"] + + if "default" in arg.attrib: + args.insert( + -1, + twd.format( + type=tlk.format( + cls=ntype, + lcls=ntype.lower()), + name=nname, + default=arg.attrib["default"])) + else: + # No default value present + args.insert( + -1, + tnd.format( + type=tlk.format( + cls=ntype, + lcls=ntype.lower()), + name=nname)) + # join the arguments together + finalstr += ", ".join(args) + # and, close the function with a ) + finalstr += " )" + # write the qualifier, if any + if "qualifiers" in node.attrib: + qualifier = node.attrib["qualifiers"] + finalstr += " " + qualifier + + finalstr += "\n" + + return finalstr + desc = "Generates documentation from a XML file to different markup languages" parser = argparse.ArgumentParser(description=desc) @@ -100,18 +238,20 @@ if "version" not in root.attrib: version = root.attrib["version"] classes = sorted(root, key=sortkey) +logging.debug("Number of classes: {}".format(len(classes))) +logging.debug("len(classes) / 2 + 1: {}".format(int(len(classes) / 2 + 1))) # first column is always longer, second column of classes should be shorter -zclasses = izip_longest(classes[:len(classes) / 2 + 1], - classes[len(classes) / 2 + 1:], - fillvalue="") +zclasses = zip_longest(classes[:int(len(classes) / 2 + 1)], + classes[int(len(classes) / 2 + 1):], + fillvalue="") # We write the class_list file and also each class file at once with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl: # Write header of table - fcl.write("|^.\n") - fcl.write("|_. Index symbol |_. Class name " - "|_. Index symbol |_. Class name |\n") - fcl.write("|-.\n") + fcl.write(tb("|^.\n")) + fcl.write(tb("|_. Index symbol |_. Class name " + "|_. Index symbol |_. Class name |\n")) + fcl.write(tb("|-.\n")) indexletterl = "" indexletterr = "" @@ -120,65 +260,119 @@ with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl: # write the index symbol column, left if indexletterl != gdclassl.attrib["name"][0]: indexletterl = gdclassl.attrib["name"][0] - fcl.write("| *{}* |".format(indexletterl.upper())) + fcl.write(tb("| *{}* |".format(indexletterl.upper()))) else: # empty cell - fcl.write("| |") + fcl.write(tb("| |")) # write the class name column, left - fcl.write("\"{name}({title})\":/class_{link}".format( + fcl.write(tb("\"{name}({title})\":/class_{link}".format( name=gdclassl.attrib["name"], title="Go to page of class " + gdclassl.attrib["name"], - link="class_" + gdclassl.attrib["name"].lower())) + link="class_" + gdclassl.attrib["name"].lower()))) # write the index symbol column, right if isinstance(gdclassr, ElementTree.Element): if indexletterr != gdclassr.attrib["name"][0]: indexletterr = gdclassr.attrib["name"][0] - fcl.write("| *{}* |".format(indexletterr.upper())) + fcl.write(tb("| *{}* |".format(indexletterr.upper()))) else: # empty cell - fcl.write("| |") + fcl.write(tb("| |")) # We are dealing with an empty string else: # two empty cell - fcl.write("| | |\n") + fcl.write(tb("| | |\n")) # We won't get the name of the class since there is no ElementTree # object for the right side of the tuple, so we iterate the next # tuple instead continue # write the class name column (if any), right - fcl.write("\"{name}({title})\":/{link} |\n".format( + fcl.write(tb("\"{name}({title})\":/{link} |\n".format( name=gdclassr.attrib["name"], title="Go to page of class " + gdclassr.attrib["name"], - link=gdclassr.attrib["name"].lower())) + link=gdclassr.attrib["name"].lower()))) # row written # # now, let's write each class page for each class for gdclass in [gdclassl, gdclassr]: - if not isinstance(ElementTree.Element, gdclass): + if not isinstance(gdclass, ElementTree.Element): continue classname = gdclass.attrib["name"] with open(path.join(args.outputdir, "{}.txt".format( classname.lower())), "wb") as clsf: # First level header with the name of the class - clsf.write("h1. {}\n".format(classname)) + clsf.write(tb("h1. {}\n\n".format(classname))) # lay the attributes if "inherits" in gdclass.attrib: inh = gdclass.attrib["inherits"].strip() - clsf.write( - "*Inherits:* \"{name}({title})\":/class_{link}\n". - format( - name=classname, - title="Go to page of class " + classname, - link=classname.lower())) + clsf.write(tb(("h4. Inherits: \"{name}" + "({title})\":/class_{link}\n\n"). + format( + name=inh, + title="Go to page of class " + inh, + link=classname.lower()))) if "category" in gdclass.attrib: - clsf.write("*Category:* {}". - format(gdclass.attrib["category"].strip())) + clsf.write(tb("h4. Category: {}\n\n". + format(gdclass.attrib["category"].strip()))) # lay child nodes - for gdchild in gdclass.iter(): - if gdchild.tag == "brief_description": - clsf.write("h2. Brief Description\n") - clsf.write(toOP(gdchild.text.strip())) - # convert commands in text + briefd = gdclass.find("brief_description") + logging.debug( + "Brief description was found?: {}".format(briefd)) + if briefd.text.strip(): + logging.debug( + "Text: {}".format(briefd.text.strip())) + clsf.write(tb("h2. Brief Description\n\n")) + clsf.write(tb(toOP(briefd.text.strip()) + + "\"read more\":#more\n\n")) + + # Write the list of member functions of this class + methods = gdclass.find("methods") + if methods and len(methods) > 0: + clsf.write(tb("\nh3. Member Functions\n\n")) + for method in methods.iter(tag='method'): + clsf.write(tb(mkfn(method))) + + signals = gdclass.find("signals") + if signals and len(signals) > 0: + clsf.write(tb("\nh3. Signals\n\n")) + for signal in signals.iter(tag='signal'): + clsf.write(tb(mkfn(signal, True))) + # TODO: tag is necessary to process? it does not + # exists in class_list.xml file. + + consts = gdclass.find("constants") + if consts and len(consts) > 0: + clsf.write(tb("\nh3. Numeric Constants\n\n")) + for const in sorted(consts, key=lambda k: + k.attrib["name"]): + if const.text.strip(): + clsf.write(tb("* *{name}* = *{value}* - {desc}\n". + format( + name=const.attrib["name"], + value=const.attrib["value"], + desc=const.text.strip()))) + else: + # Constant have no description + clsf.write(tb("* *{name}* = *{value}*\n". + format( + name=const.attrib["name"], + value=const.attrib["value"]))) + descrip = gdclass.find("description") + clsf.write(tb("\nh3(#more). Description\n\n")) + if descrip.text: + clsf.write(tb(descrip.text.strip() + "\n")) + else: + clsf.write(tb("_Nothing here, yet..._\n")) + + # and finally, the description for each method + if methods and len(methods) > 0: + clsf.write(tb("\nh3. Member Function Description\n\n")) + for method in methods.iter(tag='method'): + clsf.write(tb("h4(#{n}). {name}\n\n".format( + n=method.attrib["name"].lower(), + name=method.attrib["name"]))) + clsf.write(tb(mkfn(method) + "\n")) + clsf.write(tb(toOP(method.find( + "description").text.strip()))) -- cgit v1.2.3 From 7c843fbc048a869eb4a03f774e9271d7f18c4d68 Mon Sep 17 00:00:00 2001 From: Jorge Araya Navarro Date: Tue, 6 Oct 2015 19:50:55 -0600 Subject: Refactoring some strings and ordering imports --- tools/docdump/makedocs.py | 122 ++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 70 deletions(-) (limited to 'tools/docdump') diff --git a/tools/docdump/makedocs.py b/tools/docdump/makedocs.py index 81469eed9c..303c94f79b 100644 --- a/tools/docdump/makedocs.py +++ b/tools/docdump/makedocs.py @@ -3,9 +3,7 @@ # # makedocs.py: Generate documentation for Open Project Wiki -# # Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. -# # Contributor: Jorge Araya Navarro # @@ -24,7 +22,7 @@ # whitespace you may left. # # TODO: -# * Refactor code. Refactor strings. +# * Refactor code. # * Adapt this script for generating content in other markup formats like # DokuWiki, Markdown, etc. # * Because people will translate class_list.xml, we should implement @@ -32,17 +30,33 @@ # # Also check other TODO entries in this script for more information on what is # left to do. - -import re import argparse import logging -from os import path +import re from itertools import zip_longest +from os import path from xml.etree import ElementTree + # add an option to change the verbosity logging.basicConfig(level=logging.INFO) +# Strings +C_LINK = ("\"{gclass}(Go to page of class" + " {gclass})\":/class_{lkclass}") +MC_LINK = ("\"{gclass}.{method}(Go " + "to page {gclass}, section {method})\"" + ":/class_{lkclass}#{lkmethod}") +TM_JUMP = ("\"{method}(Jump to method" + " {method})\":#{lkmethod}") +GTC_LINK = " \"{rtype}(Go to page of class {rtype})\":/class_{link} " +DFN_JUMP = ("\"*{funcname}*(Jump to description for" + " node {funcname})\":#{link} ( ") +M_ARG_DEFAULT = C_LINK + " {name}={default}" +M_ARG = C_LINK + " {name}" + +OPENPROJ_INH = ("h4. Inherits: " + C_LINK + "\n\n") + def tb(string): """ Return a byte representation of a string @@ -69,9 +83,7 @@ def sortkey(c): def toOP(text): """ Convert commands in text to Open Project commands """ - # We are going to do something very complicated with all HTML commands - # sadly, some commands are embedded inside other commands, so some steps - # are needed before converting some commands to Textile markup + # TODO: Make this capture content between [command] ... [/command] groups = re.finditer((r'\[html (?P/?\w+/?)(\]| |=)?(\]| |=)?(?P\w+)?(\]| |=)?(?P"[^"]+")?/?\]'), text) alignstr = "" @@ -106,27 +118,21 @@ def toOP(text): for group in groups: gd = group.groupdict() if gd["class"]: - replacewith = ("\"{gclass}.{method}(Go " - "to page {gclass}, section {method})\"" - ":/class_{lkclass}#{lkmethod}". - format(gclass=gd["class"], - method=gd["method"], - lkclass=gd["class"].lower(), - lkmethod=gd["method"].lower())) + replacewith = (MC_LINK.format(gclass=gd["class"], + method=gd["method"], + lkclass=gd["class"].lower(), + lkmethod=gd["method"].lower())) else: # The method is located in the same wiki page - replacewith = ("\"{method}(Jump to method" - " {method})\":#{lkmethod}". - format(method=gd["method"], - lkmethod=gd["method"].lower())) + replacewith = (TM_JUMP.format(method=gd["method"], + lkmethod=gd["method"].lower())) text = text.replace(group.group(0), replacewith, 1) # Finally, [Classes] are around brackets, make them direct links groups = re.finditer(r'\[(?P[az0-AZ0_]+)\]', text) for group in groups: gd = group.groupdict() - replacewith = ("\"{gclass}(Go to page of class" - " {gclass})\":/class_{lkclass}". + replacewith = (C_LINK. format(gclass=gd["class"], lkclass=gd["class"].lower())) text = text.replace(group.group(0), replacewith, 1) @@ -149,18 +155,16 @@ def mkfn(node, is_signal=False): # return type if not is_signal: if rtype != "void": - finalstr += " \"{rtype}({title})\":/class_{link} ".format( + finalstr += GTC_LINK.format( rtype=rtype, - title="Go to page of class " + rtype, link=rtype.lower()) else: finalstr += " void " # function name if not is_signal: - finalstr += "\"*{funcname}*({title})\":#{link} ( ".format( + finalstr += DFN_JUMP.format( funcname=name, - title="Jump to description for node " + name, link=name.lower()) else: # Signals have no description @@ -171,31 +175,19 @@ def mkfn(node, is_signal=False): node.iter(tag="argument"), key=lambda a: int(a.attrib["index"])): - twd = "{type} {name}={default}" - tnd = "{type} {name}" - tlk = ("\"*{cls}*(Go to page of class {cls})" - "\":/class_{lcls}") ntype = arg.attrib["type"] nname = arg.attrib["name"] if "default" in arg.attrib: - args.insert( - -1, - twd.format( - type=tlk.format( - cls=ntype, - lcls=ntype.lower()), - name=nname, - default=arg.attrib["default"])) + args.insert(-1, M_ARG_DEFAULT.format( + gclass=ntype, + lkclass=ntype.lower(), + name=nname, + default=arg.attrib["default"])) else: # No default value present - args.insert( - -1, - tnd.format( - type=tlk.format( - cls=ntype, - lcls=ntype.lower()), - name=nname)) + args.insert(-1, M_ARG.format(gclass=ntype, + lkclass=ntype.lower(), name=nname)) # join the arguments together finalstr += ", ".join(args) # and, close the function with a ) @@ -265,10 +257,9 @@ with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl: # empty cell fcl.write(tb("| |")) # write the class name column, left - fcl.write(tb("\"{name}({title})\":/class_{link}".format( - name=gdclassl.attrib["name"], - title="Go to page of class " + gdclassl.attrib["name"], - link="class_" + gdclassl.attrib["name"].lower()))) + fcl.write(tb(C_LINK.format( + gclass=gdclassl.attrib["name"], + lkclass=gdclassl.attrib["name"].lower()))) # write the index symbol column, right if isinstance(gdclassr, ElementTree.Element): @@ -288,10 +279,9 @@ with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl: continue # write the class name column (if any), right - fcl.write(tb("\"{name}({title})\":/{link} |\n".format( - name=gdclassr.attrib["name"], - title="Go to page of class " + gdclassr.attrib["name"], - link=gdclassr.attrib["name"].lower()))) + fcl.write(tb(C_LINK.format( + gclass=gdclassl.attrib["name"], + lkclass=gdclassl.attrib["name"].lower()) + "|\n")) # row written # # now, let's write each class page for each class @@ -307,36 +297,28 @@ with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl: # lay the attributes if "inherits" in gdclass.attrib: inh = gdclass.attrib["inherits"].strip() - clsf.write(tb(("h4. Inherits: \"{name}" - "({title})\":/class_{link}\n\n"). - format( - name=inh, - title="Go to page of class " + inh, - link=classname.lower()))) + clsf.write(tb(OPENPROJ_INH.format(gclass=inh, + lkclass=inh.lower()))) if "category" in gdclass.attrib: clsf.write(tb("h4. Category: {}\n\n". format(gdclass.attrib["category"].strip()))) # lay child nodes briefd = gdclass.find("brief_description") - logging.debug( - "Brief description was found?: {}".format(briefd)) if briefd.text.strip(): - logging.debug( - "Text: {}".format(briefd.text.strip())) - clsf.write(tb("h2. Brief Description\n\n")) + clsf.write(b"h2. Brief Description\n\n") clsf.write(tb(toOP(briefd.text.strip()) + "\"read more\":#more\n\n")) # Write the list of member functions of this class methods = gdclass.find("methods") if methods and len(methods) > 0: - clsf.write(tb("\nh3. Member Functions\n\n")) + clsf.write(b"\nh3. Member Functions\n\n") for method in methods.iter(tag='method'): clsf.write(tb(mkfn(method))) signals = gdclass.find("signals") if signals and len(signals) > 0: - clsf.write(tb("\nh3. Signals\n\n")) + clsf.write(b"\nh3. Signals\n\n") for signal in signals.iter(tag='signal'): clsf.write(tb(mkfn(signal, True))) # TODO: tag is necessary to process? it does not @@ -344,7 +326,7 @@ with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl: consts = gdclass.find("constants") if consts and len(consts) > 0: - clsf.write(tb("\nh3. Numeric Constants\n\n")) + clsf.write(b"\nh3. Numeric Constants\n\n") for const in sorted(consts, key=lambda k: k.attrib["name"]): if const.text.strip(): @@ -360,15 +342,15 @@ with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl: name=const.attrib["name"], value=const.attrib["value"]))) descrip = gdclass.find("description") - clsf.write(tb("\nh3(#more). Description\n\n")) + clsf.write(b"\nh3(#more). Description\n\n") if descrip.text: clsf.write(tb(descrip.text.strip() + "\n")) else: - clsf.write(tb("_Nothing here, yet..._\n")) + clsf.write(b"_Nothing here, yet..._\n") # and finally, the description for each method if methods and len(methods) > 0: - clsf.write(tb("\nh3. Member Function Description\n\n")) + clsf.write(b"\nh3. Member Function Description\n\n") for method in methods.iter(tag='method'): clsf.write(tb("h4(#{n}). {name}\n\n".format( n=method.attrib["name"].lower(), -- cgit v1.2.3 From 68d005760bcfc498aad61719630b7ae21b4f31d8 Mon Sep 17 00:00:00 2001 From: Jorge Araya Navarro Date: Wed, 7 Oct 2015 13:11:17 -0600 Subject: Internationalization implemented Specify which language you want the templates translate to with the `--language` option and any choice language available. By default English is used. When class_list.xml is translated to different language than English this option will be useful to make the template language match. --- tools/docdump/locales/es/LC_MESSAGES/makedocs.mo | Bin 0 -> 2321 bytes tools/docdump/locales/es/LC_MESSAGES/makedocs.po | 142 +++++++++++++++++++++++ tools/docdump/makedocs.pot | 108 +++++++++++++++++ tools/docdump/makedocs.py | 128 +++++++++++--------- 4 files changed, 326 insertions(+), 52 deletions(-) create mode 100644 tools/docdump/locales/es/LC_MESSAGES/makedocs.mo create mode 100644 tools/docdump/locales/es/LC_MESSAGES/makedocs.po create mode 100644 tools/docdump/makedocs.pot (limited to 'tools/docdump') diff --git a/tools/docdump/locales/es/LC_MESSAGES/makedocs.mo b/tools/docdump/locales/es/LC_MESSAGES/makedocs.mo new file mode 100644 index 0000000000..8d7ea2689e Binary files /dev/null and b/tools/docdump/locales/es/LC_MESSAGES/makedocs.mo differ diff --git a/tools/docdump/locales/es/LC_MESSAGES/makedocs.po b/tools/docdump/locales/es/LC_MESSAGES/makedocs.po new file mode 100644 index 0000000000..82115dd897 --- /dev/null +++ b/tools/docdump/locales/es/LC_MESSAGES/makedocs.po @@ -0,0 +1,142 @@ +# Translations template for PROJECT. +# Copyright (C) 2015 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: makedocs\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2015-10-07 11:47-0600\n" +"PO-Revision-Date: 2015-10-07 13:10-0600\n" +"Last-Translator: Jorge Araya Navarro \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.0\n" +"X-Generator: Poedit 1.8.4\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: makedocs.py:74 +msgid "" +"\"{gclass}(Go to page of class {gclass})\":/class_{lkclass}" +msgstr "" +"\"{gclass}(Ir a la pagina de la clase {gclass})\":/" +"class_{lkclass}" + +#: makedocs.py:76 +msgid "" +"\"{gclass}.{method}(Go to page {gclass}, section {method})\":/" +"class_{lkclass}#{lkmethod}" +msgstr "" +"\"{gclass}.{method}(Ir a la pagina {gclass}, sección " +"{method})\":/class_{lkclass}#{lkmethod}" + +#: makedocs.py:79 +msgid "\"{method}(Jump to method {method})\":#{lkmethod}" +msgstr "\"{method}(Saltar al método {method})\":#{lkmethod}" + +#: makedocs.py:81 +msgid " \"{rtype}(Go to page of class {rtype})\":/class_{link} " +msgstr " \"{rtype}(Ir a la pagina de la clase {rtype})\":/class_{link} " + +#: makedocs.py:82 +msgid "" +"\"*{funcname}*(Jump to description for node {funcname})\":#{link} ( " +msgstr "" +"\"*{funcname}*(Saltar a la descripción para el nodo {funcname})\":#{link} " +"( " + +#: makedocs.py:87 +msgid "h4. Inherits: " +msgstr "h4. Hereda de: " + +#: makedocs.py:232 +msgid "'s version attribute missing" +msgstr "El atributo version de no existe" + +#: makedocs.py:246 +msgid "|_. Index symbol |_. Class name |_. Index symbol |_. Class name |\n" +msgstr "" +"|_. Índice de símbolo |_. Nombre de la clase |_. Índice de símbolo |_. " +"Nombre de la clase |\n" + +#: makedocs.py:305 +msgid "" +"h4. Category: {}\n" +"\n" +msgstr "" +"h4. Categoría: {}\n" +"\n" + +#: makedocs.py:310 +msgid "" +"h2. Brief Description\n" +"\n" +msgstr "" +"h2. Descripción breve\n" +"\n" + +#: makedocs.py:312 +msgid "" +"\"read more\":#more\n" +"\n" +msgstr "" +"\"Leer más\":#more\n" +"\n" + +#: makedocs.py:317 +msgid "" +"\n" +"h3. Member Functions\n" +"\n" +msgstr "" +"\n" +"h3. Funciones miembro\n" +"\n" + +#: makedocs.py:323 +msgid "" +"\n" +"h3. Signals\n" +"\n" +msgstr "" +"\n" +"h3. Señales\n" +"\n" + +#: makedocs.py:331 +msgid "" +"\n" +"h3. Numeric Constants\n" +"\n" +msgstr "" +"\n" +"h3. Constantes numéricas\n" +"\n" + +#: makedocs.py:347 +msgid "" +"\n" +"h3(#more). Description\n" +"\n" +msgstr "" +"\n" +"h3(#more). Descripción\n" +"\n" + +#: makedocs.py:351 +msgid "_Nothing here, yet..._\n" +msgstr "_Aún nada por aquí..._\n" + +#: makedocs.py:355 +msgid "" +"\n" +"h3. Member Function Description\n" +"\n" +msgstr "" +"\n" +"h3. Descripción de las funciones miembro\n" +"\n" diff --git a/tools/docdump/makedocs.pot b/tools/docdump/makedocs.pot new file mode 100644 index 0000000000..be3220f686 --- /dev/null +++ b/tools/docdump/makedocs.pot @@ -0,0 +1,108 @@ +# Translations template for PROJECT. +# Copyright (C) 2015 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2015. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: makedocs 0.1\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2015-10-07 11:47-0600\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.0\n" +"X-Generator: Poedit 1.8.4\n" + +#: makedocs.py:74 +msgid "\"{gclass}(Go to page of class {gclass})\":/class_{lkclass}" +msgstr "" + +#: makedocs.py:76 +msgid "\"{gclass}.{method}(Go to page {gclass}, section {method})\":/class_{lkclass}#{lkmethod}" +msgstr "" + +#: makedocs.py:79 +msgid "\"{method}(Jump to method {method})\":#{lkmethod}" +msgstr "" + +#: makedocs.py:81 +msgid " \"{rtype}(Go to page of class {rtype})\":/class_{link} " +msgstr "" + +#: makedocs.py:82 +msgid "\"*{funcname}*(Jump to description for node {funcname})\":#{link} ( " +msgstr "" + +#: makedocs.py:87 +msgid "h4. Inherits: " +msgstr "" + +#: makedocs.py:232 +msgid "'s version attribute missing" +msgstr "" + +#: makedocs.py:246 +msgid "|_. Index symbol |_. Class name |_. Index symbol |_. Class name |\n" +msgstr "" + +#: makedocs.py:305 +msgid "" +"h4. Category: {}\n" +"\n" +msgstr "" + +#: makedocs.py:310 +msgid "" +"h2. Brief Description\n" +"\n" +msgstr "" + +#: makedocs.py:312 +msgid "" +"\"read more\":#more\n" +"\n" +msgstr "" + +#: makedocs.py:317 +msgid "" +"\n" +"h3. Member Functions\n" +"\n" +msgstr "" + +#: makedocs.py:323 +msgid "" +"\n" +"h3. Signals\n" +"\n" +msgstr "" + +#: makedocs.py:331 +msgid "" +"\n" +"h3. Numeric Constants\n" +"\n" +msgstr "" + +#: makedocs.py:347 +msgid "" +"\n" +"h3(#more). Description\n" +"\n" +msgstr "" + +#: makedocs.py:351 +msgid "_Nothing here, yet..._\n" +msgstr "" + +#: makedocs.py:355 +msgid "" +"\n" +"h3. Member Function Description\n" +"\n" +msgstr "" diff --git a/tools/docdump/makedocs.py b/tools/docdump/makedocs.py index 303c94f79b..280ce03532 100644 --- a/tools/docdump/makedocs.py +++ b/tools/docdump/makedocs.py @@ -25,37 +25,88 @@ # * Refactor code. # * Adapt this script for generating content in other markup formats like # DokuWiki, Markdown, etc. -# * Because people will translate class_list.xml, we should implement -# internalization. # # Also check other TODO entries in this script for more information on what is # left to do. +import gettext import argparse import logging import re from itertools import zip_longest from os import path +from os import listdir from xml.etree import ElementTree # add an option to change the verbosity logging.basicConfig(level=logging.INFO) + +def getxmlfloc(): + """ Returns the supposed location of the XML file + """ + filepath = path.dirname(path.abspath(__file__)) + return path.join(filepath, "class_list.xml") + + +def langavailable(): + """ Return a list of languages available for translation + """ + filepath = path.join( + path.dirname(path.abspath(__file__)), "locales") + files = listdir(filepath) + choices = [x for x in files] + choices.insert(0, "none") + return choices + + +desc = "Generates documentation from a XML file to different markup languages" + +parser = argparse.ArgumentParser(description=desc) +parser.add_argument("--input", dest="xmlfp", default=getxmlfloc(), + help="Input XML file, default: {}".format(getxmlfloc())) +parser.add_argument("--output-dir", dest="outputdir", required=True, + help="Output directory for generated files") +parser.add_argument("--language", choices=langavailable(), default="none", + help=("Choose the language of translation" + " for the output files. Default is English (none). " + "Note: This is NOT for the documentation itself!")) +# TODO: add an option for outputting different markup formats + +args = parser.parse_args() +# Let's check if the file and output directory exists +if not path.isfile(args.xmlfp): + logging.critical("File not found: {}".format(args.xmlfp)) + exit(1) +elif not path.isdir(args.outputdir): + logging.critical("Path does not exist: {}".format(args.outputdir)) + exit(1) + +_ = gettext.gettext +if args.language != "none": + logging.info("Language changed to: " + args.language) + lang = gettext.translation(domain="makedocs", + localedir="locales", + languages=[args.language]) + lang.install() + + _ = lang.gettext + # Strings -C_LINK = ("\"{gclass}(Go to page of class" - " {gclass})\":/class_{lkclass}") -MC_LINK = ("\"{gclass}.{method}(Go " - "to page {gclass}, section {method})\"" - ":/class_{lkclass}#{lkmethod}") -TM_JUMP = ("\"{method}(Jump to method" - " {method})\":#{lkmethod}") -GTC_LINK = " \"{rtype}(Go to page of class {rtype})\":/class_{link} " -DFN_JUMP = ("\"*{funcname}*(Jump to description for" - " node {funcname})\":#{link} ( ") +C_LINK = _("\"{gclass}(Go to page of class" + " {gclass})\":/class_{lkclass}") +MC_LINK = _("\"{gclass}.{method}(Go " + "to page {gclass}, section {method})\"" + ":/class_{lkclass}#{lkmethod}") +TM_JUMP = _("\"{method}(Jump to method" + " {method})\":#{lkmethod}") +GTC_LINK = _(" \"{rtype}(Go to page of class {rtype})\":/class_{link} ") +DFN_JUMP = _("\"*{funcname}*(Jump to description for" + " node {funcname})\":#{link} ( ") M_ARG_DEFAULT = C_LINK + " {name}={default}" M_ARG = C_LINK + " {name}" -OPENPROJ_INH = ("h4. Inherits: " + C_LINK + "\n\n") +OPENPROJ_INH = _("h4. Inherits: ") + C_LINK + "\n\n" def tb(string): @@ -64,13 +115,6 @@ def tb(string): return bytes(string, "UTF-8") -def getxmlfloc(): - """ Returns the supposed location of the XML file - """ - filepath = path.dirname(path.abspath(__file__)) - return path.join(filepath, "class_list.xml") - - def sortkey(c): """ Symbols are first, letters second """ @@ -201,37 +245,17 @@ def mkfn(node, is_signal=False): return finalstr -desc = "Generates documentation from a XML file to different markup languages" - -parser = argparse.ArgumentParser(description=desc) -parser.add_argument("--input", dest="xmlfp", default=getxmlfloc(), - help="Input XML file, default: {}".format(getxmlfloc())) -parser.add_argument("--output-dir", dest="outputdir", required=True, - help="Output directory for generated files") -# TODO: add an option for outputting different markup formats - -args = parser.parse_args() -# Let's check if the file and output directory exists -if not path.isfile(args.xmlfp): - logging.critical("File not found: {}".format(args.xmlfp)) - exit(1) -elif not path.isdir(args.outputdir): - logging.critical("Path does not exist: {}".format(args.outputdir)) - exit(1) - # Let's begin tree = ElementTree.parse(args.xmlfp) root = tree.getroot() # Check version attribute exists in if "version" not in root.attrib: - logging.critical("'s version attribute missing") + logging.critical(_("'s version attribute missing")) exit(1) version = root.attrib["version"] classes = sorted(root, key=sortkey) -logging.debug("Number of classes: {}".format(len(classes))) -logging.debug("len(classes) / 2 + 1: {}".format(int(len(classes) / 2 + 1))) # first column is always longer, second column of classes should be shorter zclasses = zip_longest(classes[:int(len(classes) / 2 + 1)], classes[int(len(classes) / 2 + 1):], @@ -241,8 +265,8 @@ zclasses = zip_longest(classes[:int(len(classes) / 2 + 1)], with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl: # Write header of table fcl.write(tb("|^.\n")) - fcl.write(tb("|_. Index symbol |_. Class name " - "|_. Index symbol |_. Class name |\n")) + fcl.write(tb(_("|_. Index symbol |_. Class name " + "|_. Index symbol |_. Class name |\n"))) fcl.write(tb("|-.\n")) indexletterl = "" @@ -300,25 +324,25 @@ with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl: clsf.write(tb(OPENPROJ_INH.format(gclass=inh, lkclass=inh.lower()))) if "category" in gdclass.attrib: - clsf.write(tb("h4. Category: {}\n\n". + clsf.write(tb(_("h4. Category: {}\n\n"). format(gdclass.attrib["category"].strip()))) # lay child nodes briefd = gdclass.find("brief_description") if briefd.text.strip(): - clsf.write(b"h2. Brief Description\n\n") + clsf.write(tb(_("h2. Brief Description\n\n"))) clsf.write(tb(toOP(briefd.text.strip()) + - "\"read more\":#more\n\n")) + _("\"read more\":#more\n\n"))) # Write the list of member functions of this class methods = gdclass.find("methods") if methods and len(methods) > 0: - clsf.write(b"\nh3. Member Functions\n\n") + clsf.write(tb(_("\nh3. Member Functions\n\n"))) for method in methods.iter(tag='method'): clsf.write(tb(mkfn(method))) signals = gdclass.find("signals") if signals and len(signals) > 0: - clsf.write(b"\nh3. Signals\n\n") + clsf.write(tb(_("\nh3. Signals\n\n"))) for signal in signals.iter(tag='signal'): clsf.write(tb(mkfn(signal, True))) # TODO: tag is necessary to process? it does not @@ -326,7 +350,7 @@ with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl: consts = gdclass.find("constants") if consts and len(consts) > 0: - clsf.write(b"\nh3. Numeric Constants\n\n") + clsf.write(tb(_("\nh3. Numeric Constants\n\n"))) for const in sorted(consts, key=lambda k: k.attrib["name"]): if const.text.strip(): @@ -342,15 +366,15 @@ with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl: name=const.attrib["name"], value=const.attrib["value"]))) descrip = gdclass.find("description") - clsf.write(b"\nh3(#more). Description\n\n") + clsf.write(tb(_("\nh3(#more). Description\n\n"))) if descrip.text: clsf.write(tb(descrip.text.strip() + "\n")) else: - clsf.write(b"_Nothing here, yet..._\n") + clsf.write(tb(_("_Nothing here, yet..._\n"))) # and finally, the description for each method if methods and len(methods) > 0: - clsf.write(b"\nh3. Member Function Description\n\n") + clsf.write(tb(_("\nh3. Member Function Description\n\n"))) for method in methods.iter(tag='method'): clsf.write(tb("h4(#{n}). {name}\n\n".format( n=method.attrib["name"].lower(), -- cgit v1.2.3 From 0fb91ef95b7887eae1a8a7741f3e20e66c2b4998 Mon Sep 17 00:00:00 2001 From: Jorge Araya Navarro Date: Wed, 7 Oct 2015 13:15:28 -0600 Subject: Minor changes --- tools/docdump/makedocs.py | 1 - 1 file changed, 1 deletion(-) (limited to 'tools/docdump') diff --git a/tools/docdump/makedocs.py b/tools/docdump/makedocs.py index 280ce03532..921b049bd8 100644 --- a/tools/docdump/makedocs.py +++ b/tools/docdump/makedocs.py @@ -84,7 +84,6 @@ elif not path.isdir(args.outputdir): _ = gettext.gettext if args.language != "none": - logging.info("Language changed to: " + args.language) lang = gettext.translation(domain="makedocs", localedir="locales", languages=[args.language]) -- cgit v1.2.3 From 613962d48ad3dd131ef8847d5e65df1fbe2da054 Mon Sep 17 00:00:00 2001 From: Jorge Araya Navarro Date: Wed, 7 Oct 2015 13:24:52 -0600 Subject: Minor changes: Organizing imports --- tools/docdump/makedocs.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'tools/docdump') diff --git a/tools/docdump/makedocs.py b/tools/docdump/makedocs.py index 921b049bd8..be57891abc 100644 --- a/tools/docdump/makedocs.py +++ b/tools/docdump/makedocs.py @@ -28,13 +28,12 @@ # # Also check other TODO entries in this script for more information on what is # left to do. -import gettext import argparse +import gettext import logging import re from itertools import zip_longest -from os import path -from os import listdir +from os import path, listdir from xml.etree import ElementTree -- cgit v1.2.3