@@ -377,6 +377,40 @@ These transitions are accomplished using two function decorators:
377
377
poorly-timed :exc: `KeyboardInterrupt ` could leave the lock in an
378
378
inconsistent state and cause a deadlock.
379
379
380
+ Since KeyboardInterrupt protection is tracked per code object, any attempt to
381
+ conditionally protect the same block of code in different ways is unlikely to behave
382
+ how you expect. If you try to conditionally protect a closure, it will be
383
+ unconditionally protected instead::
384
+
385
+ def example(protect: bool) -> bool:
386
+ def inner() -> bool:
387
+ return trio.lowlevel.currently_ki_protected()
388
+ if protect:
389
+ inner = trio.lowlevel.enable_ki_protection(inner)
390
+ return inner()
391
+
392
+ assert example(False) == False
393
+ assert example(True) == True # once protected ...
394
+ assert example(False) == True # ... always protected
395
+
396
+ If you really need conditional protection, you can achieve it by giving each
397
+ KI-protected instance of the closure its own code object::
398
+
399
+ def example(protect: bool) -> bool:
400
+ def inner() -> bool:
401
+ return trio.lowlevel.currently_ki_protected()
402
+ if protect:
403
+ inner.__code__ = inner.__code__.replace()
404
+ inner = trio.lowlevel.enable_ki_protection(inner)
405
+ return inner()
406
+
407
+ assert example(False) == False
408
+ assert example(True) == True
409
+ assert example(False) == False
410
+
411
+ (This isn't done by default because it carries some memory overhead and reduces
412
+ the potential for specializing optimizations in recent versions of CPython.)
413
+
380
414
.. autofunction :: currently_ki_protected
381
415
382
416
0 commit comments