Skip to content

Commit

Permalink
Merge pull request #918 from tacaswell/doc/exceptions
Browse files Browse the repository at this point in the history
DOC: minor edits to documentation about exception handling
  • Loading branch information
prjemian authored Feb 9, 2024
2 parents 9c0a0ee + d7cdfdf commit 883f82c
Showing 1 changed file with 17 additions and 3 deletions.
20 changes: 17 additions & 3 deletions docs/source/examples/ho_contingency.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@
"`RE.halt()` | Do not perform cleanup — just stop.\n",
"`RE.state` | Show the RunEngine state. Check if ‘paused’ or ‘idle’.\n",
"\n",
"\n",
"If the RE is not responding to `^C`, if you hit it 10 times rapidly it will return the prompt, however the `RE` will be\n",
"left in an invalid state with no graceful recovery possible. This should be used as a last resort. If the `RE` has become hung\n",
"that is likly a bug in one of the ophyd objects methods or the plan.\n",
"\n",
"### Programmatic Interruption\n",
"\n",
"There are two ways for a program to interrupt the `RunEngine`: [suspenders](#suspenders) and [exceptions](#exceptions).\n",
Expand Down Expand Up @@ -296,13 +301,22 @@
"source": [
"### `try..except..else..finally` in bluesky plans\n",
"\n",
"In `bluesky`, `try..except` is such a common pattern that there are two [_decorator_](https://wiki.python.org/moin/PythonDecorators#What_is_a_Python_Decorator) functions available:\n",
"In `bluesky`, `try..except` is a common pattern, however there is some additional complication due to\n",
"plans being generator co-routines so two [_decorator_](https://wiki.python.org/moin/PythonDecorators#What_is_a_Python_Decorator) functions available:\n",
"\n",
"decorator | synopsis\n",
"--- | ---\n",
"`finalize_decorator` | Simple. Runs the `final_plan` no matter what happens in the decorated plan.\n",
"`contingency_decorator` | Full-featured. Handle each aspect of Python's `try..except..else..finally` clause.\n",
"\n",
"**Exception handling in generator coroutines**\n",
"\n",
"Generator coroutines [expose exception throwing](https://tacaswell.github.io/coroutines-i.html) as a user communication channel. This means\n",
"there is some [in-band encoding](https://youtu.be/iKzOBWOHGFE?si=XAtQKhk3eHboHcL-&t=1011) of Python's control exceptions with the users exceptions. When the `close()` [method](https://docs.python.org/3/reference/expressions.html#generator.close) is called on a generator coroutine, Python will throw a [`GeneratorExit`](https://docs.python.org/3/library/exceptions.html#GeneratorExit) exception into the coroutine. If you catch this exception and try to yield another `Msg`, either explicitly in an `except` block or in a `finally` block, Python will raise a `RuntimeError` at the call site.\n",
"\n",
"If you want to use `try..except..else..finally` directly, you must handle this case. See the source of these decorators for a guide.\n",
"\n",
"\n",
"**More Reading**\n",
"\n",
"- https://realpython.com/primer-on-python-decorators/\n",
Expand Down Expand Up @@ -369,8 +383,6 @@
"try:\n",
" yield from bps.mv(shutter, \"open\")\n",
" yield from bp.count([detector])\n",
"except Exception:\n",
" pass # ignore all exceptions\n",
"finally:\n",
" yield from bps.mv(shutter, \"close\")\n",
"```"
Expand Down Expand Up @@ -512,6 +524,7 @@
"def my_else_plan():\n",
" print(f\"my_else_plan(): plan completed successfully! {shutter.state=}\")\n",
" yield from bps.null()\n",
" yield from bps.null()\n",
"\n",
"def close_the_shutter():\n",
" print(f\"close_the_shutter()\")\n",
Expand Down Expand Up @@ -550,6 +563,7 @@
" yield from bps.null()\n",
"else:\n",
" yield from bps.null()\n",
" yield from bps.null()\n",
"finally:\n",
" yield from bps.mv(shutter, \"close\")\n",
"```"
Expand Down

0 comments on commit 883f82c

Please sign in to comment.