[pygccxml-commit] SF.net SVN: pygccxml: [417] pydsc_dev
Brought to you by:
mbaas,
roman_yakovenko
From: <rom...@us...> - 2006-08-17 03:44:41
|
Revision: 417 Author: roman_yakovenko Date: 2006-08-16 20:44:31 -0700 (Wed, 16 Aug 2006) ViewCVS: http://svn.sourceforge.net/pygccxml/?rev=417&view=rev Log Message: ----------- moving pydsc.py one directory up, for setup.py script Added Paths: ----------- pydsc_dev/pydsc.py Removed Paths: ------------- pydsc_dev/pydsc/ Copied: pydsc_dev/pydsc.py (from rev 415, pydsc_dev/pydsc/pydsc.py) =================================================================== --- pydsc_dev/pydsc.py (rev 0) +++ pydsc_dev/pydsc.py 2006-08-17 03:44:31 UTC (rev 417) @@ -0,0 +1,272 @@ +# Copyright 2004 Roman Yakovenko. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +""" +Python Documentation Spell Checker. + +The pydsc module contains functionality needed to check documentation strings +and comments for spelling errors, within Python code. The pydsc module depends +on PyEnchant spell checker. PyEnchant provides interface for different spell +engines: + * ispell + * aspell + * OpenOffice + +The use of the pydsc module is very simple - just import pydsc and all modules +that will be imported after it will be checked. By default all spelling errors +will be printed to sys.stdout. The pydsc checker could be customized in many +different ways: + * you can define set of files/directories that should be included/excluded + from check process + * you can redefine error messages destination + * you can redefine and/or re-configurate spell checker + +Install: +python setup.py install + +Usage example: + +import pydsc +import readline #errors will be printed to standart output + +more complex example ( taken from pygccxml project ): + +import pydsc +#test only pygccxml +#package_directory defined earlier +pydsc.doc_checker.filter.append( package_directory ) +pydsc.doc_checker.filter_type = pydsc.FILTER_TYPE.INCLUDE +# +map( pydsc.doc_checker.speller.ignore_always + , [ 'org' + , 'http' + , 'bool' + , 'str' + , 'www' + , 'param' + , 'txt' + , 'decl' + , 'decls' + , 'namespace' + , 'enum' + , 'const' + , 'GCC' + , 'xcc' + , 'TODO' + , 'typedef' + , 'os' + , 'normcase' + , 'normpath' ] ) + +""" + +__version__ = '0.1' +__author__ = 'Roman Yakovenko <rom...@gm...>' +__url__ = 'http://sourceforge.net/projects/pygccxml/' +__license__ = 'Boost Software License <http://boost.org/more/license_info.html>' + +import os +import sys +import pprint +import inspect +import __builtin__ +from enchant import checker + + +#TODO: source code encoding +# -*- coding: encoding -*- +# -*- coding: iso-8859-15 -*- + +def normalize_path( some_path ): + """return os.path.normcase( os.path.normpath( some_path ) )""" + return os.path.normcase( os.path.normpath( some_path ) ) + +class filter_by_path_t: + class FILTER_TYPE: + """defines few filter constants""" + INCLUDE = 'include' + EXCLUDE = 'exclude' + + def __init__( self, what, ftype ): + self.what = what + if None is self.what: + self.what = [] + elif isinstance( self.what, str ): + self.what = [self.what] + self.what = map( normalize_path, self.what ) + self.ftype = ftype + + @staticmethod + def contains_parent_dir( path, dirs ): + """ + returns true if one of the directories is root directory for the path, + false otherwise + + @param path: path + @type path: str + + @param dirs: list of directories and\\or files + @type dirs: [ str ] + + @return: bool + """ + #precondition: dirs and fpath should be normalize_path'ed before calling this function + return bool( filter( lambda dir: path.startswith( dir ), dirs ) ) + + def check( self, source_file ): + source_file = normalize_path( source_file ) + if source_file in self.what or self.contains_parent_dir( source_file, self.what ): + return self.ftype == self.FILTER_TYPE.INCLUDE + else: + return self.ftype == self.FILTER_TYPE.EXCLUDE + +def exclude( what ): + return filter_by_path_t( what, filter_t.FILTER_TYPE.EXCLUDE ) + +def include( what ): + return filter_by_path_t( what, filter_t.FILTER_TYPE.INCLUDE ) + + +class checker_t( object ): + """ + applies spell check process on every imported module + + This is the main class of this module. This class applies spell check + process on every imported module. Every documentation string within the + module will be checked. Some comments will be checked too. You should read + inspect module documentation, in order to find out which comments will be + checked. + """ + + def __init__( self + , speller + , writer=None + , filter=None + , ignore_identifiers=True ): + """ + initialization method + + During this method, reference to __builtin__.__import__ function is + saved in one of the members of the class, and replaced with import_ + member function. + + @param speller: reference to enchant.checker.SpellChecker object + @type speller: enchant.checker.SpellChecker + + @param writer: reference to instance of class that has write method. + By default sys.stdout will be used. + + @param filter: list of files or directories + @type filter: [ str ] + + @param filter_type: provides interpretation for content of filter parameter + @type filter_type: L{FILTER_TYPE} + + @param ignore_identifiers: often comments/documentation strings contains + class\\method\\function names. Those names, + usually introduce spell error. If ignore_identifiers + set to True, those names will be ignored. + @type ignore_identifiers: bool + """ + object.__init__( self ) + self.__checked = set() + self.__orig_import = __builtin__.__import__ + __builtin__.__import__ = self.import_ + self.__already_imported = set( sys.modules.keys() ) + self.__checked = set() + self.speller = speller + self.writer = writer + if self.writer is None: + self.writer = sys.stdout + self.filter = filter + self.identifiers = set() + self.ignore_identifiers = ignore_identifiers + + def should_be_checked( self, obj, module=None ): + if id(obj) in self.__checked: + return False + if inspect.isbuiltin( obj ): + return False + if inspect.ismodule( obj ): + if obj.__name__ in self.__already_imported: + return False #do not check already imported modules + if self.filter: + try: + source_file = inspect.getsourcefile(obj) + if source_file is None: + source_file = inspect.getfile( obj ) + return self.filter.check( source_file ) + except TypeError: + return False #built in module + else: + return True + obj_module = inspect.getmodule( obj ) + if not obj_module is module: + return False + if inspect.isclass( obj ) \ + or inspect.ismethod( obj ) \ + or inspect.isfunction( obj ) \ + or inspect.isroutine( obj ) \ + or inspect.ismethoddescriptor( obj ) \ + or inspect.isdatadescriptor( obj ): + return True + return False + + def import_( self, name, globals=None, locals=None, fromlist=None ): + pymodule = self.__orig_import( name, globals, locals, fromlist ) + if self.should_be_checked(pymodule): + #write = self.writer.write + #write( 'inspecting %s%s' % ( inspect.getsourcefile( pymodule ), os.linesep ) ) + self.__already_imported.add( name ) + self.check( pymodule ) + #write( 'inspecting %s done%s' % ( inspect.getsourcefile( pymodule ), os.linesep ) ) + return pymodule + + def __check_text_impl( self, obj, text, text_type ): + if not text: + return + if self.ignore_identifiers and hasattr( obj, '__name__' ) and obj.__name__: + self.identifiers.add( obj.__name__ ) + errors = {} + self.speller.set_text( text ) + for error in self.speller: + if error.word in self.identifiers: + continue + if not errors.has_key( error.word ): + errors[ error.word ] = [] + errors[ error.word ] = self.speller.suggest() + if not errors: + return + write = self.writer.write + if inspect.getsourcefile( inspect.getmodule( obj ) ): + write( ' error details: %s' % os.linesep ) + write( ' file : %s%s' % ( inspect.getsourcefile( inspect.getmodule( obj ) ), os.linesep ) ) + write( ' line : %d%s' % ( inspect.getsourcelines( obj )[1], os.linesep ) ) + write( ' text type : %s%s' % ( text_type, os.linesep ) ) + else: + write( ' error details: %s' % os.linesep ) + write( ' text type : %s%s' % ( text_type, os.linesep ) ) + for word, suggestions in errors.items(): + write( ' misspelled word: %s%s' % ( word, os.linesep ) ) + write( ' suggestions : %s%s' % ( `suggestions`, os.linesep ) ) + + def check_text( self, obj): + self.__check_text_impl( obj, inspect.getdoc( obj ), 'documentation string' ) + if inspect.getsourcefile( obj ): + self.__check_text_impl( obj, inspect.getcomments( obj ), 'comment' ) + + def check( self, module ): + self.check_text( module ) + to_be_checked = map( lambda x: x[1], inspect.getmembers( module ) ) + while to_be_checked: + member = to_be_checked.pop(0) + if not self.should_be_checked( member, module ): + continue + self.check_text( member ) + to_be_checked.extend( map( lambda x: x[1], inspect.getmembers( member ) ) ) + self.__checked.add( id(member) ) + +"""documentation spell checker instance""" +doc_checker = checker_t( checker.SpellChecker( "en_US" ) ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |