File: parse_xml.py

package info (click to toggle)
kdevelop-python 24.12.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 12,640 kB
  • sloc: python: 183,048; cpp: 18,798; xml: 140; sh: 14; makefile: 9
file content (130 lines) | stat: -rw-r--r-- 5,330 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
#!/usr/bin/env python2.7
# This file is part of KDevelop
# SPDX-FileCopyrightText: 2011 Victor Varvariuc <victor.varvariuc@gmail.com>

from xml.dom import minidom


def indentCode(code, level):
    return '\n'.join('    ' * level + line for line in code.splitlines())


def parseEnum(enumNode, enumName, className = ''):
    '''Parse Enum node and return its string representation.'''
    enumMembers = []
    for node in enumNode.childNodes:
        if node.nodeType == node.ELEMENT_NODE:
            if node.nodeName == 'EnumMember':
                enumMember = node.attributes['name'].value
                if enumMember.startswith(className + '.'):
                    enumMember = enumMember[len(className) + 1:]
                if enumMember == 'None':
                    enumMember = '__kdevpythondocumentation_builtin_None'
                enumMembers.append(enumMember)
            else:
                print('Unknown node in Enum %s.%s: %s' % (className, enumName, node.nodeName))
    text = ''
    for enumMember in enumMembers:
        text += '%s = int() # %s.%s enum\n' % (enumMember, className, enumName)
    return text


def parseFunction(functionNode, funcName, className = ''):
    '''Parse Function node and return its string representation.'''
    params = [] if className == '' else [("None", "self")]
    retType = 'None'
    namesUsed = []
    for node in functionNode.childNodes:
        if node.nodeType == node.ELEMENT_NODE:
            if node.nodeName == 'Argument':
                argType = node.attributes['typename'].value
                try:
                    argName = '*args' if argType == '...' else '_' + node.attributes['name'].value
                except KeyError:
                    retType = argType
                else:
                    if argName not in namesUsed:
                        params.append((argType, argName))
                    else:
                        print("adjusting arg name:", argName)
                        argName = argName + '_'
                        params.append((argType, argName))
                    namesUsed.append(argName)
            else:
                print('Unknown node in function %s.%s: %s' % (className, funcName, node.nodeName))

    descr = 'abstract ' if 'abstract' in functionNode.attributes.keys() else ''
    descr += '%s %s.%s(%s)' % (retType, className, funcName,
                ', '.join('%s %s' % p for p in params))

    print("ret type:", retType)
    if retType == 'None':
        pass # leave it like this
    elif retType.startswith('list-of-'):
        retType = '[' + retType[8:] + '()]'
    elif retType.contains("-or-"):
        a, b = retType.split("-or-")
        retType = "{0}() if True else {1}()".format(a, b)
    elif retType.startsWith("dict-of-"):
        key, value = retType[8:].split('-')
        retType = '{' + key + "():" + value + "()}"
    else:
        retType += '()'

    # prefix function arguments with '_' to deal with reserved Python keywords
    text = 'def %s(%s):\n    """%s"""\n    return %s' % (funcName, ', '.join(param[1] for param in params), descr, retType)
    return text


def parseClass(classNode):
    '''Parse Class node.'''
    try:
        parentClasses = classNode.attributes['inherits'].value.split()
    except KeyError:
        parentClasses = []
    className = classNode.attributes['name'].value
    text = 'class %s(%s):\n    """"""\n' % (className, ', '.join(parentClasses))
    for node in classNode.childNodes:
        if node.nodeType == node.ELEMENT_NODE:
            name = node.attributes['name'].value
            if name.startswith(className + '.'):
                name = name[len(className) + 1 :]
            if node.nodeName == 'Member':
                text += '    %s = None # %s member\n' % (name, node.attributes['typename'].value)
            elif node.nodeName == 'Function':
                if name not in ('exec', 'print'): # skip this invalid for Python name
                    text += indentCode(parseFunction(node, name, className), 1) + '\n'
            elif node.nodeName == 'Enum':
                text += indentCode(parseEnum(node, name, className), 1) + '\n\n'
            else:
                print('Unknown node in class %s: %s' % (className, node.nodeName))
    return text


files = ['QtGuimod.xml', 'QtCoremod.xml']
for filename in files:
    dom = minidom.parse(filename)

    module = dom.firstChild
    assert module.nodeName == 'Module'
    moduleName = module.attributes['name'].value
    print('Module name:', moduleName)

    stats = {}

    with open(moduleName + '.py', 'w') as file:
        for node in module.childNodes:
            if node.nodeType != node.ELEMENT_NODE:
                continue # skip non element nodes
            nodeName = node.nodeName
            stats[nodeName] = stats.setdefault(nodeName, 0) + 1 # stats
            if nodeName == 'Class':
                file.write(parseClass(node) + '\n\n')
            elif nodeName == 'Function':
                file.write(parseFunction(node, node.attributes['name'].value) + '\n\n')
            elif nodeName == 'Member':
                file.write('%s = None # %s member\n\n' % (node.attributes['name'].value, node.attributes['typename'].value))
            else:
                print('Unknown node:', nodeName)

    print('Stats:', stats)