File: parse_xml.py

package info (click to toggle)
kdevelop-python 24.12.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 12,640 kB
  • sloc: python: 183,048; cpp: 18,798; xml: 140; sh: 14; makefile: 9
file content (123 lines) | stat: -rw-r--r-- 5,024 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
#!/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))

    if retType == 'None':
        pass # leave it like this
    elif retType.startswith('list-of-'):
        retType = '[' + retType[8:] + '()]'
    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