eric6/Utilities/ModuleParser.py

changeset 6942
2602857055c5
parent 6815
b1b833693a38
child 7163
00166038bba5
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2003 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Parse a Python module file.
8
9 This module is based on pyclbr.py as of Python 2.2.2
10
11 <b>BUGS</b> (from pyclbr.py)
12 <ul>
13 <li>Code that doesn't pass tabnanny or python -t will confuse it, unless
14 you set the module TABWIDTH variable (default 8) to the correct tab width
15 for the file.</li>
16 </ul>
17 """
18
19 from __future__ import unicode_literals
20
21 import sys
22 import os
23 import imp
24 import re
25
26 import Utilities
27 from functools import reduce
28 import Preferences
29
30 __all__ = ["Module", "Class", "Function", "Attribute", "RbModule",
31 "readModule", "getTypeFromTypeName"]
32
33 TABWIDTH = 4
34
35 PTL_SOURCE = 128
36 RB_SOURCE = 129
37
38 SUPPORTED_TYPES = [imp.PY_SOURCE, PTL_SOURCE, RB_SOURCE]
39 TYPE_MAPPING = {
40 "Python": imp.PY_SOURCE,
41 "Python2": imp.PY_SOURCE,
42 "Python3": imp.PY_SOURCE,
43 "Ruby": RB_SOURCE,
44 }
45
46
47 def getTypeFromTypeName(name):
48 """
49 Module function to determine the module type given the module type name.
50
51 @param name module type name (string)
52 @return module type or -1 for failure (integer)
53 """
54 if name in TYPE_MAPPING:
55 return TYPE_MAPPING[name]
56 else:
57 return -1
58
59
60 _py_getnext = re.compile(
61 r"""
62 (?P<Comment>
63 \# .*? $ # ignore everything in comments
64 )
65
66 | (?P<String>
67 \""" (?P<StringContents1>
68 [^"\\]* (?:
69 (?: \\. | "(?!"") )
70 [^"\\]*
71 )*
72 )
73 \"""
74
75 | ''' (?P<StringContents2>
76 [^'\\]* (?:
77 (?: \\. | '(?!'') )
78 [^'\\]*
79 )*
80 )
81 '''
82
83 | " [^"\\\n]* (?: \\. [^"\\\n]*)* "
84
85 | ' [^'\\\n]* (?: \\. [^'\\\n]*)* '
86
87 | \#\#\# (?P<StringContents3>
88 [^#\\]* (?:
89 (?: \\. | \#(?!\#\#) )
90 [^#\\]*
91 )*
92 )
93 \#\#\#
94 )
95
96 | (?P<Docstring>
97 (?<= :) \s*
98 [ru]? \""" (?P<DocstringContents1>
99 [^"\\]* (?:
100 (?: \\. | "(?!"") )
101 [^"\\]*
102 )*
103 )
104 \"""
105
106 | (?<= :) \s*
107 [ru]? ''' (?P<DocstringContents2>
108 [^'\\]* (?:
109 (?: \\. | '(?!'') )
110 [^'\\]*
111 )*
112 )
113 '''
114
115 | (?<= :) \s*
116 \#\#\# (?P<DocstringContents3>
117 [^#\\]* (?:
118 (?: \\. | \#(?!\#\#) )
119 [^#\\]*
120 )*
121 )
122 \#\#\#
123 )
124
125 | (?P<MethodModifier>
126 ^
127 (?P<MethodModifierIndent> [ \t]* )
128 (?P<MethodModifierType> @classmethod | @staticmethod )
129 )
130
131 | (?P<Method>
132 (^ [ \t]* @ (?: PyQt[45] \. )? (?: QtCore \. )?
133 (?: pyqtSignature | pyqtSlot )
134 [ \t]* \(
135 (?P<MethodPyQtSignature> [^)]* )
136 \) \s*
137 )?
138 ^
139 (?P<MethodIndent> [ \t]* )
140 (?: async [ \t]+ )? def [ \t]+
141 (?P<MethodName> \w+ )
142 (?: [ \t]* \[ (?: plain | html ) \] )?
143 [ \t]* \(
144 (?P<MethodSignature> (?: [^)] | \)[ \t]*,? )*? )
145 \) [ \t]*
146 (?P<MethodReturnAnnotation> (?: -> [ \t]* [^:]+ )? )
147 [ \t]* :
148 )
149
150 | (?P<Class>
151 ^
152 (?P<ClassIndent> [ \t]* )
153 class [ \t]+
154 (?P<ClassName> \w+ )
155 [ \t]*
156 (?P<ClassSupers> \( [^)]* \) )?
157 [ \t]* :
158 )
159
160 | (?P<Attribute>
161 ^
162 (?P<AttributeIndent> [ \t]* )
163 self [ \t]* \. [ \t]*
164 (?P<AttributeName> \w+ )
165 [ \t]* =
166 )
167
168 | (?P<Variable>
169 ^
170 (?P<VariableIndent> [ \t]* )
171 (?P<VariableName> \w+ )
172 [ \t]* = [ \t]* (?P<VariableSignal> (?:pyqtSignal)? )
173 )
174
175 | (?P<Main>
176 ^
177 if \s+ __name__ \s* == \s* [^:]+ : $
178 )
179
180 | (?P<Import>
181 ^ [ \t]* (?: import | from [ \t]+ \. [ \t]+ import ) [ \t]+
182 (?P<ImportList> (?: [^#;\\\n]* (?: \\\n )* )* )
183 )
184
185 | (?P<ImportFrom>
186 ^ [ \t]* from [ \t]+
187 (?P<ImportFromPath>
188 \.* \w+
189 (?:
190 [ \t]* \. [ \t]* \w+
191 )*
192 )
193 [ \t]+
194 import [ \t]+
195 (?P<ImportFromList>
196 (?: \( \s* .*? \s* \) )
197 |
198 (?: [^#;\\\n]* (?: \\\n )* )* )
199 )
200
201 | (?P<ConditionalDefine>
202 ^
203 (?P<ConditionalDefineIndent> [ \t]* )
204 (?: (?: if | elif ) [ \t]+ [^:]* | else [ \t]* ) :
205 (?= \s* (?: async [ \t]+ )? def)
206 )""",
207 re.VERBOSE | re.DOTALL | re.MULTILINE).search
208
209 _rb_getnext = re.compile(
210 r"""
211 (?P<Docstring>
212 =begin [ \t]+ edoc (?P<DocstringContents> .*? ) =end
213 )
214
215 | (?P<String>
216 =begin .*? =end
217
218 | <<-? (?P<HereMarker1> [a-zA-Z0-9_]+? ) [ \t]* .*? (?P=HereMarker1)
219
220 | <<-? ['"] (?P<HereMarker2> .*? ) ['"] [ \t]* .*? (?P=HereMarker2)
221
222 | " [^"\\\n]* (?: \\. [^"\\\n]*)* "
223
224 | ' [^'\\\n]* (?: \\. [^'\\\n]*)* '
225 )
226
227 | (?P<Comment>
228 ^
229 [ \t]* \#+ .*? $
230 )
231
232 | (?P<Method>
233 ^
234 (?P<MethodIndent> [ \t]* )
235 def [ \t]+
236 (?:
237 (?P<MethodName2> [a-zA-Z0-9_]+ (?: \. | :: )
238 [a-zA-Z_] [a-zA-Z0-9_?!=]* )
239 |
240 (?P<MethodName> [a-zA-Z_] [a-zA-Z0-9_?!=]* )
241 |
242 (?P<MethodName3> [^( \t]{1,3} )
243 )
244 [ \t]*
245 (?:
246 \( (?P<MethodSignature> (?: [^)] | \)[ \t]*,? )*? ) \)
247 )?
248 [ \t]*
249 )
250
251 | (?P<Class>
252 ^
253 (?P<ClassIndent> [ \t]* )
254 class
255 (?:
256 [ \t]+
257 (?P<ClassName> [A-Z] [a-zA-Z0-9_]* )
258 [ \t]*
259 (?P<ClassSupers> < [ \t]* [A-Z] [a-zA-Z0-9_]* )?
260 |
261 [ \t]* << [ \t]*
262 (?P<ClassName2> [a-zA-Z_] [a-zA-Z0-9_]* )
263 )
264 [ \t]*
265 )
266
267 | (?P<ClassIgnored>
268 \(
269 [ \t]*
270 class
271 .*?
272 end
273 [ \t]*
274 \)
275 )
276
277 | (?P<Module>
278 ^
279 (?P<ModuleIndent> [ \t]* )
280 module [ \t]+
281 (?P<ModuleName> [A-Z] [a-zA-Z0-9_]* )
282 [ \t]*
283 )
284
285 | (?P<AccessControl>
286 ^
287 (?P<AccessControlIndent> [ \t]* )
288 (?:
289 (?P<AccessControlType> private | public | protected ) [^_]
290 |
291 (?P<AccessControlType2>
292 private_class_method | public_class_method )
293 )
294 \(?
295 [ \t]*
296 (?P<AccessControlList> (?: : [a-zA-Z0-9_]+ , \s* )*
297 (?: : [a-zA-Z0-9_]+ )+ )?
298 [ \t]*
299 \)?
300 )
301
302 | (?P<Attribute>
303 ^
304 (?P<AttributeIndent> [ \t]* )
305 (?P<AttributeName> (?: @ | @@ | [A-Z]) [a-zA-Z0-9_]* )
306 [ \t]* =
307 )
308
309 | (?P<Attr>
310 ^
311 (?P<AttrIndent> [ \t]* )
312 attr
313 (?P<AttrType> (?: _accessor | _reader | _writer ) )?
314 \(?
315 [ \t]*
316 (?P<AttrList> (?: : [a-zA-Z0-9_]+ , \s* )*
317 (?: : [a-zA-Z0-9_]+ | true | false )+ )
318 [ \t]*
319 \)?
320 )
321
322 | (?P<Begin>
323 ^
324 [ \t]*
325 (?: if | unless | case | while | until | for | begin ) \b [^_]
326 |
327 [ \t]* do [ \t]* (?: \| .*? \| )? [ \t]* $
328 )
329
330 | (?P<BeginEnd>
331 \b (?: if ) \b [^_] .*? $
332 |
333 \b (?: if ) \b [^_] .*? end [ \t]* $
334 )
335
336 | (?P<End>
337 [ \t]*
338 (?:
339 end [ \t]* $
340 |
341 end \b [^_]
342 )
343 )""",
344 re.VERBOSE | re.DOTALL | re.MULTILINE).search
345
346 _hashsub = re.compile(r"""^([ \t]*)#[ \t]?""", re.MULTILINE).sub
347
348 _commentsub = re.compile(r"""#[^\n]*\n|#[^\n]*$""").sub
349
350 _modules = {} # cache of modules we've seen
351
352
353 class VisibilityBase(object):
354 """
355 Class implementing the visibility aspect of all objects.
356 """
357 def isPrivate(self):
358 """
359 Public method to check, if the visibility is Private.
360
361 @return flag indicating Private visibility (boolean)
362 """
363 return self.visibility == 0
364
365 def isProtected(self):
366 """
367 Public method to check, if the visibility is Protected.
368
369 @return flag indicating Protected visibility (boolean)
370 """
371 return self.visibility == 1
372
373 def isPublic(self):
374 """
375 Public method to check, if the visibility is Public.
376
377 @return flag indicating Public visibility (boolean)
378 """
379 return self.visibility == 2
380
381 def setPrivate(self):
382 """
383 Public method to set the visibility to Private.
384 """
385 self.visibility = 0
386
387 def setProtected(self):
388 """
389 Public method to set the visibility to Protected.
390 """
391 self.visibility = 1
392
393 def setPublic(self):
394 """
395 Public method to set the visibility to Public.
396 """
397 self.visibility = 2
398
399
400 class Module(object):
401 """
402 Class to represent a Python module.
403 """
404 def __init__(self, name, file=None, moduleType=None):
405 """
406 Constructor
407
408 @param name name of this module (string)
409 @param file filename of file containing this module (string)
410 @param moduleType type of this module
411 """
412 self.name = name
413 self.file = file
414 self.modules = {}
415 self.modules_counts = {}
416 self.classes = {}
417 self.classes_counts = {}
418 self.functions = {}
419 self.functions_counts = {}
420 self.description = ""
421 self.globals = {}
422 self.imports = []
423 self.from_imports = {}
424 self.package = '.'.join(name.split('.')[:-1])
425 self.type = moduleType
426 if moduleType in [imp.PY_SOURCE, PTL_SOURCE]:
427 self._getnext = _py_getnext
428 elif moduleType == RB_SOURCE:
429 self._getnext = _rb_getnext
430 else:
431 self._getnext = None
432
433 def addClass(self, name, _class):
434 """
435 Public method to add information about a class.
436
437 @param name name of class to be added (string)
438 @param _class Class object to be added
439 """
440 if name in self.classes:
441 self.classes_counts[name] += 1
442 name = "{0}_{1:d}".format(name, self.classes_counts[name])
443 else:
444 self.classes_counts[name] = 0
445 self.classes[name] = _class
446
447 def addModule(self, name, module):
448 """
449 Public method to add information about a Ruby module.
450
451 @param name name of module to be added (string)
452 @param module Module object to be added
453 """
454 if name in self.modules:
455 self.modules_counts[name] += 1
456 name = "{0}_{1:d}".format(name, self.modules_counts[name])
457 else:
458 self.modules_counts[name] = 0
459 self.modules[name] = module
460
461 def addFunction(self, name, function):
462 """
463 Public method to add information about a function.
464
465 @param name name of function to be added (string)
466 @param function Function object to be added
467 """
468 if name in self.functions:
469 self.functions_counts[name] += 1
470 name = "{0}_{1:d}".format(name, self.functions_counts[name])
471 else:
472 self.functions_counts[name] = 0
473 self.functions[name] = function
474
475 def addGlobal(self, name, attr):
476 """
477 Public method to add information about global variables.
478
479 @param name name of the global to add (string)
480 @param attr Attribute object to be added
481 """
482 if name not in self.globals:
483 self.globals[name] = attr
484 else:
485 self.globals[name].addAssignment(attr.lineno)
486
487 def addDescription(self, description):
488 """
489 Public method to store the modules docstring.
490
491 @param description the docstring to be stored (string)
492 """
493 self.description = description
494
495 def scan(self, src):
496 """
497 Public method to scan the source text and retrieve the relevant
498 information.
499
500 @param src the source text to be scanned (string)
501 """
502 if self.type in [imp.PY_SOURCE, PTL_SOURCE]:
503 self.__py_scan(src)
504 elif self.type == RB_SOURCE:
505 self.__rb_scan(src)
506
507 def __py_setVisibility(self, objectRef):
508 """
509 Private method to set the visibility of an object.
510
511 @param objectRef reference to the object (Attribute, Class or Function)
512 """
513 if objectRef.name.startswith('__'):
514 objectRef.setPrivate()
515 elif objectRef.name.startswith('_'):
516 objectRef.setProtected()
517 else:
518 objectRef.setPublic()
519
520 def __py_scan(self, src):
521 """
522 Private method to scan the source text of a Python module and retrieve
523 the relevant information.
524
525 @param src the source text to be scanned (string)
526 """
527 lineno, last_lineno_pos = 1, 0
528 lastGlobalEntry = None
529 classstack = [] # stack of (class, indent) pairs
530 conditionalsstack = [] # stack of indents of conditional defines
531 deltastack = []
532 deltaindent = 0
533 deltaindentcalculated = 0
534 i = 0
535 modulelevel = True
536 cur_obj = self
537 modifierType = Function.General
538 modifierIndent = -1
539 while True:
540 m = self._getnext(src, i)
541 if not m:
542 break
543 start, i = m.span()
544
545 if m.start("MethodModifier") >= 0:
546 modifierIndent = _indent(m.group("MethodModifierIndent"))
547 modifierType = m.group("MethodModifierType")
548
549 elif m.start("Method") >= 0:
550 # found a method definition or function
551 thisindent = _indent(m.group("MethodIndent"))
552 meth_name = m.group("MethodName")
553 meth_sig = m.group("MethodSignature")
554 meth_sig = meth_sig.replace('\\\n', '')
555 meth_ret = m.group("MethodReturnAnnotation")
556 meth_ret = meth_ret.replace('\\\n', '')
557 if m.group("MethodPyQtSignature") is not None:
558 meth_pyqtSig = m.group("MethodPyQtSignature")\
559 .replace('\\\n', '')\
560 .split('result')[0]\
561 .split('name')[0]\
562 .strip("\"', \t")
563 else:
564 meth_pyqtSig = None
565 lineno = lineno + src.count('\n', last_lineno_pos, start)
566 last_lineno_pos = start
567 if modifierType and modifierIndent == thisindent:
568 if modifierType == "@staticmethod":
569 modifier = Function.Static
570 elif modifierType == "@classmethod":
571 modifier = Function.Class
572 else:
573 modifier = Function.General
574 else:
575 modifier = Function.General
576 # modify indentation level for conditional defines
577 if conditionalsstack:
578 if thisindent > conditionalsstack[-1]:
579 if not deltaindentcalculated:
580 deltastack.append(
581 thisindent - conditionalsstack[-1])
582 deltaindent = reduce(
583 lambda x, y: x + y, deltastack)
584 deltaindentcalculated = 1
585 thisindent -= deltaindent
586 else:
587 while conditionalsstack and \
588 conditionalsstack[-1] >= thisindent:
589 del conditionalsstack[-1]
590 if deltastack:
591 del deltastack[-1]
592 deltaindentcalculated = 0
593 # close all classes indented at least as much
594 while classstack and \
595 classstack[-1][1] >= thisindent:
596 if classstack[-1][0] is not None and \
597 isinstance(classstack[-1][0], (Class, Function)):
598 # record the end line of this class or function
599 classstack[-1][0].setEndLine(lineno - 1)
600 del classstack[-1]
601 if classstack:
602 csi = -1
603 while csi >= -len(classstack):
604 # nested defs are added to the class
605 cur_class = classstack[csi][0]
606 csi -= 1
607 if cur_class is None:
608 continue
609
610 if isinstance(cur_class, Class):
611 # it's a class method
612 f = Function(
613 None, meth_name, None, lineno,
614 meth_sig, meth_pyqtSig, modifierType=modifier,
615 annotation=meth_ret)
616 self.__py_setVisibility(f)
617 cur_class.addMethod(meth_name, f)
618 break
619 else:
620 # it's a nested function of a module function
621 f = Function(
622 self.name, meth_name, self.file, lineno,
623 meth_sig, meth_pyqtSig, modifierType=modifier,
624 annotation=meth_ret)
625 self.__py_setVisibility(f)
626 self.addFunction(meth_name, f)
627 else:
628 # it's a module function
629 f = Function(self.name, meth_name, self.file, lineno,
630 meth_sig, meth_pyqtSig, modifierType=modifier,
631 annotation=meth_ret)
632 self.__py_setVisibility(f)
633 self.addFunction(meth_name, f)
634 if not classstack:
635 if lastGlobalEntry:
636 lastGlobalEntry.setEndLine(lineno - 1)
637 lastGlobalEntry = f
638 if cur_obj and isinstance(cur_obj, Function):
639 cur_obj.setEndLine(lineno - 1)
640 cur_obj = f
641 classstack.append((None, thisindent)) # Marker for nested fns
642
643 # reset the modifier settings
644 modifierType = Function.General
645 modifierIndent = -1
646
647 elif m.start("Docstring") >= 0:
648 contents = m.group("DocstringContents3")
649 if contents is not None:
650 contents = _hashsub(r"\1", contents)
651 else:
652 if self.file.lower().endswith('.ptl'):
653 contents = ""
654 else:
655 contents = m.group("DocstringContents1") \
656 or m.group("DocstringContents2")
657 if cur_obj:
658 cur_obj.addDescription(contents)
659
660 elif m.start("String") >= 0:
661 if modulelevel and \
662 (src[start - len('\r\n'):start] == '\r\n' or
663 src[start - len('\n'):start] == '\n' or
664 src[start - len('\r'):start] == '\r'):
665 contents = m.group("StringContents3")
666 if contents is not None:
667 contents = _hashsub(r"\1", contents)
668 else:
669 if self.file.lower().endswith('.ptl'):
670 contents = ""
671 else:
672 contents = m.group("StringContents1") \
673 or m.group("StringContents2")
674 if cur_obj:
675 cur_obj.addDescription(contents)
676
677 elif m.start("Class") >= 0:
678 # we found a class definition
679 thisindent = _indent(m.group("ClassIndent"))
680 lineno = lineno + src.count('\n', last_lineno_pos, start)
681 last_lineno_pos = start
682 # close all classes indented at least as much
683 while classstack and \
684 classstack[-1][1] >= thisindent:
685 if classstack[-1][0] is not None and \
686 isinstance(classstack[-1][0], (Class, Function)):
687 # record the end line of this class or function
688 classstack[-1][0].setEndLine(lineno - 1)
689 del classstack[-1]
690 class_name = m.group("ClassName")
691 inherit = m.group("ClassSupers")
692 if inherit:
693 # the class inherits from other classes
694 inherit = inherit[1:-1].strip()
695 inherit = _commentsub('', inherit)
696 names = []
697 for n in inherit.split(','):
698 n = n.strip()
699 if n:
700 if n in self.classes:
701 # we know this super class
702 n = self.classes[n].name
703 else:
704 c = n.split('.')
705 if len(c) > 1:
706 # super class is of the
707 # form module.class:
708 # look in module for class
709 m = c[-2]
710 c = c[-1]
711 if m in _modules:
712 m = _modules[m]
713 n = m.name
714 names.append(n)
715 inherit = names
716 # remember this class
717 cur_class = Class(self.name, class_name, inherit,
718 self.file, lineno)
719 self.__py_setVisibility(cur_class)
720 cur_obj = cur_class
721 # add nested classes to the module
722 self.addClass(class_name, cur_class)
723 if not classstack:
724 if lastGlobalEntry:
725 lastGlobalEntry.setEndLine(lineno - 1)
726 lastGlobalEntry = cur_class
727 classstack.append((cur_class, thisindent))
728
729 elif m.start("Attribute") >= 0:
730 lineno = lineno + src.count('\n', last_lineno_pos, start)
731 last_lineno_pos = start
732 index = -1
733 while index >= -len(classstack):
734 if classstack[index][0] is not None:
735 attrName = m.group("AttributeName")
736 attr = Attribute(
737 self.name, attrName, self.file, lineno)
738 self.__py_setVisibility(attr)
739 classstack[index][0].addAttribute(attrName, attr)
740 break
741 else:
742 index -= 1
743
744 elif m.start("Main") >= 0:
745 # 'main' part of the script, reset class stack
746 lineno = lineno + src.count('\n', last_lineno_pos, start)
747 last_lineno_pos = start
748 classstack = []
749
750 elif m.start("Variable") >= 0:
751 thisindent = _indent(m.group("VariableIndent"))
752 variable_name = m.group("VariableName")
753 isSignal = m.group("VariableSignal") != ""
754 lineno = lineno + src.count('\n', last_lineno_pos, start)
755 last_lineno_pos = start
756 if thisindent == 0:
757 # global variable
758 attr = Attribute(
759 self.name, variable_name, self.file, lineno,
760 isSignal=isSignal)
761 self.__py_setVisibility(attr)
762 self.addGlobal(variable_name, attr)
763 if lastGlobalEntry:
764 lastGlobalEntry.setEndLine(lineno - 1)
765 lastGlobalEntry = None
766 else:
767 index = -1
768 while index >= -len(classstack):
769 if classstack[index][1] >= thisindent:
770 index -= 1
771 else:
772 if classstack[index][0] is not None and \
773 isinstance(classstack[index][0], Class):
774 attr = Attribute(
775 self.name, variable_name, self.file,
776 lineno, isSignal=isSignal)
777 self.__py_setVisibility(attr)
778 classstack[index][0].addGlobal(
779 variable_name, attr)
780 break
781
782 elif m.start("Import") >= 0:
783 # import module
784 names = [n.strip() for n in
785 "".join(m.group("ImportList").splitlines())
786 .replace("\\", "").split(',')]
787 self.imports.extend(
788 [name for name in names
789 if name not in self.imports])
790
791 elif m.start("ImportFrom") >= 0:
792 # from module import stuff
793 mod = m.group("ImportFromPath")
794 namesLines = (m.group("ImportFromList")
795 .replace("(", "").replace(")", "")
796 .replace("\\", "")
797 .strip().splitlines())
798 namesLines = [line.split("#")[0].strip()
799 for line in namesLines]
800 names = [n.strip() for n in
801 "".join(namesLines)
802 .split(',')]
803 if mod not in self.from_imports:
804 self.from_imports[mod] = []
805 self.from_imports[mod].extend(
806 [name for name in names
807 if name not in self.from_imports[mod]])
808
809 elif m.start("ConditionalDefine") >= 0:
810 # a conditional function/method definition
811 thisindent = _indent(m.group("ConditionalDefineIndent"))
812 while conditionalsstack and \
813 conditionalsstack[-1] >= thisindent:
814 del conditionalsstack[-1]
815 if deltastack:
816 del deltastack[-1]
817 conditionalsstack.append(thisindent)
818 deltaindentcalculated = 0
819
820 elif m.start("Comment") >= 0:
821 if modulelevel:
822 continue
823
824 else:
825 assert 0, "regexp _getnext found something unexpected"
826
827 modulelevel = False
828
829 def __rb_scan(self, src):
830 """
831 Private method to scan the source text of a Python module and retrieve
832 the relevant information.
833
834 @param src the source text to be scanned (string)
835 """
836 lineno, last_lineno_pos = 1, 0
837 classstack = [] # stack of (class, indent) pairs
838 acstack = [] # stack of (access control, indent) pairs
839 indent = 0
840 i = 0
841 cur_obj = self
842 lastGlobalEntry = None
843 while True:
844 m = self._getnext(src, i)
845 if not m:
846 break
847 start, i = m.span()
848
849 if m.start("Method") >= 0:
850 # found a method definition or function
851 thisindent = indent
852 indent += 1
853 meth_name = m.group("MethodName") or \
854 m.group("MethodName2") or \
855 m.group("MethodName3")
856 meth_sig = m.group("MethodSignature")
857 meth_sig = meth_sig and meth_sig.replace('\\\n', '') or ''
858 lineno = lineno + src.count('\n', last_lineno_pos, start)
859 last_lineno_pos = start
860 if meth_name.startswith('self.'):
861 meth_name = meth_name[5:]
862 elif meth_name.startswith('self::'):
863 meth_name = meth_name[6:]
864 # close all classes/modules indented at least as much
865 while classstack and \
866 classstack[-1][1] >= thisindent:
867 if classstack[-1][0] is not None and \
868 isinstance(classstack[-1][0],
869 (Class, Function, RbModule)):
870 # record the end line of this class, function or module
871 classstack[-1][0].setEndLine(lineno - 1)
872 del classstack[-1]
873 while acstack and \
874 acstack[-1][1] >= thisindent:
875 del acstack[-1]
876 if classstack:
877 csi = -1
878 while csi >= -len(classstack):
879 # nested defs are added to the class
880 cur_class = classstack[csi][0]
881 csi -= 1
882 if cur_class is None:
883 continue
884
885 if isinstance(cur_class, Class) or \
886 isinstance(cur_class, RbModule):
887 # it's a class/module method
888 f = Function(None, meth_name,
889 None, lineno, meth_sig)
890 cur_class.addMethod(meth_name, f)
891 break
892 else:
893 # it's a nested function of a module function
894 f = Function(
895 self.name, meth_name, self.file, lineno, meth_sig)
896 self.addFunction(meth_name, f)
897 # set access control
898 if acstack:
899 accesscontrol = acstack[-1][0]
900 if accesscontrol == "private":
901 f.setPrivate()
902 elif accesscontrol == "protected":
903 f.setProtected()
904 elif accesscontrol == "public":
905 f.setPublic()
906 else:
907 # it's a function
908 f = Function(
909 self.name, meth_name, self.file, lineno, meth_sig)
910 self.addFunction(meth_name, f)
911 if not classstack:
912 if lastGlobalEntry:
913 lastGlobalEntry.setEndLine(lineno - 1)
914 lastGlobalEntry = f
915 if cur_obj and isinstance(cur_obj, Function):
916 cur_obj.setEndLine(lineno - 1)
917 cur_obj = f
918 classstack.append((None, thisindent)) # Marker for nested fns
919
920 elif m.start("Docstring") >= 0:
921 contents = m.group("DocstringContents")
922 if contents is not None:
923 contents = _hashsub(r"\1", contents)
924 if cur_obj:
925 cur_obj.addDescription(contents)
926
927 elif m.start("String") >= 0:
928 pass
929
930 elif m.start("Comment") >= 0:
931 pass
932
933 elif m.start("ClassIgnored") >= 0:
934 pass
935
936 elif m.start("Class") >= 0:
937 # we found a class definition
938 thisindent = indent
939 indent += 1
940 lineno = lineno + src.count('\n', last_lineno_pos, start)
941 last_lineno_pos = start
942 # close all classes/modules indented at least as much
943 while classstack and \
944 classstack[-1][1] >= thisindent:
945 if classstack[-1][0] is not None and \
946 isinstance(classstack[-1][0],
947 (Class, Function, RbModule)):
948 # record the end line of this class, function or module
949 classstack[-1][0].setEndLine(lineno - 1)
950 del classstack[-1]
951 class_name = m.group("ClassName") or m.group("ClassName2")
952 inherit = m.group("ClassSupers")
953 if inherit:
954 # the class inherits from other classes
955 inherit = inherit[1:].strip()
956 inherit = [_commentsub('', inherit)]
957 # remember this class
958 cur_class = Class(self.name, class_name, inherit,
959 self.file, lineno)
960 # add nested classes to the file
961 if classstack and isinstance(classstack[-1][0], RbModule):
962 parent_obj = classstack[-1][0]
963 else:
964 parent_obj = self
965 if class_name in parent_obj.classes:
966 cur_class = parent_obj.classes[class_name]
967 elif classstack and \
968 isinstance(classstack[-1][0], Class) and \
969 class_name == "self":
970 cur_class = classstack[-1][0]
971 else:
972 parent_obj.addClass(class_name, cur_class)
973 if not classstack:
974 if lastGlobalEntry:
975 lastGlobalEntry.setEndLine(lineno - 1)
976 lastGlobalEntry = cur_class
977 cur_obj = cur_class
978 classstack.append((cur_class, thisindent))
979 while acstack and \
980 acstack[-1][1] >= thisindent:
981 del acstack[-1]
982 acstack.append(["public", thisindent])
983 # default access control is 'public'
984
985 elif m.start("Module") >= 0:
986 # we found a module definition
987 thisindent = indent
988 indent += 1
989 lineno = lineno + src.count('\n', last_lineno_pos, start)
990 last_lineno_pos = start
991 # close all classes/modules indented at least as much
992 while classstack and \
993 classstack[-1][1] >= thisindent:
994 if classstack[-1][0] is not None and \
995 isinstance(classstack[-1][0],
996 (Class, Function, RbModule)):
997 # record the end line of this class, function or module
998 classstack[-1][0].setEndLine(lineno - 1)
999 del classstack[-1]
1000 module_name = m.group("ModuleName")
1001 # remember this class
1002 cur_class = RbModule(self.name, module_name,
1003 self.file, lineno)
1004 # add nested Ruby modules to the file
1005 if module_name in self.modules:
1006 cur_class = self.modules[module_name]
1007 else:
1008 self.addModule(module_name, cur_class)
1009 if not classstack:
1010 if lastGlobalEntry:
1011 lastGlobalEntry.setEndLine(lineno - 1)
1012 lastGlobalEntry = cur_class
1013 cur_obj = cur_class
1014 classstack.append((cur_class, thisindent))
1015 while acstack and \
1016 acstack[-1][1] >= thisindent:
1017 del acstack[-1]
1018 acstack.append(["public", thisindent])
1019 # default access control is 'public'
1020
1021 elif m.start("AccessControl") >= 0:
1022 aclist = m.group("AccessControlList")
1023 if aclist is None:
1024 index = -1
1025 while index >= -len(acstack):
1026 if acstack[index][1] < indent:
1027 actype = \
1028 m.group("AccessControlType") or \
1029 m.group("AccessControlType2").split('_')[0]
1030 acstack[index][0] = actype.lower()
1031 break
1032 else:
1033 index -= 1
1034 else:
1035 index = -1
1036 while index >= -len(classstack):
1037 if classstack[index][0] is not None and \
1038 not isinstance(classstack[index][0], Function) and \
1039 not classstack[index][1] >= indent:
1040 parent = classstack[index][0]
1041 actype = \
1042 m.group("AccessControlType") or \
1043 m.group("AccessControlType2").split('_')[0]
1044 actype = actype.lower()
1045 for name in aclist.split(","):
1046 # get rid of leading ':'
1047 name = name.strip()[1:]
1048 acmeth = parent.getMethod(name)
1049 if acmeth is None:
1050 continue
1051 if actype == "private":
1052 acmeth.setPrivate()
1053 elif actype == "protected":
1054 acmeth.setProtected()
1055 elif actype == "public":
1056 acmeth.setPublic()
1057 break
1058 else:
1059 index -= 1
1060
1061 elif m.start("Attribute") >= 0:
1062 lineno = lineno + src.count('\n', last_lineno_pos, start)
1063 last_lineno_pos = start
1064 index = -1
1065 while index >= -len(classstack):
1066 if classstack[index][0] is not None and \
1067 not isinstance(classstack[index][0], Function) and \
1068 not classstack[index][1] >= indent:
1069 attrName = m.group("AttributeName")
1070 attr = Attribute(
1071 self.name, attrName, self.file, lineno)
1072 if attrName.startswith("@@") or attrName[0].isupper():
1073 classstack[index][0].addGlobal(attrName, attr)
1074 else:
1075 classstack[index][0].addAttribute(attrName, attr)
1076 break
1077 else:
1078 index -= 1
1079 else:
1080 attrName = m.group("AttributeName")
1081 if attrName[0] != "@":
1082 attr = Attribute(
1083 self.name, attrName, self.file, lineno)
1084 self.addGlobal(attrName, attr)
1085 if lastGlobalEntry:
1086 lastGlobalEntry.setEndLine(lineno - 1)
1087 lastGlobalEntry = None
1088
1089 elif m.start("Attr") >= 0:
1090 lineno = lineno + src.count('\n', last_lineno_pos, start)
1091 last_lineno_pos = start
1092 index = -1
1093 while index >= -len(classstack):
1094 if classstack[index][0] is not None and \
1095 not isinstance(classstack[index][0], Function) and \
1096 not classstack[index][1] >= indent:
1097 parent = classstack[index][0]
1098 if m.group("AttrType") is None:
1099 nv = m.group("AttrList").split(",")
1100 if not nv:
1101 break
1102 # get rid of leading ':'
1103 name = nv[0].strip()[1:]
1104 attr = parent.getAttribute("@" + name) or \
1105 parent.getAttribute("@@" + name) or \
1106 Attribute(
1107 self.name, "@" + name, self.file, lineno)
1108 if len(nv) == 1 or nv[1].strip() == "false":
1109 attr.setProtected()
1110 elif nv[1].strip() == "true":
1111 attr.setPublic()
1112 parent.addAttribute(attr.name, attr)
1113 else:
1114 access = m.group("AttrType")
1115 for name in m.group("AttrList").split(","):
1116 # get rid of leading ':'
1117 name = name.strip()[1:]
1118 attr = parent.getAttribute("@" + name) or \
1119 parent.getAttribute("@@" + name) or \
1120 Attribute(
1121 self.name, "@" + name, self.file,
1122 lineno)
1123 if access == "_accessor":
1124 attr.setPublic()
1125 elif access == "_reader" or \
1126 access == "_writer":
1127 if attr.isPrivate():
1128 attr.setProtected()
1129 elif attr.isProtected():
1130 attr.setPublic()
1131 parent.addAttribute(attr.name, attr)
1132 break
1133 else:
1134 index -= 1
1135
1136 elif m.start("Begin") >= 0:
1137 # a begin of a block we are not interested in
1138 indent += 1
1139
1140 elif m.start("End") >= 0:
1141 # an end of a block
1142 indent -= 1
1143 if indent < 0:
1144 # no negative indent allowed
1145 if classstack:
1146 # it's a class/module method
1147 indent = classstack[-1][1]
1148 else:
1149 indent = 0
1150
1151 elif m.start("BeginEnd") >= 0:
1152 pass
1153
1154 else:
1155 assert 0, "regexp _getnext found something unexpected"
1156
1157 def createHierarchy(self):
1158 """
1159 Public method to build the inheritance hierarchy for all classes of
1160 this module.
1161
1162 @return A dictionary with inheritance hierarchies.
1163 """
1164 hierarchy = {}
1165 for cls in list(list(self.classes.keys())):
1166 self.assembleHierarchy(cls, self.classes, [cls], hierarchy)
1167 for mod in list(list(self.modules.keys())):
1168 self.assembleHierarchy(mod, self.modules, [mod], hierarchy)
1169 return hierarchy
1170
1171 def assembleHierarchy(self, name, classes, path, result):
1172 """
1173 Public method to assemble the inheritance hierarchy.
1174
1175 This method will traverse the class hierarchy, from a given class
1176 and build up a nested dictionary of super-classes. The result is
1177 intended to be inverted, i.e. the highest level are the super classes.
1178
1179 This code is borrowed from Boa Constructor.
1180
1181 @param name name of class to assemble hierarchy (string)
1182 @param classes A dictionary of classes to look in.
1183 @param path
1184 @param result The resultant hierarchy
1185 """
1186 rv = {}
1187 if name in classes:
1188 for cls in classes[name].super:
1189 if cls not in classes:
1190 rv[cls] = {}
1191 exhausted = path + [cls]
1192 exhausted.reverse()
1193 self.addPathToHierarchy(
1194 exhausted, result, self.addPathToHierarchy)
1195 else:
1196 rv[cls] = self.assembleHierarchy(
1197 cls, classes, path + [cls], result)
1198
1199 if len(rv) == 0:
1200 exhausted = path
1201 exhausted.reverse()
1202 self.addPathToHierarchy(exhausted, result, self.addPathToHierarchy)
1203
1204 def addPathToHierarchy(self, path, result, fn):
1205 """
1206 Public method to put the exhausted path into the result dictionary.
1207
1208 @param path the exhausted path of classes
1209 @param result the result dictionary
1210 @param fn function to call for classe that are already part of the
1211 result dictionary
1212 """
1213 if path[0] in list(list(result.keys())):
1214 if len(path) > 1:
1215 fn(path[1:], result[path[0]], fn)
1216 else:
1217 for part in path:
1218 result[part] = {}
1219 result = result[part]
1220
1221 def getName(self):
1222 """
1223 Public method to retrieve the modules name.
1224
1225 @return module name (string)
1226 """
1227 return self.name
1228
1229 def getFileName(self):
1230 """
1231 Public method to retrieve the modules filename.
1232
1233 @return module filename (string)
1234 """
1235 return self.file
1236
1237 def getType(self):
1238 """
1239 Public method to get the type of the module's source.
1240
1241 @return type of the modules's source (string)
1242 """
1243 if self.type in [imp.PY_SOURCE, PTL_SOURCE]:
1244 py3ExtList = Preferences.getDebugger("Python3Extensions").split()
1245 if self.file.endswith(tuple(py3ExtList)):
1246 moduleType = "Python3"
1247 else:
1248 moduleType = "Python2"
1249 elif self.type == RB_SOURCE:
1250 moduleType = "Ruby"
1251 else:
1252 moduleType = ""
1253 return moduleType
1254
1255
1256 class Class(VisibilityBase):
1257 """
1258 Class to represent a Python class.
1259 """
1260 def __init__(self, module, name, superClasses, file, lineno):
1261 """
1262 Constructor
1263
1264 @param module name of module containing this class (string)
1265 @param name name of the class (string)
1266 @param superClasses list of classnames this class is inherited from
1267 (list of strings)
1268 @param file name of file containing this class (string)
1269 @param lineno linenumber of the class definition (integer)
1270 """
1271 self.module = module
1272 self.name = name
1273 if superClasses is None:
1274 superClasses = []
1275 self.super = superClasses
1276 self.methods = {}
1277 self.attributes = {}
1278 self.globals = {}
1279 self.file = file
1280 self.lineno = lineno
1281 self.endlineno = -1 # marker for "not set"
1282 self.description = ""
1283 self.setPublic()
1284
1285 def addMethod(self, name, function):
1286 """
1287 Public method to add information about a method.
1288
1289 @param name name of method to be added (string)
1290 @param function Function object to be added
1291 """
1292 self.methods[name] = function
1293
1294 def getMethod(self, name):
1295 """
1296 Public method to retrieve a method by name.
1297
1298 @param name name of the method (string)
1299 @return the named method or None
1300 """
1301 try:
1302 return self.methods[name]
1303 except KeyError:
1304 return None
1305
1306 def addAttribute(self, name, attr):
1307 """
1308 Public method to add information about attributes.
1309
1310 @param name name of the attribute to add (string)
1311 @param attr Attribute object to be added
1312 """
1313 if name not in self.attributes:
1314 self.attributes[name] = attr
1315 else:
1316 self.attributes[name].addAssignment(attr.lineno)
1317
1318 def getAttribute(self, name):
1319 """
1320 Public method to retrieve an attribute by name.
1321
1322 @param name name of the attribute (string)
1323 @return the named attribute or None
1324 """
1325 try:
1326 return self.attributes[name]
1327 except KeyError:
1328 return None
1329
1330 def addGlobal(self, name, attr):
1331 """
1332 Public method to add information about global (class) variables.
1333
1334 @param name name of the global to add (string)
1335 @param attr Attribute object to be added
1336 """
1337 if name not in self.globals:
1338 self.globals[name] = attr
1339 else:
1340 self.globals[name].addAssignment(attr.lineno)
1341
1342 def addDescription(self, description):
1343 """
1344 Public method to store the class docstring.
1345
1346 @param description the docstring to be stored (string)
1347 """
1348 self.description = description
1349
1350 def setEndLine(self, endLineNo):
1351 """
1352 Public method to record the number of the last line of a class.
1353
1354 @param endLineNo number of the last line (integer)
1355 """
1356 self.endlineno = endLineNo
1357
1358
1359 class RbModule(Class):
1360 """
1361 Class to represent a Ruby module.
1362 """
1363 def __init__(self, module, name, file, lineno):
1364 """
1365 Constructor
1366
1367 @param module name of module containing this class (string)
1368 @param name name of the class (string)
1369 @param file name of file containing this class (string)
1370 @param lineno linenumber of the class definition (integer)
1371 """
1372 Class.__init__(self, module, name, None, file, lineno)
1373 self.classes = {}
1374
1375 def addClass(self, name, _class):
1376 """
1377 Public method to add information about a class.
1378
1379 @param name name of class to be added (string)
1380 @param _class Class object to be added
1381 """
1382 self.classes[name] = _class
1383
1384
1385 class Function(VisibilityBase):
1386 """
1387 Class to represent a Python function or method.
1388 """
1389 General = 0
1390 Static = 1
1391 Class = 2
1392
1393 def __init__(self, module, name, file, lineno, signature='',
1394 pyqtSignature=None, modifierType=General, annotation=""):
1395 """
1396 Constructor
1397
1398 @param module name of module containing this function (string)
1399 @param name name of the function (string)
1400 @param file name of file containing this function (string)
1401 @param lineno linenumber of the function definition (integer)
1402 @param signature the functions call signature (string)
1403 @param pyqtSignature the functions PyQt signature (string)
1404 @param modifierType type of the function
1405 @param annotation return annotation
1406 """
1407 self.module = module
1408 self.name = name
1409 self.file = file
1410 self.lineno = lineno
1411 self.endlineno = -1 # marker for "not set"
1412 signature = _commentsub('', signature)
1413 self.parameters = [e.strip() for e in signature.split(',')]
1414 self.description = ""
1415 self.pyqtSignature = pyqtSignature
1416 self.modifier = modifierType
1417 self.annotation = annotation
1418 self.setPublic()
1419
1420 def addDescription(self, description):
1421 """
1422 Public method to store the functions docstring.
1423
1424 @param description the docstring to be stored (string)
1425 """
1426 self.description = description
1427
1428 def setEndLine(self, endLineNo):
1429 """
1430 Public method to record the number of the last line of a class.
1431
1432 @param endLineNo number of the last line (integer)
1433 """
1434 self.endlineno = endLineNo
1435
1436
1437 class Attribute(VisibilityBase):
1438 """
1439 Class to represent a Python function or method.
1440 """
1441 def __init__(self, module, name, file, lineno, isSignal=False):
1442 """
1443 Constructor
1444
1445 @param module name of module containing this function (string)
1446 @param name name of the function (string)
1447 @param file name of file containing this function (string)
1448 @param lineno linenumber of the first attribute assignment (integer)
1449 @keyparam isSignal flag indicating a signal definition (boolean)
1450 """
1451 self.module = module
1452 self.name = name
1453 self.file = file
1454 self.lineno = lineno
1455 self.isSignal = isSignal
1456 self.setPublic()
1457 self.linenos = [lineno]
1458
1459 def addAssignment(self, lineno):
1460 """
1461 Public method to add another assignment line number.
1462
1463 @param lineno linenumber of the additional attribute assignment
1464 (integer)
1465 """
1466 if lineno not in self.linenos:
1467 self.linenos.append(lineno)
1468
1469
1470 def readModule(module, path=None, inpackage=False, basename="",
1471 extensions=None, caching=True):
1472 """
1473 Function to read a module file and parse it.
1474
1475 The module is searched in path and sys.path, read and parsed.
1476 If the module was parsed before, the information is taken
1477 from a cache in order to speed up processing.
1478
1479 @param module name of the module to be parsed (string)
1480 @param path search path for the module (list of strings)
1481 @param inpackage flag indicating that module is inside a
1482 package (boolean)
1483 @param basename a path basename that is deleted from the filename of
1484 the module file to be read (string)
1485 @param extensions list of extensions, which should be considered valid
1486 source file extensions (list of strings)
1487 @param caching flag indicating that the parsed module should be
1488 cached (boolean)
1489 @return reference to a Module object containing the parsed
1490 module information (Module)
1491 """
1492 global _modules
1493
1494 if extensions is None:
1495 _extensions = ['.py', '.pyw', '.ptl', '.rb']
1496 else:
1497 _extensions = extensions[:]
1498 try:
1499 _extensions.remove('.py')
1500 except ValueError:
1501 pass
1502
1503 modname = module
1504
1505 if os.path.exists(module):
1506 path = [os.path.dirname(module)]
1507 if module.lower().endswith(".py"):
1508 module = module[:-3]
1509 if os.path.exists(os.path.join(path[0], "__init__.py")) or \
1510 os.path.exists(os.path.join(path[0], "__init__.rb")) or \
1511 inpackage:
1512 if basename:
1513 module = module.replace(basename, "")
1514 if os.path.isabs(module):
1515 modname = os.path.splitdrive(module)[1][len(os.sep):]
1516 else:
1517 modname = module
1518 modname = modname.replace(os.sep, '.')
1519 inpackage = 1
1520 else:
1521 modname = os.path.basename(module)
1522 for ext in _extensions:
1523 if modname.lower().endswith(ext):
1524 modname = modname[:-len(ext)]
1525 break
1526 module = os.path.basename(module)
1527
1528 if caching and modname in _modules:
1529 # we've seen this module before...
1530 return _modules[modname]
1531
1532 if module in sys.builtin_module_names:
1533 # this is a built-in module
1534 mod = Module(modname, None, None)
1535 if caching:
1536 _modules[modname] = mod
1537 return mod
1538
1539 # search the path for the module
1540 path = [] if path is None else path[:]
1541 f = None
1542 if inpackage:
1543 try:
1544 f, file, (suff, mode, moduleType) = find_module(
1545 module, path, _extensions)
1546 except ImportError:
1547 f = None
1548 if f is None:
1549 fullpath = path[:] + sys.path[:]
1550 f, file, (suff, mode, moduleType) = find_module(
1551 module, fullpath, _extensions)
1552 if f:
1553 f.close()
1554 if moduleType not in SUPPORTED_TYPES:
1555 # not supported source, can't do anything with this module
1556 _modules[modname] = Module(modname, None, None)
1557 return _modules[modname]
1558
1559 mod = Module(modname, file, moduleType)
1560 try:
1561 src = Utilities.readEncodedFile(file)[0]
1562 mod.scan(src)
1563 except (UnicodeError, IOError):
1564 pass
1565 if caching:
1566 _modules[modname] = mod
1567 return mod
1568
1569
1570 def _indent(ws):
1571 """
1572 Protected function to determine the indent width of a whitespace string.
1573
1574 @param ws The whitespace string to be cheked. (string)
1575 @return Length of the whitespace string after tab expansion.
1576 """
1577 return len(ws.expandtabs(TABWIDTH))
1578
1579
1580 def find_module(name, path, extensions):
1581 """
1582 Module function to extend the Python module finding mechanism.
1583
1584 This function searches for files in the given path. If the filename
1585 doesn't have an extension or an extension of .py, the normal search
1586 implemented in the imp module is used. For all other supported files
1587 only path is searched.
1588
1589 @param name filename or modulename to search for (string)
1590 @param path search path (list of strings)
1591 @param extensions list of extensions, which should be considered valid
1592 source file extensions (list of strings)
1593 @return tuple of the open file, pathname and description. Description
1594 is a tuple of file suffix, file mode and file type)
1595 @exception ImportError The file or module wasn't found.
1596 """
1597 for ext in extensions:
1598 if name.lower().endswith(ext):
1599 for p in path: # only search in path
1600 if os.path.exists(os.path.join(p, name)):
1601 pathname = os.path.join(p, name)
1602 if ext == '.ptl':
1603 # Quixote page template
1604 return (open(pathname), pathname,
1605 ('.ptl', 'r', PTL_SOURCE))
1606 elif ext == '.rb':
1607 # Ruby source file
1608 return (open(pathname), pathname,
1609 ('.rb', 'r', RB_SOURCE))
1610 else:
1611 return (open(pathname), pathname,
1612 (ext, 'r', imp.PY_SOURCE))
1613 raise ImportError
1614
1615 # standard Python module file
1616 if name.lower().endswith('.py'):
1617 name = name[:-3]
1618
1619 return imp.find_module(name, path)
1620
1621
1622 def resetParsedModules():
1623 """
1624 Module function to reset the list of modules already parsed.
1625 """
1626 _modules.clear()
1627
1628
1629 def resetParsedModule(module, basename=""):
1630 """
1631 Module function to clear one module from the list of parsed modules.
1632
1633 @param module Name of the module to be parsed (string)
1634 @param basename a path basename. This basename is deleted from
1635 the filename of the module file to be cleared. (string)
1636 """
1637 modname = module
1638
1639 if os.path.exists(module):
1640 path = [os.path.dirname(module)]
1641 if module.lower().endswith(".py"):
1642 module = module[:-3]
1643 if os.path.exists(os.path.join(path[0], "__init__.py")):
1644 if basename:
1645 module = module.replace(basename, "")
1646 modname = module.replace(os.sep, '.')
1647 else:
1648 modname = os.path.basename(module)
1649 if modname.lower().endswith(".ptl") or \
1650 modname.lower().endswith(".pyw"):
1651 modname = modname[:-4]
1652 elif modname.lower().endswith(".rb"):
1653 modname = modname[:-3]
1654 module = os.path.basename(module)
1655
1656 if modname in _modules:
1657 del _modules[modname]

eric ide

mercurial