Merge pull request #130 from njsmith/restrict-ki-to-checkpoints · python-trio/trio@8fee2bc (original) (raw)

`@@ -1040,7 +1040,8 @@ def current_instruments(self):

`

1040

1040

`# run

`

1041

1041

`################################################################

`

1042

1042

``

1043

``

`-

def run(async_fn, *args, clock=None, instruments=[]):

`

``

1043

`+

def run(async_fn, *args, clock=None, instruments=[],

`

``

1044

`+

restrict_keyboard_interrupt_to_checkpoints=False):

`

1044

1045

`"""Run a trio-flavored async function, and return the result.

`

1045

1046

``

1046

1047

` Calling::

`

`@@ -1059,23 +1060,51 @@ def run(async_fn, *args, clock=None, instruments=[]):

`

1059

1060

``

1060

1061

` Args:

`

1061

1062

` async_fn: An async function.

`

``

1063

+

1062

1064

` args: Positional arguments to be passed to async_fn. If you need to

`

1063

1065

`` pass keyword arguments, then use :func:functools.partial.

``

``

1066

+

1064

1067

``` clock: None to use the default system-specific monotonic clock;


`1065`

`1068`

``  otherwise, an object implementing the :class:`trio.abc.Clock`

``

`1066`

`1069`

``  interface, like (for example) a :class:`trio.testing.MockClock`

``

`1067`

`1070`

` instance.

`

``

`1071`

`+`

`1068`

`1072`

``  instruments (list of :class:`trio.abc.Instrument` objects): Any

``

`1069`

`1073`

` instrumentation you want to apply to this run. This can also be

`

`1070`

`1074`

``  modified during the run; see :ref:`instrumentation`.

``

`1071`

`1075`

``

``

`1076`

`+

restrict_keyboard_interrupt_to_checkpoints (bool): What happens if the

`

``

`1077`

`` +

user hits control-C while :func:`run` is running? If this argument

``

``

`1078`

`+

is False (the default), then you get the standard Python behavior: a

`

``

`1079`

`` +

:exc:`KeyboardInterrupt` exception will immediately interrupt

``

``

`1080`

`+

whatever task is running (or if no task is running, then trio will

`

``

`1081`

`+

wake up a task to be interrupted). Alternatively, if you set this

`

``

`1082`

`` +

argument to True, then :exc:`KeyboardInterrupt` delivery will be

``

``

`1083`

`` +

delayed: it will be *only* be raised at :ref:`checkpoints

``

``

`1084`

`` +

<checkpoints>`, like a :exc:`Cancelled` exception.

``

``

`1085`

`+`

``

`1086`

`+

The default behavior is nice because it means that even if you

`

``

`1087`

`+

accidentally write an infinite loop that never executes any

`

``

`1088`

`+

checkpoints, then you can still break out of it using control-C. The

`

``

`1089`

`+

the alternative behavior is nice if you're paranoid about a

`

``

`1090`

`` +

:exc:`KeyboardInterrupt` at just the wrong place leaving your

``

``

`1091`

`+

program in an inconsistent state, because it means that you only

`

``

`1092`

`` +

have to worry about :exc:`KeyboardInterrupt` at the exact same

``

``

`1093`

`` +

places where you already have to worry about :exc:`Cancelled`.

``

``

`1094`

`+`

``

`1095`

`+

This setting has no effect if your program has registered a custom

`

``

`1096`

`` +

SIGINT handler, or if :func:`run` is called from anywhere but the

``

``

`1097`

`+

main thread (this is a Python limitation), or if you use

`

``

`1098`

`` +

:func:`catch_signals` to catch SIGINT.

``

``

`1099`

`+`

`1072`

`1100`

` Returns:

`

`1073`

`1101`

```  Whatever ``async_fn`` returns.

1074

1102

``

1075

1103

` Raises:

`

1076

1104

` TrioInternalError: if an unexpected error is encountered inside trio's

`

1077

1105

`` internal machinery. This is a bug and you should `let us know

``

1078

1106

`` https://github.com/python-trio/trio/issues`__.

``

``

1107

+

1079

1108

``` Anything else: if async_fn raises an exception, then :func:run

```

1080

1109

` propagates it.

`

1081

1110

``

`@@ -1114,7 +1143,8 @@ def run(async_fn, *args, clock=None, instruments=[]):

`

1114

1143

`# where KeyboardInterrupt would be allowed and converted into an

`

1115

1144

`# TrioInternalError:

`

1116

1145

`try:

`

1117

``

`-

with ki_manager(runner.deliver_ki):

`

``

1146

`+

with ki_manager(

`

``

1147

`+

runner.deliver_ki, restrict_keyboard_interrupt_to_checkpoints):

`

1118

1148

`try:

`

1119

1149

`with closing(runner):

`

1120

1150

`# The main reason this is split off into its own function

`