File: xml-to-python.py

package info (click to toggle)
coot 1.1.18%2Bdfsg-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 220,004 kB
  • sloc: cpp: 495,934; python: 35,043; ansic: 26,143; lisp: 22,768; sh: 13,186; makefile: 2,746; awk: 441; xml: 245; csh: 14
file content (285 lines) | stat: -rw-r--r-- 13,602 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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# This script is an attempt to use the XML output of doxygen to
# create a python file that contains stubs of functions
# which can then be used to generate python documentation
# with Sphinx.
#
# It does some of that work, but to get it working properly
# will be about two weeks of work - or so.
# And spending that time to save maybe 3 hours of boring
# editing is not worth it.
#
# It is better to just create a python stub script now
# and modify it by tracking changes made to the nanobinds file.

import xml.etree.ElementTree as ET
mytree = ET.parse('xml/classmolecules__container__t.xml')
myroot = mytree.getroot()

def convert_type(tt: str) -> str:
    if tt == "const ": tt = "str" # needed for a coot::colour_t
    if tt == "const std::string &": tt = "str"
    if tt == "std::string": tt = "str"
    if tt == "unsigned int": tt = "int"
    if tt == "double": tt = "float"
    if tt == 'std::vector< ': tt = "list"
    if tt == 'const std::vector< ': tt = "list"
    # if tt == 'std::pair< int, unsigned int >': tt = "tuple"
    if tt == 'const std::vector< float > &': tt = "list"
    if tt == 'std::vector< float > &': tt = "list"
    if tt == "const std::vector< std::string > &": tt = "list"
    if tt == "const std::vector< std::string > &": tt = "list"
    if tt == 'const std::map< unsigned int, std::array< float, 3 > > &': tt = "dict"
    if tt == 'const std::map< unsigned int, std::array< float, 4 > > &': tt = "dict"
    if tt == 'const std::vector< std::pair< std::string, unsigned int > > &': tt = "list"
    if tt == 'const std::vector< std::pair< std::string, unsigned int > > &': tt = "list"
    if tt == 'const std::vector< std::pair< bool, mmdb::Residue * > > &, links: const std::vector< mmdb::Link > &': tt = "list"
    if tt == 'std::vector<': tt = list
    if tt == 'const coot::residue_spec_t &': tt = 'str'
    if tt == 'const coot::colour_t &': tt = 'list'   #use the proper type later
    if tt == 'const coot::atom_spec_t &': tt = 'str'
    if tt == 'coot::residue_spec_t &': tt = 'list'
    if tt == 'std::vector< coot::api::moved_atom_t > &': tt = 'list'
    if tt == 'const std::vector< coot::api::moved_residue_t > &': tt = 'list'

    return tt

def make_paren_string(function: dict) -> str:
    if function['kind'] == "function":
        r = ""
        try:
            for idx,param in enumerate(function['params']):
                if idx > 0:
                    r += ", "
                r += param['declname']
                r += ": "
                t = convert_type(param['type'])
                r += t
            r = "(self, " + r + ")"
            return r
        except KeyError as e:
            return "(self)"
    else:
        return ""


def make_return_type(function: dict) -> str:
    # print("--- make_return_type() dict is ", function)
    return_type = ""
    rt = ""
    t = str(function['type'])
    if t == 'int':   rt = "int"
    if t == 'bool':  rt = "bool"
    if t == 'void':  rt = "None"
    if t == 'float': rt = "float"
    if t == 'std::string':  rt = "str"
    if t == 'unsigned int': rt = "int"
    if t == 'std::pair< int, unsigned int >': rt = "tuple"
    if rt:
        return_type = " -> " + rt
    return rt, return_type


def make_python_script(functions: list) -> None:

    f = open("chapi-functions.py", "w")
    f.write("class molecules_container_t:\n")
    for function in functions:
        func_name = ""
        try:
            func_name = function['name']
        except AttributeError as e:
            pass
        print("\n--- make_python_script(): Handling function: ", func_name)

        parens = ""
        def_ = ""
        if function['kind'] == "function":
            parens = make_paren_string(function)
            return_type, return_type_with_arrow = make_return_type(function)
            # print("debug args: function ", function, "made args:", parens)
            def_ = "def "
            s = f"    {def_}{function['name']}{parens}{return_type_with_arrow}:\n"
            f.write(s)

            done_brief = False
            done_detailed = False
            f.write('        """ ')
            try:
                d = function["briefdescription"]
                # print(f"debug:: briefdescription:{d}:")
                f.write(d)
                # f.write('\n')
                done_brief = True
            except KeyError as e:
                # print("No briefdescription")
                pass
            except TypeError as e:
                pass
            # maybe use a for loop for this and the above ["briefdescription", "detaileddescription"]
            try:
                d = function["detaileddescription"]
                # print(f"debug:: detaileddescription:{d}:")
                # f.write('        """ ')
                f.write(d)
                # f.write('\n')
                done_detailed = True
            except KeyError as e:
                # print("No detaileddescription")
                pass
            except TypeError as e:
                pass
            if not done_brief:
                if not done_detailed:
                    # we need some doc string for the sphinx to pick up the function
                    f.write('        Sphinx-Doc-Placeholder')
            f.write('"""')
            f.write('\n')
            if not return_type:               f.write("        pass\n")
            if return_type == "int":          f.write("        return 0\n")
            if return_type == "float":        f.write("        return 0.0\n")
            if return_type == "str":          f.write("        return 'a-string'\n")
            if return_type == "bool":         f.write("        return True\n")

        f.write("\n")
    f.close()

functions = []

for x in myroot.iter('sectiondef'):

    print("#### x:", x)
    # print(dir(x))
    h = x.find('header')
    print(h)
    if h is not None:
        ht = h.text
        print("####### header text: ", ht)
    for child in x:
        if child.tag == "memberdef":
            keep_going = True
            try:
                name = "--unset--"
                a_function = {}
                kind = child.attrib['kind']
                print("   child kind:", kind)
                a_function['kind'] = kind
                if kind == "function":
                    print("\n -----  Handling function")
                    # if function.name ==  "molecules_container_t": continue
                    # if function.name == "~molecules_container_t": continue
                for ii,ch in enumerate(child):
                    print("      ch.tag ", ii, ch.tag, ch.text, ":")
                    if ch.tag == "definition":
                        if ch.text == "molecules_container_t::~molecules_container_t":
                            keep_going = False
                            break
                            # next memberdef
                        if ch.text == "molecules_container_t::molecules_container_t":
                            keep_going = False
                            break
                    if ch.tag == "param":
                        t = ch.find("type")
                        print("   param type:", t)
                        tt = t.text
                        print("    tt: '" + str(tt) + "'")
                        dn = ch.find("declname")
                        dn = dn.text
                        print("    dn", dn)
                        if tt:
                            try:
                                a_function['params'].append({"type": tt, "declname": dn})
                            except KeyError as e:
                                a_function['params'] = [{"type": tt, "declname": dn}]
                    if ch.tag == "name":
                        name = ch.text
                        a_function["name"] = name
                    if ch.tag == "type":
                        a_function["type"] = ch.text
                    if ch.tag == "briefdescription":
                        for c in ch:
                          if c.tag == "para":
                              brief_descr = c.text
                              a_function["briefdescription"] = brief_descr
                    parts = ''
                    if ch.tag == "detaileddescription":
                        for idx,c in enumerate(ch):
                            print("     detaileddescription: item", idx, "is:", c, c.text)
                            if c.tag == "para":
                                # a para can have a parameter list and no text
                                #   descr = c.text
                                #   if descr:
                                #       print("      detailed descr", descr)
                                #       a_function["detaileddescription"] = descr
                                if c.text:
                                    if parts:
                                        parts += "\n\n        "
                                        parts += c.text
                                    else:
                                        parts = c.text
                                # print(dir(c))
                                for jj, chunk in enumerate(c):
                                    print('      chunk', jj, ":", chunk, "len:", len(chunk))
                                    if chunk.tag == "parameterlist":
                                        print("        handle parameterlist here")

                                        for pk,pchunk in enumerate(chunk):
                                               print("pk:", pk, 'pchunk', pchunk)
                                               for ck,cchunk in enumerate(pchunk):
                                                   print("ck:", ck, 'cchunk', cchunk)

                                                   if cchunk.tag == "parameternamelist":
                                                      parts += "\n"
                                                      for kk,kchunk in enumerate(cchunk):
                                                           if kchunk.tag == "parametername":
                                                              print("kchunk", kk, "text:", kchunk.text)
                                                              parts += "\n       " + " :param " + kchunk.text + ": "

                                                   if cchunk.tag == "parameterdescription":
                                                       print('len(cchunk)', len(cchunk))
                                                       for kk,kchunk in enumerate(cchunk):
                                                           if kchunk.tag == "para":
                                                              print("kchunk", kk, "text:", kchunk.text)
                                                              parts += " " + kchunk.text
                                                              for kk,pchunk in enumerate(kchunk):
                                                                  if pchunk.tag == "computeroutput":
                                                                     if pchunk.text:
                                                                        print("        computeroutput:", pchunk.text)
                                                                        parts += "`"
                                                                        parts += pchunk.text
                                                                        parts += "`"
                                                                        parts += pchunk.tail

                                    if chunk.tag == "computeroutput":
                                        print("        computeroutput:", chunk.text)
                                        if chunk.text:
                                            parts += "`"
                                            parts += chunk.text
                                            parts += "`"
                                            parts += chunk.tail
                                    if chunk.tag == "simplesect":
                                        for kk,kchunk in enumerate(chunk):
                                            # print("kk:", kk, kchunk)
                                            if kchunk.tag == "para":
                                                print("kchunk", kk, "text:", kchunk.text)
                                                #parts += "Return" + " " + kchunk.text
                                                parts += "\n\n       " + " :return: " + kchunk.text
                                                for kk,pchunk in enumerate(kchunk):
                                                    if pchunk.tag == "computeroutput":
                                                       if pchunk.text:
                                                          print("        computeroutput:", pchunk.text)
                                                          parts += "`"
                                                          parts += pchunk.text
                                                          parts += "`"
                                                          parts += pchunk.tail


                    if parts:
                        a_function["detaileddescription"] = parts
                if a_function:
                    if keep_going:
                        functions.append(a_function)

            except AttributeError as e:
                print(e)

make_python_script(functions)