Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOC: minor edits to documentation about exception handling #918

Merged
merged 3 commits into from
Feb 9, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 generator corutine 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 explictily in an `except` block or in a `finally` block Python will raise a `RuntimeError` at the call site.\n",
prjemian marked this conversation as resolved.
Show resolved Hide resolved
"\n",
"If you want to directly use `try..except..else..finally` you must handle this case. See the source of these decorators for a guide.\n",
prjemian marked this conversation as resolved.
Show resolved Hide resolved
"\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