1""" 2Test the 'with gil:' statement. 3""" 4 5cimport cython 6from cpython.ref cimport PyObject 7 8import sys 9 10 11def redirect_stderr(func, *args, **kwargs): 12 """ 13 Helper function that redirects stderr to stdout for doctest. 14 """ 15 stderr, sys.stderr = sys.stderr, sys.stdout 16 func(*args, **kwargs) 17 sys.stderr = stderr 18 19cdef void puts(char *string) with gil: 20 """ 21 We need this for doctest, used from nogil sections. 22 """ 23 print string.decode('ascii') 24 25class ExceptionWithMsg(Exception): 26 """ 27 In python2.4 Exception is formatted as <exceptions.Exception 28 instance at 0x1b8f948> when swallowed. 29 """ 30 31 def __repr__(self): 32 return "ExceptionWithMsg(%r)" % self.args 33 34 35# Start with some normal Python functions 36 37def test_simple(): 38 """ 39 >>> test_simple() 40 ['spam', 'ham'] 41 """ 42 with nogil: 43 with gil: 44 print ['spam', 'ham'] 45 46def test_nested_gil_blocks(): 47 """ 48 >>> test_nested_gil_blocks() 49 entered outer nogil section 50 entered outer gil section 51 entered inner nogil section 52 entered inner gil section 53 leaving inner gil section 54 leaving inner nogil section 55 leaving outer gil section 56 leaving outer nogil section 57 """ 58 59 with nogil: 60 puts("entered outer nogil section") 61 62 with gil: 63 print 'entered outer gil section' 64 65 with nogil: 66 puts("entered inner nogil section") 67 with gil: 68 print 'entered inner gil section' 69 print 'leaving inner gil section' 70 puts("leaving inner nogil section") 71 72 print "leaving outer gil section" 73 puts("leaving outer nogil section") 74 75def test_propagate_exception(): 76 """ 77 >>> test_propagate_exception() 78 Traceback (most recent call last): 79 ... 80 Exception: This exception propagates! 81 """ 82 # Note, doctest doesn't support both output and exceptions 83 with nogil: 84 with gil: 85 raise Exception("This exception propagates!") 86 87def test_catch_exception(): 88 """ 89 >>> test_catch_exception() 90 This is executed 91 Exception value 92 This is also executed 93 """ 94 try: 95 with nogil: 96 with gil: 97 print "This is executed" 98 raise Exception("Exception value") 99 print "This is not executed" 100 puts("This is also not executed") 101 except Exception, e: 102 print e 103 print "This is also executed" 104 105def test_try_finally_and_outer_except(): 106 """ 107 >>> test_try_finally_and_outer_except() 108 First finally clause 109 Second finally clause 110 Caught: Some Exception 111 End of function 112 """ 113 try: 114 115 with nogil: 116 with gil: 117 try: 118 with nogil: 119 with gil: 120 try: 121 raise Exception("Some Exception") 122 finally: 123 puts("First finally clause") 124 finally: 125 puts("Second finally clause") 126 puts("This is not executed") 127 128 except Exception, e: 129 print "Caught:", e 130 131 print "End of function" 132 133def test_restore_exception(): 134 """ 135 >>> test_restore_exception() 136 Traceback (most recent call last): 137 ... 138 Exception: Override the raised exception 139 """ 140 with nogil: 141 with gil: 142 try: 143 with nogil: 144 with gil: 145 raise Exception("Override this please") 146 finally: 147 raise Exception("Override the raised exception") 148 149### DISABLED: this cannot work with flow control analysis 150## 151## def test_declared_variables(): 152## """ 153## >>> test_declared_variables() 154## None 155## None 156## ['s', 'p', 'a', 'm'] 157## ['s', 'p', 'a', 'm'] 158## """ 159## cdef object somevar 160## 161## print somevar 162## 163## with nogil: 164## with gil: 165## print somevar 166## somevar = list("spam") 167## print somevar 168## 169## print somevar 170 171### DISABLED: this cannot work with flow control analysis 172## 173## def test_undeclared_variables(): 174## """ 175## >>> test_undeclared_variables() 176## None 177## None 178## ['s', 'p', 'a', 'm'] 179## ['s', 'p', 'a', 'm'] 180## """ 181## print somevar 182## with nogil: 183## with gil: 184## print somevar 185## somevar = list("spam") 186## print somevar 187## 188## print somevar 189 190def test_loops_and_boxing(): 191 """ 192 >>> test_loops_and_boxing() 193 spamham 194 h 195 a 196 m 197 done looping 198 """ 199 cdef char c, *string = "spamham" 200 201 with nogil: 202 with gil: 203 print string.decode('ascii') 204 for c in string[4:]: 205 print "%c" % c 206 else: 207 print "done looping" 208 209cdef class SomeExtClass(object): 210 cdef int some_attribute 211 212@cython.infer_types(True) 213def test_infer_types(): 214 """ 215 >>> test_infer_types() 216 10 217 """ 218 with nogil: 219 with gil: 220 obj = SomeExtClass() 221 obj.some_attribute = 10 222 223 print obj.some_attribute 224 225def test_closure(): 226 """ 227 >>> test_closure() 228 Traceback (most recent call last): 229 ... 230 Exception: {'twinkle': 'little star'} 231 """ 232 a = dict(twinkle='little star') 233 234 def inner_function(): 235 with nogil: 236 with gil: 237 raise Exception(a) 238 239 with nogil: 240 with gil: 241 inner_function() 242 243 raise Exception("This should not be raised!") 244 245cpdef test_cpdef(): 246 """ 247 >>> test_cpdef() 248 Seems to work! 249 Or does it? 250 """ 251 with nogil: 252 with gil: 253 print "Seems to work!" 254 puts("Or does it?") 255 256 257# Now test some cdef functions with different return types 258 259cdef void void_nogil_ignore_exception() nogil: 260 with gil: 261 raise ExceptionWithMsg("This is swallowed") 262 263 puts("unreachable") 264 with gil: 265 print "unreachable" 266 267cdef void void_nogil_nested_gil() nogil: 268 with gil: 269 with nogil: 270 with gil: 271 print 'Inner gil section' 272 puts("nogil section") 273 raise ExceptionWithMsg("Swallow this") 274 puts("Don't print this") 275 276def test_nogil_void_funcs_with_gil(): 277 """ 278 >>> redirect_stderr(test_nogil_void_funcs_with_gil) # doctest: +ELLIPSIS 279 with_gil.ExceptionWithMsg: This is swallowed 280 Exception... ignored... 281 Inner gil section 282 nogil section 283 ... 284 Exception... ignored... 285 """ 286 void_nogil_ignore_exception() 287 void_nogil_nested_gil() 288 289def test_nogil_void_funcs_with_nogil(): 290 """ 291 >>> redirect_stderr(test_nogil_void_funcs_with_nogil) # doctest: +ELLIPSIS 292 with_gil.ExceptionWithMsg: This is swallowed 293 Exception... ignored... 294 Inner gil section 295 nogil section 296 with_gil.ExceptionWithMsg: Swallow this 297 Exception... ignored... 298 """ 299 with nogil: 300 void_nogil_ignore_exception() 301 void_nogil_nested_gil() 302 303 304cdef PyObject *nogil_propagate_exception() nogil except NULL: 305 with nogil: 306 with gil: 307 raise Exception("This exception propagates!") 308 return <PyObject *> 1 309 310def test_nogil_propagate_exception(): 311 """ 312 >>> test_nogil_propagate_exception() 313 Traceback (most recent call last): 314 ... 315 Exception: This exception propagates! 316 """ 317 nogil_propagate_exception() 318 319 320cdef with_gil_raise() with gil: 321 raise Exception("This exception propagates!") 322 323def test_release_gil_call_gil_func(): 324 """ 325 >>> test_release_gil_call_gil_func() 326 Traceback (most recent call last): 327 ... 328 Exception: This exception propagates! 329 """ 330 with nogil: 331 with gil: 332 with_gil_raise() 333 334 335# Test try/finally in nogil blocks 336 337def test_try_finally_in_nogil(): 338 """ 339 >>> test_try_finally_in_nogil() 340 Traceback (most recent call last): 341 ... 342 Exception: Override exception! 343 """ 344 with nogil: 345 try: 346 with gil: 347 raise Exception("This will be overridden") 348 finally: 349 with gil: 350 raise Exception("Override exception!") 351 352 with gil: 353 raise Exception("This code should not be executed!") 354 355def test_nogil_try_finally_no_exception(): 356 """ 357 >>> test_nogil_try_finally_no_exception() 358 first nogil try 359 nogil try gil 360 second nogil try 361 nogil finally 362 ------ 363 First with gil block 364 Second with gil block 365 finally block 366 """ 367 with nogil: 368 try: 369 puts("first nogil try") 370 with gil: 371 print "nogil try gil" 372 puts("second nogil try") 373 finally: 374 puts("nogil finally") 375 376 print '------' 377 378 with nogil: 379 try: 380 with gil: 381 print "First with gil block" 382 383 with gil: 384 print "Second with gil block" 385 finally: 386 puts("finally block") 387 388def test_nogil_try_finally_propagate_exception(): 389 """ 390 >>> test_nogil_try_finally_propagate_exception() 391 Execute finally clause 392 Propagate this! 393 """ 394 try: 395 with nogil: 396 try: 397 with gil: 398 raise Exception("Propagate this!") 399 with gil: 400 raise Exception("Don't reach this section!") 401 finally: 402 puts("Execute finally clause") 403 except Exception, e: 404 print e 405 406def test_nogil_try_finally_return_in_with_gil(x): 407 """ 408 >>> test_nogil_try_finally_return_in_with_gil(10) 409 print me 410 10 411 """ 412 with nogil: 413 try: 414 with gil: 415 raise Exception("Swallow me!") 416 finally: 417 with gil: 418 print "print me" 419 return x 420 421 print "I am not executed" 422 423cdef void nogil_try_finally_return() nogil: 424 try: 425 with gil: 426 raise Exception("I am swallowed in nogil code... right?") 427 finally: 428 with gil: 429 print "print me first" 430 431 return 432 433 with gil: 434 print "I am not executed" 435 436def test_nogil_try_finally_return(): 437 """ 438 >>> test_nogil_try_finally_return() 439 print me first 440 """ 441 with nogil: 442 nogil_try_finally_return() 443 444cdef int error_func() except -1 with gil: 445 raise Exception("propagate this") 446 447def test_nogil_try_finally_error_label(): 448 """ 449 >>> test_nogil_try_finally_error_label() 450 print me first 451 propagate this 452 """ 453 try: 454 with nogil: 455 try: 456 error_func() 457 finally: 458 with gil: print "print me first" 459 except Exception, e: 460 print e.args[0] 461 462 463cdef void test_timing_callback() with gil: 464 pass 465 466def test_timing(long N): 467 """ 468 >>> sorted([test_timing(10000) for _ in range(10)]) # doctest: +ELLIPSIS 469 [...] 470 """ 471 import time 472 t = time.time() 473 with nogil: 474 for _ in range(N): 475 test_timing_callback() 476 return time.time() - t 477