]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/ide/activegrid/tool/checker.py
Docview and IDE patch from Morag Hua with fix for bug #1217890
[wxWidgets.git] / wxPython / samples / ide / activegrid / tool / checker.py
1 #!/usr/bin/env python
2
3 # Copyright (c) 2001-2004, MetaSlash Inc. All rights reserved.
4
5 """
6 Copyright notice from pychecker:
7
8 Copyright (c) 2000-2001, MetaSlash Inc.
9 All rights reserved.
10
11 Redistribution and use in source and binary forms, with or without
12 modification, are permitted provided that the following conditions are
13 met:
14
15 - Redistributions of source code must retain the above copyright
16 notice, this list of conditions and the following disclaimer.
17
18 - Redistributions in binary form must reproduce the above copyright
19 notice, this list of conditions and the following disclaimer in the
20 documentation and/or other materials provided with the
21 distribution.
22
23 - Neither name of MetaSlash Inc. nor the names of contributors
24 may be used to endorse or promote products derived
25 from this software without specific prior written permission.
26
27 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
31 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 """
39
40
41 """
42 Check python source code files for possible errors and print warnings
43
44 Contact Info:
45 http://pychecker.sourceforge.net/
46 pychecker-list@lists.sourceforge.net
47 """
48
49 import string
50 import types
51 import sys
52 import imp
53 import os
54 import glob
55 import traceback
56 import re
57 import wx
58 _ = wx.GetTranslation
59
60 # see __init__.py for meaning, this must match the version there
61 LOCAL_MAIN_VERSION = 1
62
63
64 def setupNamespace(path) :
65 # remove pychecker if it's the first component, it needs to be last
66 if sys.path[0][-9:] == 'pychecker' :
67 del sys.path[0]
68
69 # make sure pychecker is last in path, so we can import
70 checker_path = os.path.dirname(os.path.dirname(path))
71 if checker_path not in sys.path :
72 sys.path.append(checker_path)
73
74 if __name__ == '__main__' :
75 setupNamespace(sys.argv[0])
76
77 from pychecker import utils
78 from pychecker import printer
79 from pychecker import warn
80 from pychecker import OP
81 from pychecker import Config
82 from pychecker import function
83 from pychecker.Warning import Warning
84
85 # Globals for storing a dictionary of info about modules and classes
86 _allModules = {}
87 _cfg = None
88
89 # Constants
90 _DEFAULT_MODULE_TOKENS = ('__builtins__', '__doc__', '__file__', '__name__',
91 '__path__')
92 _DEFAULT_CLASS_TOKENS = ('__doc__', '__name__', '__module__')
93
94 _VERSION_MISMATCH_ERROR = '''
95 There seem to be two versions of PyChecker being used.
96 One is probably in python/site-packages, the other in a local directory.
97 If you want to run the local version, you must remove the version
98 from site-packages. Or you can install the current version
99 by doing python setup.py install.
100 '''
101
102 def cfg() :
103 return utils.cfg()
104
105 def _flattenList(list) :
106 "Returns a list which contains no lists"
107
108 new_list = []
109 for element in list :
110 if type(element) == types.ListType :
111 new_list.extend(_flattenList(element))
112 else :
113 new_list.append(element)
114
115 return new_list
116
117 def getModules(arg_list) :
118 "Returns a list of module names that can be imported"
119
120 global _output
121
122 new_arguments = []
123 for arg in arg_list :
124 # is this a wildcard filespec? (necessary for windows)
125 if '*' in arg or '?' in arg or '[' in arg :
126 arg = glob.glob(arg)
127 new_arguments.append(arg)
128
129 PY_SUFFIXES = ['.py']
130 PY_SUFFIX_LENS = [3]
131 if _cfg.quixote:
132 PY_SUFFIXES.append('.ptl')
133 PY_SUFFIX_LENS.append(4)
134
135 modules = []
136 for arg in _flattenList(new_arguments) :
137 fullpath = arg
138 # is it a .py file?
139 for suf, suflen in zip(PY_SUFFIXES, PY_SUFFIX_LENS):
140 if len(arg) > suflen and arg[-suflen:] == suf:
141 arg_dir = os.path.dirname(arg)
142 if arg_dir and not os.path.exists(arg) :
143 txt = _('File or pathname element does not exist: "%s"') % arg
144 _output.AddLines(txt)
145 continue
146
147 module_name = os.path.basename(arg)[:-suflen]
148 if arg_dir not in sys.path :
149 sys.path.insert(0, arg_dir)
150 arg = module_name
151 modules.append((arg, fullpath))
152
153 return modules
154
155 def _q_file(f):
156 # crude hack!!!
157 # imp.load_module requires a real file object, so we can't just
158 # fiddle def lines and yield them
159 import tempfile
160 fd, newfname = tempfile.mkstemp(suffix=".py", text=True)
161 newf = os.fdopen(fd, 'r+')
162 os.unlink(newfname)
163 for line in f:
164 mat = re.match(r'(\s*def\s+\w+\s*)\[(html|plain)\](.*)', line)
165 if mat is None:
166 newf.write(line)
167 else:
168 newf.write(mat.group(1)+mat.group(3)+'\n')
169 newf.seek(0)
170 return newf
171
172 def _q_find_module(p, path):
173 if not _cfg.quixote:
174 return imp.find_module(p, path)
175 else:
176 for direc in path:
177 try:
178 return imp.find_module(p, [direc])
179 except ImportError:
180 f = os.path.join(direc, p+".ptl")
181 if os.path.exists(f):
182 return _q_file(file(f)), f, ('.ptl', 'U', 1)
183
184 def _findModule(name) :
185 """Returns the result of an imp.find_module(), ie, (file, filename, smt)
186 name can be a module or a package name. It is *not* a filename."""
187
188 path = sys.path[:]
189 packages = string.split(name, '.')
190 for p in packages :
191 # smt = (suffix, mode, type)
192 file, filename, smt = _q_find_module(p, path)
193 if smt[-1] == imp.PKG_DIRECTORY :
194 try :
195 # package found - read path info from init file
196 m = imp.load_module(p, file, filename, smt)
197 finally :
198 if file is not None :
199 file.close()
200
201 # importing xml plays a trick, which replaces itself with _xmlplus
202 # both have subdirs w/same name, but different modules in them
203 # we need to choose the real (replaced) version
204 if m.__name__ != p :
205 try :
206 file, filename, smt = _q_find_module(m.__name__, path)
207 m = imp.load_module(p, file, filename, smt)
208 finally :
209 if file is not None :
210 file.close()
211
212 new_path = m.__path__
213 if type(new_path) == types.ListType :
214 new_path = filename
215 if new_path not in path :
216 path.insert(1, new_path)
217 elif smt[-1] != imp.PY_COMPILED:
218 if p is not packages[-1] :
219 if file is not None :
220 file.close()
221 raise ImportError, "No module named %s" % packages[-1]
222 return file, filename, smt
223
224 # in case we have been given a package to check
225 return file, filename, smt
226
227
228 class Variable :
229 "Class to hold all information about a variable"
230
231 def __init__(self, name, type):
232 self.name = name
233 self.type = type
234 self.value = None
235
236 def __str__(self) :
237 return self.name
238
239 __repr__ = utils.std_repr
240
241
242 def _filterDir(object, ignoreList) :
243 "Return a list of tokens (attributes) in a class, except for ignoreList"
244
245 tokens = dir(object)
246 for token in ignoreList :
247 if token in tokens :
248 tokens.remove(token)
249 return tokens
250
251 def _getClassTokens(c) :
252 return _filterDir(c, _DEFAULT_CLASS_TOKENS)
253
254
255 class Class :
256 "Class to hold all information about a class"
257
258 def __init__(self, name, module) :
259 self.name = name
260 self.classObject = getattr(module, name)
261
262 modname = getattr(self.classObject, '__module__', None)
263 if modname is None:
264 # hm, some ExtensionClasses don't have a __module__ attribute
265 # so try parsing the type output
266 typerepr = repr(type(self.classObject))
267 mo = re.match("^<type ['\"](.+)['\"]>$", typerepr)
268 if mo:
269 modname = ".".join(mo.group(1).split(".")[:-1])
270
271 self.module = sys.modules.get(modname)
272 if not self.module:
273 self.module = module
274
275 global _output
276 txt = _("warning: couldn't find real module for class %s (module name: %s)\n") % (self.classObject, modname)
277 _output.AddLines(txt)
278
279 self.ignoreAttrs = 0
280 self.methods = {}
281 self.members = { '__class__': types.ClassType,
282 '__doc__': types.StringType,
283 '__dict__': types.DictType, }
284 self.memberRefs = {}
285 self.statics = {}
286 self.lineNums = {}
287
288 def __str__(self) :
289 return self.name
290
291 __repr__ = utils.std_repr
292
293 def getFirstLine(self) :
294 "Return first line we can find in THIS class, not any base classes"
295
296 lineNums = []
297 classDir = dir(self.classObject)
298 for m in self.methods.values() :
299 if m != None and m.function.func_code.co_name in classDir:
300 lineNums.append(m.function.func_code.co_firstlineno)
301 if lineNums :
302 return min(lineNums)
303 return 0
304
305
306 def allBaseClasses(self, c = None) :
307 "Return a list of all base classes for this class and it's subclasses"
308
309 baseClasses = []
310 if c == None :
311 c = self.classObject
312 for base in c.__bases__ :
313 baseClasses = baseClasses + [ base ] + self.allBaseClasses(base)
314 return baseClasses
315
316 def __getMethodName(self, func_name, className = None) :
317 if func_name[0:2] == '__' and func_name[-2:] != '__' :
318 if className == None :
319 className = self.name
320 if className[0] != '_' :
321 className = '_' + className
322 func_name = className + func_name
323 return func_name
324
325 def addMethod(self, method, methodName = None) :
326 if type(method) == types.StringType :
327 self.methods[method] = None
328 else :
329 assert methodName is not None, "must supply methodName"
330 self.methods[methodName] = function.Function(method, 1)
331
332 def addMethods(self, classObject) :
333 for classToken in _getClassTokens(classObject) :
334 token = getattr(classObject, classToken, None)
335 if token is None:
336 continue
337
338 # Looks like a method. Need to code it this way to
339 # accommodate ExtensionClass and Python 2.2. Yecchh.
340 if (hasattr(token, "func_code") and
341 hasattr(token.func_code, "co_argcount")):
342 self.addMethod(token, token.__name__)
343
344 elif hasattr(token, '__get__') and \
345 not hasattr(token, '__set__') and \
346 type(token) is not types.ClassType :
347 self.addMethod(getattr(token, '__name__', classToken))
348 else :
349 self.members[classToken] = type(token)
350 self.memberRefs[classToken] = None
351
352 self.cleanupMemberRefs()
353 # add standard methods
354 for methodName in ('__class__',) :
355 self.addMethod(methodName, classObject.__name__)
356
357 def addMembers(self, classObject) :
358 if not cfg().onlyCheckInitForMembers :
359 for classToken in _getClassTokens(classObject) :
360 method = getattr(classObject, classToken, None)
361 if type(method) == types.MethodType :
362 self.addMembersFromMethod(method.im_func)
363 else:
364 try:
365 self.addMembersFromMethod(classObject.__init__.im_func)
366 except AttributeError:
367 pass
368
369 def addMembersFromMethod(self, method) :
370 if not hasattr(method, 'func_code') :
371 return
372
373 func_code, code, i, maxCode, extended_arg = OP.initFuncCode(method)
374 stack = []
375 while i < maxCode :
376 op, oparg, i, extended_arg = OP.getInfo(code, i, extended_arg)
377 if op >= OP.HAVE_ARGUMENT :
378 operand = OP.getOperand(op, func_code, oparg)
379 if OP.LOAD_CONST(op) or OP.LOAD_FAST(op) :
380 stack.append(operand)
381 elif OP.STORE_ATTR(op) :
382 if len(stack) > 0 :
383 if stack[-1] == cfg().methodArgName:
384 value = None
385 if len(stack) > 1 :
386 value = type(stack[-2])
387 self.members[operand] = value
388 self.memberRefs[operand] = None
389 stack = []
390
391 self.cleanupMemberRefs()
392
393 def cleanupMemberRefs(self) :
394 try :
395 del self.memberRefs[Config.CHECKER_VAR]
396 except KeyError :
397 pass
398
399 def abstractMethod(self, m):
400 """Return 1 if method is abstract, None if not
401 An abstract method always raises an exception.
402 """
403 if not self.methods.get(m, None):
404 return None
405 func_code, bytes, i, maxCode, extended_arg = \
406 OP.initFuncCode(self.methods[m].function)
407 # abstract if the first conditional is RAISE_VARARGS
408 while i < maxCode:
409 op, oparg, i, extended_arg = OP.getInfo(bytes, i, extended_arg)
410 if OP.RAISE_VARARGS(op):
411 return 1
412 if OP.conditional(op):
413 break
414 return None
415
416 def isAbstract(self):
417 """Return the method names that make a class abstract.
418 An abstract class has at least one abstract method."""
419 result = []
420 for m in self.methods.keys():
421 if self.abstractMethod(m):
422 result.append(m)
423 return result
424
425 def _getLineInFile(moduleName, linenum):
426 line = ''
427 file, filename, smt = _findModule(moduleName)
428 try:
429 lines = file.readlines()
430 line = string.rstrip(lines[linenum - 1])
431 except (IOError, IndexError):
432 pass
433 file.close()
434 return line
435
436 def importError(moduleName):
437 exc_type, exc_value, tb = sys.exc_info()
438
439 # First, try to get a nice-looking name for this exception type.
440 exc_name = getattr(exc_type, '__name__', None)
441 if not exc_name:
442 # either it's a string exception or a user-defined exception class
443 # show string or fully-qualified class name
444 exc_name = str(exc_type)
445
446 # Print a traceback, unless this is an ImportError. ImportError is
447 # presumably the most common import-time exception, so this saves
448 # the clutter of a traceback most of the time. Also, the locus of
449 # the error is usually irrelevant for ImportError, so the lack of
450 # traceback shouldn't be a problem.
451 if exc_type is SyntaxError:
452 # SyntaxErrors are special, we want to control how we format
453 # the output and make it consistent for all versions of Python
454 e = exc_value
455 msg = '%s (%s, line %d)' % (e.msg, e.filename, e.lineno)
456 line = _getLineInFile(moduleName, e.lineno)
457 offset = e.offset
458 if type(offset) is not types.IntType:
459 offset = 0
460 exc_value = '%s\n %s\n %s^' % (msg, line, ' ' * offset)
461 elif exc_type is not ImportError:
462 global _output
463 txt = _(" Caught exception importing module %s:\n") % moduleName
464 _output.AddLines(txt)
465
466 try:
467 tbinfo = traceback.extract_tb(tb)
468 except:
469 tbinfo = []
470 txt = _(" Unable to format traceback\n")
471 _output.AddLines(txt)
472 for filename, line, func, text in tbinfo[1:]:
473 txt = _(" File \"%s\", line %d") % (filename, line)
474 _output.AddLines(txt)
475 if func != "?":
476 txt = _(", in %s()") % func
477 _output.AddLines(txt)
478 _output.AddLines("\n")
479 if text:
480 txt = _(" %s\n") % text
481 _output.AddLines(txt)
482
483 # And finally print the exception type and value.
484 # Careful formatting exc_value -- can fail for some user exceptions
485 txt = " %s: " % exc_name
486 _output.AddLines(txt)
487 try:
488 txt = str(exc_value) + '\n'
489 _output.AddLines(txt)
490 except:
491 txt = _('**error formatting exception value**\n')
492 _output.AddLines(txt)
493
494
495 def _getPyFile(filename):
496 """Return the file and '.py' filename from a filename which could
497 end with .py, .pyc, or .pyo"""
498
499 if filename[-1] in 'oc' and filename[-4:-1] == '.py':
500 return filename[:-1]
501 return filename
502
503 class Module :
504 "Class to hold all information for a module"
505
506 def __init__(self, moduleName, check = 1, fullpath = None) :
507 self.moduleName = moduleName
508 self.variables = {}
509 self.functions = {}
510 self.classes = {}
511 self.modules = {}
512 self.moduleLineNums = {}
513 self.attributes = [ '__dict__' ]
514 self.main_code = None
515 self.module = None
516 self.check = check
517 self.fullpath = fullpath
518 _allModules[moduleName] = self
519
520 def __str__(self) :
521 return self.moduleName
522
523 __repr__ = utils.std_repr
524
525 def addVariable(self, var, varType) :
526 self.variables[var] = Variable(var, varType)
527
528 def addFunction(self, func) :
529 self.functions[func.__name__] = function.Function(func)
530
531 def __addAttributes(self, c, classObject) :
532 for base in classObject.__bases__ :
533 self.__addAttributes(c, base)
534 c.addMethods(classObject)
535 c.addMembers(classObject)
536
537 def addClass(self, name) :
538 self.classes[name] = c = Class(name, self.module)
539 try:
540 objName = str(c.classObject)
541 except TypeError:
542 # this can happen if there is a goofy __getattr__
543 c.ignoreAttrs = 1
544 else:
545 packages = string.split(objName, '.')
546 c.ignoreAttrs = packages[0] in cfg().blacklist
547 if not c.ignoreAttrs :
548 self.__addAttributes(c, c.classObject)
549
550 def addModule(self, name) :
551 module = _allModules.get(name, None)
552 if module is None :
553 self.modules[name] = module = Module(name, 0)
554 if imp.is_builtin(name) == 0 :
555 module.load()
556 else :
557 globalModule = globals().get(name)
558 if globalModule :
559 module.attributes.extend(dir(globalModule))
560 else :
561 self.modules[name] = module
562
563 def filename(self) :
564 try :
565 filename = self.module.__file__
566 except AttributeError :
567 filename = self.moduleName
568 return _getPyFile(filename)
569
570 def load(self, warnings = None):
571 try :
572 # there's no need to reload modules we already have
573 global _output, _statusDlg, _count
574 txt = _("Loading Module %s\n") % self.moduleName
575 _output.AddLines(txt)
576 _count += 1
577 if _count == 100:
578 _count = 95
579 _statusDlg.Update(_count, txt)
580
581 module = sys.modules.get(self.moduleName)
582 if module :
583 if not _allModules[self.moduleName].module :
584 return self._initModule(module)
585 return 1
586
587 return self._initModule(self.setupMainCode())
588 except (SystemExit, KeyboardInterrupt) :
589 exc_type, exc_value, exc_tb = sys.exc_info()
590 raise exc_type, exc_value
591 except SyntaxError, (message, (fileName, line, col, text)):
592 # ActiveGrid: added this for better feedback when module couldn't be loaded.
593 w = Warning(self.fullpath, line, _("Syntax Error: %s\n%s\n%s^error near here") % (message, text, ' '*(col-1)))
594 warnings.append(w)
595 return 0
596 except:
597 exc_type, exc_value, exc_tb = sys.exc_info()
598 w = Warning(self.moduleName, 1, "%s: %s.\nUnable to import module %s." % (exc_type, exc_value, self.moduleName))
599 warnings.append(w)
600 importError(self.moduleName)
601 return 0
602
603 def initModule(self, module) :
604 if not self.module:
605 filename = _getPyFile(module.__file__)
606 if string.lower(filename[-3:]) == '.py':
607 try:
608 file = open(filename)
609 except IOError:
610 pass
611 else:
612 self._setupMainCode(file, filename, module)
613 return self._initModule(module)
614 return 1
615
616 def _initModule(self, module):
617 self.module = module
618 self.attributes = dir(self.module)
619
620 pychecker_attr = getattr(module, Config.CHECKER_VAR, None)
621 if pychecker_attr is not None :
622 utils.pushConfig()
623 utils.updateCheckerArgs(pychecker_attr, 'suppressions', 0, [])
624
625 for tokenName in _filterDir(self.module, _DEFAULT_MODULE_TOKENS) :
626 token = getattr(self.module, tokenName)
627 if isinstance(token, types.ModuleType) :
628 # get the real module name, tokenName could be an alias
629 self.addModule(token.__name__)
630 elif isinstance(token, types.FunctionType) :
631 self.addFunction(token)
632 elif isinstance(token, types.ClassType) or \
633 hasattr(token, '__bases__') :
634 self.addClass(tokenName)
635 else :
636 self.addVariable(tokenName, type(token))
637
638 if pychecker_attr is not None :
639 utils.popConfig()
640 return 1
641
642 def setupMainCode(self) :
643 file, filename, smt = _findModule(self.moduleName)
644 # FIXME: if the smt[-1] == imp.PKG_DIRECTORY : load __all__
645 module = imp.load_module(self.moduleName, file, filename, smt)
646 self._setupMainCode(file, filename, module)
647 return module
648
649 def _setupMainCode(self, file, filename, module):
650 try :
651 self.main_code = function.create_from_file(file, filename, module)
652 finally :
653 if file != None :
654 file.close()
655
656
657 def getAllModules() :
658 "Returns a list of all modules that should be checked."
659 modules = []
660 for module in _allModules.values() :
661 if module.check :
662 modules.append(module)
663 return modules
664
665 _BUILTIN_MODULE_ATTRS = { 'sys': [ 'ps1', 'ps2', 'tracebacklimit',
666 'exc_type', 'exc_value', 'exc_traceback',
667 'last_type', 'last_value', 'last_traceback',
668 ],
669 }
670
671 def fixupBuiltinModules(needs_init=0):
672 for moduleName in sys.builtin_module_names :
673 if needs_init:
674 _ = Module(moduleName, 0)
675 module = _allModules.get(moduleName, None)
676 if module is not None :
677 try :
678 m = imp.init_builtin(moduleName)
679 except ImportError :
680 pass
681 else :
682 extra_attrs = _BUILTIN_MODULE_ATTRS.get(moduleName, [])
683 module.attributes = [ '__dict__' ] + dir(m) + extra_attrs
684
685
686 def _printWarnings(warnings, stream=None):
687 if stream is None:
688 stream = sys.stdout
689
690 warnings.sort()
691 lastWarning = None
692 for warning in warnings :
693 if lastWarning != None :
694 # ignore duplicate warnings
695 if cmp(lastWarning, warning) == 0 :
696 continue
697 # print blank line between files
698 if lastWarning.file != warning.file :
699 global _output
700 _output.AddLines("\n")
701
702 lastWarning = warning
703 _output.AddLines(warning.format() + "\n")
704
705
706 def processFiles(files, cfg = None, pre_process_cb = None) :
707 # insert this here, so we find files in the local dir before std library
708 if sys.path[0] != '' :
709 sys.path.insert(0, '')
710
711 # ensure we have a config object, it's necessary
712 global _cfg
713 if cfg is not None :
714 _cfg = cfg
715 elif _cfg is None :
716 _cfg = Config.Config()
717
718 warnings = []
719 utils.initConfig(_cfg)
720 for moduleName, filename in getModules(files) :
721 if callable(pre_process_cb) :
722 pre_process_cb(moduleName)
723 module = Module(moduleName, fullpath = filename)
724
725 # reload the given module, otherwise won't get new syntax errors.
726 sysModule = sys.modules.get(moduleName)
727 if sysModule:
728 try:
729 reload(sysModule)
730 except:
731 pass
732
733 module.load(warnings)
734 utils.popConfig()
735 return warnings
736
737
738 def getWarnings(files, cfg = None, suppressions = None):
739 warnings = processFiles(files, cfg)
740 fixupBuiltinModules()
741 return warnings + warn.find(getAllModules(), _cfg, suppressions)
742
743
744 def _print_processing(name) :
745 if not _cfg.quiet :
746 global _output, _statusDlg, _count
747 txt = _("Processing %s...\n") % name
748 _output.AddLines(txt)
749 _count += 1
750 _statusDlg.Update(_count, txt)
751
752
753
754 def checkSyntax(filename, messageView):
755 """ Massively hacked version of main for ActiveGrid IDE integration """
756 global _cfg
757 _cfg, files, suppressions = Config.setupFromArgs([filename])
758 if not files :
759 return 0
760
761 global _output, _statusDlg, _count
762 _output = messageView
763 # wxBug: Need to show progress dialog box, or message window never gets updated until the method returns
764 _statusDlg = wx.ProgressDialog(_("Check Code"), _("Checking %s") % filename, maximum = 100, style = wx.PD_AUTO_HIDE | wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME)
765 _count = 0
766
767 # insert this here, so we find files in the local dir before std library
768 if sys.path[0] != '' :
769 sys.path.insert(0, '')
770
771 importWarnings = processFiles(files, _cfg, _print_processing)
772 fixupBuiltinModules()
773 if _cfg.printParse :
774 for module in getAllModules() :
775 printer.module(module)
776
777 warnings = warn.find(getAllModules(), _cfg, suppressions)
778
779 _statusDlg.Update(100, _("Done"))
780 _statusDlg.Destroy()
781
782 if not _cfg.quiet :
783 _output.AddLines(_("\nWarnings and Errors...\n"))
784 if warnings or importWarnings :
785 _printWarnings(importWarnings + warnings)
786 return 1
787
788 if not _cfg.quiet :
789 _output.AddLines(_("No Syntax Errors"))
790 return 0
791
792 ##
793 ##
794 ##def main(argv) :
795 ## __pychecker__ = 'no-miximport'
796 ## import pychecker
797 ## if LOCAL_MAIN_VERSION != pychecker.MAIN_MODULE_VERSION :
798 ## sys.stderr.write(_VERSION_MISMATCH_ERROR)
799 ## sys.exit(100)
800 ##
801 ## # remove empty arguments
802 ## argv = filter(None, argv)
803 ##
804 ## # if the first arg starts with an @, read options from the file
805 ## # after the @ (this is mostly for windows)
806 ## if len(argv) >= 2 and argv[1][0] == '@':
807 ## # read data from the file
808 ## command_file = argv[1][1:]
809 ## try:
810 ## f = open(command_file, 'r')
811 ## command_line = f.read()
812 ## f.close()
813 ## except IOError, err:
814 ## sys.stderr.write("Unable to read commands from file: %s\n %s\n" % \
815 ## (command_file, err))
816 ## sys.exit(101)
817 ##
818 ## # convert to an argv list, keeping argv[0] and the files to process
819 ## argv = argv[:1] + string.split(command_line) + argv[2:]
820 ##
821 ## global _cfg
822 ## _cfg, files, suppressions = Config.setupFromArgs(argv[1:])
823 ## if not files :
824 ## return 0
825 ##
826 ## # insert this here, so we find files in the local dir before std library
827 ## sys.path.insert(0, '')
828 ##
829 ## importWarnings = processFiles(files, _cfg, _print_processing)
830 ## fixupBuiltinModules()
831 ## if _cfg.printParse :
832 ## for module in getAllModules() :
833 ## printer.module(module)
834 ##
835 ## warnings = warn.find(getAllModules(), _cfg, suppressions)
836 ## if not _cfg.quiet :
837 ## print "\nWarnings...\n"
838 ## if warnings or importWarnings :
839 ## _printWarnings(importWarnings + warnings)
840 ## return 1
841 ##
842 ## if not _cfg.quiet :
843 ## print "None"
844 ## return 0
845 ##
846 ##
847 ##if __name__ == '__main__' :
848 ## try :
849 ## sys.exit(main(sys.argv))
850 ## except Config.UsageError :
851 ## sys.exit(127)
852 ##
853 ##else :
854 ## _orig__import__ = None
855 ## _suppressions = None
856 ## _warnings_cache = {}
857 ##
858 ## def _get_unique_warnings(warnings):
859 ## for i in range(len(warnings)-1, -1, -1):
860 ## w = warnings[i].format()
861 ## if _warnings_cache.has_key(w):
862 ## del warnings[i]
863 ## else:
864 ## _warnings_cache[w] = 1
865 ## return warnings
866 ##
867 ## def __import__(name, globals=None, locals=None, fromlist=None):
868 ## if globals is None:
869 ## globals = {}
870 ## if locals is None:
871 ## locals = {}
872 ## if fromlist is None:
873 ## fromlist = []
874 ##
875 ## check = not sys.modules.has_key(name) and name[:10] != 'pychecker.'
876 ## pymodule = _orig__import__(name, globals, locals, fromlist)
877 ## if check :
878 ## try :
879 ## module = Module(pymodule.__name__)
880 ## if module.initModule(pymodule):
881 ## warnings = warn.find([module], _cfg, _suppressions)
882 ## _printWarnings(_get_unique_warnings(warnings))
883 ## else :
884 ## print 'Unable to load module', pymodule.__name__
885 ## except Exception:
886 ## name = getattr(pymodule, '__name__', str(pymodule))
887 ## importError(name)
888 ##
889 ## return pymodule
890 ##
891 ## def _init() :
892 ## global _cfg, _suppressions, _orig__import__
893 ##
894 ## args = string.split(os.environ.get('PYCHECKER', ''))
895 ## _cfg, files, _suppressions = Config.setupFromArgs(args)
896 ## utils.initConfig(_cfg)
897 ## fixupBuiltinModules(1)
898 ##
899 ## # keep the orig __import__ around so we can call it
900 ## import __builtin__
901 ## _orig__import__ = __builtin__.__import__
902 ## __builtin__.__import__ = __import__
903 ##
904 ## if not os.environ.get('PYCHECKER_DISABLED') :
905 ## _init()
906 ##