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
)