Utilities/ModuleParser.py

changeset 945
8cd4d08fa9f6
parent 841
0d379ff260df
child 1227
c5db073a124f
equal deleted inserted replaced
944:1b59c4ba121e 945:8cd4d08fa9f6
191 | 191 |
192 (?P<MethodName> [a-zA-Z_] [a-zA-Z0-9_?!=]* ) 192 (?P<MethodName> [a-zA-Z_] [a-zA-Z0-9_?!=]* )
193 | 193 |
194 (?P<MethodName3> [^( \t]{1,3} ) 194 (?P<MethodName3> [^( \t]{1,3} )
195 ) 195 )
196 [ \t]* 196 [ \t]*
197 (?: 197 (?:
198 \( (?P<MethodSignature> (?: [^)] | \)[ \t]*,? )*? ) \) 198 \( (?P<MethodSignature> (?: [^)] | \)[ \t]*,? )*? ) \)
199 )? 199 )?
200 [ \t]* 200 [ \t]*
201 ) 201 )
202 202
208 [ \t]+ 208 [ \t]+
209 (?P<ClassName> [A-Z] [a-zA-Z0-9_]* ) 209 (?P<ClassName> [A-Z] [a-zA-Z0-9_]* )
210 [ \t]* 210 [ \t]*
211 (?P<ClassSupers> < [ \t]* [A-Z] [a-zA-Z0-9_]* )? 211 (?P<ClassSupers> < [ \t]* [A-Z] [a-zA-Z0-9_]* )?
212 | 212 |
213 [ \t]* << [ \t]* 213 [ \t]* << [ \t]*
214 (?P<ClassName2> [a-zA-Z_] [a-zA-Z0-9_]* ) 214 (?P<ClassName2> [a-zA-Z_] [a-zA-Z0-9_]* )
215 ) 215 )
216 [ \t]* 216 [ \t]*
217 ) 217 )
218 218
257 ) 257 )
258 258
259 | (?P<Attr> 259 | (?P<Attr>
260 ^ 260 ^
261 (?P<AttrIndent> [ \t]* ) 261 (?P<AttrIndent> [ \t]* )
262 attr 262 attr
263 (?P<AttrType> (?: _accessor | _reader | _writer ) )? 263 (?P<AttrType> (?: _accessor | _reader | _writer ) )?
264 \(? 264 \(?
265 [ \t]* 265 [ \t]*
266 (?P<AttrList> (?: : [a-zA-Z0-9_]+ , \s* )* (?: : [a-zA-Z0-9_]+ | true | false )+ ) 266 (?P<AttrList> (?: : [a-zA-Z0-9_]+ , \s* )* (?: : [a-zA-Z0-9_]+ | true | false )+ )
267 [ \t]* 267 [ \t]*
296 296
297 _commentsub = re.compile(r"""#[^\n]*\n|#[^\n]*$""").sub 297 _commentsub = re.compile(r"""#[^\n]*\n|#[^\n]*$""").sub
298 298
299 _modules = {} # cache of modules we've seen 299 _modules = {} # cache of modules we've seen
300 300
301
301 class VisibilityBase(object): 302 class VisibilityBase(object):
302 """ 303 """
303 Class implementing the visibility aspect of all objects. 304 Class implementing the visibility aspect of all objects.
304 """ 305 """
305 def isPrivate(self): 306 def isPrivate(self):
341 def setPublic(self): 342 def setPublic(self):
342 """ 343 """
343 Public method to set the visibility to Public. 344 Public method to set the visibility to Public.
344 """ 345 """
345 self.visibility = 2 346 self.visibility = 2
347
346 348
347 class Module(object): 349 class Module(object):
348 ''' 350 '''
349 Class to represent a Python module. 351 Class to represent a Python module.
350 ''' 352 '''
461 else: 463 else:
462 object.setPublic() 464 object.setPublic()
463 465
464 def __py_scan(self, src): 466 def __py_scan(self, src):
465 """ 467 """
466 Private method to scan the source text of a Python module and retrieve the 468 Private method to scan the source text of a Python module and retrieve the
467 relevant information. 469 relevant information.
468 470
469 @param src the source text to be scanned (string) 471 @param src the source text to be scanned (string)
470 """ 472 """
471 lineno, last_lineno_pos = 1, 0 473 lineno, last_lineno_pos = 1, 0
472 classstack = [] # stack of (class, indent) pairs 474 classstack = [] # stack of (class, indent) pairs
473 conditionalsstack = [] # stack of indents of conditional defines 475 conditionalsstack = [] # stack of indents of conditional defines
474 deltastack = [] 476 deltastack = []
475 deltaindent = 0 477 deltaindent = 0
476 deltaindentcalculated = 0 478 deltaindentcalculated = 0
477 i = 0 479 i = 0
478 modulelevel = 1 480 modulelevel = 1
502 # modify indentation level for conditional defines 504 # modify indentation level for conditional defines
503 if conditionalsstack: 505 if conditionalsstack:
504 if thisindent > conditionalsstack[-1]: 506 if thisindent > conditionalsstack[-1]:
505 if not deltaindentcalculated: 507 if not deltaindentcalculated:
506 deltastack.append(thisindent - conditionalsstack[-1]) 508 deltastack.append(thisindent - conditionalsstack[-1])
507 deltaindent = reduce(lambda x,y: x+y, deltastack) 509 deltaindent = reduce(lambda x, y: x + y, deltastack)
508 deltaindentcalculated = 1 510 deltaindentcalculated = 1
509 thisindent -= deltaindent 511 thisindent -= deltaindent
510 else: 512 else:
511 while conditionalsstack and \ 513 while conditionalsstack and \
512 conditionalsstack[-1] >= thisindent: 514 conditionalsstack[-1] >= thisindent:
533 if cur_class is None: 535 if cur_class is None:
534 continue 536 continue
535 537
536 if isinstance(cur_class, Class): 538 if isinstance(cur_class, Class):
537 # it's a class method 539 # it's a class method
538 f = Function(None, meth_name, None, lineno, 540 f = Function(None, meth_name, None, lineno,
539 meth_sig, meth_pyqtSig) 541 meth_sig, meth_pyqtSig)
540 self.__py_setVisibility(f) 542 self.__py_setVisibility(f)
541 cur_class.addMethod(meth_name, f) 543 cur_class.addMethod(meth_name, f)
542 break 544 break
543 else: 545 else:
544 # it's a nested function of a module function 546 # it's a nested function of a module function
545 f = Function(self.name, meth_name, self.file, lineno, 547 f = Function(self.name, meth_name, self.file, lineno,
546 meth_sig, meth_pyqtSig) 548 meth_sig, meth_pyqtSig)
547 self.__py_setVisibility(f) 549 self.__py_setVisibility(f)
548 self.addFunction(meth_name, f) 550 self.addFunction(meth_name, f)
549 else: 551 else:
550 # it's a module function 552 # it's a module function
551 f = Function(self.name, meth_name, self.file, lineno, 553 f = Function(self.name, meth_name, self.file, lineno,
552 meth_sig, meth_pyqtSig) 554 meth_sig, meth_pyqtSig)
553 self.__py_setVisibility(f) 555 self.__py_setVisibility(f)
554 self.addFunction(meth_name, f) 556 self.addFunction(meth_name, f)
555 cur_obj = f 557 cur_obj = f
556 classstack.append((None, thisindent)) # Marker for nested fns 558 classstack.append((None, thisindent)) # Marker for nested fns
557 559
558 elif m.start("Docstring") >= 0: 560 elif m.start("Docstring") >= 0:
559 contents = m.group("DocstringContents3") 561 contents = m.group("DocstringContents3")
560 if contents is not None: 562 if contents is not None:
561 contents = _hashsub(r"\1", contents) 563 contents = _hashsub(r"\1", contents)
568 if cur_obj: 570 if cur_obj:
569 cur_obj.addDescription(contents) 571 cur_obj.addDescription(contents)
570 572
571 elif m.start("String") >= 0: 573 elif m.start("String") >= 0:
572 if modulelevel and \ 574 if modulelevel and \
573 (src[start-len('\r\n'):start] == '\r\n' or \ 575 (src[start - len('\r\n'):start] == '\r\n' or \
574 src[start-len('\n'):start] == '\n' or \ 576 src[start - len('\n'):start] == '\n' or \
575 src[start-len('\r'):start] == '\r'): 577 src[start - len('\r'):start] == '\r'):
576 contents = m.group("StringContents3") 578 contents = m.group("StringContents3")
577 if contents is not None: 579 if contents is not None:
578 contents = _hashsub(r"\1", contents) 580 contents = _hashsub(r"\1", contents)
579 else: 581 else:
580 if self.file.lower().endswith('.ptl'): 582 if self.file.lower().endswith('.ptl'):
655 isSignal = m.group("VariableSignal") != "" 657 isSignal = m.group("VariableSignal") != ""
656 lineno = lineno + src.count('\n', last_lineno_pos, start) 658 lineno = lineno + src.count('\n', last_lineno_pos, start)
657 last_lineno_pos = start 659 last_lineno_pos = start
658 if thisindent == 0: 660 if thisindent == 0:
659 # global variable 661 # global variable
660 attr = Attribute(self.name, variable_name, self.file, lineno, 662 attr = Attribute(self.name, variable_name, self.file, lineno,
661 isSignal = isSignal) 663 isSignal=isSignal)
662 self.__py_setVisibility(attr) 664 self.__py_setVisibility(attr)
663 self.addGlobal(variable_name, attr) 665 self.addGlobal(variable_name, attr)
664 else: 666 else:
665 index = -1 667 index = -1
666 while index >= -len(classstack): 668 while index >= -len(classstack):
667 if classstack[index][1] >= thisindent: 669 if classstack[index][1] >= thisindent:
668 index -= 1 670 index -= 1
669 else: 671 else:
670 if classstack[index][0] is not None and \ 672 if classstack[index][0] is not None and \
671 isinstance(classstack[index][0], Class): 673 isinstance(classstack[index][0], Class):
672 attr = Attribute(self.name, variable_name, self.file, 674 attr = Attribute(self.name, variable_name, self.file,
673 lineno, isSignal = isSignal) 675 lineno, isSignal=isSignal)
674 self.__py_setVisibility(attr) 676 self.__py_setVisibility(attr)
675 classstack[index][0].addGlobal(variable_name, attr) 677 classstack[index][0].addGlobal(variable_name, attr)
676 break 678 break
677 679
678 elif m.start("Import") >= 0: 680 elif m.start("Import") >= 0:
708 710
709 modulelevel = 0 711 modulelevel = 0
710 712
711 def __rb_scan(self, src): 713 def __rb_scan(self, src):
712 """ 714 """
713 Private method to scan the source text of a Python module and retrieve the 715 Private method to scan the source text of a Python module and retrieve the
714 relevant information. 716 relevant information.
715 717
716 @param src the source text to be scanned (string) 718 @param src the source text to be scanned (string)
717 """ 719 """
718 lineno, last_lineno_pos = 1, 0 720 lineno, last_lineno_pos = 1, 0
719 classstack = [] # stack of (class, indent) pairs 721 classstack = [] # stack of (class, indent) pairs
720 acstack = [] # stack of (access control, indent) pairs 722 acstack = [] # stack of (access control, indent) pairs
721 indent = 0 723 indent = 0
722 i = 0 724 i = 0
723 cur_obj = self 725 cur_obj = self
724 while True: 726 while True:
781 else: 783 else:
782 # it's a function 784 # it's a function
783 f = Function(self.name, meth_name, self.file, lineno, meth_sig) 785 f = Function(self.name, meth_name, self.file, lineno, meth_sig)
784 self.addFunction(meth_name, f) 786 self.addFunction(meth_name, f)
785 cur_obj = f 787 cur_obj = f
786 classstack.append((None, thisindent)) # Marker for nested fns 788 classstack.append((None, thisindent)) # Marker for nested fns
787 789
788 elif m.start("Docstring") >= 0: 790 elif m.start("Docstring") >= 0:
789 contents = m.group("DocstringContents") 791 contents = m.group("DocstringContents")
790 if contents is not None: 792 if contents is not None:
791 contents = _hashsub(r"\1", contents) 793 contents = _hashsub(r"\1", contents)
938 if m.group("AttrType") is None: 940 if m.group("AttrType") is None:
939 nv = m.group("AttrList").split(",") 941 nv = m.group("AttrList").split(",")
940 if not nv: 942 if not nv:
941 break 943 break
942 name = nv[0].strip()[1:] # get rid of leading ':' 944 name = nv[0].strip()[1:] # get rid of leading ':'
943 attr = parent.getAttribute("@"+name) or \ 945 attr = parent.getAttribute("@" + name) or \
944 parent.getAttribute("@@"+name) or \ 946 parent.getAttribute("@@" + name) or \
945 Attribute(self.name, "@"+name, self.file, lineno) 947 Attribute(self.name, "@" + name, self.file, lineno)
946 if len(nv) == 1 or nv[1].strip() == "false": 948 if len(nv) == 1 or nv[1].strip() == "false":
947 attr.setProtected() 949 attr.setProtected()
948 elif nv[1].strip() == "true": 950 elif nv[1].strip() == "true":
949 attr.setPublic() 951 attr.setPublic()
950 parent.addAttribute(attr.name, attr) 952 parent.addAttribute(attr.name, attr)
951 else: 953 else:
952 access = m.group("AttrType") 954 access = m.group("AttrType")
953 for name in m.group("AttrList").split(","): 955 for name in m.group("AttrList").split(","):
954 name = name.strip()[1:] # get rid of leading ':' 956 name = name.strip()[1:] # get rid of leading ':'
955 attr = parent.getAttribute("@"+name) or \ 957 attr = parent.getAttribute("@" + name) or \
956 parent.getAttribute("@@"+name) or \ 958 parent.getAttribute("@@" + name) or \
957 Attribute(self.name, "@"+name, self.file, lineno) 959 Attribute(self.name, "@" + name, self.file, lineno)
958 if access == "_accessor": 960 if access == "_accessor":
959 attr.setPublic() 961 attr.setPublic()
960 elif access == "_reader" or access == "_writer": 962 elif access == "_reader" or access == "_writer":
961 if attr.isPrivate(): 963 if attr.isPrivate():
962 attr.setProtected() 964 attr.setProtected()
992 """ 994 """
993 Public method to build the inheritance hierarchy for all classes of this module. 995 Public method to build the inheritance hierarchy for all classes of this module.
994 996
995 @return A dictionary with inheritance hierarchies. 997 @return A dictionary with inheritance hierarchies.
996 """ 998 """
997 hierarchy = {} 999 hierarchy = {}
998 for cls in list(list(self.classes.keys())): 1000 for cls in list(list(self.classes.keys())):
999 self.assembleHierarchy(cls, self.classes, [cls], hierarchy) 1001 self.assembleHierarchy(cls, self.classes, [cls], hierarchy)
1000 for mod in list(list(self.modules.keys())): 1002 for mod in list(list(self.modules.keys())):
1001 self.assembleHierarchy(mod, self.modules, [mod], hierarchy) 1003 self.assembleHierarchy(mod, self.modules, [mod], hierarchy)
1002 return hierarchy 1004 return hierarchy
1011 1013
1012 This code is borrowed from Boa Constructor. 1014 This code is borrowed from Boa Constructor.
1013 1015
1014 @param name name of class to assemble hierarchy (string) 1016 @param name name of class to assemble hierarchy (string)
1015 @param classes A dictionary of classes to look in. 1017 @param classes A dictionary of classes to look in.
1016 @param path 1018 @param path
1017 @param result The resultant hierarchy 1019 @param result The resultant hierarchy
1018 """ 1020 """
1019 rv = {} 1021 rv = {}
1020 if name in classes: 1022 if name in classes:
1021 for cls in classes[name].super: 1023 for cls in classes[name].super:
1081 elif self.type == RB_SOURCE: 1083 elif self.type == RB_SOURCE:
1082 type = "Ruby" 1084 type = "Ruby"
1083 else: 1085 else:
1084 type = "" 1086 type = ""
1085 return type 1087 return type
1088
1086 1089
1087 class Class(VisibilityBase): 1090 class Class(VisibilityBase):
1088 ''' 1091 '''
1089 Class to represent a Python class. 1092 Class to represent a Python class.
1090 ''' 1093 '''
1180 1183
1181 @param endLineNo number of the last line (integer) 1184 @param endLineNo number of the last line (integer)
1182 """ 1185 """
1183 self.endlineno = endLineNo 1186 self.endlineno = endLineNo
1184 1187
1188
1185 class RbModule(Class): 1189 class RbModule(Class):
1186 ''' 1190 '''
1187 Class to represent a Ruby module. 1191 Class to represent a Ruby module.
1188 ''' 1192 '''
1189 def __init__(self, module, name, file, lineno): 1193 def __init__(self, module, name, file, lineno):
1205 @param name name of class to be added (string) 1209 @param name name of class to be added (string)
1206 @param _class Class object to be added 1210 @param _class Class object to be added
1207 """ 1211 """
1208 self.classes[name] = _class 1212 self.classes[name] = _class
1209 1213
1214
1210 class Function(VisibilityBase): 1215 class Function(VisibilityBase):
1211 ''' 1216 '''
1212 Class to represent a Python function or method. 1217 Class to represent a Python function or method.
1213 ''' 1218 '''
1214 def __init__(self, module, name, file, lineno, signature = '', pyqtSignature = None): 1219 def __init__(self, module, name, file, lineno, signature='', pyqtSignature=None):
1215 """ 1220 """
1216 Constructor 1221 Constructor
1217 1222
1218 @param module name of module containing this function (string) 1223 @param module name of module containing this function (string)
1219 @param name name of the function (string) 1224 @param name name of the function (string)
1238 1243
1239 @param description the docstring to be stored (string) 1244 @param description the docstring to be stored (string)
1240 """ 1245 """
1241 self.description = description 1246 self.description = description
1242 1247
1248
1243 class Attribute(VisibilityBase): 1249 class Attribute(VisibilityBase):
1244 ''' 1250 '''
1245 Class to represent a Python function or method. 1251 Class to represent a Python function or method.
1246 ''' 1252 '''
1247 def __init__(self, module, name, file, lineno, isSignal = False): 1253 def __init__(self, module, name, file, lineno, isSignal=False):
1248 """ 1254 """
1249 Constructor 1255 Constructor
1250 1256
1251 @param module name of module containing this function (string) 1257 @param module name of module containing this function (string)
1252 @param name name of the function (string) 1258 @param name name of the function (string)
1259 self.file = file 1265 self.file = file
1260 self.lineno = lineno 1266 self.lineno = lineno
1261 self.isSignal = isSignal 1267 self.isSignal = isSignal
1262 self.setPublic() 1268 self.setPublic()
1263 1269
1264 def readModule(module, path = [], inpackage = False, basename = "", 1270
1265 extensions = None, caching = True): 1271 def readModule(module, path=[], inpackage=False, basename="",
1272 extensions=None, caching=True):
1266 ''' 1273 '''
1267 Function to read a module file and parse it. 1274 Function to read a module file and parse it.
1268 1275
1269 The module is searched in path and sys.path, read and parsed. 1276 The module is searched in path and sys.path, read and parsed.
1270 If the module was parsed before, the information is taken 1277 If the module was parsed before, the information is taken
1276 package (boolean) 1283 package (boolean)
1277 @param basename a path basename. This basename is deleted from 1284 @param basename a path basename. This basename is deleted from
1278 the filename of the module file to be read. (string) 1285 the filename of the module file to be read. (string)
1279 @param extensions list of extensions, which should be considered valid 1286 @param extensions list of extensions, which should be considered valid
1280 source file extensions (list of strings) 1287 source file extensions (list of strings)
1281 @param caching flag indicating that the parsed module should be 1288 @param caching flag indicating that the parsed module should be
1282 cached (boolean) 1289 cached (boolean)
1283 @return reference to a Module object containing the parsed 1290 @return reference to a Module object containing the parsed
1284 module information (Module) 1291 module information (Module)
1285 ''' 1292 '''
1286 global _modules 1293 global _modules
1355 pass 1362 pass
1356 if caching: 1363 if caching:
1357 _modules[modname] = mod 1364 _modules[modname] = mod
1358 return mod 1365 return mod
1359 1366
1367
1360 def _indent(ws): 1368 def _indent(ws):
1361 """ 1369 """
1362 Protected function to determine the indent width of a whitespace string. 1370 Protected function to determine the indent width of a whitespace string.
1363 1371
1364 @param ws The whitespace string to be cheked. (string) 1372 @param ws The whitespace string to be cheked. (string)
1365 @return Length of the whitespace string after tab expansion. 1373 @return Length of the whitespace string after tab expansion.
1366 """ 1374 """
1367 return len(ws.expandtabs(TABWIDTH)) 1375 return len(ws.expandtabs(TABWIDTH))
1376
1368 1377
1369 def find_module(name, path, extensions): 1378 def find_module(name, path, extensions):
1370 """ 1379 """
1371 Module function to extend the Python module finding mechanism. 1380 Module function to extend the Python module finding mechanism.
1372 1381
1402 if name.lower().endswith('.py'): 1411 if name.lower().endswith('.py'):
1403 name = name[:-3] 1412 name = name[:-3]
1404 1413
1405 return imp.find_module(name, path) 1414 return imp.find_module(name, path)
1406 1415
1416
1407 def resetParsedModules(): 1417 def resetParsedModules():
1408 """ 1418 """
1409 Module function to reset the list of modules already parsed. 1419 Module function to reset the list of modules already parsed.
1410 """ 1420 """
1411 _modules.clear() 1421 _modules.clear()
1412 1422
1413 def resetParsedModule(module, basename = ""): 1423
1424 def resetParsedModule(module, basename=""):
1414 """ 1425 """
1415 Module function to clear one module from the list of parsed modules. 1426 Module function to clear one module from the list of parsed modules.
1416 1427
1417 @param module Name of the module to be parsed (string) 1428 @param module Name of the module to be parsed (string)
1418 @param basename a path basename. This basename is deleted from 1429 @param basename a path basename. This basename is deleted from

eric ide

mercurial