Ticket #13588: trac_13588_improve_libGAP.patch
File trac_13588_improve_libGAP.patch, 16.6 KB (added by , 10 years ago) 


sage/libs/gap/element.pxd
# HG changeset patch # User Volker Braun <vbraun@stp.dias.ie> # Date 1353350875 18000 # Node ID 92c1a501d20e6280ae830aa2adf9fe7ebd37d3fe # Parent 17f0eccc62ebd7e4819c4d6b5c36ca72bf7c5159 Improve error handling in libGAP diff git a/sage/libs/gap/element.pxd b/sage/libs/gap/element.pxd
a b 33 33 # the pointer to the GAP object (memory managed by GASMAN) 34 34 cdef libGAP_Obj value 35 35 36 # comparison 37 cdef bint _compare_by_id 38 cdef int _cmp_c_impl(self, Element other) except 2 39 cpdef _set_compare_by_id(self) 40 cpdef _assert_compare_by_id(self) 41 36 42 cdef _initialize(self, parent, libGAP_Obj obj) 37 cdef int _cmp_c_impl(self, Element other)38 43 cpdef ModuleElement _add_(self, ModuleElement right) 39 44 cpdef ModuleElement _sub_(self, ModuleElement right) 40 45 cpdef RingElement _mul_(self, RingElement right) 
sage/libs/gap/element.pyx
diff git a/sage/libs/gap/element.pyx b/sage/libs/gap/element.pyx
a b 243 243 1 244 244 """ 245 245 self.value = NULL 246 self._compare_by_id = False 246 247 247 248 248 249 def __init__(self): … … 259 260 sage: GapElement() 260 261 Traceback (most recent call last): 261 262 ... 262 TypeError: This class cannot be instantiated from Python263 TypeError: this class cannot be instantiated from Python 263 264 """ 264 raise TypeError(' This class cannot be instantiated from Python')265 raise TypeError('this class cannot be instantiated from Python') 265 266 266 267 267 268 cdef _initialize(self, parent, libGAP_Obj obj): … … 356 357 sage: lst.Adddddd(1) 357 358 Traceback (most recent call last): 358 359 ... 359 AttributeError: Name "Adddddd" is not defined in GAP.360 AttributeError: name "Adddddd" is not defined in GAP. 360 361 361 362 sage: libgap.eval('some_name := 1') 362 363 1 363 364 sage: lst.some_name 364 365 Traceback (most recent call last): 365 366 ... 366 AttributeError: Name "some_name" does not define a GAP function.367 AttributeError: name "some_name" does not define a GAP function. 367 368 """ 369 # print '__getattr__', name 370 if name in ('__dict__', '_getAttributeNames', '__custom_name', 'keys'): 371 raise AttributeError('Python special name, not a GAP function.') 368 372 try: 369 sig_on()370 373 proxy = make_GapElement_MethodProxy\ 371 374 (self.parent(), gap_eval(name), self) 372 sig_off() 373 except RuntimeError: 374 raise AttributeError, 'Name "'+str(name)+'" is not defined in GAP.' 375 except ValueError: 376 raise AttributeError('name "'+str(name)+'" is not defined in GAP.') 375 377 if not proxy.is_function(): 376 raise AttributeError , 'Name "'+str(name)+'" does not define a GAP function.'378 raise AttributeError('name "'+str(name)+'" does not define a GAP function.') 377 379 return proxy 378 380 379 381 380 def _ _repr__(self):382 def _repr_(self): 381 383 r""" 382 384 Return a string representation of ``self``. 383 385 … … 389 391 NULL 390 392 sage: libgap(0) 391 393 0 394 sage: libgap(0)._repr_() 395 '0' 392 396 """ 393 397 if self.value == NULL: 394 398 return 'NULL' … … 403 407 libgap_exit() 404 408 405 409 406 cdef int _cmp_c_impl(self, Element other): 410 cpdef _set_compare_by_id(self): 411 """ 412 Set comparison to compare by ``id`` 413 414 By default, GAP is used to compare libGAP objects. However, 415 this is not defined for all GAP objects. To have libGAP play 416 nice with ``UniqueRepresentation``, comparison must always 417 work. This method allows one to override the comparison to 418 sort by the (unique) Python ``id``. 419 420 Obviously it is a bad idea to change the comparison of objects 421 after you have inserted them into a set/dict. You also must 422 not mix libGAP objects with different sort methods in the same 423 container. 424 425 EXAMPLES:: 426 427 sage: F1 = libgap.FreeGroup(['a']) 428 sage: F2 = libgap.FreeGroup(['a']) 429 sage: F1 == F2 430 Traceback (most recent call last): 431 ... 432 ValueError: libGAP: cannot compare: Error, no method found! 433 Error, no 1st choice method found for `<' on 2 arguments 434 435 sage: F1._set_compare_by_id() 436 sage: F1 == F2 437 Traceback (most recent call last): 438 ... 439 ValueError: comparison style must be the same for both operands 440 441 sage: F1._set_compare_by_id() 442 sage: F2._set_compare_by_id() 443 sage: F1 == F2 444 False 445 """ 446 self._compare_by_id = True 447 448 449 cpdef _assert_compare_by_id(self): 450 """ 451 Ensure that comparison is by ``id`` 452 453 See :meth:`_set_compare_by_id`. 454 455 OUTPUT: 456 457 This method returns nothing. A ``ValueError`` is raised if 458 :meth:`_set_compare_by_id` has not been called on this libgap 459 object. 460 461 EXAMPLES:: 462 463 sage: x = libgap.FreeGroup(1) 464 sage: x._assert_compare_by_id() 465 Traceback (most recent call last): 466 ... 467 ValueError: requires a libGAP objects whose comparison is by "id" 468 469 sage: x._set_compare_by_id() 470 sage: x._assert_compare_by_id() 471 """ 472 if not self._compare_by_id: 473 raise ValueError('requires a libGAP objects whose comparison is by "id"') 474 475 476 cdef int _cmp_c_impl(self, Element other) except 2: 407 477 """ 408 478 Compare ``self`` with ``other``. 409 479 480 Uses the GAP comparison by default, or the Python ``id`` if 481 :meth:`_set_compare_by_id` was called. 482 410 483 OUTPUT: 411 484 412 Boolean. 485 `1`, `0`, or `+1` depending on the comparison value of 486 ``self`` and ``other``. Raises a ``ValueError`` if GAP does 487 not support comparison of ``self`` and ``other``, unless 488 :meth:`_set_compare_by_id` was called on both ``self`` and 489 ``other``. 413 490 414 491 EXAMPLES:: 415 492 … … 421 498 True 422 499 sage: a._cmp_(libgap(123)) 423 500 0 501 502 GAP does not have a comparison function for two ``FreeGroup`` 503 objects. LibGAP signals this by raising a ``ValueError`` :: 504 505 sage: F1 = libgap.FreeGroup(['a']) 506 sage: F2 = libgap.FreeGroup(['a']) 507 sage: F1 == F2 508 Traceback (most recent call last): 509 ... 510 ValueError: libGAP: cannot compare: Error, no method found! 511 Error, no 1st choice method found for `<' on 2 arguments 512 513 sage: F1._set_compare_by_id() 514 sage: F1 == F2 515 Traceback (most recent call last): 516 ... 517 ValueError: comparison style must be the same for both operands 518 519 sage: F1._set_compare_by_id() 520 sage: F2._set_compare_by_id() 521 sage: F1 == F2 522 False 424 523 """ 524 if self._compare_by_id != (<GapElement>other)._compare_by_id: 525 raise ValueError('comparison style must be the same for both operands') 526 if self._compare_by_id: 527 return cmp(id(self), id(other)) 425 528 cdef GapElement c_other = <GapElement>other 426 529 libgap_enter() 427 equal = libGAP_EQ(self.value, c_other.value) 428 if equal: 530 try: 531 sig_on() 532 equal = libGAP_EQ(self.value, c_other.value) 533 if equal: 534 sig_off() 535 return 0 536 less = libGAP_LT(self.value, c_other.value) 537 sig_off() 538 except RuntimeError, msg: 539 raise ValueError('libGAP: cannot compare: '+str(msg)) 540 finally: 429 541 libgap_exit() 430 return 0431 less = libGAP_LT(self.value, c_other.value)432 libgap_exit()433 542 return 1 if less else +1 434 543 435 544 … … 450 559 Traceback (most recent call last): 451 560 ... 452 561 ValueError: libGAP: Error, no method found! 453 For debugging hints type ?Recovery from NoMethodFound454 562 Error, no 1st choice method found for `+' on 2 arguments 455 563 """ 456 564 cdef libGAP_Obj result … … 461 569 sig_off() 462 570 except RuntimeError, msg: 463 571 libGAP_ClearError() 464 raise ValueError , 'libGAP: '+str(msg)572 raise ValueError('libGAP: '+str(msg)) 465 573 finally: 466 574 libgap_exit() 467 575 return make_any_gap_element(self.parent(), result) … … 483 591 sage: libgap(1)  libgap.CyclicGroup(2) 484 592 Traceback (most recent call last): 485 593 ... 486 ValueError: libGAP: Error, no method found! For debugging hints type ?Recovery from NoMethodFound594 ValueError: libGAP: Error, no method found! 487 595 Error, no 1st choice method found for `' on 2 arguments 488 596 """ 489 597 cdef libGAP_Obj result … … 516 624 sage: libgap(1) * libgap.CyclicGroup(2) 517 625 Traceback (most recent call last): 518 626 ... 519 ValueError: libGAP: Error, no method found! For debugging hints type ?Recovery from NoMethodFound627 ValueError: libGAP: Error, no method found! 520 628 Error, no 1st choice method found for `*' on 2 arguments 521 629 """ 522 630 cdef libGAP_Obj result … … 549 657 sage: libgap(1) / libgap.CyclicGroup(2) 550 658 Traceback (most recent call last): 551 659 ... 552 ValueError: libGAP: Error, no method found! For debugging hints type ?Recovery from NoMethodFound660 ValueError: libGAP: Error, no method found! 553 661 Error, no 1st choice method found for `/' on 2 arguments 554 662 555 663 sage: libgap(1) / libgap(0) … … 585 693 sage: libgap(1) % libgap.CyclicGroup(2) 586 694 Traceback (most recent call last): 587 695 ... 588 ValueError: libGAP: Error, no method found! For debugging hints type ?Recovery from NoMethodFound696 ValueError: libGAP: Error, no method found! 589 697 Error, no 1st choice method found for `mod' on 2 arguments 590 698 """ 591 699 cdef libGAP_Obj result … … 616 724 sage: libgap.CyclicGroup(2) ^ 2 617 725 Traceback (most recent call last): 618 726 ... 619 ValueError: libGAP: Error, no method found! For debugging hints type ?Recovery from NoMethodFound727 ValueError: libGAP: Error, no method found! 620 728 Error, no 1st choice method found for `^' on 2 arguments 621 729 622 730 sage: libgap(3) ^ Infinity … … 983 1091 raise ValueError('the GAP boolean value "fail" cannot be represented in Sage') 984 1092 985 1093 1094 def __nonzero__(self): 1095 """ 1096 Check that the boolean is "true". 1097 1098 This is syntactic sugar for using libgap. See the examples below. 1099 1100 OUTPUT: 1101 1102 Boolean. 1103 1104 EXAMPLES:: 1105 1106 sage: gap_bool = [libgap.eval('true'), libgap.eval('false'), libgap.eval('fail')] 1107 sage: for x in gap_bool: 1108 ... if x: # this calls __nonzero__ 1109 ... print x, type(x) 1110 true <type 'sage.libs.gap.element.GapElement_Boolean'> 1111 1112 sage: for x in gap_bool: 1113 ... if not x: # this calls __nonzero__ 1114 ... print x, type(x) 1115 false <type 'sage.libs.gap.element.GapElement_Boolean'> 1116 fail <type 'sage.libs.gap.element.GapElement_Boolean'> 1117 """ 1118 return self.value == libGAP_True 1119 1120 986 1121 ############################################################################ 987 1122 ### GapElement_String #################################################### 988 1123 ############################################################################ … … 1174 1309 sage: s(libgap(1), libgap(2)) 1175 1310 Traceback (most recent call last): 1176 1311 ... 1177 ValueError: libGAP: Error, no method found! For debugging hints type ?Recovery from NoMethodFound1312 ValueError: libGAP: Error, no method found! 1178 1313 Error, no 1st choice method found for `SumOp' on 2 arguments 1179 1314 1180 1315 sage: for i in range(0,100): … … 1241 1376 result = libGAP_CALL_XARGS(self.value, arg_list) 1242 1377 sig_off() 1243 1378 except RuntimeError, msg: 1244 raise ValueError , 'libGAP: '+str(msg)1379 raise ValueError('libGAP: '+str(msg)) 1245 1380 finally: 1246 1381 libgap_exit() 1247 1382 … … 1414 1549 sage: lst[10] 1415 1550 Traceback (most recent call last): 1416 1551 ... 1417 IndexError: Index out of range.1552 IndexError: index out of range. 1418 1553 """ 1419 1554 1420 1555 def __len__(self): … … 1456 1591 "first" 1457 1592 """ 1458 1593 if i<0 or i>=len(self): 1459 raise IndexError , 'Index out of range.'1594 raise IndexError('index out of range.') 1460 1595 return make_any_gap_element(self.parent(), 1461 1596 libGAP_ELM_PLIST(self.value, i+1)) 1462 1597 … … 1676 1811 result = libGAP_ELM_REC(self.value, i) 1677 1812 sig_off() 1678 1813 except RuntimeError, msg: 1679 raise IndexError , 'libGAP: '+str(msg)1814 raise IndexError('libGAP: '+str(msg)) 1680 1815 return make_any_gap_element(self.parent(), result) 1681 1816 1682 1817 
sage/libs/gap/util.pxd
diff git a/sage/libs/gap/util.pxd b/sage/libs/gap/util.pxd
a b 39 39 40 40 # To ensure that we call initialize_libgap only once. 41 41 cdef bint _gap_is_initialized = False 42 cdef voidinitialize()42 cdef initialize() 43 43 44 44 45 45 ############################################################################ 
sage/libs/gap/util.pyx
diff git a/sage/libs/gap/util.pyx b/sage/libs/gap/util.pyx
a b 160 160 gapdir = os.path.join(SAGE_LOCAL, 'gap', 'latest') 161 161 if os.path.exists(gapdir): 162 162 return gapdir 163 print 'The gap4.5.5.spkg (or later) seems to be missing!'163 print 'The gap4.5.5.spkg (or later) seems to be not installed!' 164 164 gap_sh = open(os.path.join(SAGE_LOCAL, 'bin', 'gap')).read().splitlines() 165 165 gapdir = filter(lambda dir:dir.strip().startswith('GAP_DIR'), gap_sh)[0] 166 166 gapdir = gapdir.split('"')[1] … … 168 168 return gapdir 169 169 170 170 171 cdef voidinitialize():171 cdef initialize(): 172 172 """ 173 173 Initialize the GAP library, if it hasn't already been 174 174 initialized. It is safe to call this multiple times. 175 176 INPUT: 177 178  ``max_workspace_size``  string. The size hint for GAP's memory 179 pool. Same syntax as GAP's ``o`` command line option. 180 175 181 176 TESTS:: 182 177 183 178 sage: libgap(123) # indirect doctest … … 194 189 argv[1] = "l" 195 190 s = gap_root() 196 191 argv[2] = s 197 192 193 from sage.interfaces.gap import get_gap_memory_pool_size 194 memory_pool = str(get_gap_memory_pool_size()) 198 195 argv[3] = "o" 199 import platform 200 if platform.architecture()[0] == '32bit': 201 argv[4] = "3900m" 202 else: 203 argv[4] = "16384G" 196 argv[4] = memory_pool 204 197 205 198 argv[5] = "m" 206 199 argv[6] = "64m" … … 209 202 argv[8] = "T" # no debug loop 210 203 argv[9] = NULL 211 204 cdef int argc = 9 205 206 # Initialize GAP and capture any error messages 207 # The initialization just prints error and does not use the error handler 208 libgap_start_interaction('') 212 209 libgap_initialize(argc, argv) 210 gap_error_msg = str(libgap_get_output()) 211 libgap_finish_interaction() 212 if gap_error_msg: 213 raise RuntimeError('libGAP initialization failed\n' + gap_error_msg) 214 215 # The error handler is called if a GAP evaluation fails, e.g. 1/0 213 216 libgap_set_error_handler(&error_handler) 214 libgap_enter()215 217 216 218 # Prepare global GAP variable to hold temporary GAP objects 217 219 global reference_holder 220 libgap_enter() 218 221 reference_holder = libGAP_GVarName("$SAGE_libgap_reference_holder") 222 libgap_exit() 219 223 220 224 # Finished! 221 libgap_exit()222 225 _gap_is_initialized = True 223 226 224 227 … … 325 328 The libgap error handler 326 329 327 330 We call ``abort()`` which causes us to jump back to the Sage 328 signal handler. 331 signal handler. Since we wrap libGAP C calls in ``sig_on`` / 332 ``sig_off`` blocks, this then jumps back to the ``sig_on`` and 333 raises a Python ``RuntimeError``. 329 334 """ 330 sig_str(msg) 335 # print 'error_handler:', msg 336 msg_py = msg 337 msg_py = msg_py.replace('For debugging hints type ?Recovery from NoMethodFound\n', '') 338 sig_str(msg_py) 331 339 abort() 332 340 sig_off() 333 341