src/eric7/Utilities/ModuleParser.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9364
83dea9e54ff4
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
21 import contextlib 21 import contextlib
22 22
23 import Utilities 23 import Utilities
24 from functools import reduce 24 from functools import reduce
25 25
26 __all__ = ["Module", "Class", "Function", "Attribute", "RbModule", 26 __all__ = [
27 "readModule", "getTypeFromTypeName"] 27 "Module",
28 "Class",
29 "Function",
30 "Attribute",
31 "RbModule",
32 "readModule",
33 "getTypeFromTypeName",
34 ]
28 35
29 TABWIDTH = 4 36 TABWIDTH = 4
30 37
31 SEARCH_ERROR = 0 38 SEARCH_ERROR = 0
32 PY_SOURCE = 1 39 PY_SOURCE = 1
44 51
45 52
46 def getTypeFromTypeName(name): 53 def getTypeFromTypeName(name):
47 """ 54 """
48 Module function to determine the module type given the module type name. 55 Module function to determine the module type given the module type name.
49 56
50 @param name module type name (string) 57 @param name module type name (string)
51 @return module type or -1 for failure (integer) 58 @return module type or -1 for failure (integer)
52 """ 59 """
53 if name in TYPE_MAPPING: 60 if name in TYPE_MAPPING:
54 return TYPE_MAPPING[name] 61 return TYPE_MAPPING[name]
202 ^ 209 ^
203 (?P<ConditionalDefineIndent> [ \t]* ) 210 (?P<ConditionalDefineIndent> [ \t]* )
204 (?: (?: if | elif ) [ \t]+ [^:]* | else [ \t]* ) : 211 (?: (?: if | elif ) [ \t]+ [^:]* | else [ \t]* ) :
205 (?= \s* (?: async [ \t]+ )? def) 212 (?= \s* (?: async [ \t]+ )? def)
206 )""", 213 )""",
207 re.VERBOSE | re.DOTALL | re.MULTILINE).search 214 re.VERBOSE | re.DOTALL | re.MULTILINE,
215 ).search
208 216
209 _rb_getnext = re.compile( 217 _rb_getnext = re.compile(
210 r""" 218 r"""
211 (?P<Docstring> 219 (?P<Docstring>
212 =begin [ \t]+ edoc (?P<DocstringContents> .*? ) =end 220 =begin [ \t]+ edoc (?P<DocstringContents> .*? ) =end
339 end [ \t]* $ 347 end [ \t]* $
340 | 348 |
341 end \b [^_] 349 end \b [^_]
342 ) 350 )
343 )""", 351 )""",
344 re.VERBOSE | re.DOTALL | re.MULTILINE).search 352 re.VERBOSE | re.DOTALL | re.MULTILINE,
353 ).search
345 354
346 _hashsub = re.compile(r"""^([ \t]*)#[ \t]?""", re.MULTILINE).sub 355 _hashsub = re.compile(r"""^([ \t]*)#[ \t]?""", re.MULTILINE).sub
347 356
348 _commentsub = re.compile(r"""#[^\n]*\n|#[^\n]*$""").sub 357 _commentsub = re.compile(r"""#[^\n]*\n|#[^\n]*$""").sub
349 358
350 _modules = {} # cache of modules we've seen 359 _modules = {} # cache of modules we've seen
351 360
352 361
353 class VisibilityBase: 362 class VisibilityBase:
354 """ 363 """
355 Class implementing the visibility aspect of all objects. 364 Class implementing the visibility aspect of all objects.
356 """ 365 """
366
357 def isPrivate(self): 367 def isPrivate(self):
358 """ 368 """
359 Public method to check, if the visibility is Private. 369 Public method to check, if the visibility is Private.
360 370
361 @return flag indicating Private visibility (boolean) 371 @return flag indicating Private visibility (boolean)
362 """ 372 """
363 return self.visibility == 0 373 return self.visibility == 0
364 374
365 def isProtected(self): 375 def isProtected(self):
366 """ 376 """
367 Public method to check, if the visibility is Protected. 377 Public method to check, if the visibility is Protected.
368 378
369 @return flag indicating Protected visibility (boolean) 379 @return flag indicating Protected visibility (boolean)
370 """ 380 """
371 return self.visibility == 1 381 return self.visibility == 1
372 382
373 def isPublic(self): 383 def isPublic(self):
374 """ 384 """
375 Public method to check, if the visibility is Public. 385 Public method to check, if the visibility is Public.
376 386
377 @return flag indicating Public visibility (boolean) 387 @return flag indicating Public visibility (boolean)
378 """ 388 """
379 return self.visibility == 2 389 return self.visibility == 2
380 390
381 def setPrivate(self): 391 def setPrivate(self):
382 """ 392 """
383 Public method to set the visibility to Private. 393 Public method to set the visibility to Private.
384 """ 394 """
385 self.visibility = 0 395 self.visibility = 0
386 396
387 def setProtected(self): 397 def setProtected(self):
388 """ 398 """
389 Public method to set the visibility to Protected. 399 Public method to set the visibility to Protected.
390 """ 400 """
391 self.visibility = 1 401 self.visibility = 1
392 402
393 def setPublic(self): 403 def setPublic(self):
394 """ 404 """
395 Public method to set the visibility to Public. 405 Public method to set the visibility to Public.
396 """ 406 """
397 self.visibility = 2 407 self.visibility = 2
399 409
400 class Module: 410 class Module:
401 """ 411 """
402 Class to represent a Python module. 412 Class to represent a Python module.
403 """ 413 """
414
404 def __init__(self, name, file=None, moduleType=None): 415 def __init__(self, name, file=None, moduleType=None):
405 """ 416 """
406 Constructor 417 Constructor
407 418
408 @param name name of this module (string) 419 @param name name of this module (string)
409 @param file filename of file containing this module (string) 420 @param file filename of file containing this module (string)
410 @param moduleType type of this module 421 @param moduleType type of this module
411 """ 422 """
412 self.name = name 423 self.name = name
419 self.functions_counts = {} 430 self.functions_counts = {}
420 self.description = "" 431 self.description = ""
421 self.globals = {} 432 self.globals = {}
422 self.imports = [] 433 self.imports = []
423 self.from_imports = {} 434 self.from_imports = {}
424 self.package = '.'.join(name.split('.')[:-1]) 435 self.package = ".".join(name.split(".")[:-1])
425 self.type = moduleType 436 self.type = moduleType
426 if moduleType in [PY_SOURCE, PTL_SOURCE]: 437 if moduleType in [PY_SOURCE, PTL_SOURCE]:
427 self._getnext = _py_getnext 438 self._getnext = _py_getnext
428 elif moduleType == RB_SOURCE: 439 elif moduleType == RB_SOURCE:
429 self._getnext = _rb_getnext 440 self._getnext = _rb_getnext
430 else: 441 else:
431 self._getnext = None 442 self._getnext = None
432 443
433 def addClass(self, name, _class): 444 def addClass(self, name, _class):
434 """ 445 """
435 Public method to add information about a class. 446 Public method to add information about a class.
436 447
437 @param name name of class to be added (string) 448 @param name name of class to be added (string)
438 @param _class Class object to be added 449 @param _class Class object to be added
439 """ 450 """
440 if name in self.classes: 451 if name in self.classes:
441 self.classes_counts[name] += 1 452 self.classes_counts[name] += 1
442 name = "{0}_{1:d}".format(name, self.classes_counts[name]) 453 name = "{0}_{1:d}".format(name, self.classes_counts[name])
443 else: 454 else:
444 self.classes_counts[name] = 0 455 self.classes_counts[name] = 0
445 self.classes[name] = _class 456 self.classes[name] = _class
446 457
447 def addModule(self, name, module): 458 def addModule(self, name, module):
448 """ 459 """
449 Public method to add information about a Ruby module. 460 Public method to add information about a Ruby module.
450 461
451 @param name name of module to be added (string) 462 @param name name of module to be added (string)
452 @param module Module object to be added 463 @param module Module object to be added
453 """ 464 """
454 if name in self.modules: 465 if name in self.modules:
455 self.modules_counts[name] += 1 466 self.modules_counts[name] += 1
456 name = "{0}_{1:d}".format(name, self.modules_counts[name]) 467 name = "{0}_{1:d}".format(name, self.modules_counts[name])
457 else: 468 else:
458 self.modules_counts[name] = 0 469 self.modules_counts[name] = 0
459 self.modules[name] = module 470 self.modules[name] = module
460 471
461 def addFunction(self, name, function): 472 def addFunction(self, name, function):
462 """ 473 """
463 Public method to add information about a function. 474 Public method to add information about a function.
464 475
465 @param name name of function to be added (string) 476 @param name name of function to be added (string)
466 @param function Function object to be added 477 @param function Function object to be added
467 """ 478 """
468 if name in self.functions: 479 if name in self.functions:
469 self.functions_counts[name] += 1 480 self.functions_counts[name] += 1
470 name = "{0}_{1:d}".format(name, self.functions_counts[name]) 481 name = "{0}_{1:d}".format(name, self.functions_counts[name])
471 else: 482 else:
472 self.functions_counts[name] = 0 483 self.functions_counts[name] = 0
473 self.functions[name] = function 484 self.functions[name] = function
474 485
475 def addGlobal(self, name, attr): 486 def addGlobal(self, name, attr):
476 """ 487 """
477 Public method to add information about global variables. 488 Public method to add information about global variables.
478 489
479 @param name name of the global to add (string) 490 @param name name of the global to add (string)
480 @param attr Attribute object to be added 491 @param attr Attribute object to be added
481 """ 492 """
482 if name not in self.globals: 493 if name not in self.globals:
483 self.globals[name] = attr 494 self.globals[name] = attr
484 else: 495 else:
485 self.globals[name].addAssignment(attr.lineno) 496 self.globals[name].addAssignment(attr.lineno)
486 497
487 def addDescription(self, description): 498 def addDescription(self, description):
488 """ 499 """
489 Public method to store the modules docstring. 500 Public method to store the modules docstring.
490 501
491 @param description the docstring to be stored (string) 502 @param description the docstring to be stored (string)
492 """ 503 """
493 self.description = description 504 self.description = description
494 505
495 def scan(self, src): 506 def scan(self, src):
496 """ 507 """
497 Public method to scan the source text and retrieve the relevant 508 Public method to scan the source text and retrieve the relevant
498 information. 509 information.
499 510
500 @param src the source text to be scanned (string) 511 @param src the source text to be scanned (string)
501 """ 512 """
502 # convert eol markers the Python style 513 # convert eol markers the Python style
503 src = src.replace("\r\n", "\n").replace("\r", "\n") 514 src = src.replace("\r\n", "\n").replace("\r", "\n")
504 if self.type in [PY_SOURCE, PTL_SOURCE]: 515 if self.type in [PY_SOURCE, PTL_SOURCE]:
505 self.__py_scan(src) 516 self.__py_scan(src)
506 elif self.type == RB_SOURCE: 517 elif self.type == RB_SOURCE:
507 self.__rb_scan(src) 518 self.__rb_scan(src)
508 519
509 def __py_setVisibility(self, objectRef): 520 def __py_setVisibility(self, objectRef):
510 """ 521 """
511 Private method to set the visibility of an object. 522 Private method to set the visibility of an object.
512 523
513 @param objectRef reference to the object (Attribute, Class or Function) 524 @param objectRef reference to the object (Attribute, Class or Function)
514 """ 525 """
515 if objectRef.name.startswith('__'): 526 if objectRef.name.startswith("__"):
516 objectRef.setPrivate() 527 objectRef.setPrivate()
517 elif objectRef.name.startswith('_'): 528 elif objectRef.name.startswith("_"):
518 objectRef.setProtected() 529 objectRef.setProtected()
519 else: 530 else:
520 objectRef.setPublic() 531 objectRef.setPublic()
521 532
522 def __py_scan(self, src): 533 def __py_scan(self, src):
523 """ 534 """
524 Private method to scan the source text of a Python module and retrieve 535 Private method to scan the source text of a Python module and retrieve
525 the relevant information. 536 the relevant information.
526 537
527 @param src the source text to be scanned (string) 538 @param src the source text to be scanned (string)
528 """ 539 """
529 # __IGNORE_WARNING_D234__ 540 # __IGNORE_WARNING_D234__
530 def calculateEndline(lineno, lines, indent): 541 def calculateEndline(lineno, lines, indent):
531 """ 542 """
532 Function to calculate the end line of a class or method/function. 543 Function to calculate the end line of a class or method/function.
533 544
534 @param lineno line number to start at (one based) 545 @param lineno line number to start at (one based)
535 @type int 546 @type int
536 @param lines list of source lines 547 @param lines list of source lines
537 @type list of str 548 @type list of str
538 @param indent indent length the class/method/function definition 549 @param indent indent length the class/method/function definition
548 # a comment sign 559 # a comment sign
549 lineIndent = _indent(line.replace(line.lstrip(), "")) 560 lineIndent = _indent(line.replace(line.lstrip(), ""))
550 if lineIndent <= indent: 561 if lineIndent <= indent:
551 return lineno 562 return lineno
552 lineno += 1 563 lineno += 1
553 564
554 # nothing found 565 # nothing found
555 return -1 566 return -1
556 567
557 srcLines = src.splitlines() 568 srcLines = src.splitlines()
558 569
559 lineno, last_lineno_pos = 1, 0 570 lineno, last_lineno_pos = 1, 0
560 classstack = [] # stack of (class, indent) pairs 571 classstack = [] # stack of (class, indent) pairs
561 conditionalsstack = [] # stack of indents of conditional defines 572 conditionalsstack = [] # stack of indents of conditional defines
562 deltastack = [] 573 deltastack = []
563 deltaindent = 0 574 deltaindent = 0
570 while True: 581 while True:
571 m = self._getnext(src, i) 582 m = self._getnext(src, i)
572 if not m: 583 if not m:
573 break 584 break
574 start, i = m.span() 585 start, i = m.span()
575 586
576 if m.start("MethodModifier") >= 0: 587 if m.start("MethodModifier") >= 0:
577 modifierIndent = _indent(m.group("MethodModifierIndent")) 588 modifierIndent = _indent(m.group("MethodModifierIndent"))
578 modifierType = m.group("MethodModifierType") 589 modifierType = m.group("MethodModifierType")
579 590
580 elif m.start("Method") >= 0: 591 elif m.start("Method") >= 0:
581 # found a method definition or function 592 # found a method definition or function
582 thisindent = _indent(m.group("MethodIndent")) 593 thisindent = _indent(m.group("MethodIndent"))
583 meth_name = m.group("MethodName") 594 meth_name = m.group("MethodName")
584 meth_sig = m.group("MethodSignature") 595 meth_sig = m.group("MethodSignature")
585 meth_sig = meth_sig.replace('\\\n', '') 596 meth_sig = meth_sig.replace("\\\n", "")
586 meth_ret = m.group("MethodReturnAnnotation") 597 meth_ret = m.group("MethodReturnAnnotation")
587 meth_ret = meth_ret.replace('\\\n', '') 598 meth_ret = meth_ret.replace("\\\n", "")
588 if m.group("MethodPyQtSignature") is not None: 599 if m.group("MethodPyQtSignature") is not None:
589 meth_pyqtSig = ( 600 meth_pyqtSig = (
590 m.group("MethodPyQtSignature") 601 m.group("MethodPyQtSignature")
591 .replace('\\\n', '') 602 .replace("\\\n", "")
592 .split('result')[0] 603 .split("result")[0]
593 .split('name')[0] 604 .split("name")[0]
594 .strip("\"', \t") 605 .strip("\"', \t")
595 ) 606 )
596 else: 607 else:
597 meth_pyqtSig = None 608 meth_pyqtSig = None
598 lineno += src.count('\n', last_lineno_pos, start) 609 lineno += src.count("\n", last_lineno_pos, start)
599 last_lineno_pos = start 610 last_lineno_pos = start
600 if modifierType and modifierIndent == thisindent: 611 if modifierType and modifierIndent == thisindent:
601 if modifierType == "@staticmethod": 612 if modifierType == "@staticmethod":
602 modifier = Function.Static 613 modifier = Function.Static
603 elif modifierType == "@classmethod": 614 elif modifierType == "@classmethod":
608 modifier = Function.General 619 modifier = Function.General
609 # modify indentation level for conditional defines 620 # modify indentation level for conditional defines
610 if conditionalsstack: 621 if conditionalsstack:
611 if thisindent > conditionalsstack[-1]: 622 if thisindent > conditionalsstack[-1]:
612 if not deltaindentcalculated: 623 if not deltaindentcalculated:
613 deltastack.append( 624 deltastack.append(thisindent - conditionalsstack[-1])
614 thisindent - conditionalsstack[-1]) 625 deltaindent = reduce(lambda x, y: x + y, deltastack)
615 deltaindent = reduce(
616 lambda x, y: x + y, deltastack)
617 deltaindentcalculated = 1 626 deltaindentcalculated = 1
618 thisindent -= deltaindent 627 thisindent -= deltaindent
619 else: 628 else:
620 while ( 629 while conditionalsstack and conditionalsstack[-1] >= thisindent:
621 conditionalsstack and
622 conditionalsstack[-1] >= thisindent
623 ):
624 del conditionalsstack[-1] 630 del conditionalsstack[-1]
625 if deltastack: 631 if deltastack:
626 del deltastack[-1] 632 del deltastack[-1]
627 deltaindentcalculated = 0 633 deltaindentcalculated = 0
628 # close all classes indented at least as much 634 # close all classes indented at least as much
634 # nested defs are added to the class 640 # nested defs are added to the class
635 cur_class = classstack[csi][0] 641 cur_class = classstack[csi][0]
636 csi -= 1 642 csi -= 1
637 if cur_class is None: 643 if cur_class is None:
638 continue 644 continue
639 645
640 if isinstance(cur_class, Class): 646 if isinstance(cur_class, Class):
641 # it's a class method 647 # it's a class method
642 f = Function( 648 f = Function(
643 None, meth_name, None, lineno, 649 None,
644 meth_sig, meth_pyqtSig, modifierType=modifier, 650 meth_name,
645 annotation=meth_ret) 651 None,
652 lineno,
653 meth_sig,
654 meth_pyqtSig,
655 modifierType=modifier,
656 annotation=meth_ret,
657 )
646 self.__py_setVisibility(f) 658 self.__py_setVisibility(f)
647 cur_class.addMethod(meth_name, f) 659 cur_class.addMethod(meth_name, f)
648 break 660 break
649 else: 661 else:
650 # it's a nested function of a module function 662 # it's a nested function of a module function
651 f = Function( 663 f = Function(
652 self.name, meth_name, self.file, lineno, 664 self.name,
653 meth_sig, meth_pyqtSig, modifierType=modifier, 665 meth_name,
654 annotation=meth_ret) 666 self.file,
667 lineno,
668 meth_sig,
669 meth_pyqtSig,
670 modifierType=modifier,
671 annotation=meth_ret,
672 )
655 self.__py_setVisibility(f) 673 self.__py_setVisibility(f)
656 self.addFunction(meth_name, f) 674 self.addFunction(meth_name, f)
657 else: 675 else:
658 # it's a module function 676 # it's a module function
659 f = Function(self.name, meth_name, self.file, lineno, 677 f = Function(
660 meth_sig, meth_pyqtSig, modifierType=modifier, 678 self.name,
661 annotation=meth_ret) 679 meth_name,
680 self.file,
681 lineno,
682 meth_sig,
683 meth_pyqtSig,
684 modifierType=modifier,
685 annotation=meth_ret,
686 )
662 self.__py_setVisibility(f) 687 self.__py_setVisibility(f)
663 self.addFunction(meth_name, f) 688 self.addFunction(meth_name, f)
664 endlineno = calculateEndline(lineno, srcLines, thisindent) 689 endlineno = calculateEndline(lineno, srcLines, thisindent)
665 f.setEndLine(endlineno) 690 f.setEndLine(endlineno)
666 cur_obj = f 691 cur_obj = f
667 classstack.append((None, thisindent)) # Marker for nested fns 692 classstack.append((None, thisindent)) # Marker for nested fns
668 693
669 # reset the modifier settings 694 # reset the modifier settings
670 modifierType = Function.General 695 modifierType = Function.General
671 modifierIndent = -1 696 modifierIndent = -1
672 697
673 elif m.start("Docstring") >= 0: 698 elif m.start("Docstring") >= 0:
674 contents = m.group("DocstringContents3") 699 contents = m.group("DocstringContents3")
675 if contents is not None: 700 if contents is not None:
676 contents = _hashsub(r"\1", contents) 701 contents = _hashsub(r"\1", contents)
677 else: 702 else:
678 if self.file.lower().endswith('.ptl'): 703 if self.file.lower().endswith(".ptl"):
679 contents = "" 704 contents = ""
680 else: 705 else:
681 contents = ( 706 contents = m.group("DocstringContents1") or m.group(
682 m.group("DocstringContents1") or 707 "DocstringContents2"
683 m.group("DocstringContents2")
684 ) 708 )
685 if cur_obj: 709 if cur_obj:
686 cur_obj.addDescription(contents) 710 cur_obj.addDescription(contents)
687 711
688 elif m.start("String") >= 0: 712 elif m.start("String") >= 0:
689 if ( 713 if modulelevel and (
690 modulelevel and ( 714 src[start - len("\r\n") : start] == "\r\n"
691 src[start - len('\r\n'):start] == '\r\n' or 715 or src[start - len("\n") : start] == "\n"
692 src[start - len('\n'):start] == '\n' or 716 or src[start - len("\r") : start] == "\r"
693 src[start - len('\r'):start] == '\r'
694 )
695 ): 717 ):
696 contents = m.group("StringContents3") 718 contents = m.group("StringContents3")
697 if contents is not None: 719 if contents is not None:
698 contents = _hashsub(r"\1", contents) 720 contents = _hashsub(r"\1", contents)
699 else: 721 else:
700 if self.file.lower().endswith('.ptl'): 722 if self.file.lower().endswith(".ptl"):
701 contents = "" 723 contents = ""
702 else: 724 else:
703 contents = ( 725 contents = m.group("StringContents1") or m.group(
704 m.group("StringContents1") or 726 "StringContents2"
705 m.group("StringContents2")
706 ) 727 )
707 if cur_obj: 728 if cur_obj:
708 cur_obj.addDescription(contents) 729 cur_obj.addDescription(contents)
709 730
710 elif m.start("Class") >= 0: 731 elif m.start("Class") >= 0:
711 # we found a class definition 732 # we found a class definition
712 thisindent = _indent(m.group("ClassIndent")) 733 thisindent = _indent(m.group("ClassIndent"))
713 lineno += src.count('\n', last_lineno_pos, start) 734 lineno += src.count("\n", last_lineno_pos, start)
714 last_lineno_pos = start 735 last_lineno_pos = start
715 # close all classes indented at least as much 736 # close all classes indented at least as much
716 while classstack and classstack[-1][1] >= thisindent: 737 while classstack and classstack[-1][1] >= thisindent:
717 del classstack[-1] 738 del classstack[-1]
718 class_name = m.group("ClassName") 739 class_name = m.group("ClassName")
719 inherit = m.group("ClassSupers") 740 inherit = m.group("ClassSupers")
720 if inherit: 741 if inherit:
721 # the class inherits from other classes 742 # the class inherits from other classes
722 inherit = inherit[1:-1].strip() 743 inherit = inherit[1:-1].strip()
723 inherit = _commentsub('', inherit) 744 inherit = _commentsub("", inherit)
724 names = [] 745 names = []
725 for n in inherit.split(','): 746 for n in inherit.split(","):
726 n = n.strip() 747 n = n.strip()
727 if n: 748 if n:
728 if n in self.classes: 749 if n in self.classes:
729 # we know this super class 750 # we know this super class
730 n = self.classes[n].name 751 n = self.classes[n].name
731 else: 752 else:
732 c = n.split('.') 753 c = n.split(".")
733 if len(c) > 1: 754 if len(c) > 1:
734 # super class is of the 755 # super class is of the
735 # form module.class: 756 # form module.class:
736 # look in module for class 757 # look in module for class
737 m = c[-2] 758 m = c[-2]
743 inherit = names 764 inherit = names
744 # modify indentation level for conditional defines 765 # modify indentation level for conditional defines
745 if conditionalsstack: 766 if conditionalsstack:
746 if thisindent > conditionalsstack[-1]: 767 if thisindent > conditionalsstack[-1]:
747 if not deltaindentcalculated: 768 if not deltaindentcalculated:
748 deltastack.append( 769 deltastack.append(thisindent - conditionalsstack[-1])
749 thisindent - conditionalsstack[-1] 770 deltaindent = reduce(lambda x, y: x + y, deltastack)
750 )
751 deltaindent = reduce(
752 lambda x, y: x + y, deltastack
753 )
754 deltaindentcalculated = True 771 deltaindentcalculated = True
755 thisindent -= deltaindent 772 thisindent -= deltaindent
756 else: 773 else:
757 while ( 774 while conditionalsstack and conditionalsstack[-1] >= thisindent:
758 conditionalsstack and
759 conditionalsstack[-1] >= thisindent
760 ):
761 del conditionalsstack[-1] 775 del conditionalsstack[-1]
762 if deltastack: 776 if deltastack:
763 del deltastack[-1] 777 del deltastack[-1]
764 deltaindentcalculated = False 778 deltaindentcalculated = False
765 # remember this class 779 # remember this class
766 cur_class = Class(self.name, class_name, inherit, 780 cur_class = Class(self.name, class_name, inherit, self.file, lineno)
767 self.file, lineno)
768 self.__py_setVisibility(cur_class) 781 self.__py_setVisibility(cur_class)
769 endlineno = calculateEndline(lineno, srcLines, thisindent) 782 endlineno = calculateEndline(lineno, srcLines, thisindent)
770 cur_class.setEndLine(endlineno) 783 cur_class.setEndLine(endlineno)
771 cur_obj = cur_class 784 cur_obj = cur_class
772 self.addClass(class_name, cur_class) 785 self.addClass(class_name, cur_class)
773 # add nested classes to the module 786 # add nested classes to the module
774 classstack.append((cur_class, thisindent)) 787 classstack.append((cur_class, thisindent))
775 788
776 elif m.start("Attribute") >= 0: 789 elif m.start("Attribute") >= 0:
777 lineno += src.count('\n', last_lineno_pos, start) 790 lineno += src.count("\n", last_lineno_pos, start)
778 last_lineno_pos = start 791 last_lineno_pos = start
779 index = -1 792 index = -1
780 while index >= -len(classstack): 793 while index >= -len(classstack):
781 if classstack[index][0] is not None: 794 if classstack[index][0] is not None:
782 attrName = m.group("AttributeName") 795 attrName = m.group("AttributeName")
783 attr = Attribute( 796 attr = Attribute(self.name, attrName, self.file, lineno)
784 self.name, attrName, self.file, lineno)
785 self.__py_setVisibility(attr) 797 self.__py_setVisibility(attr)
786 classstack[index][0].addAttribute(attrName, attr) 798 classstack[index][0].addAttribute(attrName, attr)
787 break 799 break
788 else: 800 else:
789 index -= 1 801 index -= 1
790 802
791 elif m.start("Main") >= 0: 803 elif m.start("Main") >= 0:
792 # 'main' part of the script, reset class stack 804 # 'main' part of the script, reset class stack
793 lineno += src.count('\n', last_lineno_pos, start) 805 lineno += src.count("\n", last_lineno_pos, start)
794 last_lineno_pos = start 806 last_lineno_pos = start
795 classstack = [] 807 classstack = []
796 808
797 elif m.start("Variable") >= 0: 809 elif m.start("Variable") >= 0:
798 thisindent = _indent(m.group("VariableIndent")) 810 thisindent = _indent(m.group("VariableIndent"))
799 variable_name = m.group("VariableName") 811 variable_name = m.group("VariableName")
800 isSignal = m.group("VariableSignal") != "" 812 isSignal = m.group("VariableSignal") != ""
801 lineno += src.count('\n', last_lineno_pos, start) 813 lineno += src.count("\n", last_lineno_pos, start)
802 last_lineno_pos = start 814 last_lineno_pos = start
803 if thisindent == 0: 815 if thisindent == 0:
804 # global variable 816 # global variable
805 attr = Attribute( 817 attr = Attribute(
806 self.name, variable_name, self.file, lineno, 818 self.name, variable_name, self.file, lineno, isSignal=isSignal
807 isSignal=isSignal) 819 )
808 self.__py_setVisibility(attr) 820 self.__py_setVisibility(attr)
809 self.addGlobal(variable_name, attr) 821 self.addGlobal(variable_name, attr)
810 else: 822 else:
811 index = -1 823 index = -1
812 while index >= -len(classstack): 824 while index >= -len(classstack):
813 if classstack[index][1] >= thisindent: 825 if classstack[index][1] >= thisindent:
814 index -= 1 826 index -= 1
815 else: 827 else:
816 if ( 828 if classstack[index][0] is not None and isinstance(
817 classstack[index][0] is not None and 829 classstack[index][0], Class
818 isinstance(classstack[index][0], Class)
819 ): 830 ):
820 attr = Attribute( 831 attr = Attribute(
821 self.name, variable_name, self.file, 832 self.name,
822 lineno, isSignal=isSignal) 833 variable_name,
834 self.file,
835 lineno,
836 isSignal=isSignal,
837 )
823 self.__py_setVisibility(attr) 838 self.__py_setVisibility(attr)
824 classstack[index][0].addGlobal( 839 classstack[index][0].addGlobal(variable_name, attr)
825 variable_name, attr)
826 break 840 break
827 841
828 elif m.start("Import") >= 0: 842 elif m.start("Import") >= 0:
829 #- import module 843 # - import module
830 names = [n.strip() for n in 844 names = [
831 "".join(m.group("ImportList").splitlines()) 845 n.strip()
832 .replace("\\", "").split(',')] 846 for n in "".join(m.group("ImportList").splitlines())
847 .replace("\\", "")
848 .split(",")
849 ]
833 self.imports.extend( 850 self.imports.extend(
834 [name for name in names 851 [name for name in names if name not in self.imports]
835 if name not in self.imports]) 852 )
836 853
837 elif m.start("ImportFrom") >= 0: 854 elif m.start("ImportFrom") >= 0:
838 #- from module import stuff 855 # - from module import stuff
839 mod = m.group("ImportFromPath") 856 mod = m.group("ImportFromPath")
840 namesLines = (m.group("ImportFromList") 857 namesLines = (
841 .replace("(", "").replace(")", "") 858 m.group("ImportFromList")
842 .replace("\\", "") 859 .replace("(", "")
843 .strip().splitlines()) 860 .replace(")", "")
844 namesLines = [line.split("#")[0].strip() 861 .replace("\\", "")
845 for line in namesLines] 862 .strip()
846 names = [n.strip() for n in 863 .splitlines()
847 "".join(namesLines) 864 )
848 .split(',')] 865 namesLines = [line.split("#")[0].strip() for line in namesLines]
866 names = [n.strip() for n in "".join(namesLines).split(",")]
849 if mod not in self.from_imports: 867 if mod not in self.from_imports:
850 self.from_imports[mod] = [] 868 self.from_imports[mod] = []
851 self.from_imports[mod].extend( 869 self.from_imports[mod].extend(
852 [name for name in names 870 [name for name in names if name not in self.from_imports[mod]]
853 if name not in self.from_imports[mod]]) 871 )
854 872
855 elif m.start("ConditionalDefine") >= 0: 873 elif m.start("ConditionalDefine") >= 0:
856 # a conditional function/method definition 874 # a conditional function/method definition
857 thisindent = _indent(m.group("ConditionalDefineIndent")) 875 thisindent = _indent(m.group("ConditionalDefineIndent"))
858 while ( 876 while conditionalsstack and conditionalsstack[-1] >= thisindent:
859 conditionalsstack and
860 conditionalsstack[-1] >= thisindent
861 ):
862 del conditionalsstack[-1] 877 del conditionalsstack[-1]
863 if deltastack: 878 if deltastack:
864 del deltastack[-1] 879 del deltastack[-1]
865 conditionalsstack.append(thisindent) 880 conditionalsstack.append(thisindent)
866 deltaindentcalculated = 0 881 deltaindentcalculated = 0
867 882
868 elif m.start("Comment") >= 0 and modulelevel: 883 elif m.start("Comment") >= 0 and modulelevel:
869 continue 884 continue
870 885
871 modulelevel = False 886 modulelevel = False
872 887
873 def __rb_scan(self, src): 888 def __rb_scan(self, src):
874 """ 889 """
875 Private method to scan the source text of a Python module and retrieve 890 Private method to scan the source text of a Python module and retrieve
876 the relevant information. 891 the relevant information.
877 892
878 @param src the source text to be scanned 893 @param src the source text to be scanned
879 @type str 894 @type str
880 """ 895 """
881 lineno, last_lineno_pos = 1, 0 896 lineno, last_lineno_pos = 1, 0
882 classstack = [] # stack of (class, indent) pairs 897 classstack = [] # stack of (class, indent) pairs
883 acstack = [] # stack of (access control, indent) pairs 898 acstack = [] # stack of (access control, indent) pairs
884 indent = 0 899 indent = 0
885 i = 0 900 i = 0
886 cur_obj = self 901 cur_obj = self
887 lastGlobalEntry = None 902 lastGlobalEntry = None
888 while True: 903 while True:
889 m = self._getnext(src, i) 904 m = self._getnext(src, i)
890 if not m: 905 if not m:
891 break 906 break
892 start, i = m.span() 907 start, i = m.span()
893 908
894 if m.start("Method") >= 0: 909 if m.start("Method") >= 0:
895 # found a method definition or function 910 # found a method definition or function
896 thisindent = indent 911 thisindent = indent
897 indent += 1 912 indent += 1
898 meth_name = ( 913 meth_name = (
899 m.group("MethodName") or 914 m.group("MethodName")
900 m.group("MethodName2") or 915 or m.group("MethodName2")
901 m.group("MethodName3") 916 or m.group("MethodName3")
902 ) 917 )
903 meth_sig = m.group("MethodSignature") 918 meth_sig = m.group("MethodSignature")
904 meth_sig = meth_sig and meth_sig.replace('\\\n', '') or '' 919 meth_sig = meth_sig and meth_sig.replace("\\\n", "") or ""
905 lineno += src.count('\n', last_lineno_pos, start) 920 lineno += src.count("\n", last_lineno_pos, start)
906 last_lineno_pos = start 921 last_lineno_pos = start
907 if meth_name.startswith('self.'): 922 if meth_name.startswith("self."):
908 meth_name = meth_name[5:] 923 meth_name = meth_name[5:]
909 elif meth_name.startswith('self::'): 924 elif meth_name.startswith("self::"):
910 meth_name = meth_name[6:] 925 meth_name = meth_name[6:]
911 # close all classes/modules indented at least as much 926 # close all classes/modules indented at least as much
912 while classstack and classstack[-1][1] >= thisindent: 927 while classstack and classstack[-1][1] >= thisindent:
913 if ( 928 if classstack[-1][0] is not None and isinstance(
914 classstack[-1][0] is not None and 929 classstack[-1][0], (Class, Function, RbModule)
915 isinstance(classstack[-1][0],
916 (Class, Function, RbModule))
917 ): 930 ):
918 # record the end line of this class, function or module 931 # record the end line of this class, function or module
919 classstack[-1][0].setEndLine(lineno - 1) 932 classstack[-1][0].setEndLine(lineno - 1)
920 del classstack[-1] 933 del classstack[-1]
921 while acstack and acstack[-1][1] >= thisindent: 934 while acstack and acstack[-1][1] >= thisindent:
926 # nested defs are added to the class 939 # nested defs are added to the class
927 cur_class = classstack[csi][0] 940 cur_class = classstack[csi][0]
928 csi -= 1 941 csi -= 1
929 if cur_class is None: 942 if cur_class is None:
930 continue 943 continue
931 944
932 if isinstance(cur_class, (Class, RbModule)): 945 if isinstance(cur_class, (Class, RbModule)):
933 # it's a class/module method 946 # it's a class/module method
934 f = Function(None, meth_name, 947 f = Function(None, meth_name, None, lineno, meth_sig)
935 None, lineno, meth_sig)
936 cur_class.addMethod(meth_name, f) 948 cur_class.addMethod(meth_name, f)
937 break 949 break
938 else: 950 else:
939 # it's a nested function of a module function 951 # it's a nested function of a module function
940 f = Function( 952 f = Function(self.name, meth_name, self.file, lineno, meth_sig)
941 self.name, meth_name, self.file, lineno, meth_sig)
942 self.addFunction(meth_name, f) 953 self.addFunction(meth_name, f)
943 # set access control 954 # set access control
944 if acstack: 955 if acstack:
945 accesscontrol = acstack[-1][0] 956 accesscontrol = acstack[-1][0]
946 if accesscontrol == "private": 957 if accesscontrol == "private":
949 f.setProtected() 960 f.setProtected()
950 elif accesscontrol == "public": 961 elif accesscontrol == "public":
951 f.setPublic() 962 f.setPublic()
952 else: 963 else:
953 # it's a function 964 # it's a function
954 f = Function( 965 f = Function(self.name, meth_name, self.file, lineno, meth_sig)
955 self.name, meth_name, self.file, lineno, meth_sig)
956 self.addFunction(meth_name, f) 966 self.addFunction(meth_name, f)
957 if not classstack: 967 if not classstack:
958 if lastGlobalEntry: 968 if lastGlobalEntry:
959 lastGlobalEntry.setEndLine(lineno - 1) 969 lastGlobalEntry.setEndLine(lineno - 1)
960 lastGlobalEntry = f 970 lastGlobalEntry = f
961 if cur_obj and isinstance(cur_obj, Function): 971 if cur_obj and isinstance(cur_obj, Function):
962 cur_obj.setEndLine(lineno - 1) 972 cur_obj.setEndLine(lineno - 1)
963 cur_obj = f 973 cur_obj = f
964 classstack.append((None, thisindent)) # Marker for nested fns 974 classstack.append((None, thisindent)) # Marker for nested fns
965 975
966 elif m.start("Docstring") >= 0: 976 elif m.start("Docstring") >= 0:
967 contents = m.group("DocstringContents") 977 contents = m.group("DocstringContents")
968 if contents is not None: 978 if contents is not None:
969 contents = _hashsub(r"\1", contents) 979 contents = _hashsub(r"\1", contents)
970 if cur_obj: 980 if cur_obj:
971 cur_obj.addDescription(contents) 981 cur_obj.addDescription(contents)
972 982
973 elif m.start("Class") >= 0: 983 elif m.start("Class") >= 0:
974 # we found a class definition 984 # we found a class definition
975 thisindent = indent 985 thisindent = indent
976 indent += 1 986 indent += 1
977 lineno += src.count('\n', last_lineno_pos, start) 987 lineno += src.count("\n", last_lineno_pos, start)
978 last_lineno_pos = start 988 last_lineno_pos = start
979 # close all classes/modules indented at least as much 989 # close all classes/modules indented at least as much
980 while classstack and classstack[-1][1] >= thisindent: 990 while classstack and classstack[-1][1] >= thisindent:
981 if ( 991 if classstack[-1][0] is not None and isinstance(
982 classstack[-1][0] is not None and 992 classstack[-1][0], (Class, Function, RbModule)
983 isinstance(classstack[-1][0],
984 (Class, Function, RbModule))
985 ): 993 ):
986 # record the end line of this class, function or module 994 # record the end line of this class, function or module
987 classstack[-1][0].setEndLine(lineno - 1) 995 classstack[-1][0].setEndLine(lineno - 1)
988 del classstack[-1] 996 del classstack[-1]
989 class_name = m.group("ClassName") or m.group("ClassName2") 997 class_name = m.group("ClassName") or m.group("ClassName2")
990 inherit = m.group("ClassSupers") 998 inherit = m.group("ClassSupers")
991 if inherit: 999 if inherit:
992 # the class inherits from other classes 1000 # the class inherits from other classes
993 inherit = inherit[1:].strip() 1001 inherit = inherit[1:].strip()
994 inherit = [_commentsub('', inherit)] 1002 inherit = [_commentsub("", inherit)]
995 # remember this class 1003 # remember this class
996 cur_class = Class(self.name, class_name, inherit, 1004 cur_class = Class(self.name, class_name, inherit, self.file, lineno)
997 self.file, lineno)
998 # add nested classes to the file 1005 # add nested classes to the file
999 if classstack and isinstance(classstack[-1][0], RbModule): 1006 if classstack and isinstance(classstack[-1][0], RbModule):
1000 parent_obj = classstack[-1][0] 1007 parent_obj = classstack[-1][0]
1001 else: 1008 else:
1002 parent_obj = self 1009 parent_obj = self
1003 if class_name in parent_obj.classes: 1010 if class_name in parent_obj.classes:
1004 cur_class = parent_obj.classes[class_name] 1011 cur_class = parent_obj.classes[class_name]
1005 elif ( 1012 elif (
1006 classstack and 1013 classstack
1007 isinstance(classstack[-1][0], Class) and 1014 and isinstance(classstack[-1][0], Class)
1008 class_name == "self" 1015 and class_name == "self"
1009 ): 1016 ):
1010 cur_class = classstack[-1][0] 1017 cur_class = classstack[-1][0]
1011 else: 1018 else:
1012 parent_obj.addClass(class_name, cur_class) 1019 parent_obj.addClass(class_name, cur_class)
1013 if not classstack: 1020 if not classstack:
1018 classstack.append((cur_class, thisindent)) 1025 classstack.append((cur_class, thisindent))
1019 while acstack and acstack[-1][1] >= thisindent: 1026 while acstack and acstack[-1][1] >= thisindent:
1020 del acstack[-1] 1027 del acstack[-1]
1021 acstack.append(["public", thisindent]) 1028 acstack.append(["public", thisindent])
1022 # default access control is 'public' 1029 # default access control is 'public'
1023 1030
1024 elif m.start("Module") >= 0: 1031 elif m.start("Module") >= 0:
1025 # we found a module definition 1032 # we found a module definition
1026 thisindent = indent 1033 thisindent = indent
1027 indent += 1 1034 indent += 1
1028 lineno += src.count('\n', last_lineno_pos, start) 1035 lineno += src.count("\n", last_lineno_pos, start)
1029 last_lineno_pos = start 1036 last_lineno_pos = start
1030 # close all classes/modules indented at least as much 1037 # close all classes/modules indented at least as much
1031 while classstack and classstack[-1][1] >= thisindent: 1038 while classstack and classstack[-1][1] >= thisindent:
1032 if ( 1039 if classstack[-1][0] is not None and isinstance(
1033 classstack[-1][0] is not None and 1040 classstack[-1][0], (Class, Function, RbModule)
1034 isinstance(classstack[-1][0],
1035 (Class, Function, RbModule))
1036 ): 1041 ):
1037 # record the end line of this class, function or module 1042 # record the end line of this class, function or module
1038 classstack[-1][0].setEndLine(lineno - 1) 1043 classstack[-1][0].setEndLine(lineno - 1)
1039 del classstack[-1] 1044 del classstack[-1]
1040 module_name = m.group("ModuleName") 1045 module_name = m.group("ModuleName")
1041 # remember this class 1046 # remember this class
1042 cur_class = RbModule(self.name, module_name, 1047 cur_class = RbModule(self.name, module_name, self.file, lineno)
1043 self.file, lineno)
1044 # add nested Ruby modules to the file 1048 # add nested Ruby modules to the file
1045 if module_name in self.modules: 1049 if module_name in self.modules:
1046 cur_class = self.modules[module_name] 1050 cur_class = self.modules[module_name]
1047 else: 1051 else:
1048 self.addModule(module_name, cur_class) 1052 self.addModule(module_name, cur_class)
1054 classstack.append((cur_class, thisindent)) 1058 classstack.append((cur_class, thisindent))
1055 while acstack and acstack[-1][1] >= thisindent: 1059 while acstack and acstack[-1][1] >= thisindent:
1056 del acstack[-1] 1060 del acstack[-1]
1057 acstack.append(["public", thisindent]) 1061 acstack.append(["public", thisindent])
1058 # default access control is 'public' 1062 # default access control is 'public'
1059 1063
1060 elif m.start("AccessControl") >= 0: 1064 elif m.start("AccessControl") >= 0:
1061 aclist = m.group("AccessControlList") 1065 aclist = m.group("AccessControlList")
1062 if aclist is None: 1066 if aclist is None:
1063 index = -1 1067 index = -1
1064 while index >= -len(acstack): 1068 while index >= -len(acstack):
1065 if acstack[index][1] < indent: 1069 if acstack[index][1] < indent:
1066 actype = ( 1070 actype = (
1067 m.group("AccessControlType") or 1071 m.group("AccessControlType")
1068 m.group("AccessControlType2").split('_')[0] 1072 or m.group("AccessControlType2").split("_")[0]
1069 ) 1073 )
1070 acstack[index][0] = actype.lower() 1074 acstack[index][0] = actype.lower()
1071 break 1075 break
1072 else: 1076 else:
1073 index -= 1 1077 index -= 1
1074 else: 1078 else:
1075 index = -1 1079 index = -1
1076 while index >= -len(classstack): 1080 while index >= -len(classstack):
1077 if ( 1081 if (
1078 classstack[index][0] is not None and 1082 classstack[index][0] is not None
1079 not isinstance(classstack[index][0], Function) and 1083 and not isinstance(classstack[index][0], Function)
1080 classstack[index][1] < indent 1084 and classstack[index][1] < indent
1081 ): 1085 ):
1082 parent = classstack[index][0] 1086 parent = classstack[index][0]
1083 actype = ( 1087 actype = (
1084 m.group("AccessControlType") or 1088 m.group("AccessControlType")
1085 m.group("AccessControlType2").split('_')[0] 1089 or m.group("AccessControlType2").split("_")[0]
1086 ) 1090 )
1087 actype = actype.lower() 1091 actype = actype.lower()
1088 for name in aclist.split(","): 1092 for name in aclist.split(","):
1089 # get rid of leading ':' 1093 # get rid of leading ':'
1090 name = name.strip()[1:] 1094 name = name.strip()[1:]
1100 break 1104 break
1101 else: 1105 else:
1102 index -= 1 1106 index -= 1
1103 1107
1104 elif m.start("Attribute") >= 0: 1108 elif m.start("Attribute") >= 0:
1105 lineno += src.count('\n', last_lineno_pos, start) 1109 lineno += src.count("\n", last_lineno_pos, start)
1106 last_lineno_pos = start 1110 last_lineno_pos = start
1107 index = -1 1111 index = -1
1108 while index >= -len(classstack): 1112 while index >= -len(classstack):
1109 if ( 1113 if (
1110 classstack[index][0] is not None and 1114 classstack[index][0] is not None
1111 not isinstance(classstack[index][0], Function) and 1115 and not isinstance(classstack[index][0], Function)
1112 classstack[index][1] < indent 1116 and classstack[index][1] < indent
1113 ): 1117 ):
1114 attrName = m.group("AttributeName") 1118 attrName = m.group("AttributeName")
1115 attr = Attribute( 1119 attr = Attribute(self.name, attrName, self.file, lineno)
1116 self.name, attrName, self.file, lineno)
1117 if attrName.startswith("@@") or attrName[0].isupper(): 1120 if attrName.startswith("@@") or attrName[0].isupper():
1118 classstack[index][0].addGlobal(attrName, attr) 1121 classstack[index][0].addGlobal(attrName, attr)
1119 else: 1122 else:
1120 classstack[index][0].addAttribute(attrName, attr) 1123 classstack[index][0].addAttribute(attrName, attr)
1121 break 1124 break
1122 else: 1125 else:
1123 index -= 1 1126 index -= 1
1124 else: 1127 else:
1125 attrName = m.group("AttributeName") 1128 attrName = m.group("AttributeName")
1126 if attrName[0] != "@": 1129 if attrName[0] != "@":
1127 attr = Attribute( 1130 attr = Attribute(self.name, attrName, self.file, lineno)
1128 self.name, attrName, self.file, lineno)
1129 self.addGlobal(attrName, attr) 1131 self.addGlobal(attrName, attr)
1130 if lastGlobalEntry: 1132 if lastGlobalEntry:
1131 lastGlobalEntry.setEndLine(lineno - 1) 1133 lastGlobalEntry.setEndLine(lineno - 1)
1132 lastGlobalEntry = None 1134 lastGlobalEntry = None
1133 1135
1134 elif m.start("Attr") >= 0: 1136 elif m.start("Attr") >= 0:
1135 lineno += src.count('\n', last_lineno_pos, start) 1137 lineno += src.count("\n", last_lineno_pos, start)
1136 last_lineno_pos = start 1138 last_lineno_pos = start
1137 index = -1 1139 index = -1
1138 while index >= -len(classstack): 1140 while index >= -len(classstack):
1139 if ( 1141 if (
1140 classstack[index][0] is not None and 1142 classstack[index][0] is not None
1141 not isinstance(classstack[index][0], Function) and 1143 and not isinstance(classstack[index][0], Function)
1142 classstack[index][1] < indent 1144 and classstack[index][1] < indent
1143 ): 1145 ):
1144 parent = classstack[index][0] 1146 parent = classstack[index][0]
1145 if m.group("AttrType") is None: 1147 if m.group("AttrType") is None:
1146 nv = m.group("AttrList").split(",") 1148 nv = m.group("AttrList").split(",")
1147 if not nv: 1149 if not nv:
1148 break 1150 break
1149 # get rid of leading ':' 1151 # get rid of leading ':'
1150 name = nv[0].strip()[1:] 1152 name = nv[0].strip()[1:]
1151 attr = ( 1153 attr = (
1152 parent.getAttribute("@" + name) or 1154 parent.getAttribute("@" + name)
1153 parent.getAttribute("@@" + name) or 1155 or parent.getAttribute("@@" + name)
1154 Attribute( 1156 or Attribute(self.name, "@" + name, self.file, lineno)
1155 self.name, "@" + name, self.file, lineno)
1156 ) 1157 )
1157 if len(nv) == 1 or nv[1].strip() == "false": 1158 if len(nv) == 1 or nv[1].strip() == "false":
1158 attr.setProtected() 1159 attr.setProtected()
1159 elif nv[1].strip() == "true": 1160 elif nv[1].strip() == "true":
1160 attr.setPublic() 1161 attr.setPublic()
1163 access = m.group("AttrType") 1164 access = m.group("AttrType")
1164 for name in m.group("AttrList").split(","): 1165 for name in m.group("AttrList").split(","):
1165 # get rid of leading ':' 1166 # get rid of leading ':'
1166 name = name.strip()[1:] 1167 name = name.strip()[1:]
1167 attr = ( 1168 attr = (
1168 parent.getAttribute("@" + name) or 1169 parent.getAttribute("@" + name)
1169 parent.getAttribute("@@" + name) or 1170 or parent.getAttribute("@@" + name)
1170 Attribute( 1171 or Attribute(
1171 self.name, "@" + name, self.file, 1172 self.name, "@" + name, self.file, lineno
1172 lineno) 1173 )
1173 ) 1174 )
1174 if access == "_accessor": 1175 if access == "_accessor":
1175 attr.setPublic() 1176 attr.setPublic()
1176 elif access in ("_reader", "_writer"): 1177 elif access in ("_reader", "_writer"):
1177 if attr.isPrivate(): 1178 if attr.isPrivate():
1184 index -= 1 1185 index -= 1
1185 1186
1186 elif m.start("Begin") >= 0: 1187 elif m.start("Begin") >= 0:
1187 # a begin of a block we are not interested in 1188 # a begin of a block we are not interested in
1188 indent += 1 1189 indent += 1
1189 1190
1190 elif m.start("End") >= 0: 1191 elif m.start("End") >= 0:
1191 # an end of a block 1192 # an end of a block
1192 indent -= 1 1193 indent -= 1
1193 if indent < 0: 1194 if indent < 0:
1194 # no negative indent allowed 1195 # no negative indent allowed
1195 if classstack: 1196 if classstack:
1196 # it's a class/module method 1197 # it's a class/module method
1197 indent = classstack[-1][1] 1198 indent = classstack[-1][1]
1198 else: 1199 else:
1199 indent = 0 1200 indent = 0
1200 1201
1201 elif ( 1202 elif (
1202 m.start("String") >= 0 or 1203 m.start("String") >= 0
1203 m.start("Comment") >= 0 or 1204 or m.start("Comment") >= 0
1204 m.start("ClassIgnored") >= 0 or 1205 or m.start("ClassIgnored") >= 0
1205 m.start("BeginEnd") >= 0 1206 or m.start("BeginEnd") >= 0
1206 ): 1207 ):
1207 pass 1208 pass
1208 1209
1209 def createHierarchy(self): 1210 def createHierarchy(self):
1210 """ 1211 """
1211 Public method to build the inheritance hierarchy for all classes of 1212 Public method to build the inheritance hierarchy for all classes of
1212 this module. 1213 this module.
1213 1214
1214 @return A dictionary with inheritance hierarchies. 1215 @return A dictionary with inheritance hierarchies.
1215 """ 1216 """
1216 hierarchy = {} 1217 hierarchy = {}
1217 for class_ in self.classes: 1218 for class_ in self.classes:
1218 self.assembleHierarchy(class_, self.classes, [class_], hierarchy) 1219 self.assembleHierarchy(class_, self.classes, [class_], hierarchy)
1219 for module in self.modules: 1220 for module in self.modules:
1220 self.assembleHierarchy(module, self.modules, [module], hierarchy) 1221 self.assembleHierarchy(module, self.modules, [module], hierarchy)
1221 return hierarchy 1222 return hierarchy
1222 1223
1223 def assembleHierarchy(self, name, classes, path, result): 1224 def assembleHierarchy(self, name, classes, path, result):
1224 """ 1225 """
1225 Public method to assemble the inheritance hierarchy. 1226 Public method to assemble the inheritance hierarchy.
1226 1227
1227 This method will traverse the class hierarchy, from a given class 1228 This method will traverse the class hierarchy, from a given class
1228 and build up a nested dictionary of super-classes. The result is 1229 and build up a nested dictionary of super-classes. The result is
1229 intended to be inverted, i.e. the highest level are the super classes. 1230 intended to be inverted, i.e. the highest level are the super classes.
1230 1231
1231 This code is borrowed from Boa Constructor. 1232 This code is borrowed from Boa Constructor.
1232 1233
1233 @param name name of class to assemble hierarchy (string) 1234 @param name name of class to assemble hierarchy (string)
1234 @param classes A dictionary of classes to look in. 1235 @param classes A dictionary of classes to look in.
1235 @param path 1236 @param path
1236 @param result The resultant hierarchy 1237 @param result The resultant hierarchy
1237 """ 1238 """
1240 for class_ in classes[name].super: 1241 for class_ in classes[name].super:
1241 if class_ not in classes: 1242 if class_ not in classes:
1242 rv[class_] = {} 1243 rv[class_] = {}
1243 exhausted = path + [class_] 1244 exhausted = path + [class_]
1244 exhausted.reverse() 1245 exhausted.reverse()
1245 self.addPathToHierarchy( 1246 self.addPathToHierarchy(exhausted, result, self.addPathToHierarchy)
1246 exhausted, result, self.addPathToHierarchy)
1247 else: 1247 else:
1248 rv[class_] = self.assembleHierarchy( 1248 rv[class_] = self.assembleHierarchy(
1249 class_, classes, path + [class_], result) 1249 class_, classes, path + [class_], result
1250 1250 )
1251
1251 if len(rv) == 0: 1252 if len(rv) == 0:
1252 exhausted = path 1253 exhausted = path
1253 exhausted.reverse() 1254 exhausted.reverse()
1254 self.addPathToHierarchy(exhausted, result, self.addPathToHierarchy) 1255 self.addPathToHierarchy(exhausted, result, self.addPathToHierarchy)
1255 1256
1256 def addPathToHierarchy(self, path, result, fn): 1257 def addPathToHierarchy(self, path, result, fn):
1257 """ 1258 """
1258 Public method to put the exhausted path into the result dictionary. 1259 Public method to put the exhausted path into the result dictionary.
1259 1260
1260 @param path the exhausted path of classes 1261 @param path the exhausted path of classes
1261 @param result the result dictionary 1262 @param result the result dictionary
1262 @param fn function to call for classe that are already part of the 1263 @param fn function to call for classe that are already part of the
1263 result dictionary 1264 result dictionary
1264 """ 1265 """
1267 fn(path[1:], result[path[0]], fn) 1268 fn(path[1:], result[path[0]], fn)
1268 else: 1269 else:
1269 for part in path: 1270 for part in path:
1270 result[part] = {} 1271 result[part] = {}
1271 result = result[part] 1272 result = result[part]
1272 1273
1273 def getName(self): 1274 def getName(self):
1274 """ 1275 """
1275 Public method to retrieve the modules name. 1276 Public method to retrieve the modules name.
1276 1277
1277 @return module name (string) 1278 @return module name (string)
1278 """ 1279 """
1279 return self.name 1280 return self.name
1280 1281
1281 def getFileName(self): 1282 def getFileName(self):
1282 """ 1283 """
1283 Public method to retrieve the modules filename. 1284 Public method to retrieve the modules filename.
1284 1285
1285 @return module filename (string) 1286 @return module filename (string)
1286 """ 1287 """
1287 return self.file 1288 return self.file
1288 1289
1289 def getType(self): 1290 def getType(self):
1290 """ 1291 """
1291 Public method to get the type of the module's source. 1292 Public method to get the type of the module's source.
1292 1293
1293 @return type of the modules's source (string) 1294 @return type of the modules's source (string)
1294 """ 1295 """
1295 if self.type in [PY_SOURCE, PTL_SOURCE]: 1296 if self.type in [PY_SOURCE, PTL_SOURCE]:
1296 moduleType = "Python3" 1297 moduleType = "Python3"
1297 elif self.type == RB_SOURCE: 1298 elif self.type == RB_SOURCE:
1303 1304
1304 class Class(VisibilityBase): 1305 class Class(VisibilityBase):
1305 """ 1306 """
1306 Class to represent a Python class. 1307 Class to represent a Python class.
1307 """ 1308 """
1309
1308 def __init__(self, module, name, superClasses, file, lineno): 1310 def __init__(self, module, name, superClasses, file, lineno):
1309 """ 1311 """
1310 Constructor 1312 Constructor
1311 1313
1312 @param module name of module containing this class (string) 1314 @param module name of module containing this class (string)
1313 @param name name of the class (string) 1315 @param name name of the class (string)
1314 @param superClasses list of classnames this class is inherited from 1316 @param superClasses list of classnames this class is inherited from
1315 (list of strings) 1317 (list of strings)
1316 @param file name of file containing this class (string) 1318 @param file name of file containing this class (string)
1324 self.methods = {} 1326 self.methods = {}
1325 self.attributes = {} 1327 self.attributes = {}
1326 self.globals = {} 1328 self.globals = {}
1327 self.file = file 1329 self.file = file
1328 self.lineno = lineno 1330 self.lineno = lineno
1329 self.endlineno = -1 # marker for "not set" 1331 self.endlineno = -1 # marker for "not set"
1330 self.description = "" 1332 self.description = ""
1331 self.setPublic() 1333 self.setPublic()
1332 1334
1333 def addMethod(self, name, function): 1335 def addMethod(self, name, function):
1334 """ 1336 """
1335 Public method to add information about a method. 1337 Public method to add information about a method.
1336 1338
1337 @param name name of method to be added (string) 1339 @param name name of method to be added (string)
1338 @param function Function object to be added 1340 @param function Function object to be added
1339 """ 1341 """
1340 self.methods[name] = function 1342 self.methods[name] = function
1341 1343
1342 def getMethod(self, name): 1344 def getMethod(self, name):
1343 """ 1345 """
1344 Public method to retrieve a method by name. 1346 Public method to retrieve a method by name.
1345 1347
1346 @param name name of the method (string) 1348 @param name name of the method (string)
1347 @return the named method or None 1349 @return the named method or None
1348 """ 1350 """
1349 try: 1351 try:
1350 return self.methods[name] 1352 return self.methods[name]
1351 except KeyError: 1353 except KeyError:
1352 return None 1354 return None
1353 1355
1354 def addAttribute(self, name, attr): 1356 def addAttribute(self, name, attr):
1355 """ 1357 """
1356 Public method to add information about attributes. 1358 Public method to add information about attributes.
1357 1359
1358 @param name name of the attribute to add (string) 1360 @param name name of the attribute to add (string)
1359 @param attr Attribute object to be added 1361 @param attr Attribute object to be added
1360 """ 1362 """
1361 if name not in self.attributes: 1363 if name not in self.attributes:
1362 self.attributes[name] = attr 1364 self.attributes[name] = attr
1363 else: 1365 else:
1364 self.attributes[name].addAssignment(attr.lineno) 1366 self.attributes[name].addAssignment(attr.lineno)
1365 1367
1366 def getAttribute(self, name): 1368 def getAttribute(self, name):
1367 """ 1369 """
1368 Public method to retrieve an attribute by name. 1370 Public method to retrieve an attribute by name.
1369 1371
1370 @param name name of the attribute (string) 1372 @param name name of the attribute (string)
1371 @return the named attribute or None 1373 @return the named attribute or None
1372 """ 1374 """
1373 try: 1375 try:
1374 return self.attributes[name] 1376 return self.attributes[name]
1375 except KeyError: 1377 except KeyError:
1376 return None 1378 return None
1377 1379
1378 def addGlobal(self, name, attr): 1380 def addGlobal(self, name, attr):
1379 """ 1381 """
1380 Public method to add information about global (class) variables. 1382 Public method to add information about global (class) variables.
1381 1383
1382 @param name name of the global to add (string) 1384 @param name name of the global to add (string)
1383 @param attr Attribute object to be added 1385 @param attr Attribute object to be added
1384 """ 1386 """
1385 if name not in self.globals: 1387 if name not in self.globals:
1386 self.globals[name] = attr 1388 self.globals[name] = attr
1387 else: 1389 else:
1388 self.globals[name].addAssignment(attr.lineno) 1390 self.globals[name].addAssignment(attr.lineno)
1389 1391
1390 def addDescription(self, description): 1392 def addDescription(self, description):
1391 """ 1393 """
1392 Public method to store the class docstring. 1394 Public method to store the class docstring.
1393 1395
1394 @param description the docstring to be stored (string) 1396 @param description the docstring to be stored (string)
1395 """ 1397 """
1396 self.description = description 1398 self.description = description
1397 1399
1398 def setEndLine(self, endLineNo): 1400 def setEndLine(self, endLineNo):
1399 """ 1401 """
1400 Public method to record the number of the last line of a class. 1402 Public method to record the number of the last line of a class.
1401 1403
1402 @param endLineNo number of the last line (integer) 1404 @param endLineNo number of the last line (integer)
1403 """ 1405 """
1404 self.endlineno = endLineNo 1406 self.endlineno = endLineNo
1405 1407
1406 1408
1407 class RbModule(Class): 1409 class RbModule(Class):
1408 """ 1410 """
1409 Class to represent a Ruby module. 1411 Class to represent a Ruby module.
1410 """ 1412 """
1413
1411 def __init__(self, module, name, file, lineno): 1414 def __init__(self, module, name, file, lineno):
1412 """ 1415 """
1413 Constructor 1416 Constructor
1414 1417
1415 @param module name of module containing this class (string) 1418 @param module name of module containing this class (string)
1416 @param name name of the class (string) 1419 @param name name of the class (string)
1417 @param file name of file containing this class (string) 1420 @param file name of file containing this class (string)
1418 @param lineno linenumber of the class definition (integer) 1421 @param lineno linenumber of the class definition (integer)
1419 """ 1422 """
1420 Class.__init__(self, module, name, None, file, lineno) 1423 Class.__init__(self, module, name, None, file, lineno)
1421 self.classes = {} 1424 self.classes = {}
1422 1425
1423 def addClass(self, name, _class): 1426 def addClass(self, name, _class):
1424 """ 1427 """
1425 Public method to add information about a class. 1428 Public method to add information about a class.
1426 1429
1427 @param name name of class to be added (string) 1430 @param name name of class to be added (string)
1428 @param _class Class object to be added 1431 @param _class Class object to be added
1429 """ 1432 """
1430 self.classes[name] = _class 1433 self.classes[name] = _class
1431 1434
1432 1435
1433 class Function(VisibilityBase): 1436 class Function(VisibilityBase):
1434 """ 1437 """
1435 Class to represent a Python function or method. 1438 Class to represent a Python function or method.
1436 """ 1439 """
1440
1437 General = 0 1441 General = 0
1438 Static = 1 1442 Static = 1
1439 Class = 2 1443 Class = 2
1440 1444
1441 def __init__(self, module, name, file, lineno, signature='', 1445 def __init__(
1442 pyqtSignature=None, modifierType=General, annotation=""): 1446 self,
1447 module,
1448 name,
1449 file,
1450 lineno,
1451 signature="",
1452 pyqtSignature=None,
1453 modifierType=General,
1454 annotation="",
1455 ):
1443 """ 1456 """
1444 Constructor 1457 Constructor
1445 1458
1446 @param module name of module containing this function (string) 1459 @param module name of module containing this function (string)
1447 @param name name of the function (string) 1460 @param name name of the function (string)
1448 @param file name of file containing this function (string) 1461 @param file name of file containing this function (string)
1449 @param lineno linenumber of the function definition (integer) 1462 @param lineno linenumber of the function definition (integer)
1450 @param signature the functions call signature (string) 1463 @param signature the functions call signature (string)
1454 """ 1467 """
1455 self.module = module 1468 self.module = module
1456 self.name = name 1469 self.name = name
1457 self.file = file 1470 self.file = file
1458 self.lineno = lineno 1471 self.lineno = lineno
1459 self.endlineno = -1 # marker for "not set" 1472 self.endlineno = -1 # marker for "not set"
1460 signature = _commentsub('', signature) 1473 signature = _commentsub("", signature)
1461 self.parameters = [e.strip() for e in signature.split(',')] 1474 self.parameters = [e.strip() for e in signature.split(",")]
1462 self.description = "" 1475 self.description = ""
1463 self.pyqtSignature = pyqtSignature 1476 self.pyqtSignature = pyqtSignature
1464 self.modifier = modifierType 1477 self.modifier = modifierType
1465 self.annotation = annotation 1478 self.annotation = annotation
1466 self.setPublic() 1479 self.setPublic()
1467 1480
1468 def addDescription(self, description): 1481 def addDescription(self, description):
1469 """ 1482 """
1470 Public method to store the functions docstring. 1483 Public method to store the functions docstring.
1471 1484
1472 @param description the docstring to be stored (string) 1485 @param description the docstring to be stored (string)
1473 """ 1486 """
1474 self.description = description 1487 self.description = description
1475 1488
1476 def setEndLine(self, endLineNo): 1489 def setEndLine(self, endLineNo):
1477 """ 1490 """
1478 Public method to record the number of the last line of a class. 1491 Public method to record the number of the last line of a class.
1479 1492
1480 @param endLineNo number of the last line (integer) 1493 @param endLineNo number of the last line (integer)
1481 """ 1494 """
1482 self.endlineno = endLineNo 1495 self.endlineno = endLineNo
1483 1496
1484 1497
1485 class Attribute(VisibilityBase): 1498 class Attribute(VisibilityBase):
1486 """ 1499 """
1487 Class to represent a Python function or method. 1500 Class to represent a Python function or method.
1488 """ 1501 """
1502
1489 def __init__(self, module, name, file, lineno, isSignal=False): 1503 def __init__(self, module, name, file, lineno, isSignal=False):
1490 """ 1504 """
1491 Constructor 1505 Constructor
1492 1506
1493 @param module name of module containing this function (string) 1507 @param module name of module containing this function (string)
1494 @param name name of the function (string) 1508 @param name name of the function (string)
1495 @param file name of file containing this function (string) 1509 @param file name of file containing this function (string)
1496 @param lineno linenumber of the first attribute assignment (integer) 1510 @param lineno linenumber of the first attribute assignment (integer)
1497 @param isSignal flag indicating a signal definition (boolean) 1511 @param isSignal flag indicating a signal definition (boolean)
1501 self.file = file 1515 self.file = file
1502 self.lineno = lineno 1516 self.lineno = lineno
1503 self.isSignal = isSignal 1517 self.isSignal = isSignal
1504 self.setPublic() 1518 self.setPublic()
1505 self.linenos = [lineno] 1519 self.linenos = [lineno]
1506 1520
1507 def addAssignment(self, lineno): 1521 def addAssignment(self, lineno):
1508 """ 1522 """
1509 Public method to add another assignment line number. 1523 Public method to add another assignment line number.
1510 1524
1511 @param lineno linenumber of the additional attribute assignment 1525 @param lineno linenumber of the additional attribute assignment
1512 (integer) 1526 (integer)
1513 """ 1527 """
1514 if lineno not in self.linenos: 1528 if lineno not in self.linenos:
1515 self.linenos.append(lineno) 1529 self.linenos.append(lineno)
1516 1530
1517 1531
1518 def readModule(module, path=None, inpackage=False, basename="", 1532 def readModule(
1519 extensions=None, caching=True, ignoreBuiltinModules=False): 1533 module,
1534 path=None,
1535 inpackage=False,
1536 basename="",
1537 extensions=None,
1538 caching=True,
1539 ignoreBuiltinModules=False,
1540 ):
1520 """ 1541 """
1521 Function to read a module file and parse it. 1542 Function to read a module file and parse it.
1522 1543
1523 The module is searched in path and sys.path, read and parsed. 1544 The module is searched in path and sys.path, read and parsed.
1524 If the module was parsed before, the information is taken 1545 If the module was parsed before, the information is taken
1525 from a cache in order to speed up processing. 1546 from a cache in order to speed up processing.
1526 1547
1527 @param module name of the module to be parsed (string) 1548 @param module name of the module to be parsed (string)
1528 @param path search path for the module (list of strings) 1549 @param path search path for the module (list of strings)
1529 @param inpackage flag indicating that module is inside a 1550 @param inpackage flag indicating that module is inside a
1530 package (boolean) 1551 package (boolean)
1531 @param basename a path basename that is deleted from the filename of 1552 @param basename a path basename that is deleted from the filename of
1538 (boolean) 1559 (boolean)
1539 @return reference to a Module object containing the parsed 1560 @return reference to a Module object containing the parsed
1540 module information (Module) 1561 module information (Module)
1541 """ 1562 """
1542 global _modules 1563 global _modules
1543 1564
1544 _extensions = ( 1565 _extensions = (
1545 ['.py', '.pyw', '.ptl', '.rb'] 1566 [".py", ".pyw", ".ptl", ".rb"] if extensions is None else extensions[:]
1546 if extensions is None else
1547 extensions[:]
1548 ) 1567 )
1549 with contextlib.suppress(ValueError): 1568 with contextlib.suppress(ValueError):
1550 _extensions.remove('.py') 1569 _extensions.remove(".py")
1551 1570
1552 modname = module 1571 modname = module
1553 1572
1554 if os.path.exists(module): 1573 if os.path.exists(module):
1555 path = [os.path.dirname(module)] 1574 path = [os.path.dirname(module)]
1556 if module.lower().endswith(".py"): 1575 if module.lower().endswith(".py"):
1557 module = module[:-3] 1576 module = module[:-3]
1558 if ( 1577 if (
1559 os.path.exists(os.path.join(path[0], "__init__.py")) or 1578 os.path.exists(os.path.join(path[0], "__init__.py"))
1560 os.path.exists(os.path.join(path[0], "__init__.rb")) or 1579 or os.path.exists(os.path.join(path[0], "__init__.rb"))
1561 inpackage 1580 or inpackage
1562 ): 1581 ):
1563 if basename: 1582 if basename:
1564 module = module.replace(basename, "") 1583 module = module.replace(basename, "")
1565 if os.path.isabs(module): 1584 if os.path.isabs(module):
1566 modname = os.path.splitdrive(module)[1][len(os.sep):] 1585 modname = os.path.splitdrive(module)[1][len(os.sep) :]
1567 else: 1586 else:
1568 modname = module 1587 modname = module
1569 modname = modname.replace(os.sep, '.') 1588 modname = modname.replace(os.sep, ".")
1570 inpackage = 1 1589 inpackage = 1
1571 else: 1590 else:
1572 modname = os.path.basename(module) 1591 modname = os.path.basename(module)
1573 for ext in _extensions: 1592 for ext in _extensions:
1574 if modname.lower().endswith(ext): 1593 if modname.lower().endswith(ext):
1575 modname = modname[:-len(ext)] 1594 modname = modname[: -len(ext)]
1576 break 1595 break
1577 module = os.path.basename(module) 1596 module = os.path.basename(module)
1578 1597
1579 if caching and modname in _modules: 1598 if caching and modname in _modules:
1580 # we've seen this module before... 1599 # we've seen this module before...
1581 return _modules[modname] 1600 return _modules[modname]
1582 1601
1583 if not ignoreBuiltinModules and module in sys.builtin_module_names: 1602 if not ignoreBuiltinModules and module in sys.builtin_module_names:
1584 # this is a built-in module 1603 # this is a built-in module
1585 mod = Module(modname, None, None) 1604 mod = Module(modname, None, None)
1586 if caching: 1605 if caching:
1587 _modules[modname] = mod 1606 _modules[modname] = mod
1588 return mod 1607 return mod
1589 1608
1590 # search the path for the module 1609 # search the path for the module
1591 path = [] if path is None else path[:] 1610 path = [] if path is None else path[:]
1592 f = None 1611 f = None
1593 if inpackage: 1612 if inpackage:
1594 try: 1613 try:
1595 f, file, (suff, mode, moduleType) = find_module( 1614 f, file, (suff, mode, moduleType) = find_module(module, path, _extensions)
1596 module, path, _extensions)
1597 except ImportError: 1615 except ImportError:
1598 f = None 1616 f = None
1599 if f is None: 1617 if f is None:
1600 fullpath = path[:] + sys.path[:] 1618 fullpath = path[:] + sys.path[:]
1601 f, file, (suff, mode, moduleType) = find_module( 1619 f, file, (suff, mode, moduleType) = find_module(module, fullpath, _extensions)
1602 module, fullpath, _extensions)
1603 if f: 1620 if f:
1604 f.close() 1621 f.close()
1605 if moduleType not in SUPPORTED_TYPES: 1622 if moduleType not in SUPPORTED_TYPES:
1606 # not supported source, can't do anything with this module 1623 # not supported source, can't do anything with this module
1607 _modules[modname] = Module(modname, None, None) 1624 _modules[modname] = Module(modname, None, None)
1608 return _modules[modname] 1625 return _modules[modname]
1609 1626
1610 mod = Module(modname, file, moduleType) 1627 mod = Module(modname, file, moduleType)
1611 with contextlib.suppress(UnicodeError, OSError): 1628 with contextlib.suppress(UnicodeError, OSError):
1612 src = Utilities.readEncodedFile(file)[0] 1629 src = Utilities.readEncodedFile(file)[0]
1613 mod.scan(src) 1630 mod.scan(src)
1614 if caching: 1631 if caching:
1617 1634
1618 1635
1619 def _indent(ws): 1636 def _indent(ws):
1620 """ 1637 """
1621 Protected function to determine the indent width of a whitespace string. 1638 Protected function to determine the indent width of a whitespace string.
1622 1639
1623 @param ws The whitespace string to be cheked. (string) 1640 @param ws The whitespace string to be cheked. (string)
1624 @return Length of the whitespace string after tab expansion. 1641 @return Length of the whitespace string after tab expansion.
1625 """ 1642 """
1626 return len(ws.expandtabs(TABWIDTH)) 1643 return len(ws.expandtabs(TABWIDTH))
1627 1644
1628 1645
1629 def find_module(name, path, extensions): 1646 def find_module(name, path, extensions):
1630 """ 1647 """
1631 Module function to extend the Python module finding mechanism. 1648 Module function to extend the Python module finding mechanism.
1632 1649
1633 This function searches for files in the given path. If the filename 1650 This function searches for files in the given path. If the filename
1634 doesn't have an extension or an extension of .py, the normal search 1651 doesn't have an extension or an extension of .py, the normal search
1635 implemented in the imp module is used. For all other supported files 1652 implemented in the imp module is used. For all other supported files
1636 only path is searched. 1653 only path is searched.
1637 1654
1638 @param name filename or modulename to search for (string) 1655 @param name filename or modulename to search for (string)
1639 @param path search path (list of strings) 1656 @param path search path (list of strings)
1640 @param extensions list of extensions, which should be considered valid 1657 @param extensions list of extensions, which should be considered valid
1641 source file extensions (list of strings) 1658 source file extensions (list of strings)
1642 @return tuple of the open file, pathname and description. Description 1659 @return tuple of the open file, pathname and description. Description
1643 is a tuple of file suffix, file mode and file type) 1660 is a tuple of file suffix, file mode and file type)
1644 @exception ImportError The file or module wasn't found. 1661 @exception ImportError The file or module wasn't found.
1645 """ 1662 """
1646 for ext in extensions: 1663 for ext in extensions:
1647 if name.lower().endswith(ext): 1664 if name.lower().endswith(ext):
1648 for p in path: # only search in path 1665 for p in path: # only search in path
1649 if os.path.exists(os.path.join(p, name)): 1666 if os.path.exists(os.path.join(p, name)):
1650 pathname = os.path.join(p, name) 1667 pathname = os.path.join(p, name)
1651 if ext == '.ptl': 1668 if ext == ".ptl":
1652 # Quixote page template 1669 # Quixote page template
1653 return ( 1670 return (
1654 open(pathname), pathname, 1671 open(pathname), # __IGNORE_WARNING_Y115__
1655 # __IGNORE_WARNING_Y115__ 1672 pathname,
1656 ('.ptl', 'r', PTL_SOURCE) 1673 (".ptl", "r", PTL_SOURCE),
1657 ) 1674 )
1658 elif ext == '.rb': 1675 elif ext == ".rb":
1659 # Ruby source file 1676 # Ruby source file
1660 return ( 1677 return (
1661 open(pathname), pathname, 1678 open(pathname), # __IGNORE_WARNING_Y115__
1662 # __IGNORE_WARNING_Y115__ 1679 pathname,
1663 ('.rb', 'r', RB_SOURCE) 1680 (".rb", "r", RB_SOURCE),
1664 ) 1681 )
1665 else: 1682 else:
1666 return ( 1683 return (
1667 open(pathname), pathname, 1684 open(pathname), # __IGNORE_WARNING_Y115__
1668 # __IGNORE_WARNING_Y115__ 1685 pathname,
1669 (ext, 'r', PY_SOURCE) 1686 (ext, "r", PY_SOURCE),
1670 ) 1687 )
1671 raise ImportError 1688 raise ImportError
1672 1689
1673 # standard Python module file 1690 # standard Python module file
1674 if name.lower().endswith('.py'): 1691 if name.lower().endswith(".py"):
1675 name = name[:-3] 1692 name = name[:-3]
1676 1693
1677 spec = importlib.machinery.PathFinder.find_spec(name, path) 1694 spec = importlib.machinery.PathFinder.find_spec(name, path)
1678 if spec is None: 1695 if spec is None:
1679 raise ImportError 1696 raise ImportError
1680 if isinstance(spec.loader, importlib.machinery.SourceFileLoader): 1697 if isinstance(spec.loader, importlib.machinery.SourceFileLoader):
1681 ext = os.path.splitext(spec.origin)[-1] 1698 ext = os.path.splitext(spec.origin)[-1]
1682 return (open(spec.origin), spec.origin, (ext, 'r', PY_SOURCE)) 1699 return (open(spec.origin), spec.origin, (ext, "r", PY_SOURCE))
1683 # __IGNORE_WARNING_Y115__ 1700 # __IGNORE_WARNING_Y115__
1684 1701
1685 raise ImportError 1702 raise ImportError
1686 1703
1687 1704
1688 def resetParsedModules(): 1705 def resetParsedModules():
1689 """ 1706 """
1690 Module function to reset the list of modules already parsed. 1707 Module function to reset the list of modules already parsed.
1691 """ 1708 """
1692 _modules.clear() 1709 _modules.clear()
1693 1710
1694 1711
1695 def resetParsedModule(module, basename=""): 1712 def resetParsedModule(module, basename=""):
1696 """ 1713 """
1697 Module function to clear one module from the list of parsed modules. 1714 Module function to clear one module from the list of parsed modules.
1698 1715
1699 @param module Name of the module to be parsed (string) 1716 @param module Name of the module to be parsed (string)
1700 @param basename a path basename. This basename is deleted from 1717 @param basename a path basename. This basename is deleted from
1701 the filename of the module file to be cleared. (string) 1718 the filename of the module file to be cleared. (string)
1702 """ 1719 """
1703 modname = module 1720 modname = module
1704 1721
1705 if os.path.exists(module): 1722 if os.path.exists(module):
1706 path = [os.path.dirname(module)] 1723 path = [os.path.dirname(module)]
1707 if module.lower().endswith(".py"): 1724 if module.lower().endswith(".py"):
1708 module = module[:-3] 1725 module = module[:-3]
1709 if os.path.exists(os.path.join(path[0], "__init__.py")): 1726 if os.path.exists(os.path.join(path[0], "__init__.py")):
1710 if basename: 1727 if basename:
1711 module = module.replace(basename, "") 1728 module = module.replace(basename, "")
1712 modname = module.replace(os.sep, '.') 1729 modname = module.replace(os.sep, ".")
1713 else: 1730 else:
1714 modname = os.path.basename(module) 1731 modname = os.path.basename(module)
1715 if ( 1732 if modname.lower().endswith(".ptl") or modname.lower().endswith(".pyw"):
1716 modname.lower().endswith(".ptl") or
1717 modname.lower().endswith(".pyw")
1718 ):
1719 modname = modname[:-4] 1733 modname = modname[:-4]
1720 elif modname.lower().endswith(".rb"): 1734 elif modname.lower().endswith(".rb"):
1721 modname = modname[:-3] 1735 modname = modname[:-3]
1722 module = os.path.basename(module) 1736 module = os.path.basename(module)
1723 1737
1724 if modname in _modules: 1738 if modname in _modules:
1725 del _modules[modname] 1739 del _modules[modname]

eric ide

mercurial