1 import sys
, os
, string
, glob
3 from docparser
.wxclasses
import *
13 class_desc_re
= """<H2>.*?</H2>(.*?)<B><FONT COLOR="#FF0000">"""
14 win_styles_re
= """<B><FONT COLOR="#FF0000">Window styles</FONT></B><P>(.*?)<B><FONT COLOR="#FF0000">"""
15 win_styles_extra_re
= """<B><FONT COLOR="#FF0000">Extra window styles</FONT></B><P>(.*?)<B><FONT COLOR="#FF0000">"""
16 win_style_re
= """<TR><TD VALIGN=TOP WIDTH=.*?>\s*?<FONT FACE=".*?">\s*?<B>(.*?)</B>\s*?</FONT></TD>\s*?<TD VALIGN=TOP>\s*?<FONT FACE=".*?">(.*?)</FONT></TD></TR>"""
17 derived_re
= """<B><FONT COLOR="#FF0000">Derived from</FONT></B><P>(.*?)<P>"""
18 derived_class_re
= """<A HREF=".*?">(.*?)</A>"""
24 # groups - header, description
25 method_re
= "<H3>(.*?)</H3>\s*?<P>(.*?)<HR>"
26 lastmethod_re
= "<H3>(.*?)</H3>\s*?<P>(.*?)\s*?<P>\s*?</FONT>"
27 headings_re
= "<B><FONT COLOR=\"#FF0000\">(.*?)</FONT></B><P>(.*?)"
28 # groups = param name, param value
29 param_re
= "<I>(.*?)</I><UL><UL>(.*?)</UL></UL>"
30 # groups - return type, method name, arguments
31 proto_re
= "<B>(.*?)</B>.*?<B>(.*?)</B>\s*?\((.*?)\)"
32 # groups - arg type, arg name
33 args_re
= "<B>(.*?)</B>.*?<I>(.*?)</I>"
34 code_re
= "<PRE>(.*?)</PRE>"
35 link_re
= "<A href=\"(.*?)\"><B>(.*?)</B></A><BR>"
38 # wxPython/wxPerl note REs
42 wxperl_overload_re
= "<B><FONT COLOR=\"#0000C8\">wxPerl note:</FONT></B> In wxPerl there are two methods instead of a single overloaded method:<P>\s*?<UL><UL>(.*?)</UL></UL>"
43 wxperl_re
= "<B><FONT COLOR=\"#0000C8\">wxPerl note:</FONT></B>(.*?)<P>"
45 wxpython_constructors_re
= """<B><FONT COLOR="#0000C8">wxPython note:</FONT></B> Constructors supported by wxPython are:<P>\s*?<UL><UL>(.*?)</UL></UL>"""
46 wxpython_overload_re
= """<TR><TD VALIGN=TOP.*?>\s*?<FONT FACE=".*?">\s*?<B>(.*?)</B>\s*?</FONT></TD>\s*?<TD VALIGN=TOP>\s*?<FONT FACE=".*?">(.*?)</FONT></TD></TR>"""
48 wxpython_overloads_re
= "<B><FONT COLOR=\"#0000C8\">wxPython note:</FONT></B> In place of a single overloaded method name, wxPython\s*?implements the following methods:<P>\s*?<UL><UL>(.*?)</UL></UL>"
49 wxpython_re
= "<B><FONT COLOR=\"#0000C8\">wxPython note:</FONT></B>(.*?)<P>"
52 # convert wxWhatever to wx.Whatever
53 def namespacify_wxClasses(contents
):
54 wx_regex
= re
.compile(wx_re
, re
.MULTILINE | re
.DOTALL
)
56 result
= wx_regex
.sub(wxReplaceFunc
, contents
)
59 def wxReplaceFunc(match
):
61 if text
.find("wxWidgets") == -1 and text
.find("wxPython") == -1 and text
.find("wxPerl") == -1:
62 text
= text
.replace("wx", "wx.")
67 # Methods to de-C++itize data.
68 def pythonize_text(contents
):
70 Remove C++isms that definitely shouldn't be in any text.
72 contents
= contents
.replace("false", "False")
73 contents
= contents
.replace("true", "True")
74 contents
= contents
.replace("non-NULL", "not None")
75 contents
= contents
.replace("NULL", "None")
76 contents
= contents
.replace("const ", "")
77 contents
= contents
.replace("::", ".")
78 contents
= contents
.replace("\r\n", "\n")
79 contents
= contents
.replace("\r", "\n")
80 contents
= contents
.replace("''", "\"")
81 return namespacify_wxClasses(contents
)
83 def pythonize_args(contents
):
85 Remove C++isms from arguments (some of these terms may be used in other
86 contexts in actual documentation, so we don't remove them there).
88 contents
= contents
.replace("static", "")
89 contents
= contents
.replace("virtual void", "")
90 contents
= contents
.replace("virtual", "")
91 contents
= contents
.replace("void*", "int")
92 contents
= contents
.replace("void", "")
94 contents
= contents
.replace("off_t", "long")
95 contents
= contents
.replace("size_t", "long")
96 contents
= contents
.replace("*", "")
97 contents
= contents
.replace("&", "")
98 contents
= contents
.replace("&", "")
99 contents
= contents
.replace("char", "string")
100 contents
= contents
.replace("wxChar", "string")
101 contents
= contents
.replace("wxCoord", "int")
102 contents
= contents
.replace("<A HREF=\"wx_wxstring.html#wxstring\">wxString</A>", "string")
104 return pythonize_text(contents
)
106 def formatMethodProtos(protos
):
108 Remove C++isms in the method prototypes.
111 proto
[0] = pythonize_args(proto
[0])
112 proto
[0] = proto
[0].strip()
114 proto
[1] = namespacify_wxClasses(proto
[1])
116 arg
[0] = pythonize_args(arg
[0])
119 # for arg names, we should be more careful about what we replace
120 arg
[1] = pythonize_text(arg
[1])
121 arg
[1] = arg
[1].replace("*", "")
122 arg
[1] = arg
[1].replace("&", "")
128 # functions for getting data from methods
129 def getMethodWxPythonOverrides(text
, isConstructor
=False):
130 overloads_re
= wxpython_overloads_re
132 overloads_re
= wxpython_constructors_re
133 overload_regex
= re
.compile(overloads_re
, re
.MULTILINE | re
.DOTALL | re
.IGNORECASE
)
134 match
= overload_regex
.search(text
, 0)
140 def getWxPythonOverridesFromMatch(match
):
141 return [namespacify_wxClasses(match
.group(1)), pythonize_text(match
.group(2))]
143 start
= match
.start()
145 overrides
, returntext
= findAllMatches(wxpython_overload_re
, match
.group(1), getWxPythonOverridesFromMatch
)
149 if start
!= -1 and end
!= -1:
150 #print "note is: " + text[start:end]
151 returntext
= text
.replace(text
[start
:end
], "")
153 return overrides
, returntext
155 def getMethodWxPythonNote(text
):
156 python_regex
= re
.compile(wxpython_re
, re
.MULTILINE | re
.DOTALL | re
.IGNORECASE
)
157 match
= python_regex
.search(text
)
162 start
= match
.start()
164 note
= match
.group(1)
168 if start
!= -1 and end
!= -1:
169 #print "note is: " + text[start:end]
170 returntext
= text
.replace(text
[start
:end
], "")
172 return note
, returntext
174 def findAllMatches(re_string
, text
, handler
, start
=0):
176 findAllMatches finds matches for a given regex, then runs the handler function
177 on each match, and returns a list of objects, along with a version of the
178 text with the area matches were found stripped.
179 Note the stripping of text is not generally usable yet, it assumes matches
180 are in continuous blocks, which is true of the wx docs.
182 regex
= re
.compile(re_string
, re
.MULTILINE | re
.DOTALL | re
.IGNORECASE
)
183 match
= regex
.search(text
, start
)
190 startpoint
= match
.start()
194 results
.append(handler(match
))
195 endpoint
= match
.end()
196 match
= regex
.search(text
, start
)
199 if startpoint
!= -1 and endpoint
!= -1:
200 returntext
= text
.replace(text
[startpoint
:endpoint
], "")
202 return results
, returntext
204 def getMethodParams(text
):
205 paramstart
= text
.find("<B><FONT COLOR=\"#FF0000\">Parameters</FONT></B><P>")
206 params
, returntext
= findAllMatches(param_re
, text
, getMethodParamsFromMatch
, paramstart
)
208 return params
, returntext
210 def getMethodParamsFromMatch(match
):
211 return [match
.group(1).strip(), pythonize_text(match
.group(2)).strip()]
213 def getPrototypeFromMatch(match
):
214 return [match
.group(1), match
.group(2), getProtoArgs(match
.group(3))]
216 def getProtoArgsFromMatch(match
):
217 return [match
.group(1), match
.group(2)]
221 # These methods parse the docs, finding matches and then using the FromMatch
222 # functions to parse the data. After that, the results are "Pythonized"
223 # by removing C++isms.
224 def getMethodProtos(text
):
225 protos
, returntext
= findAllMatches(proto_re
, text
, getPrototypeFromMatch
)
226 return formatMethodProtos(protos
), returntext
228 def getProtoArgs(text
):
229 args
, returntext
= findAllMatches(args_re
, text
, getProtoArgsFromMatch
)
232 def getMethodDesc(text
):
233 heading_text
= "<B><FONT COLOR=\"#FF0000\">"
235 end
= text
.find(heading_text
)
237 return_text
= text
[0:end
]
239 return pythonize_text(return_text
)
242 def removeWxPerlNotes(text
):
243 perl_overload_regex
= re
.compile(wxperl_overload_re
, re
.MULTILINE | re
.DOTALL | re
.IGNORECASE
)
244 result
= perl_overload_regex
.sub("", text
)
246 perl_regex
= re
.compile(wxperl_re
, re
.MULTILINE | re
.DOTALL | re
.IGNORECASE
)
247 result
= perl_regex
.sub("", result
)
251 def removeCPPCode(text
):
252 code_regex
= re
.compile(code_re
, re
.MULTILINE | re
.DOTALL | re
.IGNORECASE
)
254 result
= code_regex
.sub("", text
)
258 def getMethod(match
, parent
):
259 name
= match
.group(1)
260 if name
.find("::") != -1:
261 name
= name
.split("::")[1]
262 name
= namespacify_wxClasses(name
).strip()
264 protos
, remainder
= getMethodProtos(match
.group(2))
266 isConstructor
= False
267 #print "name: %s, parent name: %s" % (name, parent.name)
268 if name
== parent
.name
.replace("wx", "wx."):
270 overrides
, remainder
= getMethodWxPythonOverrides(remainder
, isConstructor
)
272 note
, remainder
= getMethodWxPythonNote(remainder
)
273 params
, remainder
= getMethodParams(remainder
)
274 desc
= getMethodDesc(remainder
)
275 method
= wxMethod(name
, parent
, protos
, params
, desc
)
276 method
.pythonNote
= note
277 method
.pythonOverrides
= overrides
278 if len(method
.pythonOverrides
) > 0:
279 print "has overrides!\n\n\n\n"
282 def getClassDerivedFrom(text
):
284 def getDerivedClassesFromMatch(match
):
285 return namespacify_wxClasses(match
.group(1))
288 derived_regex
= re
.compile(derived_re
, re
.MULTILINE | re
.DOTALL | re
.IGNORECASE
)
289 match
= derived_regex
.search(text
)
291 derived_classes
, returntext
= findAllMatches(derived_class_re
, match
.group(1), getDerivedClassesFromMatch
)
293 return derived_classes
295 def getClassDescription(text
):
297 def getClassDescriptionFromMatch(match
):
298 return match
.group(1)
300 desc
, returntext
= findAllMatches(class_desc_re
, text
, getClassDescriptionFromMatch
)
302 return pythonize_text(desc
[0])
304 def getClassStyles(text
, extraStyles
=False):
305 styles_re
= win_styles_re
307 styles_re
= win_styles_extra_re
308 styles_regex
= re
.compile(styles_re
, re
.MULTILINE | re
.DOTALL | re
.IGNORECASE
)
309 match
= styles_regex
.search(text
)
313 def getClassStyleFromMatch(match
):
314 return [namespacify_wxClasses(match
.group(1)), pythonize_text(match
.group(2))]
316 styles
, remainder
= findAllMatches(win_style_re
, match
.group(1), getClassStyleFromMatch
)
320 # Main functions - these drive the process.
321 def getClassMethods(doc
, parent
):
322 contents
= open(doc
, "rb").read()
324 # get rid of some particularly tricky parts before parsing
325 contents
= contents
.replace("<B>const</B>", "")
326 contents
= removeWxPerlNotes(contents
)
327 contents
= removeCPPCode(contents
)
329 method_regex
= re
.compile(method_re
, re
.MULTILINE | re
.DOTALL | re
.IGNORECASE
)
330 match
= method_regex
.search(contents
)
335 newmethod
= getMethod(match
, parent
)
336 basename
= parent
.name
.replace("wx", "")
337 isConstructor
= (basename
== newmethod
.name
.replace("wx.", ""))
338 if isConstructor
or eval("newmethod.name in dir(wx.%s)" % basename
):
339 print "Adding %s.%s" % (parent
.name
, newmethod
.name
)
340 methods
[newmethod
.name
] = newmethod
341 match
= method_regex
.search(contents
, start
)
343 lastmethod_regex
= re
.compile(lastmethod_re
, re
.MULTILINE | re
.DOTALL | re
.IGNORECASE
)
344 match
= lastmethod_regex
.search(contents
, start
)
346 newmethod
= getMethod(match
, parent
)
347 basename
= parent
.name
.replace("wx", "")
348 isConstructor
= (basename
== newmethod
.name
.replace("wx.", ""))
349 if isConstructor
or eval("newmethod.name in dir(wx.%s)" % basename
):
350 print "Adding %s.%s" % (parent
.name
, newmethod
.name
)
351 methods
[newmethod
.name
] = newmethod
354 if name
[0:3] == "Get":
356 basename
= parent
.name
.replace("wx", "")
357 if not propname
in eval("dir(wx.%s)" % basename
):
358 parent
.props
.append(propname
)
360 parent
.propConflicts
.append(parent
.name
+ "." + propname
)
361 # get rid of the destructor and operator methods
362 ignore_methods
= ["~" + namespacify_wxClasses(parent
.name
), "operator ==",
363 "operator <<", "operator >>", "operator =",
364 "operator !=", "operator*", "operator++" ]
365 for method
in ignore_methods
:
366 if method
in methods
:
373 contents
= open(doc
, "rb").read()
374 link_regex
= re
.compile(link_re
, re
.MULTILINE | re
.DOTALL | re
.IGNORECASE
)
375 start
= contents
.find("<H2>Alphabetical class reference</H2>")
376 result
= link_regex
.search(contents
, start
)
380 name
= result
.group(2).strip()
381 classpage
= result
.group(1).split("#")[0]
382 basename
= name
.replace("wx", "")
383 if basename
in dir(wx
):
384 classfile
= os
.path
.join(os
.path
.dirname(doc
), classpage
)
385 classtext
= open(classfile
, "rb").read()
386 derivedClasses
= getClassDerivedFrom(classtext
)
387 description
= getClassDescription(classtext
)
388 styles
= getClassStyles(classtext
)
389 extra_styles
= getClassStyles(classtext
, extraStyles
=True)
390 classes
[name
] = wxClass(name
, description
, derivedClasses
, styles
, extra_styles
)
391 classes
[name
].methods
= getClassMethods(classfile
, classes
[name
])
392 result
= link_regex
.search(contents
, start
)