File indexing completed on 2024-04-21 05:44:46
0001 # -*- coding: iso-8859-2 -*- 0002 # Aspell interface using ctypes. 0003 # $Date: 2007-04-07 14:27:33 $, $Revision: 1.3 $ 0004 # 0005 # This is straightforward translation of my 0006 # aspell-python, C extension. 0007 # 0008 # License: BSD 0009 # 0010 # author: Wojciech Muła 0011 # e-mail: wojciech_mula@poczta.onet.pl 0012 # www : http://wmula.republika.pl/proj/aspell-python/ 0013 # 0014 # TODO: add method to get/change **current** speller's config 0015 0016 try: 0017 import ctypes 0018 import ctypes.util 0019 except ImportError: 0020 raise ImportError("ctypes library is needed") 0021 0022 0023 class AspellError(Exception): pass 0024 class AspellConfigError(AspellError): pass 0025 class AspellSpellerError(AspellError): pass 0026 0027 0028 class AspellLinux(object): 0029 """ 0030 Aspell speller object. Allows to check spelling, get suggested 0031 spelling list, manage user dictionarias, and other. 0032 0033 Must be closed with 'close' method, or one may experience 0034 problems, like segfaults. 0035 """ 0036 0037 def __init__(self, configkeys=None, libname=None): 0038 """ 0039 Parameters: 0040 * configkeys - list of configuration parameters; 0041 each element is a pair key & value (both strings) 0042 if None, then default configuration is used 0043 * libname - explicity set aspell library name; 0044 if None then default name is used 0045 """ 0046 if libname is None: 0047 libname = ctypes.util.find_library('aspell') 0048 self.__lib = ctypes.CDLL(libname) 0049 0050 # Initialize speller 0051 0052 # 1. create configuration 0053 config = self.__lib.new_aspell_config() 0054 if config == None: 0055 raise AspellError("Can't create aspell config object") 0056 0057 # 2. parse configkeys arg. 0058 if configkeys is not None: 0059 assert type(configkeys) in [tuple, list], "Tuple or list expeced" 0060 if len(configkeys) == 2 and \ 0061 type(configkeys[0]) is str and \ 0062 type(configkeys[1]) is str: 0063 configkeys = [configkeys] 0064 0065 for key, value in configkeys: 0066 assert type(key) is str, "Key must be string" 0067 assert type(value) is str, "Value must be string" 0068 if not self.__lib.aspell_config_replace(config, key, value): 0069 raise self._aspell_config_error(config) 0070 0071 # 3. create speller 0072 possible_error = self.__lib.new_aspell_speller(config) 0073 self.__lib.delete_aspell_config(config) 0074 0075 if self.__lib.aspell_error_number(possible_error) != 0: 0076 self.__lib.delete_aspell_can_have_error(possible_error) 0077 raise AspellError("Can't create speller object") 0078 0079 self.__speller = self.__lib.to_aspell_speller(possible_error) 0080 0081 0082 def check(self, word): 0083 """ 0084 Check if word is present in main, personal or session 0085 dictionary. Boolean value is returned 0086 """ 0087 if type(word) is str: 0088 return bool( 0089 self.__lib.aspell_speller_check( 0090 self.__speller, 0091 word, 0092 len(word) 0093 )) 0094 else: 0095 raise TypeError("String expeced") 0096 0097 0098 def suggest(self, word): 0099 """ 0100 Return list of spelling suggestions of given word. 0101 Works even if word is correct. 0102 """ 0103 if type(word) is str: 0104 return self._aspellwordlist( 0105 self.__lib.aspell_speller_suggest( 0106 self.__speller, 0107 word, 0108 len(word) 0109 )) 0110 else: 0111 raise TypeError("String expeced") 0112 0113 0114 def personal_dict(self, word=None): 0115 """ 0116 Aspell's personal dictionary is a user defined, persistent 0117 list of word (saved in certain file). 0118 0119 If 'word' is not given, then method returns list of words stored in 0120 dict. If 'word' is given, then is added to personal dict. New words 0121 are not saved automatically, method 'save_all' have to be call. 0122 """ 0123 if word is not None: 0124 # add new word 0125 assert type(word) is str, "String expeced" 0126 self.__lib.aspell_speller_add_to_personal( 0127 self.__speller, 0128 word, 0129 len(word) 0130 ) 0131 self._aspell_check_error() 0132 else: 0133 # return list of words from personal dictionary 0134 return self._aspellwordlist( 0135 self.__lib.aspell_speller_personal_word_list(self.__speller) 0136 ) 0137 0138 0139 def session_dict(self, word=None, clear=False): 0140 """ 0141 Aspell's session dictionary is a user defined, volatile 0142 list of word, that is destroyed with aspell object. 0143 0144 If 'word' is None, then list of words from session dictionary 0145 is returned. If 'word' is present, then is added to dict. 0146 If 'clear' is True, then session dictionary is cleared. 0147 """ 0148 if clear: 0149 self.__lib.aspell_speller_clear_session(self.__speller) 0150 self._aspell_check_error() 0151 return 0152 0153 0154 if word is not None: 0155 # add new word 0156 assert type(word) is str, "String expeced" 0157 self.__lib.aspell_speller_add_to_session( 0158 self.__speller, 0159 word, 0160 len(word) 0161 ) 0162 self._aspell_check_error() 0163 else: 0164 # return list of words from personal dictionary 0165 return self._aspellwordlist( 0166 self.__lib.aspell_speller_session_word_list(self.__speller) 0167 ) 0168 0169 0170 def add_replacement_pair(self, misspelled, correct): 0171 """ 0172 Add replacement pair, i.e. pair of misspelled and correct 0173 word. It affects on order of words appear on list returned 0174 by 'suggest' method. 0175 """ 0176 assert type(misspelled) is str, "String is required" 0177 assert type(correct) is str, "String is required" 0178 0179 self.__lib.aspell_speller_store_replacement( 0180 self.__speller, 0181 misspelled, 0182 len(misspelled), 0183 correct, 0184 len(correct) 0185 ) 0186 self._aspell_check_error() 0187 0188 0189 def save_all(self): 0190 """ 0191 Saves all words added to personal or session dictionary to 0192 the apell's defined file. 0193 """ 0194 self.__lib.spell_speller_save_all_word_lists(self.__speller) 0195 self._aspell_check_error() 0196 0197 0198 def configkeys(self): 0199 """ 0200 Returns list of all available config keys that can be passed 0201 to contructor. 0202 0203 List contains a 3-tuples: 0204 1. key name 0205 2. default value of type: 0206 * bool 0207 * int 0208 * string 0209 * list of string 0210 3. short description 0211 if None, then this key is undocumented is should not 0212 be used, unless one know what really do 0213 """ 0214 0215 config = self.__lib.aspell_speller_config(self.__speller) 0216 if config is None: 0217 raise AspellConfigError("Can't get speller's config") 0218 0219 keys_enum = self.__lib.aspell_config_possible_elements(config, 1) 0220 if keys_enum is None: 0221 raise AspellError("Can't get list of config keys") 0222 0223 class KeyInfo(ctypes.Structure): 0224 _fields_ = [ 0225 ("name", ctypes.c_char_p), 0226 ("type", ctypes.c_int), 0227 ("default", ctypes.c_char_p), 0228 ("desc", ctypes.c_char_p), 0229 ("flags", ctypes.c_int), 0230 ("other_data", ctypes.c_int), 0231 ] 0232 0233 key_next = self.__lib.aspell_key_info_enumeration_next 0234 key_next.restype = ctypes.POINTER(KeyInfo) 0235 0236 list = [] 0237 while True: 0238 key_info = key_next(keys_enum) 0239 if not key_info: 0240 break 0241 else: 0242 key_info = key_info.contents 0243 0244 if key_info.type == 0: 0245 # string 0246 list.append(( 0247 key_info.name, 0248 key_info.default, 0249 key_info.desc, 0250 )) 0251 0252 elif key_info.type == 1: 0253 # integer 0254 list.append(( 0255 key_info.name, 0256 int(key_info.default), 0257 key_info.desc, 0258 )) 0259 elif key_info.type == 2: 0260 # boolean 0261 if key_info.default.lower() == 'true': 0262 list.append(( 0263 key_info.name, 0264 True, 0265 key_info.desc, 0266 )) 0267 else: 0268 list.append(( 0269 key_info.name, 0270 False, 0271 key_info.desc, 0272 )) 0273 elif key_info.type == 3: 0274 # list 0275 list.append(( 0276 key_info.name, 0277 key_info.default.split(), 0278 key_info.desc, 0279 )) 0280 0281 self.__lib.delete_aspell_key_info_enumeration(keys_enum) 0282 return list 0283 0284 0285 def close(self): 0286 """ 0287 Close aspell speller object. 0288 """ 0289 self.__lib.delete_aspell_speller(self.__speller) 0290 0291 0292 # XXX: internal function, do not call directly 0293 def _aspellwordlist(self, wordlist_id): 0294 """ 0295 XXX: internal function 0296 0297 Converts aspell list into python list. 0298 """ 0299 elements = self.__lib.aspell_word_list_elements(wordlist_id) 0300 list = [] 0301 while True: 0302 wordptr = self.__lib.aspell_string_enumeration_next(elements) 0303 if not wordptr: 0304 break 0305 else: 0306 word = ctypes.c_char_p(wordptr) 0307 list.append(word.value) 0308 0309 self.__lib.delete_aspell_string_enumeration(elements) 0310 return list 0311 0312 0313 def _aspell_config_error(self, config): 0314 """ 0315 XXX: internal function 0316 0317 Raise excpetion if operation of speller config 0318 caused an error. Additionaly destroy config object. 0319 """ 0320 # make exception object & copy error msg 0321 exc = AspellConfigError( 0322 ctypes.c_char_p( 0323 self.__lib.aspell_config_error_message(config) 0324 ).value 0325 ) 0326 0327 # then destroy config objcet 0328 self.__lib.delete_aspell_config(config) 0329 0330 # and then raise exception 0331 raise exc 0332 0333 0334 def _aspell_check_error(self): 0335 """ 0336 XXX: internal function 0337 0338 Raise exception if previous speller operation 0339 caused an error. 0340 """ 0341 if self.__lib.aspell_speller_error(self.__speller) != 0: 0342 msg = self.__lib.aspell_speller_error_message(self.__speller) 0343 raise AspellSpellerError(msg) 0344 #class 0345 0346 Aspell = AspellLinux 0347 0348 0349 if __name__ == '__main__': 0350 # TODO: more test cases 0351 a = Aspell(("lang", "en")) 0352 print(a.check("when")) 0353 print(a.suggest("wehn")) 0354 a.add_replacement_pair("wehn", "ween") 0355 print(a.suggest("wehn")) 0356 0357 print(a.session_dict()) 0358 print(a.check("pyaspell")) 0359 a.session_dict("pyaspell") 0360 print(a.session_dict()) 0361 print(a.check("pyaspell")) 0362 a.session_dict(clear=True) 0363 print(a.session_dict()) 0364 0365 a.close() 0366 0367 # vim: ts=4 sw=4