Package spade :: Module pyxf
[hide private]
[frames] | no frames]

Source Code for Module spade.pyxf

  1  __doc__ = ''' Python interface to XSB Prolog, SWI Prolog, ECLiPSe Prolog and Flora2 
  2   by Markus Schatten <markus_dot_schatten_at_foi_dot_hr> 
  3   Faculty of Organization and Informatics, 
  4   Varazdin, Croatia, 2011 
  5   
  6   This library is free software; you can redistribute it and/or 
  7   modify it under the terms of the GNU Lesser General Public 
  8   License as published by the Free Software Foundation; either 
  9   version 2.1 of the License, or (at your option) any later version. 
 10   
 11   This library is distributed in the hope that it will be useful, 
 12   but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 14   Lesser General Public License for more details. 
 15   
 16   You should have received a copy of the GNU Lesser General Public 
 17   License along with this library; if not, write to the Free Software 
 18   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA''' 
 19   
 20  __version__ = '1.0.1' 
 21   
 22  import pexpect as px 
 23  import re 
 24   
 25  xsbprompt = '[|][ ][?][-][ ]' 
 26  xsberror = '[+][+]Error.*' 
 27   
 28  var_re = re.compile( '[^a-zA-Z0-9_]([A-Z][a-zA-Z0-9_]*)' ) 
 29  res_re = re.compile( "res[\(]'([A-Z][a-zA-Z0-9_]*)',[ ]?(.*)[\)]" ) 
 30   
31 -class XSBExecutableNotFound( Exception ):
32 '''Exception raised if XSB executable is not found on the specified path.''' 33 pass
34
35 -class XSBCompileError( Exception ):
36 '''Exception raised if loaded module has compile errors.''' 37 pass 38
39 -class XSBQueryError( Exception ):
40 '''Exception raised if query raises an error.''' 41 pass 42
43 -class xsb:
44 '''Python interface to XSB Prolog (http://xsb.sf.net)'''
45 - def __init__( self, path='xsb', args='--nobanner --quietload' ):
46 '''Constructor method 47 Usage: xsb( path, args ) 48 path - path to XSB executable (default: 'xsb') 49 args - command line arguments (default: '--nobanner --quietload') 50 51 self.engine becomes pexpect spawn instance of XSB Prolog shell 52 53 Raises: XSBExecutableNotFound''' 54 try: 55 self.engine = px.spawn( path + ' ' + args, timeout=5 ) 56 self.engine.expect( xsbprompt ) 57 except px.ExceptionPexpect: 58 raise XSBExecutableNotFound, 'XSB executable not found on the specified path. Try using xsb( "/path/to/XSB/bin/xsb" )'
59
60 - def load( self, module ):
61 '''Loads module into self.engine 62 Usage: instance.load( path ) 63 path - path to module file 64 65 Raises: XSBCompileError''' 66 self.engine.sendline( "['" + module + "']." ) 67 index = self.engine.expect( [ xsbprompt, xsberror ] ) 68 if index == 1: 69 raise XSBCompileError, 'Error while compiling module "' + module + '". Error from XSB:\n' + self.engine.after
70
71 - def query( self, query ):
72 '''Queries current engine state 73 Usage: instance.query( query ) 74 query - usual XSB Prolog query (example: 'likes( X, Y )') 75 76 Returns: 77 True - if yes/no query and answer is yes 78 False - if yes/no query and answer is no 79 List of dictionaries - if normal query. Dictionary keys are returned 80 variable names. Example: 81 >>> instance.query( 'likes( Person, Food )' ) 82 [{'Person': 'john', 'Food': 'curry'}, {'Person': 'sandy', 'Food': 'mushrooms'}] 83 84 Raises: XSBQueryError''' 85 query = query.strip() 86 if query[ -1 ] != '.': 87 query += '.' 88 lvars = var_re.findall( query ) 89 lvars = list( set( lvars ) ) 90 if lvars == []: # yes/no query (no variables) 91 self.engine.sendline( query ) 92 index = self.engine.expect( [ xsbprompt, xsberror ] ) 93 if index == 1: 94 raise XSBQueryError, 'Error while executing query "' + query + '". Error from XSB:\n' + self.engine.after 95 else: 96 if 'yes' in self.engine.before: 97 return True 98 else: 99 return False 100 else: # normal query 101 printer = self._printer( lvars, query ) 102 self.engine.sendline( printer ) 103 index = self.engine.expect( [ xsberror, xsbprompt ] ) 104 if index == 0: 105 raise XSBQueryError, 'Error while executing query "' + query + '". Error from XSB:\n' + self.engine.after 106 else: 107 res = res_re.findall( self.engine.before.split( ',nl,fail.\n' )[ -1 ] ) 108 results = [] 109 counter = 0 110 temp = [] 111 for i in res: 112 counter += 1 113 temp.append( i ) 114 if counter % len( lvars ) == 0: 115 results.append( dict( temp ) ) 116 temp = [] 117 if results == []: 118 return False 119 return results
120
121 - def _printer( self, lvars, query ):
122 '''Private method for constructing a result printing query. 123 Usage: instance._printer( lvars, query ) 124 lvars - list of logical variables to print 125 query - query containing the variables to be printed 126 127 Returns: string of the form 'query, writeln( res( 'VarName1', VarName1 ) ) ... writeln( res( 'VarNameN', VarNameN ) ),nl,fail.' 128 ''' 129 query = query[ :-1 ] 130 elems = [ "writeln( res('''" + i + "'''," + i + ") )" for i in lvars ] 131 printer = query + ',' + ','.join( elems ) + ',nl,fail.' 132 return printer
133 134 swiprompt = '[?][-][ ]' 135 swierror = 'ERROR.*' 136
137 -class SWIExecutableNotFound( Exception ):
138 '''Exception raised if SWI-Prolog executable is not found on the specified path.''' 139 pass
140
141 -class SWICompileError( Exception ):
142 '''Exception raised if loaded module has compile errors.''' 143 pass 144
145 -class SWIQueryError( Exception ):
146 '''Exception raised if query raises an error.''' 147 pass 148
149 -class swipl:
150 '''Python interface to SWI Prolog (http://www.swi-prolog.org)'''
151 - def __init__( self, path='swipl', args='-q +tty' ):
152 '''Constructor method 153 Usage: swipl( path, args ) 154 path - path to SWI executable (default: 'swipl') 155 args - command line arguments (default: '-q +tty') 156 157 self.engine becomes pexpect spawn instance of SWI Prolog shell 158 159 Raises: SWIExecutableNotFound''' 160 try: 161 self.engine = px.spawn( path + ' ' + args, timeout=5 ) 162 self.engine.expect( swiprompt ) 163 except px.ExceptionPexpect: 164 raise SWIExecutableNotFound, 'SWI-Prolog executable not found on the specified path. Try installing swi-prolog or using swipl( "/path/to/swipl" )'
165
166 - def load( self, module ):
167 '''Loads module into self.engine 168 Usage: instance.load( path ) 169 path - path to module file 170 171 Raises: SWICompileError''' 172 self.engine.sendline( "['" + module + "']." ) 173 index = self.engine.expect( [ swierror, swiprompt ] ) 174 if index == 0: 175 raise SWICompileError, 'Error while compiling module "' + module + '". Error from SWI:\n' + self.engine.after
176
177 - def query( self, query ):
178 '''Queries current engine state 179 Usage: instance.query( query ) 180 query - usual SWI Prolog query (example: 'likes( X, Y )') 181 182 Returns: 183 True - if yes/no query and answer is yes 184 False - if yes/no query and answer is no 185 List of dictionaries - if normal query. Dictionary keys are returned 186 variable names. Example: 187 >>> instance.query( 'likes( Person, Food )' ) 188 [{'Person': 'john', 'Food': 'curry'}, {'Person': 'sandy', 'Food': 'mushrooms'}] 189 190 Raises: SWIQueryError''' 191 query = query.strip() 192 if query[ -1 ] != '.': 193 query += '.' 194 lvars = var_re.findall( query ) 195 lvars = list( set( lvars ) ) 196 if lvars == []: # yes/no query (no variables) 197 self.engine.sendline( query ) 198 index = self.engine.expect( [ swiprompt, swierror ] ) 199 if index == 1: 200 raise SWIQueryError, 'Error while executing query "' + query + '". Error from SWI:\n' + self.engine.after 201 else: 202 if 'true' in self.engine.before: 203 return True 204 else: 205 return False 206 else: # normal query 207 printer = self._printer( lvars, query ) 208 self.engine.sendline( printer ) 209 index = self.engine.expect( [ swierror, swiprompt ] ) 210 if index == 0: 211 raise SWIQueryError, 'Error while executing query "' + query + '". Error from SWI:\n' + self.engine.after 212 else: 213 res = res_re.findall( self.engine.before.split( ',nl,fail.\n' )[ -1 ] ) 214 results = [] 215 counter = 0 216 temp = [] 217 for i in res: 218 counter += 1 219 temp.append( i ) 220 if counter % len( lvars ) == 0: 221 results.append( dict( temp ) ) 222 temp = [] 223 if results == []: 224 return False 225 return results
226
227 - def _printer( self, lvars, query ):
228 '''Private method for constructing a result printing query. 229 Usage: instance._printer( lvars, query ) 230 lvars - list of logical variables to print 231 query - query containing the variables to be printed 232 233 Returns: string of the form 'query, writeln( res( 'VarName1', VarName1 ) ) ... writeln( res( 'VarNameN', VarNameN ) ),nl,fail.' 234 ''' 235 query = query[ :-1 ] 236 elems = [ "writeln( res('''" + i + "'''," + i + ") )" for i in lvars ] 237 printer = query + ',' + ','.join( elems ) + ',nl,fail.' 238 return printer
239 240 eclipseprompt = '[\[]eclipse [0-9]+[\]][:] ' 241 eclipseerror = 'Abort.*' 242
243 -class ECLiPSeExecutableNotFound( Exception ):
244 '''Exception raised if ECLiPSe-Prolog executable is not found on the specified path.''' 245 pass
246
247 -class ECLiPSeCompileError( Exception ):
248 '''Exception raised if loaded module has compile errors.''' 249 pass 250
251 -class ECLiPSeQueryError( Exception ):
252 '''Exception raised if query raises an error.''' 253 pass 254
255 -class eclipse:
256 '''Python interface to ECLiPSe Prolog (http://eclipseclp.org)'''
257 - def __init__( self, path='eclipse', args='' ):
258 '''Constructor method 259 Usage: eclipse( path, args ) 260 path - path to ECLiPSe executable (default: 'eclipse') 261 args - command line arguments (default: '') 262 263 self.engine becomes pexpect spawn instance of ECLiPSe Prolog shell 264 265 Raises: ECLiPSeExecutableNotFound''' 266 try: 267 self.engine = px.spawn( path + ' ' + args, timeout=5 ) 268 except px.ExceptionPexpect: 269 raise ECLiPSeExecutableNotFound, 'ECLiPSe Prolog executable not found on the specified path.' 270 self.engine.expect( eclipseprompt )
271
272 - def load( self, module ):
273 '''Loads module into self.engine 274 Usage: instance.load( path ) 275 path - path to module file 276 277 Raises: ECLiPSeCompileError''' 278 self.engine.sendline( "['" + module + "']." ) 279 index = self.engine.expect( [ eclipseerror, eclipseprompt ] ) 280 if index == 0: 281 raise ECLiPSeCompileError, 'Error while compiling module "' + module + '". Error from ECLiPSe:\n' + self.engine.after
282
283 - def query( self, query ):
284 '''Queries current engine state 285 Usage: instance.query( query ) 286 query - usual ECLiPSe Prolog query (example: 'likes( X, Y )') 287 288 Returns: 289 True - if yes/no query and answer is yes 290 False - if yes/no query and answer is no 291 List of dictionaries - if normal query. Dictionary keys are returned 292 variable names. Example: 293 >>> instance.query( 'likes( Person, Food )' ) 294 [{'Person': 'john', 'Food': 'curry'}, {'Person': 'sandy', 'Food': 'mushrooms'}] 295 296 Raises: ECLiPSeQueryError''' 297 query = query.strip() 298 if query[ -1 ] != '.': 299 query += '.' 300 lvars = var_re.findall( query ) 301 lvars = list( set( lvars ) ) 302 if lvars == []: # yes/no query (no variables) 303 self.engine.sendline( query ) 304 index = self.engine.expect( [ eclipseprompt, eclipseerror ] ) 305 if index == 1: 306 raise ECLiPSeQueryError, 'Error while executing query "' + query + '". Error from ECLiPSe:\n' + self.engine.after 307 else: 308 if 'Yes' in self.engine.before: 309 return True 310 else: 311 return False 312 else: # normal query 313 printer = self._printer( lvars, query ) 314 self.engine.sendline( printer ) 315 index = self.engine.expect( [ eclipseerror, eclipseprompt ] ) 316 if index == 0: 317 raise ECLiPSeQueryError, 'Error while executing query "' + query + '". Error from ECLiPSe:\n' + self.engine.after 318 else: 319 res = res_re.findall( self.engine.before.split( ',nl,fail.\n' )[ -1 ] ) 320 results = [] 321 counter = 0 322 temp = [] 323 for i in res: 324 counter += 1 325 temp.append( i ) 326 if counter % len( lvars ) == 0: 327 results.append( dict( temp ) ) 328 temp = [] 329 if results == []: 330 return False 331 return results
332
333 - def _printer( self, lvars, query ):
334 '''Private method for constructing a result printing query. 335 Usage: instance._printer( lvars, query ) 336 lvars - list of logical variables to print 337 query - query containing the variables to be printed 338 339 Returns: string of the form 'query, writeln( res( 'VarName1', VarName1 ) ) ... writeln( res( 'VarNameN', VarNameN ) ),nl,fail.' 340 ''' 341 query = query[ :-1 ] 342 elems = [ "writeln( res('\\'" + i + "\\''," + i + ") )" for i in lvars ] 343 printer = query + ',' + ','.join( elems ) + ',nl,fail.' 344 return printer
345 346 flora2prompt = 'flora2 [?][-][ ]' 347 flora2error = '[+][+]Error.*' 348 349 fvar_re = re.compile( '[?][a-zA-Z0-9][a-zA-Z0-9_]*' ) 350 fres_re = re.compile( "[?]([a-zA-Z0-9_]*) [=] ([^\r]+)" ) 351 352
353 -class Flora2ExecutableNotFound( Exception ):
354 '''Exception raised if Flora2 executable is not found on the specified path.''' 355 pass
356
357 -class Flora2CompileError( Exception ):
358 '''Exception raised if loaded module has compile errors.''' 359 pass 360
361 -class Flora2QueryError( Exception ):
362 '''Exception raised if query raises an error.''' 363 pass 364
365 -class flora2:
366 '''Python interface to Flora2 (http://flora.sf.net)'''
367 - def __init__( self, path='runflora', args='--nobanner --quietload' ):
368 '''Constructor method 369 Usage: flora2( path, args ) 370 path - path to Flora2 executable (default: 'runflora') 371 args - command line arguments (default: '--nobanner --quietload') 372 373 self.engine becomes pexpect spawn instance of Flora2 shell 374 375 Raises: SWIExecutableNotFound''' 376 try: 377 self.engine = px.spawn( path + ' ' + args, timeout=5 ) 378 self.engine.expect( flora2prompt ) 379 self.engine.expect( flora2prompt ) 380 except px.ExceptionPexpect: 381 raise Flora2ExecutableNotFound, 'Flora-2 executable not found on the specified path. Try using flora2( "/path/to/flora2/runflora" )'
382
383 - def load( self, module ):
384 '''Loads module into self.engine 385 Usage: instance.load( path ) 386 path - path to module file 387 388 Raises: Flora2CompileError''' 389 self.engine.sendline( "['" + module + "']." ) 390 index = self.engine.expect( [ flora2prompt, flora2error ] ) 391 if index == 1: 392 raise Flora2CompileError, 'Error while compiling module "' + module + '". Error from Flora2:\n' + self.engine.after
393
394 - def query( self, query ):
395 '''Queries current engine state 396 Usage: instance.query( query ) 397 query - usual Flora2 query (example: '?x[ likes->?y ]') 398 399 Returns: 400 True - if yes/no query and answer is yes 401 False - if yes/no query and answer is no 402 List of dictionaries - if normal query. Dictionary keys are returned 403 variable names. Example: 404 >>> instance.query( '?person[ likes->?food ]' ) 405 [{'person': 'john', 'food': 'curry'}, {'person': 'sandy', 'food': 'mushrooms'}] 406 407 Raises: Flora2QueryError''' 408 query = query.strip() 409 if query[ -1 ] != '.': 410 query += '.' 411 lvars = fvar_re.findall( query ) 412 lvars = list( set( lvars ) ) 413 if lvars == []: # yes/no query (no variables) 414 self.engine.sendline( query ) 415 index = self.engine.expect( [ flora2prompt, flora2error ] ) 416 if index == 1: 417 raise Flora2QueryError, 'Error while executing query "' + query + '". Error from Flora2:\n' + self.engine.after 418 else: 419 if 'Yes' in self.engine.before: 420 return True 421 else: 422 return False 423 else: # normal query 424 self.engine.sendline( query ) 425 index = self.engine.expect( [ flora2error, flora2prompt ] ) 426 if index == 0: 427 raise Flora2QueryError, 'Error while executing query "' + query + '". Error from Flora2:\n' + self.engine.after 428 else: 429 res = fres_re.findall( self.engine.before ) 430 results = [] 431 counter = 0 432 temp = [] 433 for i in res: 434 counter += 1 435 temp.append( i ) 436 if counter % len( lvars ) == 0: 437 results.append( dict( temp ) ) 438 temp = [] 439 return results
440 441 if __name__ == '__main__': 442 x = xsb() 443 x.load( '../test/logic/test_xsb' ) 444 print x.query( 'dislikes( john, mushrooms )' ) 445 print x.query( 'likes( Person, Food )' ) 446 del x 447 448 print "=======" 449 450 s = swipl() 451 s.load( '../test/logic/test_swi' ) 452 print s.query( 'dislikes( john, mushrooms )' ) 453 print s.query( 'likes( Person, Food )' ) 454 del s 455 456 e = eclipse() 457 e.load( '../test/logic/test_eclipse' ) 458 print e.query( 'dislikes( john, mushrooms )' ) 459 print e.query( 'likes( Person, Food )' ) 460 del e 461 462 f = flora2() 463 f.load( '../test/logic/test_flora' ) 464 print f.query( 'john[ dislikes->mushrooms ]' ) 465 print f.query( '?person[ likes->?food ]' ) 466 del f 467