File: build_modules_xml.py

package info (click to toggle)
grass 8.4.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 277,040 kB
  • sloc: ansic: 460,798; python: 227,732; cpp: 42,026; sh: 11,262; makefile: 7,007; xml: 3,637; sql: 968; lex: 520; javascript: 484; yacc: 450; asm: 387; perl: 157; sed: 25; objc: 6; ruby: 4
file content (155 lines) | stat: -rw-r--r-- 4,447 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
"""
@package tools.build_modules_xml

@brief Builds XML metadata of GRASS modules. Runs only during compilation.

(C) 2013 by the GRASS Development Team

This program is free software under the GNU General Public License
(>=v2). Read the file COPYING that comes with GRASS for details.

@author Vaclav Petras <wenzeslaus gmail.com>
@author Anna Petrasova <kratochanna gmail.com>
"""

import sys

import grass.script.core as gcore
import grass.script.task as gtask
from grass.exceptions import ScriptError


def escapeXML(text):
    """This is a duplicate of function in core/toolboxes.

    >>> escapeXML("<>&")
    '&amp;lt;&gt;&amp;'
    """
    return text.replace("<", "&lt;").replace("&", "&amp;").replace(">", "&gt;")


def do_doctest_gettext_workaround():
    """This is a duplicate of function in core/toolboxes."""

    def new_displayhook(string):
        """A replacement for default `sys.displayhook`"""
        if string is not None:
            sys.stdout.write("%r\n" % (string,))

    def new_translator(string):
        """A fake gettext underscore function."""
        return string

    sys.displayhook = new_displayhook
    sys.__displayhook__ = new_displayhook

    import builtins

    builtins.__dict__["_"] = new_translator


def parse_modules(fd):
    """Writes metadata to xml file."""
    # TODO: what about ms windows? does gtask handle this?
    mlist = list(gcore.get_commands()[0])
    indent = 4
    for m in sorted(mlist):
        # TODO: get rid of g.mapsets_picker.py
        if m == "g.mapsets_picker.py" or m == "g.parser":
            continue
        desc, keyw = get_module_metadata(m)
        fd.write('%s<module-item name="%s">\n' % (" " * indent, m))
        indent += 4
        fd.write("%s<module>%s</module>\n" % (" " * indent, m))
        fd.write("%s<description>%s</description>\n" % (" " * indent, escapeXML(desc)))
        fd.write(
            "%s<keywords>%s</keywords>\n" % (" " * indent, escapeXML(",".join(keyw)))
        )
        indent -= 4
        fd.write("%s</module-item>\n" % (" " * indent))


def get_module_metadata(name):
    """

    >>> get_module_metadata("g.region")
    ('Manages the boundary definitions for the geographic region.', ['general', 'settings'])
    >>> get_module_metadata("m.proj")
    ('Converts coordinates from one projection to another (cs2cs frontend).', ['miscellaneous', 'projection'])
    """  # noqa: E501
    try:
        task = gtask.parse_interface(name)
    except ScriptError as exc:
        sys.stderr.write(
            "Cannot parse interface for module %s. Empty strings"
            " will be placed instead of description and keywords."
            " Reason: %s\n" % (name, str(exc))
        )
        return "", ""

    return task.get_description(full=True), task.get_keywords()


def header(fd):
    fd.write('<?xml version="1.0" encoding="UTF-8"?>\n')
    fd.write('<!DOCTYPE module-items SYSTEM "module_items.dtd">\n')
    fd.write("<!--This file is automatically generated using %s-->\n" % sys.argv[0])
    # g.version -r is crashing, commenting this block for now
    #    vInfo = gcore.version()
    #    fd.write('<!--version="%s" revision="%s" date="%s"-->\n' % \
    #                 (vInfo['version'].split('.')[0],
    #                  vInfo['revision'],
    #                  datetime.now()))
    fd.write("<module-items>\n")


def footer(fd):
    fd.write("</module-items>\n")


def doc_test():
    """Tests the module using doctest

    :return: a number of failed tests
    """
    import doctest

    do_doctest_gettext_workaround()
    return doctest.testmod().failed


def module_test():
    grass_commands = gcore.get_commands()[0]
    if "g.region" not in grass_commands:
        print("No g.region")
        return 1
    if "m.proj" not in grass_commands:
        print("No m.proj")
        return 1
    if "t.rast.univar" not in grass_commands:
        print("No t.rast.univar")
        return 1
    print(get_module_metadata("g.region"))
    print(get_module_metadata("m.proj"))
    print(get_module_metadata("t.rast.univar"))


def main():
    fh = sys.stdout

    header(fh)
    parse_modules(fh)
    footer(fh)

    return 0


if __name__ == "__main__":
    if len(sys.argv) > 1:
        if sys.argv[1] == "doctest":
            sys.exit(doc_test())
        elif sys.argv[1] == "test":
            sys.exit(module_test())
        else:
            gcore.fatal("Unrecognized parameter.")
    sys.exit(main())